VirtualBox

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

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

BIOS: Try to find the right floppy data rate.

  • Property svn:eol-style set to native
File size: 337.1 KB
Line 
1/////////////////////////////////////////////////////////////////////////
2// $Id: rombios.c,v 1.176 2006/12/30 17:13:17 vruppert Exp $
3/////////////////////////////////////////////////////////////////////////
4//
5// Copyright (C) 2002 MandrakeSoft S.A.
6//
7// MandrakeSoft S.A.
8// 43, rue d'Aboukir
9// 75002 Paris - France
10// http://www.linux-mandrake.com/
11// http://www.mandrakesoft.com/
12//
13// This library is free software; you can redistribute it and/or
14// modify it under the terms of the GNU Lesser General Public
15// License as published by the Free Software Foundation; either
16// version 2 of the License, or (at your option) any later version.
17//
18// This library is distributed in the hope that it will be useful,
19// but WITHOUT ANY WARRANTY; without even the implied warranty of
20// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21// Lesser General Public License for more details.
22//
23// You should have received a copy of the GNU Lesser General Public
24// License along with this library; if not, write to the Free Software
25// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
26
27
28/*
29 * Oracle LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
30 * other than GPL or LGPL is available it will apply instead, Oracle elects to use only
31 * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
32 * a choice of LGPL license versions is made available with the language indicating
33 * that LGPLv2 or any later version may be used, or where a choice of which version
34 * of the LGPL is applied is otherwise unspecified.
35 */
36
37// ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
38
39
40// ROM BIOS compatibility entry points:
41// ===================================
42// $e05b ; POST Entry Point
43// $e2c3 ; NMI Handler Entry Point
44// $e3fe ; INT 13h Fixed Disk Services Entry Point
45// $e401 ; Fixed Disk Parameter Table
46// $e6f2 ; INT 19h Boot Load Service Entry Point
47// $e6f5 ; Configuration Data Table
48// $e729 ; Baud Rate Generator Table
49// $e739 ; INT 14h Serial Communications Service Entry Point
50// $e82e ; INT 16h Keyboard Service Entry Point
51// $e987 ; INT 09h Keyboard Service Entry Point
52// $ec59 ; INT 13h Diskette Service Entry Point
53// $ef57 ; INT 0Eh Diskette Hardware ISR Entry Point
54// $efc7 ; Diskette Controller Parameter Table
55// $efd2 ; INT 17h Printer Service Entry Point
56// $f045 ; INT 10 Functions 0-Fh Entry Point
57// $f065 ; INT 10h Video Support Service Entry Point
58// $f0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
59// $f841 ; INT 12h Memory Size Service Entry Point
60// $f84d ; INT 11h Equipment List Service Entry Point
61// $f859 ; INT 15h System Services Entry Point
62// $fa6e ; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
63// $fe6e ; INT 1Ah Time-of-day Service Entry Point
64// $fea5 ; INT 08h System Timer ISR Entry Point
65// $fef3 ; Initial Interrupt Vector Offsets Loaded by POST
66// $ff53 ; IRET Instruction for Dummy Interrupt Handler
67// $ff54 ; INT 05h Print Screen Service Entry Point
68// $fff0 ; Power-up Entry Point
69// $fff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
70// $fffe ; System Model ID
71
72// NOTES for ATA/ATAPI driver ([email protected])
73// Features
74// - supports up to 4 ATA interfaces
75// - device/geometry detection
76// - 16bits/32bits device access
77// - pchs/lba access
78// - datain/dataout/packet command support
79//
80// NOTES for El-Torito Boot ([email protected])
81// - CD-ROM booting is only available if ATA/ATAPI Driver is available
82// - Current code is only able to boot mono-session cds
83// - Current code can not boot and emulate a hard-disk
84// the bios will panic otherwise
85// - Current code also use memory in EBDA segment.
86// - I used cmos byte 0x3D to store extended information on boot-device
87// - Code has to be modified modified to handle multiple cdrom drives
88// - Here are the cdrom boot failure codes:
89// 1 : no atapi device found
90// 2 : no atapi cdrom found
91// 3 : can not read cd - BRVD
92// 4 : cd is not eltorito (BRVD)
93// 5 : cd is not eltorito (ISO TAG)
94// 6 : cd is not eltorito (ELTORITO TAG)
95// 7 : can not read cd - boot catalog
96// 8 : boot catalog : bad header
97// 9 : boot catalog : bad platform
98// 10 : boot catalog : bad signature
99// 11 : boot catalog : bootable flag not set
100// 12 : can not read cd - boot image
101//
102// ATA driver
103// - EBDA segment.
104// I used memory starting at 0x121 in the segment
105#ifndef VBOX
106// - the translation policy is defined in cmos regs 0x39 & 0x3a
107#endif /* !VBOX */
108//
109// TODO :
110//
111// int74
112// - needs to be reworked. Uses direct [bp] offsets. (?)
113//
114// int13:
115// - f04 (verify sectors) isn't complete (?)
116// - f02/03/04 should set current cyl,etc in BDA (?)
117// - rewrite int13_relocated & clean up int13 entry code
118//
119// NOTES:
120// - NMI access (bit7 of addr written to 70h)
121//
122// ATA driver
123// - should handle the "don't detect" bit (cmos regs 0x3b & 0x3c)
124// - could send the multiple-sector read/write commands
125//
126// El-Torito
127// - Emulate a Hard-disk (currently only diskette can be emulated) see "FIXME ElTorito Harddisk"
128// - Implement remaining int13_cdemu functions (as defined by El-Torito specs)
129// - cdrom drive is hardcoded to ide 0 device 1 in several places. see "FIXME ElTorito Hardcoded"
130// - int13 Fix DL when emulating a cd. In that case DL is decremented before calling real int13.
131// This is ok. But DL should be reincremented afterwards.
132// - Fix all "FIXME ElTorito Various"
133// - should be able to boot any cdrom instead of the first one
134//
135// BCC Bug: find a generic way to handle the bug of #asm after an "if" (fixed in 0.16.7)
136
137#ifdef VBOX
138#include "DevPcBios.h"
139#include <VBox/version.h>
140#endif
141
142#define BX_ROMBIOS32 0
143#define DEBUG_ROMBIOS 0
144
145#define DEBUG_ATA 0
146#define DEBUG_INT13_HD 0
147#define DEBUG_INT13_CD 0
148#define DEBUG_INT13_ET 0
149#define DEBUG_INT13_FL 0
150#define DEBUG_INT15 0
151#define DEBUG_INT16 0
152#define DEBUG_INT1A 0
153#define DEBUG_INT74 0
154#define DEBUG_APM 0
155
156#define BX_CPU 3
157#define BX_USE_PS2_MOUSE 1
158#define BX_CALL_INT15_4F 1
159#define BX_USE_EBDA 1
160#define BX_SUPPORT_FLOPPY 1
161#define BX_FLOPPY_ON_CNT 37 /* 2 seconds */
162#define BX_PCIBIOS 1
163#define BX_APM 1
164
165#define BX_USE_ATADRV 1
166#define BX_ELTORITO_BOOT 1
167
168#define BX_MAX_ATA_INTERFACES 4
169#define BX_MAX_ATA_DEVICES (BX_MAX_ATA_INTERFACES*2)
170
171#define BX_VIRTUAL_PORTS 1 /* normal output to Bochs ports */
172#define BX_DEBUG_SERIAL 0 /* output to COM1 */
173
174 /* model byte 0xFC = AT */
175#define SYS_MODEL_ID 0xFC
176#define SYS_SUBMODEL_ID 0x00
177#define BIOS_REVISION 1
178#define BIOS_CONFIG_TABLE 0xe6f5
179
180#ifndef BIOS_BUILD_DATE
181# define BIOS_BUILD_DATE "06/23/99"
182#endif
183
184 // 1K of base memory used for Extended Bios Data Area (EBDA)
185 // EBDA is used for PS/2 mouse support, and IDE BIOS, etc.
186#define EBDA_SEG 0x9FC0
187#define EBDA_SIZE 1 // In KiB
188#define BASE_MEM_IN_K (640 - EBDA_SIZE)
189
190#define ACPI_DATA_SIZE 0x00010000L
191
192 // Define the application NAME
193#if defined(BX_QEMU)
194# define BX_APPNAME "QEMU"
195#elif defined(PLEX86)
196# define BX_APPNAME "Plex86"
197#else
198# define BX_APPNAME "Bochs"
199#endif
200
201 // Sanity Checks
202#if BX_USE_ATADRV && BX_CPU<3
203# error The ATA/ATAPI Driver can only to be used with a 386+ cpu
204#endif
205#if BX_USE_ATADRV && !BX_USE_EBDA
206# error ATA/ATAPI Driver can only be used if EBDA is available
207#endif
208#if BX_ELTORITO_BOOT && !BX_USE_ATADRV
209# error El-Torito Boot can only be use if ATA/ATAPI Driver is available
210#endif
211#if BX_PCIBIOS && BX_CPU<3
212# error PCI BIOS can only be used with 386+ cpu
213#endif
214#if BX_APM && BX_CPU<3
215# error APM BIOS can only be used with 386+ cpu
216#endif
217
218#if defined(VBOX) && !BX_USE_ATADRV
219# error VBOX requires enabling the ATA/ATAPI driver
220#endif
221
222#ifdef VBOX_WITH_SCSI
223/* Enough for now */
224# define BX_MAX_SCSI_DEVICES 4
225# define BX_MAX_STORAGE_DEVICES (BX_MAX_ATA_DEVICES + BX_MAX_SCSI_DEVICES)
226
227/* A SCSI device starts always at BX_MAX_ATA_DEVICES. */
228# define VBOX_IS_SCSI_DEVICE(device_id) (device_id >= BX_MAX_ATA_DEVICES)
229# define VBOX_GET_SCSI_DEVICE(device_id) (device_id - BX_MAX_ATA_DEVICES)
230#else
231# define BX_MAX_STORAGE_DEVICES BX_MAX_ATA_DEVICES
232#endif
233
234#ifndef VBOX
235#define PANIC_PORT 0x400
236#define PANIC_PORT2 0x401
237#define INFO_PORT 0x402
238#define DEBUG_PORT 0x403
239#else /* VBOX */
240/* Redirect INFO output to backdoor logging port. */
241#define PANIC_PORT 0x400
242#define PANIC_PORT2 0x401
243#define INFO_PORT 0x504
244#define DEBUG_PORT 0x403
245#endif /* VBOX */
246
247// define this if you want to make PCIBIOS working on a specific bridge only
248// undef enables PCIBIOS when at least one PCI device is found
249// i440FX is emulated by Bochs and QEMU
250#define PCI_FIXED_HOST_BRIDGE_1 0x12378086 ;; i440FX PCI bridge
251#define PCI_FIXED_HOST_BRIDGE_2 0x244e8086 ;; ICH9 PCI bridge
252
253// #20 is dec 20
254// #$20 is hex 20 = 32
255// #0x20 is hex 20 = 32
256// LDA #$20
257// JSR $E820
258// LDD .i,S
259// JSR $C682
260// mov al, #$20
261
262// all hex literals should be prefixed with '0x'
263// grep "#[0-9a-fA-F][0-9a-fA-F]" rombios.c
264// no mov SEG-REG, #value, must mov register into seg-reg
265// grep -i "mov[ ]*.s" rombios.c
266
267// This is for compiling with gcc2 and gcc3
268#define ASM_START #asm
269#define ASM_END #endasm
270
271ASM_START
272.rom
273
274.org 0x0000
275
276#if BX_CPU >= 3
277use16 386
278#else
279use16 286
280#endif
281
282MACRO HALT
283 ;; the HALT macro is called with the line number of the HALT call.
284 ;; The line number is then sent to the PANIC_PORT, causing Bochs/Plex
285 ;; to print a BX_PANIC message. This will normally halt the simulation
286 ;; with a message such as "BIOS panic at rombios.c, line 4091".
287 ;; However, users can choose to make panics non-fatal and continue.
288#if BX_VIRTUAL_PORTS
289 mov dx,#PANIC_PORT
290 mov ax,#?1
291 out dx,ax
292#else
293 mov dx,#0x80
294 mov ax,#?1
295 out dx,al
296#endif
297MEND
298
299MACRO JMP_AP
300 db 0xea
301 dw ?2
302 dw ?1
303MEND
304
305MACRO SET_INT_VECTOR
306 mov ax, ?3
307 mov ?1*4, ax
308 mov ax, ?2
309 mov ?1*4+2, ax
310MEND
311
312ASM_END
313
314typedef unsigned char Bit8u;
315typedef unsigned short Bit16u;
316typedef unsigned short bx_bool;
317typedef unsigned long Bit32u;
318
319#if BX_USE_ATADRV
320
321 void memsetb(seg,offset,value,count);
322 void memcpyb(dseg,doffset,sseg,soffset,count);
323 void memcpyd(dseg,doffset,sseg,soffset,count);
324
325 // memset of count bytes
326 void
327 memsetb(seg,offset,value,count)
328 Bit16u seg;
329 Bit16u offset;
330 Bit16u value;
331 Bit16u count;
332 {
333 ASM_START
334 push bp
335 mov bp, sp
336
337 push ax
338 push cx
339 push es
340 push di
341
342 mov cx, 10[bp] ; count
343 test cx, cx
344 je memsetb_end
345 mov ax, 4[bp] ; segment
346 mov es, ax
347 mov ax, 6[bp] ; offset
348 mov di, ax
349 mov al, 8[bp] ; value
350 cld
351 rep
352 stosb
353
354 memsetb_end:
355 pop di
356 pop es
357 pop cx
358 pop ax
359
360 pop bp
361 ASM_END
362 }
363
364#if 0
365 // memcpy of count bytes
366 void
367 memcpyb(dseg,doffset,sseg,soffset,count)
368 Bit16u dseg;
369 Bit16u doffset;
370 Bit16u sseg;
371 Bit16u soffset;
372 Bit16u count;
373 {
374 ASM_START
375 push bp
376 mov bp, sp
377
378 push ax
379 push cx
380 push es
381 push di
382 push ds
383 push si
384
385 mov cx, 12[bp] ; count
386 cmp cx, #0x0000
387 je memcpyb_end
388 mov ax, 4[bp] ; dsegment
389 mov es, ax
390 mov ax, 6[bp] ; doffset
391 mov di, ax
392 mov ax, 8[bp] ; ssegment
393 mov ds, ax
394 mov ax, 10[bp] ; soffset
395 mov si, ax
396 cld
397 rep
398 movsb
399
400 memcpyb_end:
401 pop si
402 pop ds
403 pop di
404 pop es
405 pop cx
406 pop ax
407
408 pop bp
409 ASM_END
410 }
411
412 // memcpy of count dword
413 void
414 memcpyd(dseg,doffset,sseg,soffset,count)
415 Bit16u dseg;
416 Bit16u doffset;
417 Bit16u sseg;
418 Bit16u soffset;
419 Bit16u count;
420 {
421 ASM_START
422 push bp
423 mov bp, sp
424
425 push ax
426 push cx
427 push es
428 push di
429 push ds
430 push si
431
432 mov cx, 12[bp] ; count
433 test cx, cx
434 je memcpyd_end
435 mov ax, 4[bp] ; dsegment
436 mov es, ax
437 mov ax, 6[bp] ; doffset
438 mov di, ax
439 mov ax, 8[bp] ; ssegment
440 mov ds, ax
441 mov ax, 10[bp] ; soffset
442 mov si, ax
443 cld
444 rep
445 movsd
446
447 memcpyd_end:
448 pop si
449 pop ds
450 pop di
451 pop es
452 pop cx
453 pop ax
454
455 pop bp
456 ASM_END
457 }
458#endif
459#endif //BX_USE_ATADRV
460
461 // read_dword and write_dword functions
462 static Bit32u read_dword();
463 static void write_dword();
464
465 Bit32u
466 read_dword(seg, offset)
467 Bit16u seg;
468 Bit16u offset;
469 {
470 ASM_START
471 push bp
472 mov bp, sp
473
474 push bx
475 push ds
476 mov ax, 4[bp] ; segment
477 mov ds, ax
478 mov bx, 6[bp] ; offset
479 mov ax, [bx]
480 add bx, #2
481 mov dx, [bx]
482 ;; ax = return value (word)
483 ;; dx = return value (word)
484 pop ds
485 pop bx
486
487 pop bp
488 ASM_END
489 }
490
491 void
492 write_dword(seg, offset, data)
493 Bit16u seg;
494 Bit16u offset;
495 Bit32u data;
496 {
497 ASM_START
498 push bp
499 mov bp, sp
500
501 push ax
502 push bx
503 push ds
504 mov ax, 4[bp] ; segment
505 mov ds, ax
506 mov bx, 6[bp] ; offset
507 mov ax, 8[bp] ; data word
508 mov [bx], ax ; write data word
509 add bx, #2
510 mov ax, 10[bp] ; data word
511 mov [bx], ax ; write data word
512 pop ds
513 pop bx
514 pop ax
515
516 pop bp
517 ASM_END
518 }
519
520 // Bit32u (unsigned long) and long helper functions
521 ASM_START
522
523 ;; and function
524 landl:
525 landul:
526 SEG SS
527 and ax,[di]
528 SEG SS
529 and bx,2[di]
530 ret
531
532 ;; add function
533 laddl:
534 laddul:
535 SEG SS
536 add ax,[di]
537 SEG SS
538 adc bx,2[di]
539 ret
540
541 ;; cmp function
542 lcmpl:
543 lcmpul:
544 and eax, #0x0000FFFF
545 shl ebx, #16
546 or eax, ebx
547 shr ebx, #16
548 SEG SS
549 cmp eax, dword ptr [di]
550 ret
551
552 ;; sub function
553 lsubl:
554 lsubul:
555 SEG SS
556 sub ax,[di]
557 SEG SS
558 sbb bx,2[di]
559 ret
560
561 ;; mul function
562 lmull:
563 lmulul:
564 and eax, #0x0000FFFF
565 shl ebx, #16
566 or eax, ebx
567 SEG SS
568 mul eax, dword ptr [di]
569 mov ebx, eax
570 shr ebx, #16
571 ret
572
573 ;; dec function
574 ldecl:
575 ldecul:
576 SEG SS
577 dec dword ptr [bx]
578 ret
579
580 ;; or function
581 lorl:
582 lorul:
583 SEG SS
584 or ax,[di]
585 SEG SS
586 or bx,2[di]
587 ret
588
589 ;; inc function
590 lincl:
591 lincul:
592 SEG SS
593 inc dword ptr [bx]
594 ret
595
596 ;; tst function
597 ltstl:
598 ltstul:
599 and eax, #0x0000FFFF
600 shl ebx, #16
601 or eax, ebx
602 shr ebx, #16
603 test eax, eax
604 ret
605
606 ;; sr function
607 lsrul:
608 mov cx,di
609 jcxz lsr_exit
610 and eax, #0x0000FFFF
611 shl ebx, #16
612 or eax, ebx
613 lsr_loop:
614 shr eax, #1
615 loop lsr_loop
616 mov ebx, eax
617 shr ebx, #16
618 lsr_exit:
619 ret
620
621 ;; sl function
622 lsll:
623 lslul:
624 mov cx,di
625 jcxz lsl_exit
626 and eax, #0x0000FFFF
627 shl ebx, #16
628 or eax, ebx
629 lsl_loop:
630 shl eax, #1
631 loop lsl_loop
632 mov ebx, eax
633 shr ebx, #16
634 lsl_exit:
635 ret
636
637 idiv_:
638 cwd
639 idiv bx
640 ret
641
642 idiv_u:
643 xor dx,dx
644 div bx
645 ret
646
647 ldivul:
648 and eax, #0x0000FFFF
649 shl ebx, #16
650 or eax, ebx
651 xor edx, edx
652 SEG SS
653 mov bx, 2[di]
654 shl ebx, #16
655 SEG SS
656 mov bx, [di]
657 div ebx
658 mov ebx, eax
659 shr ebx, #16
660 ret
661
662 ASM_END
663
664// for access to RAM area which is used by interrupt vectors
665// and BIOS Data Area
666
667typedef struct {
668 unsigned char filler1[0x400];
669 unsigned char filler2[0x6c];
670 Bit16u ticks_low;
671 Bit16u ticks_high;
672 Bit8u midnight_flag;
673 } bios_data_t;
674
675#define BiosData ((bios_data_t *) 0)
676
677#if BX_USE_ATADRV
678 typedef struct {
679 Bit16u heads; // # heads
680 Bit16u cylinders; // # cylinders
681 Bit16u spt; // # sectors / track
682 } chs_t;
683
684 // DPTE definition
685 typedef struct {
686 Bit16u iobase1;
687 Bit16u iobase2;
688 Bit8u prefix;
689 Bit8u unused;
690 Bit8u irq;
691 Bit8u blkcount;
692 Bit8u dma;
693 Bit8u pio;
694 Bit16u options;
695 Bit16u reserved;
696 Bit8u revision;
697 Bit8u checksum;
698 } dpte_t;
699
700 typedef struct {
701 Bit8u iface; // ISA or PCI
702 Bit16u iobase1; // IO Base 1
703 Bit16u iobase2; // IO Base 2
704 Bit8u irq; // IRQ
705 } ata_channel_t;
706
707 typedef struct {
708 Bit8u type; // Detected type of ata (ata/atapi/none/unknown/scsi)
709 Bit8u device; // Detected type of attached devices (hd/cd/none)
710 Bit8u removable; // Removable device flag
711 Bit8u lock; // Locks for removable devices
712 Bit8u mode; // transfer mode : PIO 16/32 bits - IRQ - ISADMA - PCIDMA
713 Bit16u blksize; // block size
714
715 Bit8u translation; // type of translation
716 chs_t lchs; // Logical CHS
717 chs_t pchs; // Physical CHS
718
719 Bit32u sectors; // Total sectors count
720 } ata_device_t;
721
722 typedef struct {
723 // ATA channels info
724 ata_channel_t channels[BX_MAX_ATA_INTERFACES];
725
726 // ATA devices info
727 ata_device_t devices[BX_MAX_ATA_DEVICES];
728 //
729 // map between (bios hd id - 0x80) and ata channels and scsi disks.
730 Bit8u hdcount, hdidmap[BX_MAX_STORAGE_DEVICES];
731
732 // map between (bios cd id - 0xE0) and ata channels
733 Bit8u cdcount, cdidmap[BX_MAX_STORAGE_DEVICES];
734
735 // Buffer for DPTE table
736 dpte_t dpte;
737
738 // Count of transferred sectors and bytes
739 Bit16u trsfsectors;
740 Bit32u trsfbytes;
741
742 } ata_t;
743
744#if BX_ELTORITO_BOOT
745 // ElTorito Device Emulation data
746 typedef struct {
747 Bit8u active;
748 Bit8u media;
749 Bit8u emulated_drive;
750 Bit8u controller_index;
751 Bit16u device_spec;
752 Bit32u ilba;
753 Bit16u buffer_segment;
754 Bit16u load_segment;
755 Bit16u sector_count;
756
757 // Virtual device
758 chs_t vdevice;
759 } cdemu_t;
760#endif // BX_ELTORITO_BOOT
761
762#ifdef VBOX_WITH_SCSI
763 typedef struct {
764 // I/O port this device is attached to.
765 Bit16u io_base;
766 // Target Id.
767 Bit8u target_id;
768 // SCSI devices info
769 ata_device_t device_info;
770 } scsi_device_t;
771
772 typedef struct {
773 // SCSi device info
774 scsi_device_t devices[BX_MAX_SCSI_DEVICES];
775 // Number of scsi disks.
776 Bit8u hdcount;
777 } scsi_t;
778#endif
779
780 // for access to EBDA area
781 // The EBDA structure should conform to
782 // http://www.frontiernet.net/~fys/rombios.htm document
783 // I made the ata and cdemu structs begin at 0x121 in the EBDA seg
784 typedef struct {
785 unsigned char filler1[0x3D];
786
787 // FDPT - Can be split into data members if needed
788 unsigned char fdpt0[0x10];
789 unsigned char fdpt1[0x10];
790
791 unsigned char filler2[0xC4];
792
793 // ATA Driver data
794 ata_t ata;
795
796#if BX_ELTORITO_BOOT
797 // El Torito Emulation data
798 cdemu_t cdemu;
799#endif // BX_ELTORITO_BOOT
800
801#ifdef VBOX
802
803#ifdef VBOX_WITH_SCSI
804 // SCSI Driver data
805 scsi_t scsi;
806# endif
807
808 unsigned char uForceBootDrive;
809 unsigned char uForceBootDevice;
810#endif /* VBOX */
811
812 } ebda_data_t;
813
814#ifdef VBOX
815 // the last 16 bytes of the EBDA segment are used for the MPS floating
816 // pointer structure (only if an IOAPIC is present)
817#endif
818
819 #define EbdaData ((ebda_data_t *) 0)
820
821 // for access to the int13ext structure
822 typedef struct {
823 Bit8u size;
824 Bit8u reserved;
825 Bit16u count;
826 Bit16u offset;
827 Bit16u segment;
828 Bit32u lba1;
829 Bit32u lba2;
830 } int13ext_t;
831
832 #define Int13Ext ((int13ext_t *) 0)
833
834 // Disk Physical Table definition
835 typedef struct {
836 Bit16u size;
837 Bit16u infos;
838 Bit32u cylinders;
839 Bit32u heads;
840 Bit32u spt;
841 Bit32u sector_count1;
842 Bit32u sector_count2;
843 Bit16u blksize;
844 Bit16u dpte_offset;
845 Bit16u dpte_segment;
846 Bit16u key;
847 Bit8u dpi_length;
848 Bit8u reserved1;
849 Bit16u reserved2;
850 Bit8u host_bus[4];
851 Bit8u iface_type[8];
852 Bit8u iface_path[8];
853 Bit8u device_path[8];
854 Bit8u reserved3;
855 Bit8u checksum;
856 } dpt_t;
857
858 #define Int13DPT ((dpt_t *) 0)
859
860#endif // BX_USE_ATADRV
861
862typedef struct {
863 union {
864 struct {
865 Bit16u di, si, bp, sp;
866 Bit16u bx, dx, cx, ax;
867 } r16;
868 struct {
869 Bit16u filler[4];
870 Bit8u bl, bh, dl, dh, cl, ch, al, ah;
871 } r8;
872 } u;
873 } pusha_regs_t;
874
875typedef struct {
876 union {
877 struct {
878 Bit32u edi, esi, ebp, esp;
879 Bit32u ebx, edx, ecx, eax;
880 } r32;
881 struct {
882 Bit16u di, filler1, si, filler2, bp, filler3, sp, filler4;
883 Bit16u bx, filler5, dx, filler6, cx, filler7, ax, filler8;
884 } r16;
885 struct {
886 Bit32u filler[4];
887 Bit8u bl, bh;
888 Bit16u filler1;
889 Bit8u dl, dh;
890 Bit16u filler2;
891 Bit8u cl, ch;
892 Bit16u filler3;
893 Bit8u al, ah;
894 Bit16u filler4;
895 } r8;
896 } u;
897} pushad_regs_t;
898
899typedef struct {
900 union {
901 struct {
902 Bit16u flags;
903 } r16;
904 struct {
905 Bit8u flagsl;
906 Bit8u flagsh;
907 } r8;
908 } u;
909 } flags_t;
910
911#define SetCF(x) x.u.r8.flagsl |= 0x01
912#define SetZF(x) x.u.r8.flagsl |= 0x40
913#define ClearCF(x) x.u.r8.flagsl &= 0xfe
914#define ClearZF(x) x.u.r8.flagsl &= 0xbf
915#define GetCF(x) (x.u.r8.flagsl & 0x01)
916
917typedef struct {
918 Bit16u ip;
919 Bit16u cs;
920 flags_t flags;
921 } iret_addr_t;
922
923
924
925static Bit8u inb();
926static Bit8u inb_cmos();
927static void outb();
928static void outb_cmos();
929static Bit16u inw();
930static void outw();
931static void init_rtc();
932static bx_bool rtc_updating();
933
934static Bit8u read_byte();
935static Bit16u read_word();
936static void write_byte();
937static void write_word();
938static void bios_printf();
939
940static Bit8u send_to_mouse_ctrl();
941static Bit8u get_mouse_data();
942static void set_kbd_command_byte();
943
944static void int09_function();
945static void int13_harddisk();
946static void int13_cdrom();
947static void int13_cdemu();
948static void int13_eltorito();
949static void int13_diskette_function();
950static void int14_function();
951static void int15_function();
952static void int16_function();
953static void int17_function();
954static Bit32u int19_function();
955static void int1a_function();
956static void int70_function();
957static void int74_function();
958static void dummy_isr_function();
959static Bit16u get_CS();
960static Bit16u get_SS();
961static unsigned int enqueue_key();
962static unsigned int dequeue_key();
963static void get_hd_geometry();
964static void set_diskette_ret_status();
965static void set_diskette_current_cyl();
966static void determine_floppy_media();
967static bx_bool floppy_drive_exists();
968static bx_bool floppy_drive_recal();
969static bx_bool floppy_media_known();
970static bx_bool floppy_media_sense();
971static bx_bool set_enable_a20();
972static void debugger_on();
973static void debugger_off();
974static void keyboard_init();
975static void keyboard_panic();
976static void shutdown_status_panic();
977static void nmi_handler_msg();
978
979static void print_bios_banner();
980static void print_boot_device();
981static void print_boot_failure();
982static void print_cdromboot_failure();
983
984# if BX_USE_ATADRV
985
986// ATA / ATAPI driver
987void ata_init();
988void ata_detect();
989void ata_reset();
990
991Bit16u ata_cmd_non_data();
992Bit16u ata_cmd_data_in();
993Bit16u ata_cmd_data_out();
994Bit16u ata_cmd_packet();
995
996Bit16u atapi_get_sense();
997Bit16u atapi_is_ready();
998Bit16u atapi_is_cdrom();
999
1000#endif // BX_USE_ATADRV
1001
1002#if BX_ELTORITO_BOOT
1003
1004void cdemu_init();
1005Bit8u cdemu_isactive();
1006Bit8u cdemu_emulated_drive();
1007
1008Bit16u cdrom_boot();
1009
1010#endif // BX_ELTORITO_BOOT
1011
1012#ifdef VBOX
1013static char bios_prefix_string[] = "BIOS: ";
1014/* Do not use build timestamps in this string. Otherwise even rebuilding the
1015 * very same code will lead to compare errors when restoring saved state. */
1016static char bios_cvs_version_string[] = "VirtualBox " VBOX_VERSION_STRING;
1017#define BIOS_COPYRIGHT_STRING "Oracle VM VirtualBox BIOS"
1018#else /* !VBOX */
1019static char bios_cvs_version_string[] = "$Revision: 1.176 $ $Date: 2006/12/30 17:13:17 $";
1020
1021#define BIOS_COPYRIGHT_STRING "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team."
1022#endif /* !VBOX */
1023
1024#define BIOS_PRINTF_HALT 1
1025#define BIOS_PRINTF_SCREEN 2
1026#define BIOS_PRINTF_INFO 4
1027#define BIOS_PRINTF_DEBUG 8
1028#define BIOS_PRINTF_ALL (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO)
1029#define BIOS_PRINTF_DEBHALT (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO | BIOS_PRINTF_HALT)
1030
1031#define printf(format, p...) bios_printf(BIOS_PRINTF_SCREEN, format, ##p)
1032
1033// Defines the output macros.
1034// BX_DEBUG goes to INFO port until we can easily choose debug info on a
1035// per-device basis. Debug info are sent only in debug mode
1036#if DEBUG_ROMBIOS
1037# define BX_DEBUG(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
1038#else
1039# define BX_DEBUG(format, p...)
1040#endif
1041#ifdef VBOX
1042#define BX_INFO(format, p...) do { put_str(BIOS_PRINTF_INFO, get_CS(), bios_prefix_string); bios_printf(BIOS_PRINTF_INFO, format, ##p); } while (0)
1043#else /* !VBOX */
1044#define BX_INFO(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
1045#endif /* !VBOX */
1046#define BX_PANIC(format, p...) bios_printf(BIOS_PRINTF_DEBHALT, format, ##p)
1047
1048#if DEBUG_ATA
1049# define BX_DEBUG_ATA(a...) BX_DEBUG(a)
1050#else
1051# define BX_DEBUG_ATA(a...)
1052#endif
1053#if DEBUG_INT13_HD
1054# define BX_DEBUG_INT13_HD(a...) BX_DEBUG(a)
1055#else
1056# define BX_DEBUG_INT13_HD(a...)
1057#endif
1058#if DEBUG_INT13_CD
1059# define BX_DEBUG_INT13_CD(a...) BX_DEBUG(a)
1060#else
1061# define BX_DEBUG_INT13_CD(a...)
1062#endif
1063#if DEBUG_INT13_ET
1064# define BX_DEBUG_INT13_ET(a...) BX_DEBUG(a)
1065#else
1066# define BX_DEBUG_INT13_ET(a...)
1067#endif
1068#if DEBUG_INT13_FL
1069# define BX_DEBUG_INT13_FL(a...) BX_DEBUG(a)
1070#else
1071# define BX_DEBUG_INT13_FL(a...)
1072#endif
1073#if DEBUG_INT15
1074# define BX_DEBUG_INT15(a...) BX_DEBUG(a)
1075#else
1076# define BX_DEBUG_INT15(a...)
1077#endif
1078#if DEBUG_INT16
1079# define BX_DEBUG_INT16(a...) BX_DEBUG(a)
1080#else
1081# define BX_DEBUG_INT16(a...)
1082#endif
1083#if DEBUG_INT1A
1084# define BX_DEBUG_INT1A(a...) BX_DEBUG(a)
1085#else
1086# define BX_DEBUG_INT1A(a...)
1087#endif
1088#if DEBUG_INT74
1089# define BX_DEBUG_INT74(a...) BX_DEBUG(a)
1090#else
1091# define BX_DEBUG_INT74(a...)
1092#endif
1093
1094#define SET_AL(val8) AX = ((AX & 0xff00) | (val8))
1095#define SET_BL(val8) BX = ((BX & 0xff00) | (val8))
1096#define SET_CL(val8) CX = ((CX & 0xff00) | (val8))
1097#define SET_DL(val8) DX = ((DX & 0xff00) | (val8))
1098#define SET_AH(val8) AX = ((AX & 0x00ff) | ((val8) << 8))
1099#define SET_BH(val8) BX = ((BX & 0x00ff) | ((val8) << 8))
1100#define SET_CH(val8) CX = ((CX & 0x00ff) | ((val8) << 8))
1101#define SET_DH(val8) DX = ((DX & 0x00ff) | ((val8) << 8))
1102
1103#define GET_AL() ( AX & 0x00ff )
1104#define GET_BL() ( BX & 0x00ff )
1105#define GET_CL() ( CX & 0x00ff )
1106#define GET_DL() ( DX & 0x00ff )
1107#define GET_AH() ( AX >> 8 )
1108#define GET_BH() ( BX >> 8 )
1109#define GET_CH() ( CX >> 8 )
1110#define GET_DH() ( DX >> 8 )
1111
1112#define GET_ELDL() ( ELDX & 0x00ff )
1113#define GET_ELDH() ( ELDX >> 8 )
1114
1115#define SET_CF() FLAGS |= 0x0001
1116#define CLEAR_CF() FLAGS &= 0xfffe
1117#define GET_CF() (FLAGS & 0x0001)
1118
1119#define SET_ZF() FLAGS |= 0x0040
1120#define CLEAR_ZF() FLAGS &= 0xffbf
1121#define GET_ZF() (FLAGS & 0x0040)
1122
1123#define UNSUPPORTED_FUNCTION 0x86
1124
1125#define none 0
1126#define MAX_SCAN_CODE 0x58
1127
1128static struct {
1129 Bit16u normal;
1130 Bit16u shift;
1131 Bit16u control;
1132 Bit16u alt;
1133 Bit8u lock_flags;
1134 } scan_to_scanascii[MAX_SCAN_CODE + 1] = {
1135 { none, none, none, none, none },
1136 { 0x011b, 0x011b, 0x011b, 0x0100, none }, /* escape */
1137 { 0x0231, 0x0221, none, 0x7800, none }, /* 1! */
1138 { 0x0332, 0x0340, 0x0300, 0x7900, none }, /* 2@ */
1139 { 0x0433, 0x0423, none, 0x7a00, none }, /* 3# */
1140 { 0x0534, 0x0524, none, 0x7b00, none }, /* 4$ */
1141 { 0x0635, 0x0625, none, 0x7c00, none }, /* 5% */
1142 { 0x0736, 0x075e, 0x071e, 0x7d00, none }, /* 6^ */
1143 { 0x0837, 0x0826, none, 0x7e00, none }, /* 7& */
1144 { 0x0938, 0x092a, none, 0x7f00, none }, /* 8* */
1145 { 0x0a39, 0x0a28, none, 0x8000, none }, /* 9( */
1146 { 0x0b30, 0x0b29, none, 0x8100, none }, /* 0) */
1147 { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200, none }, /* -_ */
1148 { 0x0d3d, 0x0d2b, none, 0x8300, none }, /* =+ */
1149 { 0x0e08, 0x0e08, 0x0e7f, none, none }, /* backspace */
1150 { 0x0f09, 0x0f00, none, none, none }, /* tab */
1151 { 0x1071, 0x1051, 0x1011, 0x1000, 0x40 }, /* Q */
1152 { 0x1177, 0x1157, 0x1117, 0x1100, 0x40 }, /* W */
1153 { 0x1265, 0x1245, 0x1205, 0x1200, 0x40 }, /* E */
1154 { 0x1372, 0x1352, 0x1312, 0x1300, 0x40 }, /* R */
1155 { 0x1474, 0x1454, 0x1414, 0x1400, 0x40 }, /* T */
1156 { 0x1579, 0x1559, 0x1519, 0x1500, 0x40 }, /* Y */
1157 { 0x1675, 0x1655, 0x1615, 0x1600, 0x40 }, /* U */
1158 { 0x1769, 0x1749, 0x1709, 0x1700, 0x40 }, /* I */
1159 { 0x186f, 0x184f, 0x180f, 0x1800, 0x40 }, /* O */
1160 { 0x1970, 0x1950, 0x1910, 0x1900, 0x40 }, /* P */
1161 { 0x1a5b, 0x1a7b, 0x1a1b, none, none }, /* [{ */
1162 { 0x1b5d, 0x1b7d, 0x1b1d, none, none }, /* ]} */
1163 { 0x1c0d, 0x1c0d, 0x1c0a, none, none }, /* Enter */
1164 { none, none, none, none, none }, /* L Ctrl */
1165 { 0x1e61, 0x1e41, 0x1e01, 0x1e00, 0x40 }, /* A */
1166 { 0x1f73, 0x1f53, 0x1f13, 0x1f00, 0x40 }, /* S */
1167 { 0x2064, 0x2044, 0x2004, 0x2000, 0x40 }, /* D */
1168 { 0x2166, 0x2146, 0x2106, 0x2100, 0x40 }, /* F */
1169 { 0x2267, 0x2247, 0x2207, 0x2200, 0x40 }, /* G */
1170 { 0x2368, 0x2348, 0x2308, 0x2300, 0x40 }, /* H */
1171 { 0x246a, 0x244a, 0x240a, 0x2400, 0x40 }, /* J */
1172 { 0x256b, 0x254b, 0x250b, 0x2500, 0x40 }, /* K */
1173 { 0x266c, 0x264c, 0x260c, 0x2600, 0x40 }, /* L */
1174 { 0x273b, 0x273a, none, none, none }, /* ;: */
1175 { 0x2827, 0x2822, none, none, none }, /* '" */
1176 { 0x2960, 0x297e, none, none, none }, /* `~ */
1177 { none, none, none, none, none }, /* L shift */
1178 { 0x2b5c, 0x2b7c, 0x2b1c, none, none }, /* |\ */
1179 { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, 0x40 }, /* Z */
1180 { 0x2d78, 0x2d58, 0x2d18, 0x2d00, 0x40 }, /* X */
1181 { 0x2e63, 0x2e43, 0x2e03, 0x2e00, 0x40 }, /* C */
1182 { 0x2f76, 0x2f56, 0x2f16, 0x2f00, 0x40 }, /* V */
1183 { 0x3062, 0x3042, 0x3002, 0x3000, 0x40 }, /* B */
1184 { 0x316e, 0x314e, 0x310e, 0x3100, 0x40 }, /* N */
1185 { 0x326d, 0x324d, 0x320d, 0x3200, 0x40 }, /* M */
1186 { 0x332c, 0x333c, none, none, none }, /* ,< */
1187 { 0x342e, 0x343e, none, none, none }, /* .> */
1188 { 0x352f, 0x353f, none, none, none }, /* /? */
1189 { none, none, none, none, none }, /* R Shift */
1190 { 0x372a, 0x372a, none, none, none }, /* * */
1191 { none, none, none, none, none }, /* L Alt */
1192 { 0x3920, 0x3920, 0x3920, 0x3920, none }, /* space */
1193 { none, none, none, none, none }, /* caps lock */
1194 { 0x3b00, 0x5400, 0x5e00, 0x6800, none }, /* F1 */
1195 { 0x3c00, 0x5500, 0x5f00, 0x6900, none }, /* F2 */
1196 { 0x3d00, 0x5600, 0x6000, 0x6a00, none }, /* F3 */
1197 { 0x3e00, 0x5700, 0x6100, 0x6b00, none }, /* F4 */
1198 { 0x3f00, 0x5800, 0x6200, 0x6c00, none }, /* F5 */
1199 { 0x4000, 0x5900, 0x6300, 0x6d00, none }, /* F6 */
1200 { 0x4100, 0x5a00, 0x6400, 0x6e00, none }, /* F7 */
1201 { 0x4200, 0x5b00, 0x6500, 0x6f00, none }, /* F8 */
1202 { 0x4300, 0x5c00, 0x6600, 0x7000, none }, /* F9 */
1203 { 0x4400, 0x5d00, 0x6700, 0x7100, none }, /* F10 */
1204 { none, none, none, none, none }, /* Num Lock */
1205 { none, none, none, none, none }, /* Scroll Lock */
1206 { 0x4700, 0x4737, 0x7700, none, 0x20 }, /* 7 Home */
1207 { 0x4800, 0x4838, none, none, 0x20 }, /* 8 UP */
1208 { 0x4900, 0x4939, 0x8400, none, 0x20 }, /* 9 PgUp */
1209 { 0x4a2d, 0x4a2d, none, none, none }, /* - */
1210 { 0x4b00, 0x4b34, 0x7300, none, 0x20 }, /* 4 Left */
1211 { 0x4c00, 0x4c35, none, none, 0x20 }, /* 5 */
1212 { 0x4d00, 0x4d36, 0x7400, none, 0x20 }, /* 6 Right */
1213 { 0x4e2b, 0x4e2b, none, none, none }, /* + */
1214 { 0x4f00, 0x4f31, 0x7500, none, 0x20 }, /* 1 End */
1215 { 0x5000, 0x5032, none, none, 0x20 }, /* 2 Down */
1216 { 0x5100, 0x5133, 0x7600, none, 0x20 }, /* 3 PgDn */
1217 { 0x5200, 0x5230, none, none, 0x20 }, /* 0 Ins */
1218 { 0x5300, 0x532e, none, none, 0x20 }, /* Del */
1219 { none, none, none, none, none },
1220 { none, none, none, none, none },
1221 { 0x565c, 0x567c, none, none, none }, /* \| */
1222#ifndef VBOX
1223 { 0x5700, 0x5700, none, none, none }, /* F11 */
1224 { 0x5800, 0x5800, none, none, none } /* F12 */
1225#else
1226 { 0x8500, 0x8700, 0x8900, 0x8b00, none }, /* F11 */
1227 { 0x8600, 0x8800, 0x8a00, 0x8c00, none } /* F12 */
1228#endif
1229 };
1230
1231 Bit8u
1232inb(port)
1233 Bit16u port;
1234{
1235ASM_START
1236 push bp
1237 mov bp, sp
1238
1239 push dx
1240 mov dx, 4[bp]
1241 in al, dx
1242 pop dx
1243
1244 pop bp
1245ASM_END
1246}
1247
1248#if BX_USE_ATADRV
1249 Bit16u
1250inw(port)
1251 Bit16u port;
1252{
1253ASM_START
1254 push bp
1255 mov bp, sp
1256
1257 push dx
1258 mov dx, 4[bp]
1259 in ax, dx
1260 pop dx
1261
1262 pop bp
1263ASM_END
1264}
1265#endif
1266
1267 void
1268outb(port, val)
1269 Bit16u port;
1270 Bit8u val;
1271{
1272ASM_START
1273 push bp
1274 mov bp, sp
1275
1276 push ax
1277 push dx
1278 mov dx, 4[bp]
1279 mov al, 6[bp]
1280 out dx, al
1281 pop dx
1282 pop ax
1283
1284 pop bp
1285ASM_END
1286}
1287
1288#if BX_USE_ATADRV
1289 void
1290outw(port, val)
1291 Bit16u port;
1292 Bit16u val;
1293{
1294ASM_START
1295 push bp
1296 mov bp, sp
1297
1298 push ax
1299 push dx
1300 mov dx, 4[bp]
1301 mov ax, 6[bp]
1302 out dx, ax
1303 pop dx
1304 pop ax
1305
1306 pop bp
1307ASM_END
1308}
1309#endif
1310
1311 void
1312outb_cmos(cmos_reg, val)
1313 Bit8u cmos_reg;
1314 Bit8u val;
1315{
1316ASM_START
1317 push bp
1318 mov bp, sp
1319
1320 mov al, 4[bp] ;; cmos_reg
1321 out 0x70, al
1322 mov al, 6[bp] ;; val
1323 out 0x71, al
1324
1325 pop bp
1326ASM_END
1327}
1328
1329 Bit8u
1330inb_cmos(cmos_reg)
1331 Bit8u cmos_reg;
1332{
1333ASM_START
1334 push bp
1335 mov bp, sp
1336
1337 mov al, 4[bp] ;; cmos_reg
1338 out 0x70, al
1339 in al, 0x71
1340
1341 pop bp
1342ASM_END
1343}
1344
1345 void
1346init_rtc()
1347{
1348 outb_cmos(0x0a, 0x26);
1349 outb_cmos(0x0b, 0x02);
1350 inb_cmos(0x0c);
1351 inb_cmos(0x0d);
1352}
1353
1354 bx_bool
1355rtc_updating()
1356{
1357 // This function checks to see if the update-in-progress bit
1358 // is set in CMOS Status Register A. If not, it returns 0.
1359 // If it is set, it tries to wait until there is a transition
1360 // to 0, and will return 0 if such a transition occurs. A 1
1361 // is returned only after timing out. The maximum period
1362 // that this bit should be set is constrained to 244useconds.
1363 // The count I use below guarantees coverage or more than
1364 // this time, with any reasonable IPS setting.
1365
1366 Bit16u count;
1367
1368 count = 25000;
1369 while (--count != 0) {
1370 if ( (inb_cmos(0x0a) & 0x80) == 0 )
1371 return(0);
1372 }
1373 return(1); // update-in-progress never transitioned to 0
1374}
1375
1376
1377 Bit8u
1378read_byte(seg, offset)
1379 Bit16u seg;
1380 Bit16u offset;
1381{
1382ASM_START
1383 push bp
1384 mov bp, sp
1385
1386 push bx
1387 push ds
1388 mov ax, 4[bp] ; segment
1389 mov ds, ax
1390 mov bx, 6[bp] ; offset
1391 mov al, [bx]
1392 ;; al = return value (byte)
1393 pop ds
1394 pop bx
1395
1396 pop bp
1397ASM_END
1398}
1399
1400 Bit16u
1401read_word(seg, offset)
1402 Bit16u seg;
1403 Bit16u offset;
1404{
1405ASM_START
1406 push bp
1407 mov bp, sp
1408
1409 push bx
1410 push ds
1411 mov ax, 4[bp] ; segment
1412 mov ds, ax
1413 mov bx, 6[bp] ; offset
1414 mov ax, [bx]
1415 ;; ax = return value (word)
1416 pop ds
1417 pop bx
1418
1419 pop bp
1420ASM_END
1421}
1422
1423 void
1424write_byte(seg, offset, data)
1425 Bit16u seg;
1426 Bit16u offset;
1427 Bit8u data;
1428{
1429ASM_START
1430 push bp
1431 mov bp, sp
1432
1433 push ax
1434 push bx
1435 push ds
1436 mov ax, 4[bp] ; segment
1437 mov ds, ax
1438 mov bx, 6[bp] ; offset
1439 mov al, 8[bp] ; data byte
1440 mov [bx], al ; write data byte
1441 pop ds
1442 pop bx
1443 pop ax
1444
1445 pop bp
1446ASM_END
1447}
1448
1449 void
1450write_word(seg, offset, data)
1451 Bit16u seg;
1452 Bit16u offset;
1453 Bit16u data;
1454{
1455ASM_START
1456 push bp
1457 mov bp, sp
1458
1459 push ax
1460 push bx
1461 push ds
1462 mov ax, 4[bp] ; segment
1463 mov ds, ax
1464 mov bx, 6[bp] ; offset
1465 mov ax, 8[bp] ; data word
1466 mov [bx], ax ; write data word
1467 pop ds
1468 pop bx
1469 pop ax
1470
1471 pop bp
1472ASM_END
1473}
1474
1475 Bit16u
1476get_CS()
1477{
1478ASM_START
1479 mov ax, cs
1480ASM_END
1481}
1482
1483 Bit16u
1484get_SS()
1485{
1486ASM_START
1487 mov ax, ss
1488ASM_END
1489}
1490
1491#if BX_DEBUG_SERIAL
1492/* serial debug port*/
1493#define BX_DEBUG_PORT 0x03f8
1494
1495/* data */
1496#define UART_RBR 0x00
1497#define UART_THR 0x00
1498
1499/* control */
1500#define UART_IER 0x01
1501#define UART_IIR 0x02
1502#define UART_FCR 0x02
1503#define UART_LCR 0x03
1504#define UART_MCR 0x04
1505#define UART_DLL 0x00
1506#define UART_DLM 0x01
1507
1508/* status */
1509#define UART_LSR 0x05
1510#define UART_MSR 0x06
1511#define UART_SCR 0x07
1512
1513int uart_can_tx_byte(base_port)
1514 Bit16u base_port;
1515{
1516 return inb(base_port + UART_LSR) & 0x20;
1517}
1518
1519void uart_wait_to_tx_byte(base_port)
1520 Bit16u base_port;
1521{
1522 while (!uart_can_tx_byte(base_port));
1523}
1524
1525void uart_wait_until_sent(base_port)
1526 Bit16u base_port;
1527{
1528 while (!(inb(base_port + UART_LSR) & 0x40));
1529}
1530
1531void uart_tx_byte(base_port, data)
1532 Bit16u base_port;
1533 Bit8u data;
1534{
1535 uart_wait_to_tx_byte(base_port);
1536 outb(base_port + UART_THR, data);
1537 uart_wait_until_sent(base_port);
1538}
1539#endif
1540
1541 void
1542wrch(c)
1543 Bit8u c;
1544{
1545 ASM_START
1546 push bp
1547 mov bp, sp
1548
1549 push bx
1550 mov ah, #0x0e
1551 mov al, 4[bp]
1552 xor bx,bx
1553 int #0x10
1554 pop bx
1555
1556 pop bp
1557 ASM_END
1558}
1559
1560 void
1561send(action, c)
1562 Bit16u action;
1563 Bit8u c;
1564{
1565#if BX_DEBUG_SERIAL
1566 if (c == '\n') uart_tx_byte(BX_DEBUG_PORT, '\r');
1567 uart_tx_byte(BX_DEBUG_PORT, c);
1568#endif
1569#if BX_VIRTUAL_PORTS
1570 if (action & BIOS_PRINTF_DEBUG) outb(DEBUG_PORT, c);
1571 if (action & BIOS_PRINTF_INFO) outb(INFO_PORT, c);
1572#endif
1573 if (action & BIOS_PRINTF_SCREEN) {
1574 if (c == '\n') wrch('\r');
1575 wrch(c);
1576 }
1577}
1578
1579 void
1580put_int(action, val, width, neg)
1581 Bit16u action;
1582 short val, width;
1583 bx_bool neg;
1584{
1585 short nval = val / 10;
1586 if (nval)
1587 put_int(action, nval, width - 1, neg);
1588 else {
1589 while (--width > 0) send(action, ' ');
1590 if (neg) send(action, '-');
1591 }
1592 send(action, val - (nval * 10) + '0');
1593}
1594
1595 void
1596put_uint(action, val, width, neg)
1597 Bit16u action;
1598 unsigned short val;
1599 short width;
1600 bx_bool neg;
1601{
1602 unsigned short nval = val / 10;
1603 if (nval)
1604 put_uint(action, nval, width - 1, neg);
1605 else {
1606 while (--width > 0) send(action, ' ');
1607 if (neg) send(action, '-');
1608 }
1609 send(action, val - (nval * 10) + '0');
1610}
1611
1612 void
1613put_luint(action, val, width, neg)
1614 Bit16u action;
1615 unsigned long val;
1616 short width;
1617 bx_bool neg;
1618{
1619 unsigned long nval = val / 10;
1620 if (nval)
1621 put_luint(action, nval, width - 1, neg);
1622 else {
1623 while (--width > 0) send(action, ' ');
1624 if (neg) send(action, '-');
1625 }
1626 send(action, val - (nval * 10) + '0');
1627}
1628
1629void put_str(action, segment, offset)
1630 Bit16u action;
1631 Bit16u segment;
1632 Bit16u offset;
1633{
1634 Bit8u c;
1635
1636 while (c = read_byte(segment, offset)) {
1637 send(action, c);
1638 offset++;
1639 }
1640}
1641
1642
1643//--------------------------------------------------------------------------
1644// bios_printf()
1645// A compact variable argument printf function.
1646//
1647// Supports %[format_width][length]format
1648// where format can be x,X,u,d,s,S,c
1649// and the optional length modifier is l (ell)
1650//--------------------------------------------------------------------------
1651 void
1652bios_printf(action, s)
1653 Bit16u action;
1654 Bit8u *s;
1655{
1656 Bit8u c, format_char;
1657 bx_bool in_format;
1658 short i;
1659 Bit16u *arg_ptr;
1660 Bit16u arg_seg, arg, nibble, hibyte, shift_count, format_width, hexadd;
1661
1662 arg_ptr = &s;
1663 arg_seg = get_SS();
1664
1665 in_format = 0;
1666 format_width = 0;
1667
1668 if ((action & BIOS_PRINTF_DEBHALT) == BIOS_PRINTF_DEBHALT) {
1669#if BX_VIRTUAL_PORTS
1670 outb(PANIC_PORT2, 0x00);
1671#endif
1672 bios_printf (BIOS_PRINTF_SCREEN, "FATAL: ");
1673 }
1674
1675 while (c = read_byte(get_CS(), s)) {
1676 if ( c == '%' ) {
1677 in_format = 1;
1678 format_width = 0;
1679 }
1680 else if (in_format) {
1681 if ( (c>='0') && (c<='9') ) {
1682 format_width = (format_width * 10) + (c - '0');
1683 }
1684 else {
1685 arg_ptr++; // increment to next arg
1686 arg = read_word(arg_seg, arg_ptr);
1687 if (c == 'x' || c == 'X') {
1688 if (format_width == 0)
1689 format_width = 4;
1690 if (c == 'x')
1691 hexadd = 'a';
1692 else
1693 hexadd = 'A';
1694 for (i=format_width-1; i>=0; i--) {
1695 nibble = (arg >> (4 * i)) & 0x000f;
1696 send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd));
1697 }
1698 }
1699 else if (c == 'u') {
1700 put_uint(action, arg, format_width, 0);
1701 }
1702 else if (c == 'l') {
1703 s++;
1704 c = read_byte(get_CS(), s); /* is it ld,lx,lu? */
1705 arg_ptr++; /* increment to next arg */
1706 hibyte = read_word(arg_seg, arg_ptr);
1707 if (c == 'd') {
1708 if (hibyte & 0x8000)
1709 put_luint(action, 0L-(((Bit32u) hibyte << 16) | arg), format_width-1, 1);
1710 else
1711 put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
1712 }
1713 else if (c == 'u') {
1714 put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
1715 }
1716 else if (c == 'x' || c == 'X')
1717 {
1718 if (format_width == 0)
1719 format_width = 8;
1720 if (c == 'x')
1721 hexadd = 'a';
1722 else
1723 hexadd = 'A';
1724 for (i=format_width-1; i>=0; i--) {
1725 nibble = ((((Bit32u) hibyte <<16) | arg) >> (4 * i)) & 0x000f;
1726 send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd));
1727 }
1728 }
1729 }
1730 else if (c == 'd') {
1731 if (arg & 0x8000)
1732 put_int(action, -arg, format_width - 1, 1);
1733 else
1734 put_int(action, arg, format_width, 0);
1735 }
1736 else if (c == 's') {
1737 put_str(action, get_CS(), arg);
1738 }
1739 else if (c == 'S') {
1740 hibyte = arg;
1741 arg_ptr++;
1742 arg = read_word(arg_seg, arg_ptr);
1743 put_str(action, hibyte, arg);
1744 }
1745 else if (c == 'c') {
1746 send(action, arg);
1747 }
1748 else
1749 BX_PANIC("bios_printf: unknown format\n");
1750 in_format = 0;
1751 }
1752 }
1753 else {
1754 send(action, c);
1755 }
1756 s ++;
1757 }
1758
1759 if (action & BIOS_PRINTF_HALT) {
1760 // freeze in a busy loop.
1761ASM_START
1762 cli
1763 halt2_loop:
1764 hlt
1765 jmp halt2_loop
1766ASM_END
1767 }
1768}
1769
1770//--------------------------------------------------------------------------
1771// keyboard_init
1772//--------------------------------------------------------------------------
1773// this file is based on LinuxBIOS implementation of keyboard.c
1774// could convert to #asm to gain space
1775 void
1776keyboard_init()
1777{
1778 Bit16u max;
1779
1780 /* ------------------- Flush buffers ------------------------*/
1781 /* Wait until buffer is empty */
1782 max=0xffff;
1783 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
1784
1785 /* flush incoming keys */
1786 max=4;
1787 while (--max > 0) {
1788 outb(0x80, 0x00);
1789 if (inb(0x64) & 0x01) {
1790 inb(0x60);
1791 max = 4;
1792 }
1793 }
1794
1795 // Due to timer issues, and if the IPS setting is > 15000000,
1796 // the incoming keys might not be flushed here. That will
1797 // cause a panic a few lines below. See sourceforge bug report :
1798 // [ 642031 ] FATAL: Keyboard RESET error:993
1799
1800 /* ------------------- controller side ----------------------*/
1801 /* send cmd = 0xAA, self test 8042 */
1802 outb(0x64, 0xaa);
1803
1804 /* Wait until buffer is empty */
1805 max=0xffff;
1806 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
1807 if (max==0x0) keyboard_panic(00);
1808
1809 /* Wait for data */
1810 max=0xffff;
1811 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x01);
1812 if (max==0x0) keyboard_panic(01);
1813
1814 /* read self-test result, 0x55 should be returned from 0x60 */
1815 if ((inb(0x60) != 0x55)){
1816 keyboard_panic(991);
1817 }
1818
1819 /* send cmd = 0xAB, keyboard interface test */
1820 outb(0x64,0xab);
1821
1822 /* Wait until buffer is empty */
1823 max=0xffff;
1824 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x10);
1825 if (max==0x0) keyboard_panic(10);
1826
1827 /* Wait for data */
1828 max=0xffff;
1829 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x11);
1830 if (max==0x0) keyboard_panic(11);
1831
1832 /* read keyboard interface test result, */
1833 /* 0x00 should be returned form 0x60 */
1834 if ((inb(0x60) != 0x00)) {
1835 keyboard_panic(992);
1836 }
1837
1838 /* Enable Keyboard clock */
1839 outb(0x64,0xae);
1840 outb(0x64,0xa8);
1841
1842 /* ------------------- keyboard side ------------------------*/
1843 /* reset keyboard and self test (keyboard side) */
1844 outb(0x60, 0xff);
1845
1846 /* Wait until buffer is empty */
1847 max=0xffff;
1848 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x20);
1849 if (max==0x0) keyboard_panic(20);
1850
1851 /* Wait for data */
1852 max=0xffff;
1853 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x21);
1854 if (max==0x0) keyboard_panic(21);
1855
1856 /* keyboard should return ACK */
1857 if ((inb(0x60) != 0xfa)) {
1858 keyboard_panic(993);
1859 }
1860
1861 /* Wait for data */
1862 max=0xffff;
1863 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x31);
1864 if (max==0x0) keyboard_panic(31);
1865
1866 if ((inb(0x60) != 0xaa)) {
1867 keyboard_panic(994);
1868 }
1869
1870 /* Disable keyboard */
1871 outb(0x60, 0xf5);
1872
1873 /* Wait until buffer is empty */
1874 max=0xffff;
1875 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x40);
1876 if (max==0x0) keyboard_panic(40);
1877
1878 /* Wait for data */
1879 max=0xffff;
1880 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x41);
1881 if (max==0x0) keyboard_panic(41);
1882
1883 /* keyboard should return ACK */
1884 if ((inb(0x60) != 0xfa)) {
1885 keyboard_panic(995);
1886 }
1887
1888 /* Write Keyboard Mode */
1889 outb(0x64, 0x60);
1890
1891 /* Wait until buffer is empty */
1892 max=0xffff;
1893 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x50);
1894 if (max==0x0) keyboard_panic(50);
1895
1896 /* send cmd: scan code convert, disable mouse, enable IRQ 1 */
1897 outb(0x60, 0x65);
1898
1899 /* Wait until buffer is empty */
1900 max=0xffff;
1901 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x60);
1902 if (max==0x0) keyboard_panic(60);
1903
1904 /* Enable keyboard */
1905 outb(0x60, 0xf4);
1906
1907 /* Wait until buffer is empty */
1908 max=0xffff;
1909 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x70);
1910 if (max==0x0) keyboard_panic(70);
1911
1912 /* Wait for data */
1913 max=0xffff;
1914 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x71);
1915 if (max==0x0) keyboard_panic(70);
1916
1917 /* keyboard should return ACK */
1918 if ((inb(0x60) != 0xfa)) {
1919 keyboard_panic(996);
1920 }
1921
1922 outb(0x80, 0x77);
1923}
1924
1925//--------------------------------------------------------------------------
1926// keyboard_panic
1927//--------------------------------------------------------------------------
1928 void
1929keyboard_panic(status)
1930 Bit16u status;
1931{
1932 // If you're getting a 993 keyboard panic here,
1933 // please see the comment in keyboard_init
1934
1935 BX_PANIC("Keyboard error:%u\n",status);
1936}
1937
1938//--------------------------------------------------------------------------
1939// shutdown_status_panic
1940// called when the shutdown status is not implemented, displays the status
1941//--------------------------------------------------------------------------
1942 void
1943shutdown_status_panic(status)
1944 Bit16u status;
1945{
1946 BX_PANIC("Unimplemented shutdown status: %02x\n",(Bit8u)status);
1947}
1948
1949#ifdef VBOX
1950#include "logo.c"
1951#endif /* VBOX */
1952
1953//--------------------------------------------------------------------------
1954// print_bios_banner
1955// displays a the bios version
1956//--------------------------------------------------------------------------
1957void
1958print_bios_banner()
1959{
1960#ifdef VBOX
1961 // Skip the logo if a warm boot is requested.
1962 Bit16u warm_boot = read_word(0x0040,0x0072);
1963 write_word(0x0040,0x0072, 0);
1964 if (warm_boot == 0x1234)
1965 return;
1966 /* show graphical logo */
1967 show_logo();
1968#else /* !VBOX */
1969 printf(BX_APPNAME" BIOS - build: %s\n%s\nOptions: ",
1970 BIOS_BUILD_DATE, bios_cvs_version_string);
1971 printf(
1972#if BX_APM
1973 "apmbios "
1974#endif
1975#if BX_PCIBIOS
1976 "pcibios "
1977#endif
1978#if BX_ELTORITO_BOOT
1979 "eltorito "
1980#endif
1981#if BX_ROMBIOS32
1982 "rombios32 "
1983#endif
1984 "\n\n");
1985#endif /* VBOX */
1986}
1987
1988//--------------------------------------------------------------------------
1989// print_boot_device
1990// displays the boot device
1991//--------------------------------------------------------------------------
1992
1993#ifdef VBOX
1994static char drivetypes[][10]={"Floppy","Hard Disk","CD-ROM","LAN"};
1995#else /* !VBOX */
1996static char drivetypes[][10]={"Floppy","Hard Disk","CD-Rom"};
1997#endif /* !VBOX */
1998
1999#ifdef VBOX
2000void
2001print_boot_device(cdboot, lanboot, drive)
2002 Bit8u cdboot; Bit8u lanboot; Bit16u drive;
2003#else /* !VBOX */
2004void
2005print_boot_device(cdboot, drive)
2006 Bit8u cdboot; Bit16u drive;
2007#endif /* !VBOX */
2008{
2009 Bit8u i;
2010
2011#ifdef VBOX
2012 // cdboot contains 0 if lan/floppy/harddisk, 1 otherwise
2013 // lanboot contains 0 if floppy/harddisk, 1 otherwise
2014#else /* !VBOX */
2015 // cdboot contains 0 if floppy/harddisk, 1 otherwise
2016#endif /* !VBOX */
2017 // drive contains real/emulated boot drive
2018
2019 if(cdboot)i=2; // CD-Rom
2020#ifdef VBOX
2021 else if(lanboot)i=3; // LAN
2022#endif /* VBOX */
2023 else if((drive&0x0080)==0x00)i=0; // Floppy
2024 else if((drive&0x0080)==0x80)i=1; // Hard drive
2025 else return;
2026
2027#ifdef VBOX
2028 BX_INFO("Booting from %s...\n",drivetypes[i]);
2029#else /* !VBOX */
2030 printf("Booting from %s...\n",drivetypes[i]);
2031#endif /* !VBOX */
2032}
2033
2034//--------------------------------------------------------------------------
2035// print_boot_failure
2036// displays the reason why boot failed
2037//--------------------------------------------------------------------------
2038#ifdef VBOX
2039 void
2040print_boot_failure(cdboot, lanboot, drive, reason, lastdrive)
2041 Bit8u cdboot; Bit8u lanboot; Bit8u drive; Bit8u reason; Bit8u lastdrive;
2042#else /* !VBOX */
2043 void
2044print_boot_failure(cdboot, drive, reason, lastdrive)
2045 Bit8u cdboot; Bit8u drive; Bit8u lastdrive;
2046#endif /* !VBOX */
2047{
2048 Bit16u drivenum = drive&0x7f;
2049
2050 // cdboot: 1 if boot from cd, 0 otherwise
2051#ifdef VBOX
2052 // lanboot: 1 if boot from lan, 0 otherwise
2053#endif /* VBOX */
2054 // drive : drive number
2055 // reason: 0 signature check failed, 1 read error
2056 // lastdrive: 1 boot drive is the last one in boot sequence
2057
2058 if (cdboot)
2059#ifndef VBOX
2060 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s failed\n",drivetypes[2]);
2061#else /* VBOX */
2062 BX_INFO("Boot from %s failed\n",drivetypes[2]);
2063 else if (lanboot)
2064 BX_INFO("Boot from %s failed\n",drivetypes[3]);
2065#endif /* VBOX */
2066 else if (drive & 0x80)
2067#ifndef VBOX
2068 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[1],drivenum);
2069#else /* VBOX */
2070 BX_INFO("Boot from %s %d failed\n", drivetypes[1],drivenum);
2071#endif /* VBOX */
2072 else
2073#ifndef VBOX
2074 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[0],drivenum);
2075#else /* VBOX */
2076 BX_INFO("Boot from %s %d failed\n", drivetypes[0],drivenum);
2077#endif /* VBOX */
2078
2079 if (lastdrive==1) {
2080 if (reason==0)
2081#ifndef VBOX
2082 BX_PANIC("Not a bootable disk\n");
2083#else /* VBOX */
2084 BX_PANIC("No bootable medium found! System halted.\n");
2085#endif /* VBOX */
2086 else
2087#ifndef VBOX
2088 BX_PANIC("Could not read the boot disk\n");
2089#else /* VBOX */
2090 BX_PANIC("Could not read from the boot medium! System halted.\n");
2091#endif /* VBOX */
2092 }
2093}
2094
2095//--------------------------------------------------------------------------
2096// print_cdromboot_failure
2097// displays the reason why boot failed
2098//--------------------------------------------------------------------------
2099 void
2100print_cdromboot_failure( code )
2101 Bit16u code;
2102{
2103#ifndef VBOX
2104 bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "CDROM boot failure code : %04x\n",code);
2105#else /* VBOX */
2106 BX_INFO("CDROM boot failure code : %04x\n",code);
2107#endif /* VBOX */
2108
2109 return;
2110}
2111
2112void
2113nmi_handler_msg()
2114{
2115 BX_PANIC("NMI Handler called\n");
2116}
2117
2118void
2119int18_panic_msg()
2120{
2121 BX_PANIC("INT18: BOOT FAILURE\n");
2122}
2123
2124void
2125log_bios_start()
2126{
2127#if BX_DEBUG_SERIAL
2128 outb(BX_DEBUG_PORT+UART_LCR, 0x03); /* setup for serial logging: 8N1 */
2129#endif
2130 BX_INFO("%s\n", bios_cvs_version_string);
2131}
2132
2133 bx_bool
2134set_enable_a20(val)
2135 bx_bool val;
2136{
2137 Bit8u oldval;
2138
2139 // Use PS2 System Control port A to set A20 enable
2140
2141 // get current setting first
2142 oldval = inb(0x92);
2143
2144 // change A20 status
2145 if (val)
2146 outb(0x92, oldval | 0x02);
2147 else
2148 outb(0x92, oldval & 0xfd);
2149
2150 return((oldval & 0x02) != 0);
2151}
2152
2153 void
2154debugger_on()
2155{
2156 outb(0xfedc, 0x01);
2157}
2158
2159 void
2160debugger_off()
2161{
2162 outb(0xfedc, 0x00);
2163}
2164
2165#if BX_USE_ATADRV
2166
2167// ---------------------------------------------------------------------------
2168// Start of ATA/ATAPI Driver
2169// ---------------------------------------------------------------------------
2170
2171// Global defines -- ATA register and register bits.
2172// command block & control block regs
2173#define ATA_CB_DATA 0 // data reg in/out pio_base_addr1+0
2174#define ATA_CB_ERR 1 // error in pio_base_addr1+1
2175#define ATA_CB_FR 1 // feature reg out pio_base_addr1+1
2176#define ATA_CB_SC 2 // sector count in/out pio_base_addr1+2
2177#define ATA_CB_SN 3 // sector number in/out pio_base_addr1+3
2178#define ATA_CB_CL 4 // cylinder low in/out pio_base_addr1+4
2179#define ATA_CB_CH 5 // cylinder high in/out pio_base_addr1+5
2180#define ATA_CB_DH 6 // device head in/out pio_base_addr1+6
2181#define ATA_CB_STAT 7 // primary status in pio_base_addr1+7
2182#define ATA_CB_CMD 7 // command out pio_base_addr1+7
2183#define ATA_CB_ASTAT 6 // alternate status in pio_base_addr2+6
2184#define ATA_CB_DC 6 // device control out pio_base_addr2+6
2185#define ATA_CB_DA 7 // device address in pio_base_addr2+7
2186
2187#define ATA_CB_ER_ICRC 0x80 // ATA Ultra DMA bad CRC
2188#define ATA_CB_ER_BBK 0x80 // ATA bad block
2189#define ATA_CB_ER_UNC 0x40 // ATA uncorrected error
2190#define ATA_CB_ER_MC 0x20 // ATA media change
2191#define ATA_CB_ER_IDNF 0x10 // ATA id not found
2192#define ATA_CB_ER_MCR 0x08 // ATA media change request
2193#define ATA_CB_ER_ABRT 0x04 // ATA command aborted
2194#define ATA_CB_ER_NTK0 0x02 // ATA track 0 not found
2195#define ATA_CB_ER_NDAM 0x01 // ATA address mark not found
2196
2197#define ATA_CB_ER_P_SNSKEY 0xf0 // ATAPI sense key (mask)
2198#define ATA_CB_ER_P_MCR 0x08 // ATAPI Media Change Request
2199#define ATA_CB_ER_P_ABRT 0x04 // ATAPI command abort
2200#define ATA_CB_ER_P_EOM 0x02 // ATAPI End of Media
2201#define ATA_CB_ER_P_ILI 0x01 // ATAPI Illegal Length Indication
2202
2203// ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC)
2204#define ATA_CB_SC_P_TAG 0xf8 // ATAPI tag (mask)
2205#define ATA_CB_SC_P_REL 0x04 // ATAPI release
2206#define ATA_CB_SC_P_IO 0x02 // ATAPI I/O
2207#define ATA_CB_SC_P_CD 0x01 // ATAPI C/D
2208
2209// bits 7-4 of the device/head (CB_DH) reg
2210#define ATA_CB_DH_DEV0 0xa0 // select device 0
2211#define ATA_CB_DH_DEV1 0xb0 // select device 1
2212
2213// status reg (CB_STAT and CB_ASTAT) bits
2214#define ATA_CB_STAT_BSY 0x80 // busy
2215#define ATA_CB_STAT_RDY 0x40 // ready
2216#define ATA_CB_STAT_DF 0x20 // device fault
2217#define ATA_CB_STAT_WFT 0x20 // write fault (old name)
2218#define ATA_CB_STAT_SKC 0x10 // seek complete
2219#define ATA_CB_STAT_SERV 0x10 // service
2220#define ATA_CB_STAT_DRQ 0x08 // data request
2221#define ATA_CB_STAT_CORR 0x04 // corrected
2222#define ATA_CB_STAT_IDX 0x02 // index
2223#define ATA_CB_STAT_ERR 0x01 // error (ATA)
2224#define ATA_CB_STAT_CHK 0x01 // check (ATAPI)
2225
2226// device control reg (CB_DC) bits
2227#define ATA_CB_DC_HD15 0x08 // bit should always be set to one
2228#define ATA_CB_DC_SRST 0x04 // soft reset
2229#define ATA_CB_DC_NIEN 0x02 // disable interrupts
2230
2231// Most mandatory and optional ATA commands (from ATA-3),
2232#define ATA_CMD_CFA_ERASE_SECTORS 0xC0
2233#define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03
2234#define ATA_CMD_CFA_TRANSLATE_SECTOR 0x87
2235#define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD
2236#define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38
2237#define ATA_CMD_CHECK_POWER_MODE1 0xE5
2238#define ATA_CMD_CHECK_POWER_MODE2 0x98
2239#define ATA_CMD_DEVICE_RESET 0x08
2240#define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90
2241#define ATA_CMD_FLUSH_CACHE 0xE7
2242#define ATA_CMD_FORMAT_TRACK 0x50
2243#define ATA_CMD_IDENTIFY_DEVICE 0xEC
2244#define ATA_CMD_IDENTIFY_DEVICE_PACKET 0xA1
2245#define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xA1
2246#define ATA_CMD_IDLE1 0xE3
2247#define ATA_CMD_IDLE2 0x97
2248#define ATA_CMD_IDLE_IMMEDIATE1 0xE1
2249#define ATA_CMD_IDLE_IMMEDIATE2 0x95
2250#define ATA_CMD_INITIALIZE_DRIVE_PARAMETERS 0x91
2251#define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
2252#define ATA_CMD_NOP 0x00
2253#define ATA_CMD_PACKET 0xA0
2254#define ATA_CMD_READ_BUFFER 0xE4
2255#define ATA_CMD_READ_DMA 0xC8
2256#define ATA_CMD_READ_DMA_QUEUED 0xC7
2257#define ATA_CMD_READ_MULTIPLE 0xC4
2258#define ATA_CMD_READ_SECTORS 0x20
2259#ifdef VBOX
2260#define ATA_CMD_READ_SECTORS_EXT 0x24
2261#define ATA_CMD_READ_MULTIPLE_EXT 0x29
2262#define ATA_CMD_WRITE_MULTIPLE_EXT 0x39
2263#endif /* VBOX */
2264#define ATA_CMD_READ_VERIFY_SECTORS 0x40
2265#define ATA_CMD_RECALIBRATE 0x10
2266#define ATA_CMD_SEEK 0x70
2267#define ATA_CMD_SET_FEATURES 0xEF
2268#define ATA_CMD_SET_MULTIPLE_MODE 0xC6
2269#define ATA_CMD_SLEEP1 0xE6
2270#define ATA_CMD_SLEEP2 0x99
2271#define ATA_CMD_STANDBY1 0xE2
2272#define ATA_CMD_STANDBY2 0x96
2273#define ATA_CMD_STANDBY_IMMEDIATE1 0xE0
2274#define ATA_CMD_STANDBY_IMMEDIATE2 0x94
2275#define ATA_CMD_WRITE_BUFFER 0xE8
2276#define ATA_CMD_WRITE_DMA 0xCA
2277#define ATA_CMD_WRITE_DMA_QUEUED 0xCC
2278#define ATA_CMD_WRITE_MULTIPLE 0xC5
2279#define ATA_CMD_WRITE_SECTORS 0x30
2280#ifdef VBOX
2281#define ATA_CMD_WRITE_SECTORS_EXT 0x34
2282#endif /* VBOX */
2283#define ATA_CMD_WRITE_VERIFY 0x3C
2284
2285#define ATA_IFACE_NONE 0x00
2286#define ATA_IFACE_ISA 0x00
2287#define ATA_IFACE_PCI 0x01
2288
2289#define ATA_TYPE_NONE 0x00
2290#define ATA_TYPE_UNKNOWN 0x01
2291#define ATA_TYPE_ATA 0x02
2292#define ATA_TYPE_ATAPI 0x03
2293#ifdef VBOX
2294#define ATA_TYPE_SCSI 0x04 // SCSI disk
2295#endif
2296
2297#define ATA_DEVICE_NONE 0x00
2298#define ATA_DEVICE_HD 0xFF
2299#define ATA_DEVICE_CDROM 0x05
2300
2301#define ATA_MODE_NONE 0x00
2302#define ATA_MODE_PIO16 0x00
2303#define ATA_MODE_PIO32 0x01
2304#define ATA_MODE_ISADMA 0x02
2305#define ATA_MODE_PCIDMA 0x03
2306#define ATA_MODE_USEIRQ 0x10
2307
2308#define ATA_TRANSLATION_NONE 0
2309#define ATA_TRANSLATION_LBA 1
2310#define ATA_TRANSLATION_LARGE 2
2311#define ATA_TRANSLATION_RECHS 3
2312
2313#define ATA_DATA_NO 0x00
2314#define ATA_DATA_IN 0x01
2315#define ATA_DATA_OUT 0x02
2316
2317// ---------------------------------------------------------------------------
2318// ATA/ATAPI driver : initialization
2319// ---------------------------------------------------------------------------
2320void ata_init( )
2321{
2322 Bit16u ebda_seg=read_word(0x0040,0x000E);
2323 Bit8u channel, device;
2324
2325 // Channels info init.
2326 for (channel=0; channel<BX_MAX_ATA_INTERFACES; channel++) {
2327 write_byte(ebda_seg,&EbdaData->ata.channels[channel].iface,ATA_IFACE_NONE);
2328 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1,0x0);
2329 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2,0x0);
2330 write_byte(ebda_seg,&EbdaData->ata.channels[channel].irq,0);
2331 }
2332
2333 // Devices info init.
2334 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2335 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
2336 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_NONE);
2337 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable,0);
2338 write_byte(ebda_seg,&EbdaData->ata.devices[device].lock,0);
2339 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode,ATA_MODE_NONE);
2340 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,0x200);
2341 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation,ATA_TRANSLATION_NONE);
2342 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads,0);
2343 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders,0);
2344 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt,0);
2345 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads,0);
2346 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders,0);
2347 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt,0);
2348
2349 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors,0L);
2350 }
2351
2352 // hdidmap and cdidmap init.
2353 for (device=0; device<BX_MAX_STORAGE_DEVICES; device++) {
2354 write_byte(ebda_seg,&EbdaData->ata.hdidmap[device],BX_MAX_STORAGE_DEVICES);
2355 write_byte(ebda_seg,&EbdaData->ata.cdidmap[device],BX_MAX_STORAGE_DEVICES);
2356 }
2357
2358 write_byte(ebda_seg,&EbdaData->ata.hdcount,0);
2359 write_byte(ebda_seg,&EbdaData->ata.cdcount,0);
2360}
2361
2362// ---------------------------------------------------------------------------
2363// ATA/ATAPI driver : device detection
2364// ---------------------------------------------------------------------------
2365
2366void ata_detect( )
2367{
2368 Bit16u ebda_seg=read_word(0x0040,0x000E);
2369 Bit8u hdcount, cdcount, device, type;
2370 Bit8u buffer[0x0200];
2371
2372#if BX_MAX_ATA_INTERFACES > 0
2373 write_byte(ebda_seg,&EbdaData->ata.channels[0].iface,ATA_IFACE_ISA);
2374 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase1,0x1f0);
2375 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase2,0x3f0);
2376 write_byte(ebda_seg,&EbdaData->ata.channels[0].irq,14);
2377#endif
2378#if BX_MAX_ATA_INTERFACES > 1
2379 write_byte(ebda_seg,&EbdaData->ata.channels[1].iface,ATA_IFACE_ISA);
2380 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase1,0x170);
2381 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase2,0x370);
2382 write_byte(ebda_seg,&EbdaData->ata.channels[1].irq,15);
2383#endif
2384#if BX_MAX_ATA_INTERFACES > 2
2385 write_byte(ebda_seg,&EbdaData->ata.channels[2].iface,ATA_IFACE_ISA);
2386 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase1,0x1e8);
2387 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase2,0x3e0);
2388 write_byte(ebda_seg,&EbdaData->ata.channels[2].irq,12);
2389#endif
2390#if BX_MAX_ATA_INTERFACES > 3
2391 write_byte(ebda_seg,&EbdaData->ata.channels[3].iface,ATA_IFACE_ISA);
2392 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase1,0x168);
2393 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase2,0x360);
2394 write_byte(ebda_seg,&EbdaData->ata.channels[3].irq,11);
2395#endif
2396#if BX_MAX_ATA_INTERFACES > 4
2397#error Please fill the ATA interface informations
2398#endif
2399
2400 // Device detection
2401 hdcount=cdcount=0;
2402
2403 for(device=0; device<BX_MAX_ATA_DEVICES; device++) {
2404 Bit16u iobase1, iobase2;
2405 Bit8u channel, slave, shift;
2406 Bit8u sc, sn, cl, ch, st;
2407
2408 channel = device / 2;
2409 slave = device % 2;
2410
2411 iobase1 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1);
2412 iobase2 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2);
2413
2414 // Disable interrupts
2415 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2416
2417 // Look for device
2418 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2419 outb(iobase1+ATA_CB_SC, 0x55);
2420 outb(iobase1+ATA_CB_SN, 0xaa);
2421 outb(iobase1+ATA_CB_SC, 0xaa);
2422 outb(iobase1+ATA_CB_SN, 0x55);
2423 outb(iobase1+ATA_CB_SC, 0x55);
2424 outb(iobase1+ATA_CB_SN, 0xaa);
2425
2426 // If we found something
2427 sc = inb(iobase1+ATA_CB_SC);
2428 sn = inb(iobase1+ATA_CB_SN);
2429
2430 if ( (sc == 0x55) && (sn == 0xaa) ) {
2431 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_UNKNOWN);
2432
2433 // reset the channel
2434 ata_reset(device);
2435
2436 // check for ATA or ATAPI
2437 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2438 sc = inb(iobase1+ATA_CB_SC);
2439 sn = inb(iobase1+ATA_CB_SN);
2440 if ((sc==0x01) && (sn==0x01)) {
2441 cl = inb(iobase1+ATA_CB_CL);
2442 ch = inb(iobase1+ATA_CB_CH);
2443 st = inb(iobase1+ATA_CB_STAT);
2444
2445 if ((cl==0x14) && (ch==0xeb)) {
2446 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATAPI);
2447 } else if ((cl==0x00) && (ch==0x00) && (st!=0x00)) {
2448 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATA);
2449 } else if ((cl==0xff) && (ch==0xff)) {
2450 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
2451 }
2452 }
2453 }
2454
2455#ifdef VBOX
2456 // Enable interrupts
2457 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2458#endif /* VBOX */
2459
2460 type=read_byte(ebda_seg,&EbdaData->ata.devices[device].type);
2461
2462 // Now we send a IDENTIFY command to ATA device
2463 if(type == ATA_TYPE_ATA) {
2464 Bit32u sectors;
2465 Bit16u cylinders, heads, spt, blksize;
2466#ifdef VBOX
2467 Bit16u lcylinders, lheads, lspt;
2468 Bit8u chsgeo_base;
2469#endif /* VBOX */
2470 Bit8u translation, removable, mode;
2471
2472 //Temporary values to do the transfer
2473 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2474 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2475
2476 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE, 1, 0, 0, 0, 0L, get_SS(),buffer) !=0 )
2477 BX_PANIC("ata-detect: Failed to detect ATA device\n");
2478
2479 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2480 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2481#ifdef VBOX
2482 blksize = 512; /* There is no sector size field any more. */
2483#else /* !VBOX */
2484 blksize = read_word(get_SS(),buffer+10);
2485#endif /* !VBOX */
2486
2487 cylinders = read_word(get_SS(),buffer+(1*2)); // word 1
2488 heads = read_word(get_SS(),buffer+(3*2)); // word 3
2489 spt = read_word(get_SS(),buffer+(6*2)); // word 6
2490
2491 sectors = read_dword(get_SS(),buffer+(60*2)); // word 60 and word 61
2492#ifdef VBOX
2493 /** @todo update sectors to be a 64 bit number (also lba...). */
2494 if (sectors == 268435455)
2495 sectors = read_dword(get_SS(),buffer+(100*2)); // words 100 to 103 (someday)
2496 switch (device)
2497 {
2498 case 0:
2499 chsgeo_base = 0x1e;
2500 break;
2501 case 1:
2502 chsgeo_base = 0x26;
2503 break;
2504 case 2:
2505 chsgeo_base = 0x67;
2506 break;
2507 case 3:
2508 chsgeo_base = 0x70;
2509 break;
2510 case 4:
2511 chsgeo_base = 0x40;
2512 break;
2513 case 5:
2514 chsgeo_base = 0x48;
2515 break;
2516 case 6:
2517 chsgeo_base = 0x50;
2518 break;
2519 case 7:
2520 chsgeo_base = 0x58;
2521 break;
2522 default:
2523 chsgeo_base = 0;
2524 }
2525 if (chsgeo_base != 0)
2526 {
2527 lcylinders = inb_cmos(chsgeo_base) + (inb_cmos(chsgeo_base+1) << 8);
2528 lheads = inb_cmos(chsgeo_base+2);
2529 lspt = inb_cmos(chsgeo_base+7);
2530 }
2531 else
2532 {
2533 lcylinders = 0;
2534 lheads = 0;
2535 lspt = 0;
2536 }
2537 BX_INFO("ata%d-%d: PCHS=%u/%d/%d LCHS=%u/%u/%u\n", channel, slave, cylinders, heads, spt, lcylinders, lheads, lspt);
2538#endif /* VBOX */
2539
2540 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2541 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2542 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2543 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2544 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads, heads);
2545 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders, cylinders);
2546 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt, spt);
2547 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors, sectors);
2548#ifdef VBOX
2549 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, lheads);
2550 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, lcylinders);
2551 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, lspt);
2552 if (device < 2)
2553 {
2554 Bit8u sum, i;
2555 unsigned char *fdpt;
2556 if (device == 0)
2557 fdpt = &EbdaData->fdpt0;
2558 else
2559 fdpt = &EbdaData->fdpt1;
2560
2561 /* Update the DPT for drive 0/1 pointed to by Int41/46. This used
2562 * to be done at POST time with lots of ugly assembler code, which
2563 * isn't worth the effort of converting from AMI to Award CMOS
2564 * format. Just do it here. */
2565 write_word(ebda_seg, fdpt + 0x00, lcylinders);
2566 write_byte(ebda_seg, fdpt + 0x02, lheads);
2567 write_byte(ebda_seg, fdpt + 0x0e, lspt);
2568 write_word(ebda_seg, fdpt + 0x09, cylinders);
2569 write_byte(ebda_seg, fdpt + 0x0b, heads);
2570 write_byte(ebda_seg, fdpt + 0x04, spt);
2571 write_byte(ebda_seg, fdpt + 0x03, 0xa0);
2572 sum = 0;
2573 for (i = 0; i < 0xf; i++)
2574 sum += read_byte(ebda_seg, fdpt + i);
2575 sum = 1 - sum;
2576 write_byte(ebda_seg, fdpt + 0x0f, sum);
2577 }
2578#else /* !VBOX */
2579 BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel, slave,cylinders, heads, spt);
2580
2581 translation = inb_cmos(0x39 + channel/2);
2582 for (shift=device%4; shift>0; shift--) translation >>= 2;
2583 translation &= 0x03;
2584
2585 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation, translation);
2586
2587 switch (translation) {
2588 case ATA_TRANSLATION_NONE:
2589 BX_INFO("none");
2590 break;
2591 case ATA_TRANSLATION_LBA:
2592 BX_INFO("lba");
2593 break;
2594 case ATA_TRANSLATION_LARGE:
2595 BX_INFO("large");
2596 break;
2597 case ATA_TRANSLATION_RECHS:
2598 BX_INFO("r-echs");
2599 break;
2600 }
2601 switch (translation) {
2602 case ATA_TRANSLATION_NONE:
2603 break;
2604 case ATA_TRANSLATION_LBA:
2605 spt = 63;
2606 sectors /= 63;
2607 heads = sectors / 1024;
2608 if (heads>128) heads = 255;
2609 else if (heads>64) heads = 128;
2610 else if (heads>32) heads = 64;
2611 else if (heads>16) heads = 32;
2612 else heads=16;
2613 cylinders = sectors / heads;
2614 break;
2615 case ATA_TRANSLATION_RECHS:
2616 // Take care not to overflow
2617 if (heads==16) {
2618 if(cylinders>61439) cylinders=61439;
2619 heads=15;
2620 cylinders = (Bit16u)((Bit32u)(cylinders)*16/15);
2621 }
2622 // then go through the large bitshift process
2623 case ATA_TRANSLATION_LARGE:
2624 while(cylinders > 1024) {
2625 cylinders >>= 1;
2626 heads <<= 1;
2627
2628 // If we max out the head count
2629 if (heads > 127) break;
2630 }
2631 break;
2632 }
2633 // clip to 1024 cylinders in lchs
2634 if (cylinders > 1024) cylinders=1024;
2635 BX_INFO(" LCHS=%d/%d/%d\n", cylinders, heads, spt);
2636
2637 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, heads);
2638 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, cylinders);
2639 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, spt);
2640#endif /* VBOX */
2641
2642 // fill hdidmap
2643 write_byte(ebda_seg,&EbdaData->ata.hdidmap[hdcount], device);
2644 hdcount++;
2645 }
2646
2647 // Now we send a IDENTIFY command to ATAPI device
2648 if(type == ATA_TYPE_ATAPI) {
2649
2650 Bit8u type, removable, mode;
2651 Bit16u blksize;
2652
2653 //Temporary values to do the transfer
2654 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_CDROM);
2655 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2656
2657 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE_PACKET, 1, 0, 0, 0, 0L, get_SS(),buffer) != 0)
2658 BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
2659
2660 type = read_byte(get_SS(),buffer+1) & 0x1f;
2661 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2662 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2663 blksize = 2048;
2664
2665 write_byte(ebda_seg,&EbdaData->ata.devices[device].device, type);
2666 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2667 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2668 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2669
2670 // fill cdidmap
2671 write_byte(ebda_seg,&EbdaData->ata.cdidmap[cdcount], device);
2672 cdcount++;
2673 }
2674
2675 {
2676 Bit32u sizeinmb;
2677 Bit16u ataversion;
2678 Bit8u c, i, version, model[41];
2679
2680 switch (type) {
2681 case ATA_TYPE_ATA:
2682 sizeinmb = read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors);
2683 sizeinmb >>= 11;
2684 case ATA_TYPE_ATAPI:
2685 // Read ATA/ATAPI version
2686 ataversion=((Bit16u)(read_byte(get_SS(),buffer+161))<<8)|read_byte(get_SS(),buffer+160);
2687 for(version=15;version>0;version--) {
2688 if((ataversion&(1<<version))!=0)
2689 break;
2690 }
2691
2692 // Read model name
2693 for(i=0;i<20;i++){
2694 write_byte(get_SS(),model+(i*2),read_byte(get_SS(),buffer+(i*2)+54+1));
2695 write_byte(get_SS(),model+(i*2)+1,read_byte(get_SS(),buffer+(i*2)+54));
2696 }
2697
2698 // Reformat
2699 write_byte(get_SS(),model+40,0x00);
2700 for(i=39;i>0;i--){
2701 if(read_byte(get_SS(),model+i)==0x20)
2702 write_byte(get_SS(),model+i,0x00);
2703 else break;
2704 }
2705 break;
2706 }
2707
2708#ifdef VBOX
2709 // we don't want any noisy output for now
2710#else /* !VBOX */
2711 switch (type) {
2712 case ATA_TYPE_ATA:
2713 printf("ata%d %s: ",channel,slave?" slave":"master");
2714 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2715 printf(" ATA-%d Hard-Disk (%lu MBytes)\n", version, sizeinmb);
2716 break;
2717 case ATA_TYPE_ATAPI:
2718 printf("ata%d %s: ",channel,slave?" slave":"master");
2719 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2720 if(read_byte(ebda_seg,&EbdaData->ata.devices[device].device)==ATA_DEVICE_CDROM)
2721 printf(" ATAPI-%d CD-Rom/DVD-Rom\n",version);
2722 else
2723 printf(" ATAPI-%d Device\n",version);
2724 break;
2725 case ATA_TYPE_UNKNOWN:
2726 printf("ata%d %s: Unknown device\n",channel,slave?" slave":"master");
2727 break;
2728 }
2729#endif /* !VBOX */
2730 }
2731 }
2732
2733 // Store the devices counts
2734 write_byte(ebda_seg,&EbdaData->ata.hdcount, hdcount);
2735 write_byte(ebda_seg,&EbdaData->ata.cdcount, cdcount);
2736 write_byte(0x40,0x75, hdcount);
2737
2738#ifdef VBOX
2739 // we don't want any noisy output for now
2740#else /* !VBOX */
2741 printf("\n");
2742#endif /* !VBOX */
2743
2744 // FIXME : should use bios=cmos|auto|disable bits
2745 // FIXME : should know about translation bits
2746 // FIXME : move hard_drive_post here
2747
2748}
2749
2750// ---------------------------------------------------------------------------
2751// ATA/ATAPI driver : software reset
2752// ---------------------------------------------------------------------------
2753// ATA-3
2754// 8.2.1 Software reset - Device 0
2755
2756void ata_reset(device)
2757Bit16u device;
2758{
2759 Bit16u ebda_seg=read_word(0x0040,0x000E);
2760 Bit16u iobase1, iobase2;
2761 Bit8u channel, slave, sn, sc;
2762 Bit16u max;
2763#ifdef VBOX
2764 Bit16u pdelay;
2765#endif /* VBOX */
2766
2767 channel = device / 2;
2768 slave = device % 2;
2769
2770 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2771 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2772
2773 // Reset
2774
2775// 8.2.1 (a) -- set SRST in DC
2776 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN | ATA_CB_DC_SRST);
2777
2778// 8.2.1 (b) -- wait for BSY
2779 max=0xff;
2780 while(--max>0) {
2781 Bit8u status = inb(iobase1+ATA_CB_STAT);
2782 if ((status & ATA_CB_STAT_BSY) != 0) break;
2783 }
2784
2785// 8.2.1 (f) -- clear SRST
2786 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2787
2788 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_NONE) {
2789
2790// 8.2.1 (g) -- check for sc==sn==0x01
2791 // select device
2792 outb(iobase1+ATA_CB_DH, slave?ATA_CB_DH_DEV1:ATA_CB_DH_DEV0);
2793 sc = inb(iobase1+ATA_CB_SC);
2794 sn = inb(iobase1+ATA_CB_SN);
2795
2796 if ( (sc==0x01) && (sn==0x01) ) {
2797
2798// 8.2.1 (h) -- wait for not BSY
2799#ifdef VBOX
2800 max=0xffff; /* The ATA specification says that the drive may be busy for up to 30 seconds. */
2801#else /* !VBOX */
2802 max=0xff;
2803#endif /* !VBOX */
2804 while(--max>0) {
2805 Bit8u status = inb(iobase1+ATA_CB_STAT);
2806 if ((status & ATA_CB_STAT_BSY) == 0) break;
2807#ifdef VBOX
2808 pdelay=0xffff;
2809 while (--pdelay>0) {
2810 /* nothing */
2811 }
2812#endif /* VBOX */
2813 }
2814 }
2815 }
2816
2817// 8.2.1 (i) -- wait for DRDY
2818#ifdef VBOX
2819 max=0x10; /* Speed up for virtual drives. Disks are immediately ready, CDs never */
2820#else /* !VBOX */
2821 max=0xfff;
2822#endif /* !VBOX */
2823 while(--max>0) {
2824 Bit8u status = inb(iobase1+ATA_CB_STAT);
2825 if ((status & ATA_CB_STAT_RDY) != 0) break;
2826 }
2827
2828 // Enable interrupts
2829 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2830}
2831
2832// ---------------------------------------------------------------------------
2833// ATA/ATAPI driver : execute a non data command
2834// ---------------------------------------------------------------------------
2835
2836Bit16u ata_cmd_non_data()
2837{return 0;}
2838
2839// ---------------------------------------------------------------------------
2840// ATA/ATAPI driver : execute a data-in command
2841// ---------------------------------------------------------------------------
2842 // returns
2843 // 0 : no error
2844 // 1 : BUSY bit set
2845 // 2 : read error
2846 // 3 : expected DRQ=1
2847 // 4 : no sectors left to read/verify
2848 // 5 : more sectors to read/verify
2849 // 6 : no sectors left to write
2850 // 7 : more sectors to write
2851Bit16u ata_cmd_data_in(device, command, count, cylinder, head, sector, lba, segment, offset)
2852Bit16u device, command, count, cylinder, head, sector, segment, offset;
2853Bit32u lba;
2854{
2855 Bit16u ebda_seg=read_word(0x0040,0x000E);
2856 Bit16u iobase1, iobase2, blksize, mult_blk_cnt;
2857 Bit8u channel, slave;
2858 Bit8u status, current, mode;
2859
2860 channel = device / 2;
2861 slave = device % 2;
2862
2863 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2864 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2865 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2866 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2867 if (blksize == 0) { /* If transfer size is exactly 64K */
2868 if (mode == ATA_MODE_PIO32) blksize=0x4000;
2869 else blksize=0x8000;
2870 } else {
2871 if (mode == ATA_MODE_PIO32) blksize>>=2;
2872 else blksize>>=1;
2873 }
2874
2875#ifdef VBOX
2876 status = inb(iobase1 + ATA_CB_STAT);
2877 if (status & ATA_CB_STAT_BSY)
2878 {
2879 BX_DEBUG_ATA("ata_cmd_data_in : disk busy\n");
2880 // Enable interrupts
2881 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2882 return 1;
2883 }
2884#endif /* VBOX */
2885
2886 // sector will be 0 only on lba access. Convert to lba-chs
2887 if (sector == 0) {
2888#ifdef VBOX
2889 if (lba + count >= 268435456)
2890 {
2891 sector = (lba & 0xff000000L) >> 24;
2892 cylinder = 0; /* The parameter lba is just a 32 bit value. */
2893 outb(iobase1 + ATA_CB_SC, (count & 0xff00) >> 8);
2894 outb(iobase1 + ATA_CB_SN, sector);
2895 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2896 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2897 /* Leave the bottom 24 bits as is, they are treated correctly by the
2898 * LBA28 code path. */
2899 lba &= 0xffffff;
2900 }
2901#endif /* VBOX */
2902 sector = (Bit16u) (lba & 0x000000ffL);
2903 lba >>= 8;
2904 cylinder = (Bit16u) (lba & 0x0000ffffL);
2905 lba >>= 16;
2906 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
2907 }
2908
2909 // Reset count of transferred data
2910 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2911 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2912 current = 0;
2913
2914#ifndef VBOX
2915 status = inb(iobase1 + ATA_CB_STAT);
2916 if (status & ATA_CB_STAT_BSY) return 1;
2917#endif /* !VBOX */
2918
2919 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2920 outb(iobase1 + ATA_CB_FR, 0x00);
2921 outb(iobase1 + ATA_CB_SC, count);
2922 outb(iobase1 + ATA_CB_SN, sector);
2923 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2924 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2925 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
2926 outb(iobase1 + ATA_CB_CMD, command);
2927
2928 if (command == ATA_CMD_READ_MULTIPLE || command == ATA_CMD_READ_MULTIPLE_EXT) {
2929 mult_blk_cnt = count;
2930 count = 1;
2931 } else {
2932 mult_blk_cnt = 1;
2933 }
2934
2935 while (1) {
2936 status = inb(iobase1 + ATA_CB_STAT);
2937 if ( !(status & ATA_CB_STAT_BSY) ) break;
2938 }
2939
2940 if (status & ATA_CB_STAT_ERR) {
2941 BX_DEBUG_ATA("ata_cmd_data_in : read error\n");
2942#ifdef VBOX
2943 // Enable interrupts
2944 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2945#endif /* VBOX */
2946 return 2;
2947 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2948 BX_DEBUG_ATA("ata_cmd_data_in : DRQ not set (status %02x)\n", (unsigned) status);
2949#ifdef VBOX
2950 // Enable interrupts
2951 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2952#endif /* VBOX */
2953 return 3;
2954 }
2955
2956 // FIXME : move seg/off translation here
2957
2958ASM_START
2959 sti ;; enable higher priority interrupts
2960ASM_END
2961
2962 while (1) {
2963
2964ASM_START
2965 push bp
2966 mov bp, sp
2967 mov di, _ata_cmd_data_in.offset + 2[bp]
2968 mov ax, _ata_cmd_data_in.segment + 2[bp]
2969 mov cx, _ata_cmd_data_in.blksize + 2[bp]
2970
2971 ;; adjust if there will be an overrun. 2K max sector size
2972 cmp di, #0xf800 ;;
2973 jbe ata_in_no_adjust
2974
2975ata_in_adjust:
2976 sub di, #0x0800 ;; sub 2 kbytes from offset
2977 add ax, #0x0080 ;; add 2 Kbytes to segment
2978
2979ata_in_no_adjust:
2980 mov es, ax ;; segment in es
2981
2982 mov dx, _ata_cmd_data_in.iobase1 + 2[bp] ;; ATA data read port
2983
2984 mov ah, _ata_cmd_data_in.mode + 2[bp]
2985 cmp ah, #ATA_MODE_PIO32
2986 je ata_in_32
2987
2988ata_in_16:
2989 rep
2990 insw ;; CX words transferred from port(DX) to ES:[DI]
2991 jmp ata_in_done
2992
2993ata_in_32:
2994 rep
2995 insd ;; CX dwords transferred from port(DX) to ES:[DI]
2996
2997ata_in_done:
2998 mov _ata_cmd_data_in.offset + 2[bp], di
2999 mov _ata_cmd_data_in.segment + 2[bp], es
3000 pop bp
3001ASM_END
3002
3003 current += mult_blk_cnt;
3004 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
3005 count--;
3006#ifdef VBOX
3007 while (1) {
3008 status = inb(iobase1 + ATA_CB_STAT);
3009 if ( !(status & ATA_CB_STAT_BSY) ) break;
3010 }
3011#else /* !VBOX */
3012 status = inb(iobase1 + ATA_CB_STAT);
3013#endif /* !VBOX */
3014 if (count == 0) {
3015 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3016 != ATA_CB_STAT_RDY ) {
3017 BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n", (unsigned) status);
3018#ifdef VBOX
3019 // Enable interrupts
3020 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3021#endif /* VBOX */
3022 return 4;
3023 }
3024 break;
3025 }
3026 else {
3027 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3028 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3029 BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n", (unsigned) status);
3030#ifdef VBOX
3031 // Enable interrupts
3032 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3033#endif /* VBOX */
3034 return 5;
3035 }
3036 continue;
3037 }
3038 }
3039 // Enable interrupts
3040 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3041 return 0;
3042}
3043
3044// ---------------------------------------------------------------------------
3045// ATA/ATAPI driver : execute a data-out command
3046// ---------------------------------------------------------------------------
3047 // returns
3048 // 0 : no error
3049 // 1 : BUSY bit set
3050 // 2 : read error
3051 // 3 : expected DRQ=1
3052 // 4 : no sectors left to read/verify
3053 // 5 : more sectors to read/verify
3054 // 6 : no sectors left to write
3055 // 7 : more sectors to write
3056Bit16u ata_cmd_data_out(device, command, count, cylinder, head, sector, lba, segment, offset)
3057Bit16u device, command, count, cylinder, head, sector, segment, offset;
3058Bit32u lba;
3059{
3060 Bit16u ebda_seg=read_word(0x0040,0x000E);
3061 Bit16u iobase1, iobase2, blksize;
3062 Bit8u channel, slave;
3063 Bit8u status, current, mode;
3064
3065 channel = device / 2;
3066 slave = device % 2;
3067
3068 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
3069 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
3070 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
3071 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
3072 if (mode == ATA_MODE_PIO32) blksize>>=2;
3073 else blksize>>=1;
3074
3075#ifdef VBOX
3076 status = inb(iobase1 + ATA_CB_STAT);
3077 if (status & ATA_CB_STAT_BSY)
3078 {
3079 // Enable interrupts
3080 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3081 return 1;
3082 }
3083#endif /* VBOX */
3084
3085 // sector will be 0 only on lba access. Convert to lba-chs
3086 if (sector == 0) {
3087#ifdef VBOX
3088 if (lba + count >= 268435456)
3089 {
3090 sector = (lba & 0xff000000L) >> 24;
3091 cylinder = 0; /* The parameter lba is just a 32 bit value. */
3092 outb(iobase1 + ATA_CB_SC, (count & 0xff00) >> 8);
3093 outb(iobase1 + ATA_CB_SN, sector);
3094 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
3095 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
3096 /* Leave the bottom 24 bits as is, they are treated correctly by the
3097 * LBA28 code path. */
3098 lba &= 0xffffff;
3099 }
3100#endif /* VBOX */
3101 sector = (Bit16u) (lba & 0x000000ffL);
3102 lba >>= 8;
3103 cylinder = (Bit16u) (lba & 0x0000ffffL);
3104 lba >>= 16;
3105 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
3106 }
3107
3108 // Reset count of transferred data
3109 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
3110 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
3111 current = 0;
3112
3113#ifndef VBOX
3114 status = inb(iobase1 + ATA_CB_STAT);
3115 if (status & ATA_CB_STAT_BSY) return 1;
3116#endif /* !VBOX */
3117
3118 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
3119 outb(iobase1 + ATA_CB_FR, 0x00);
3120 outb(iobase1 + ATA_CB_SC, count);
3121 outb(iobase1 + ATA_CB_SN, sector);
3122 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
3123 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
3124 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
3125 outb(iobase1 + ATA_CB_CMD, command);
3126
3127 while (1) {
3128 status = inb(iobase1 + ATA_CB_STAT);
3129 if ( !(status & ATA_CB_STAT_BSY) ) break;
3130 }
3131
3132 if (status & ATA_CB_STAT_ERR) {
3133 BX_DEBUG_ATA("ata_cmd_data_out : read error\n");
3134#ifdef VBOX
3135 // Enable interrupts
3136 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3137#endif /* VBOX */
3138 return 2;
3139 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
3140 BX_DEBUG_ATA("ata_cmd_data_out : DRQ not set (status %02x)\n", (unsigned) status);
3141#ifdef VBOX
3142 // Enable interrupts
3143 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3144#endif /* VBOX */
3145 return 3;
3146 }
3147
3148 // FIXME : move seg/off translation here
3149
3150ASM_START
3151 sti ;; enable higher priority interrupts
3152ASM_END
3153
3154 while (1) {
3155
3156ASM_START
3157 push bp
3158 mov bp, sp
3159 mov si, _ata_cmd_data_out.offset + 2[bp]
3160 mov ax, _ata_cmd_data_out.segment + 2[bp]
3161 mov cx, _ata_cmd_data_out.blksize + 2[bp]
3162
3163 ;; adjust if there will be an overrun. 2K max sector size
3164 cmp si, #0xf800 ;;
3165 jbe ata_out_no_adjust
3166
3167ata_out_adjust:
3168 sub si, #0x0800 ;; sub 2 kbytes from offset
3169 add ax, #0x0080 ;; add 2 Kbytes to segment
3170
3171ata_out_no_adjust:
3172 mov es, ax ;; segment in es
3173
3174 mov dx, _ata_cmd_data_out.iobase1 + 2[bp] ;; ATA data write port
3175
3176 mov ah, _ata_cmd_data_out.mode + 2[bp]
3177 cmp ah, #ATA_MODE_PIO32
3178 je ata_out_32
3179
3180ata_out_16:
3181 seg ES
3182 rep
3183 outsw ;; CX words transferred from port(DX) to ES:[SI]
3184 jmp ata_out_done
3185
3186ata_out_32:
3187 seg ES
3188 rep
3189 outsd ;; CX dwords transferred from port(DX) to ES:[SI]
3190
3191ata_out_done:
3192 mov _ata_cmd_data_out.offset + 2[bp], si
3193 mov _ata_cmd_data_out.segment + 2[bp], es
3194 pop bp
3195ASM_END
3196
3197 current++;
3198 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
3199 count--;
3200#ifdef VBOX
3201 while (1) {
3202 status = inb(iobase1 + ATA_CB_STAT);
3203 if ( !(status & ATA_CB_STAT_BSY) ) break;
3204 }
3205#else /* !VBOX */
3206 status = inb(iobase1 + ATA_CB_STAT);
3207#endif /* VBOX */
3208 if (count == 0) {
3209 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3210 != ATA_CB_STAT_RDY ) {
3211 BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n", (unsigned) status);
3212#ifdef VBOX
3213 // Enable interrupts
3214 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3215#endif /* VBOX */
3216 return 6;
3217 }
3218 break;
3219 }
3220 else {
3221 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3222 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3223 BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n", (unsigned) status);
3224#ifdef VBOX
3225 // Enable interrupts
3226 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3227#endif /* VBOX */
3228 return 7;
3229 }
3230 continue;
3231 }
3232 }
3233 // Enable interrupts
3234 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3235 return 0;
3236}
3237
3238// ---------------------------------------------------------------------------
3239// ATA/ATAPI driver : execute a packet command
3240// ---------------------------------------------------------------------------
3241 // returns
3242 // 0 : no error
3243 // 1 : error in parameters
3244 // 2 : BUSY bit set
3245 // 3 : error
3246 // 4 : not ready
3247Bit16u ata_cmd_packet(device, cmdlen, cmdseg, cmdoff, header, length, inout, bufseg, bufoff)
3248Bit8u cmdlen,inout;
3249Bit16u device,cmdseg, cmdoff, bufseg, bufoff;
3250Bit16u header;
3251Bit32u length;
3252{
3253 Bit16u ebda_seg=read_word(0x0040,0x000E);
3254 Bit16u iobase1, iobase2;
3255 Bit16u lcount, lbefore, lafter, count;
3256 Bit8u channel, slave;
3257 Bit8u status, mode, lmode;
3258 Bit32u total, transfer;
3259
3260 channel = device / 2;
3261 slave = device % 2;
3262
3263 // Data out is not supported yet
3264 if (inout == ATA_DATA_OUT) {
3265 BX_INFO("ata_cmd_packet: DATA_OUT not supported yet\n");
3266 return 1;
3267 }
3268
3269 // The header length must be even
3270 if (header & 1) {
3271 BX_DEBUG_ATA("ata_cmd_packet : header must be even (%04x)\n",header);
3272 return 1;
3273 }
3274
3275 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
3276 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
3277 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
3278 transfer= 0L;
3279
3280 if (cmdlen < 12) cmdlen=12;
3281 if (cmdlen > 12) cmdlen=16;
3282 cmdlen>>=1;
3283
3284 // Reset count of transferred data
3285 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
3286 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
3287
3288 status = inb(iobase1 + ATA_CB_STAT);
3289 if (status & ATA_CB_STAT_BSY) return 2;
3290
3291 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
3292 // outb(iobase1 + ATA_CB_FR, 0x00);
3293 // outb(iobase1 + ATA_CB_SC, 0x00);
3294 // outb(iobase1 + ATA_CB_SN, 0x00);
3295 outb(iobase1 + ATA_CB_CL, 0xfff0 & 0x00ff);
3296 outb(iobase1 + ATA_CB_CH, 0xfff0 >> 8);
3297 outb(iobase1 + ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
3298 outb(iobase1 + ATA_CB_CMD, ATA_CMD_PACKET);
3299
3300 // Device should ok to receive command
3301 while (1) {
3302 status = inb(iobase1 + ATA_CB_STAT);
3303 if ( !(status & ATA_CB_STAT_BSY) ) break;
3304 }
3305
3306 if (status & ATA_CB_STAT_ERR) {
3307 BX_DEBUG_ATA("ata_cmd_packet : error, status is %02x\n",status);
3308#ifdef VBOX
3309 // Enable interrupts
3310 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3311#endif /* VBOX */
3312 return 3;
3313 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
3314 BX_DEBUG_ATA("ata_cmd_packet : DRQ not set (status %02x)\n", (unsigned) status);
3315#ifdef VBOX
3316 // Enable interrupts
3317 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3318#endif /* VBOX */
3319 return 4;
3320 }
3321
3322 // Normalize address
3323 cmdseg += (cmdoff / 16);
3324 cmdoff %= 16;
3325
3326 // Send command to device
3327ASM_START
3328 sti ;; enable higher priority interrupts
3329
3330 push bp
3331 mov bp, sp
3332
3333 mov si, _ata_cmd_packet.cmdoff + 2[bp]
3334 mov ax, _ata_cmd_packet.cmdseg + 2[bp]
3335 mov cx, _ata_cmd_packet.cmdlen + 2[bp]
3336 mov es, ax ;; segment in es
3337
3338 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data write port
3339
3340 seg ES
3341 rep
3342 outsw ;; CX words transferred from port(DX) to ES:[SI]
3343
3344 pop bp
3345ASM_END
3346
3347 if (inout == ATA_DATA_NO) {
3348 status = inb(iobase1 + ATA_CB_STAT);
3349 }
3350 else {
3351 while (1) {
3352
3353#ifdef VBOX
3354 while (1) {
3355 status = inb(iobase1 + ATA_CB_STAT);
3356 if ( !(status & ATA_CB_STAT_BSY) ) break;
3357 }
3358#else /* VBOX */
3359 status = inb(iobase1 + ATA_CB_STAT);
3360#endif /* VBOX */
3361
3362 // Check if command completed
3363 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_DRQ) ) ==0 ) break;
3364
3365 if (status & ATA_CB_STAT_ERR) {
3366 BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status);
3367#ifdef VBOX
3368 // Enable interrupts
3369 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3370#endif /* VBOX */
3371 return 3;
3372 }
3373
3374 // Device must be ready to send data
3375 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3376 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3377 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", status);
3378#ifdef VBOX
3379 // Enable interrupts
3380 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3381#endif /* VBOX */
3382 return 4;
3383 }
3384
3385 // Normalize address
3386 bufseg += (bufoff / 16);
3387 bufoff %= 16;
3388
3389 // Get the byte count
3390 lcount = ((Bit16u)(inb(iobase1 + ATA_CB_CH))<<8)+inb(iobase1 + ATA_CB_CL);
3391
3392 // adjust to read what we want
3393 if(header>lcount) {
3394 lbefore=lcount;
3395 header-=lcount;
3396 lcount=0;
3397 }
3398 else {
3399 lbefore=header;
3400 header=0;
3401 lcount-=lbefore;
3402 }
3403
3404 if(lcount>length) {
3405 lafter=lcount-length;
3406 lcount=length;
3407 length=0;
3408 }
3409 else {
3410 lafter=0;
3411 length-=lcount;
3412 }
3413
3414 // Save byte count
3415 count = lcount;
3416
3417 BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore+lcount+lafter,lbefore,lcount,lafter);
3418 BX_DEBUG_ATA("to 0x%04x:0x%04x\n",bufseg,bufoff);
3419
3420 // If counts not dividable by 4, use 16bits mode
3421 lmode = mode;
3422 if (lbefore & 0x03) lmode=ATA_MODE_PIO16;
3423 if (lcount & 0x03) lmode=ATA_MODE_PIO16;
3424 if (lafter & 0x03) lmode=ATA_MODE_PIO16;
3425
3426 // adds an extra byte if count are odd. before is always even
3427 if (lcount & 0x01) {
3428 lcount+=1;
3429 if ((lafter > 0) && (lafter & 0x01)) {
3430 lafter-=1;
3431 }
3432 }
3433
3434 if (lmode == ATA_MODE_PIO32) {
3435 lcount>>=2; lbefore>>=2; lafter>>=2;
3436 }
3437 else {
3438 lcount>>=1; lbefore>>=1; lafter>>=1;
3439 }
3440
3441 ; // FIXME bcc bug
3442
3443ASM_START
3444 push bp
3445 mov bp, sp
3446
3447 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data read port
3448
3449 mov cx, _ata_cmd_packet.lbefore + 2[bp]
3450 jcxz ata_packet_no_before
3451
3452 mov ah, _ata_cmd_packet.lmode + 2[bp]
3453 cmp ah, #ATA_MODE_PIO32
3454 je ata_packet_in_before_32
3455
3456ata_packet_in_before_16:
3457 in ax, dx
3458 loop ata_packet_in_before_16
3459 jmp ata_packet_no_before
3460
3461ata_packet_in_before_32:
3462 push eax
3463ata_packet_in_before_32_loop:
3464 in eax, dx
3465 loop ata_packet_in_before_32_loop
3466 pop eax
3467
3468ata_packet_no_before:
3469 mov cx, _ata_cmd_packet.lcount + 2[bp]
3470 jcxz ata_packet_after
3471
3472 mov di, _ata_cmd_packet.bufoff + 2[bp]
3473 mov ax, _ata_cmd_packet.bufseg + 2[bp]
3474 mov es, ax
3475
3476 mov ah, _ata_cmd_packet.lmode + 2[bp]
3477 cmp ah, #ATA_MODE_PIO32
3478 je ata_packet_in_32
3479
3480ata_packet_in_16:
3481 rep
3482 insw ;; CX words transferred tp port(DX) to ES:[DI]
3483 jmp ata_packet_after
3484
3485ata_packet_in_32:
3486 rep
3487 insd ;; CX dwords transferred to port(DX) to ES:[DI]
3488
3489ata_packet_after:
3490 mov cx, _ata_cmd_packet.lafter + 2[bp]
3491 jcxz ata_packet_done
3492
3493 mov ah, _ata_cmd_packet.lmode + 2[bp]
3494 cmp ah, #ATA_MODE_PIO32
3495 je ata_packet_in_after_32
3496
3497ata_packet_in_after_16:
3498 in ax, dx
3499 loop ata_packet_in_after_16
3500 jmp ata_packet_done
3501
3502ata_packet_in_after_32:
3503 push eax
3504ata_packet_in_after_32_loop:
3505 in eax, dx
3506 loop ata_packet_in_after_32_loop
3507 pop eax
3508
3509ata_packet_done:
3510 pop bp
3511ASM_END
3512
3513 // Compute new buffer address
3514 bufoff += count;
3515
3516 // Save transferred bytes count
3517 transfer += count;
3518 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,transfer);
3519 }
3520 }
3521
3522 // Final check, device must be ready
3523 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3524 != ATA_CB_STAT_RDY ) {
3525 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", (unsigned) status);
3526#ifdef VBOX
3527 // Enable interrupts
3528 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3529#endif /* VBOX */
3530 return 4;
3531 }
3532
3533 // Enable interrupts
3534 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3535 return 0;
3536}
3537
3538// ---------------------------------------------------------------------------
3539// End of ATA/ATAPI Driver
3540// ---------------------------------------------------------------------------
3541
3542// ---------------------------------------------------------------------------
3543// Start of ATA/ATAPI generic functions
3544// ---------------------------------------------------------------------------
3545
3546#if 0 // currently unused
3547 Bit16u
3548atapi_get_sense(device)
3549 Bit16u device;
3550{
3551 Bit8u atacmd[12];
3552 Bit8u buffer[16];
3553 Bit8u i;
3554
3555 memsetb(get_SS(),atacmd,0,12);
3556
3557 // Request SENSE
3558 atacmd[0]=0x03;
3559 atacmd[4]=0x20;
3560 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 16L, ATA_DATA_IN, get_SS(), buffer) != 0)
3561 return 0x0002;
3562
3563 if ((buffer[0] & 0x7e) == 0x70) {
3564 return (((Bit16u)buffer[2]&0x0f)*0x100)+buffer[12];
3565 }
3566
3567 return 0;
3568}
3569
3570 Bit16u
3571atapi_is_ready(device)
3572 Bit16u device;
3573{
3574 Bit8u atacmd[12];
3575 Bit8u buffer[];
3576
3577 memsetb(get_SS(),atacmd,0,12);
3578
3579 // Test Unit Ready
3580 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3581 return 0x000f;
3582
3583 if (atapi_get_sense(device) !=0 ) {
3584 memsetb(get_SS(),atacmd,0,12);
3585
3586 // try to send Test Unit Ready again
3587 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3588 return 0x000f;
3589
3590 return atapi_get_sense(device);
3591 }
3592 return 0;
3593}
3594#endif
3595
3596 Bit16u
3597atapi_is_cdrom(device)
3598 Bit8u device;
3599{
3600 Bit16u ebda_seg=read_word(0x0040,0x000E);
3601
3602 if (device >= BX_MAX_ATA_DEVICES)
3603 return 0;
3604
3605 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_ATAPI)
3606 return 0;
3607
3608 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].device) != ATA_DEVICE_CDROM)
3609 return 0;
3610
3611 return 1;
3612}
3613
3614// ---------------------------------------------------------------------------
3615// End of ATA/ATAPI generic functions
3616// ---------------------------------------------------------------------------
3617
3618#endif // BX_USE_ATADRV
3619
3620#if BX_ELTORITO_BOOT
3621
3622// ---------------------------------------------------------------------------
3623// Start of El-Torito boot functions
3624// ---------------------------------------------------------------------------
3625
3626 void
3627cdemu_init()
3628{
3629 Bit16u ebda_seg=read_word(0x0040,0x000E);
3630
3631 // the only important data is this one for now
3632 write_byte(ebda_seg,&EbdaData->cdemu.active,0x00);
3633}
3634
3635 Bit8u
3636cdemu_isactive()
3637{
3638 Bit16u ebda_seg=read_word(0x0040,0x000E);
3639
3640 return(read_byte(ebda_seg,&EbdaData->cdemu.active));
3641}
3642
3643 Bit8u
3644cdemu_emulated_drive()
3645{
3646 Bit16u ebda_seg=read_word(0x0040,0x000E);
3647
3648 return(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
3649}
3650
3651static char isotag[6]="CD001";
3652static char eltorito[24]="EL TORITO SPECIFICATION";
3653//
3654// Returns ah: emulated drive, al: error code
3655//
3656 Bit16u
3657cdrom_boot()
3658{
3659 Bit16u ebda_seg=read_word(0x0040,0x000E);
3660 Bit8u atacmd[12], buffer[2048];
3661 Bit32u lba;
3662 Bit16u boot_segment, nbsectors, i, error;
3663 Bit8u device;
3664#ifdef VBOX
3665 Bit8u read_try;
3666#endif /* VBOX */
3667
3668 // Find out the first cdrom
3669 for (device=0; device<BX_MAX_ATA_DEVICES;device++) {
3670 if (atapi_is_cdrom(device)) break;
3671 }
3672
3673 // if not found
3674 if(device >= BX_MAX_ATA_DEVICES) return 2;
3675
3676 // Read the Boot Record Volume Descriptor
3677 memsetb(get_SS(),atacmd,0,12);
3678 atacmd[0]=0x28; // READ command
3679 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3680 atacmd[8]=(0x01 & 0x00ff); // Sectors
3681 atacmd[2]=(0x11 & 0xff000000) >> 24; // LBA
3682 atacmd[3]=(0x11 & 0x00ff0000) >> 16;
3683 atacmd[4]=(0x11 & 0x0000ff00) >> 8;
3684 atacmd[5]=(0x11 & 0x000000ff);
3685#ifdef VBOX
3686 for (read_try = 0; read_try <= 4; read_try++)
3687 {
3688 error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer);
3689 if (!error)
3690 break;
3691 }
3692 if (error)
3693 return 3;
3694#else /* !VBOX */
3695 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3696 return 3;
3697#endif /* !VBOX */
3698
3699 // Validity checks
3700 if(buffer[0]!=0)return 4;
3701 for(i=0;i<5;i++){
3702 if(buffer[1+i]!=read_byte(0xf000,&isotag[i]))return 5;
3703 }
3704 for(i=0;i<23;i++)
3705 if(buffer[7+i]!=read_byte(0xf000,&eltorito[i]))return 6;
3706
3707 // ok, now we calculate the Boot catalog address
3708 lba=buffer[0x4A]*0x1000000+buffer[0x49]*0x10000+buffer[0x48]*0x100+buffer[0x47];
3709
3710 // And we read the Boot Catalog
3711 memsetb(get_SS(),atacmd,0,12);
3712 atacmd[0]=0x28; // READ command
3713 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3714 atacmd[8]=(0x01 & 0x00ff); // Sectors
3715 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3716 atacmd[3]=(lba & 0x00ff0000) >> 16;
3717 atacmd[4]=(lba & 0x0000ff00) >> 8;
3718 atacmd[5]=(lba & 0x000000ff);
3719 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3720 return 7;
3721
3722 // Validation entry
3723 if(buffer[0x00]!=0x01)return 8; // Header
3724 if(buffer[0x01]!=0x00)return 9; // Platform
3725 if(buffer[0x1E]!=0x55)return 10; // key 1
3726 if(buffer[0x1F]!=0xAA)return 10; // key 2
3727
3728 // Initial/Default Entry
3729 if(buffer[0x20]!=0x88)return 11; // Bootable
3730
3731 write_byte(ebda_seg,&EbdaData->cdemu.media,buffer[0x21]);
3732 if(buffer[0x21]==0){
3733 // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
3734 // Win2000 cd boot needs to know it booted from cd
3735 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0xE0);
3736 }
3737 else if(buffer[0x21]<4)
3738 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x00);
3739 else
3740 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x80);
3741
3742 write_byte(ebda_seg,&EbdaData->cdemu.controller_index,device/2);
3743 write_byte(ebda_seg,&EbdaData->cdemu.device_spec,device%2);
3744
3745 boot_segment=buffer[0x23]*0x100+buffer[0x22];
3746 if(boot_segment==0x0000)boot_segment=0x07C0;
3747
3748 write_word(ebda_seg,&EbdaData->cdemu.load_segment,boot_segment);
3749 write_word(ebda_seg,&EbdaData->cdemu.buffer_segment,0x0000);
3750
3751 nbsectors=buffer[0x27]*0x100+buffer[0x26];
3752 write_word(ebda_seg,&EbdaData->cdemu.sector_count,nbsectors);
3753
3754 lba=buffer[0x2B]*0x1000000+buffer[0x2A]*0x10000+buffer[0x29]*0x100+buffer[0x28];
3755 write_dword(ebda_seg,&EbdaData->cdemu.ilba,lba);
3756
3757 // And we read the image in memory
3758 memsetb(get_SS(),atacmd,0,12);
3759 atacmd[0]=0x28; // READ command
3760 atacmd[7]=((1+(nbsectors-1)/4) & 0xff00) >> 8; // Sectors
3761 atacmd[8]=((1+(nbsectors-1)/4) & 0x00ff); // Sectors
3762 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3763 atacmd[3]=(lba & 0x00ff0000) >> 16;
3764 atacmd[4]=(lba & 0x0000ff00) >> 8;
3765 atacmd[5]=(lba & 0x000000ff);
3766 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, nbsectors*512L, ATA_DATA_IN, boot_segment,0)) != 0)
3767 return 12;
3768
3769 // Remember the media type
3770 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
3771 case 0x01: // 1.2M floppy
3772 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,15);
3773 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3774 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3775 break;
3776 case 0x02: // 1.44M floppy
3777 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,18);
3778 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3779 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3780 break;
3781 case 0x03: // 2.88M floppy
3782 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,36);
3783 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3784 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3785 break;
3786 case 0x04: // Harddrive
3787 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,read_byte(boot_segment,446+6)&0x3f);
3788 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,
3789 (read_byte(boot_segment,446+6)<<2) + read_byte(boot_segment,446+7) + 1);
3790 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,read_byte(boot_segment,446+5) + 1);
3791 break;
3792 }
3793
3794 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0) {
3795 // Increase bios installed hardware number of devices
3796 if(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)==0x00)
3797 write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
3798 else
3799 write_byte(ebda_seg, &EbdaData->ata.hdcount, read_byte(ebda_seg, &EbdaData->ata.hdcount) + 1);
3800 }
3801
3802
3803 // everything is ok, so from now on, the emulation is active
3804 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0)
3805 write_byte(ebda_seg,&EbdaData->cdemu.active,0x01);
3806
3807 // return the boot drive + no error
3808 return (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)*0x100)+0;
3809}
3810
3811// ---------------------------------------------------------------------------
3812// End of El-Torito boot functions
3813// ---------------------------------------------------------------------------
3814#endif // BX_ELTORITO_BOOT
3815
3816#ifdef VBOX_WITH_SCSI
3817# include "scsi.c"
3818#endif
3819
3820 void
3821int14_function(regs, ds, iret_addr)
3822 pusha_regs_t regs; // regs pushed from PUSHA instruction
3823 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
3824 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
3825{
3826 Bit16u addr,timer,val16;
3827 Bit8u timeout;
3828
3829 ASM_START
3830 sti
3831 ASM_END
3832
3833 addr = read_word(0x0040, (regs.u.r16.dx << 1));
3834 timeout = read_byte(0x0040, 0x007C + regs.u.r16.dx);
3835 if ((regs.u.r16.dx < 4) && (addr > 0)) {
3836 switch (regs.u.r8.ah) {
3837 case 0:
3838 outb(addr+3, inb(addr+3) | 0x80);
3839 if (regs.u.r8.al & 0xE0 == 0) {
3840 outb(addr, 0x17);
3841 outb(addr+1, 0x04);
3842 } else {
3843 val16 = 0x600 >> ((regs.u.r8.al & 0xE0) >> 5);
3844 outb(addr, val16 & 0xFF);
3845 outb(addr+1, val16 >> 8);
3846 }
3847 outb(addr+3, regs.u.r8.al & 0x1F);
3848 regs.u.r8.ah = inb(addr+5);
3849 regs.u.r8.al = inb(addr+6);
3850 ClearCF(iret_addr.flags);
3851 break;
3852 case 1:
3853 timer = read_word(0x0040, 0x006C);
3854 while (((inb(addr+5) & 0x60) != 0x60) && (timeout)) {
3855 val16 = read_word(0x0040, 0x006C);
3856 if (val16 != timer) {
3857 timer = val16;
3858 timeout--;
3859 }
3860 }
3861 if (timeout) outb(addr, regs.u.r8.al);
3862 regs.u.r8.ah = inb(addr+5);
3863 if (!timeout) regs.u.r8.ah |= 0x80;
3864 ClearCF(iret_addr.flags);
3865 break;
3866 case 2:
3867 timer = read_word(0x0040, 0x006C);
3868 while (((inb(addr+5) & 0x01) == 0) && (timeout)) {
3869 val16 = read_word(0x0040, 0x006C);
3870 if (val16 != timer) {
3871 timer = val16;
3872 timeout--;
3873 }
3874 }
3875 if (timeout) {
3876 regs.u.r8.ah = 0;
3877 regs.u.r8.al = inb(addr);
3878 } else {
3879 regs.u.r8.ah = inb(addr+5);
3880 }
3881 ClearCF(iret_addr.flags);
3882 break;
3883 case 3:
3884 regs.u.r8.ah = inb(addr+5);
3885 regs.u.r8.al = inb(addr+6);
3886 ClearCF(iret_addr.flags);
3887 break;
3888 default:
3889 SetCF(iret_addr.flags); // Unsupported
3890 }
3891 } else {
3892 SetCF(iret_addr.flags); // Unsupported
3893 }
3894}
3895
3896 void
3897int15_function(regs, ES, DS, FLAGS)
3898 pusha_regs_t regs; // REGS pushed via pusha
3899 Bit16u ES, DS, FLAGS;
3900{
3901 Bit16u ebda_seg=read_word(0x0040,0x000E);
3902 bx_bool prev_a20_enable;
3903 Bit16u base15_00;
3904 Bit8u base23_16;
3905 Bit16u ss;
3906 Bit16u BX,CX,DX;
3907
3908 Bit16u bRegister;
3909 Bit8u irqDisable;
3910
3911BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
3912
3913 switch (regs.u.r8.ah) {
3914#ifdef VBOX
3915 case 0x00: /* assorted functions */
3916 if (regs.u.r8.al != 0xc0)
3917 goto undecoded;
3918 /* GRUB calls int15 with ax=0x00c0 to get the ROM configuration table,
3919 * which we don't support, but logging that event is annoying. In fact
3920 * it is likely that they just misread some specs, because there is a
3921 * int15 BIOS function AH=0xc0 which sounds quite similar to what GRUB
3922 * wants to achieve. */
3923 SET_CF();
3924 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3925 break;
3926#endif
3927 case 0x24: /* A20 Control */
3928 switch (regs.u.r8.al) {
3929 case 0x00:
3930 set_enable_a20(0);
3931 CLEAR_CF();
3932 regs.u.r8.ah = 0;
3933 break;
3934 case 0x01:
3935 set_enable_a20(1);
3936 CLEAR_CF();
3937 regs.u.r8.ah = 0;
3938 break;
3939 case 0x02:
3940 regs.u.r8.al = (inb(0x92) >> 1) & 0x01;
3941 CLEAR_CF();
3942 regs.u.r8.ah = 0;
3943 break;
3944 case 0x03:
3945 CLEAR_CF();
3946 regs.u.r8.ah = 0;
3947 regs.u.r16.bx = 3;
3948 break;
3949 default:
3950 BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs.u.r8.al);
3951 SET_CF();
3952 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3953 }
3954 break;
3955
3956 case 0x41:
3957 SET_CF();
3958 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3959 break;
3960
3961 case 0x4f:
3962 /* keyboard intercept */
3963#if BX_CPU < 2
3964 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3965#else
3966 // nop
3967#endif
3968 SET_CF();
3969 break;
3970
3971 case 0x52: // removable media eject
3972 CLEAR_CF();
3973 regs.u.r8.ah = 0; // "ok ejection may proceed"
3974 break;
3975
3976 case 0x83: {
3977 if( regs.u.r8.al == 0 ) {
3978 // Set Interval requested.
3979 if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
3980 // Interval not already set.
3981 write_byte( 0x40, 0xA0, 1 ); // Set status byte.
3982 write_word( 0x40, 0x98, ES ); // Byte location, segment
3983 write_word( 0x40, 0x9A, regs.u.r16.bx ); // Byte location, offset
3984 write_word( 0x40, 0x9C, regs.u.r16.dx ); // Low word, delay
3985 write_word( 0x40, 0x9E, regs.u.r16.cx ); // High word, delay.
3986 CLEAR_CF( );
3987 irqDisable = inb( 0xA1 );
3988 outb( 0xA1, irqDisable & 0xFE );
3989 bRegister = inb_cmos( 0xB ); // Unmask IRQ8 so INT70 will get through.
3990 outb_cmos( 0xB, bRegister | 0x40 ); // Turn on the Periodic Interrupt timer
3991 } else {
3992 // Interval already set.
3993 BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
3994 SET_CF();
3995 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3996 }
3997 } else if( regs.u.r8.al == 1 ) {
3998 // Clear Interval requested
3999 write_byte( 0x40, 0xA0, 0 ); // Clear status byte
4000 CLEAR_CF( );
4001 bRegister = inb_cmos( 0xB );
4002 outb_cmos( 0xB, bRegister & ~0x40 ); // Turn off the Periodic Interrupt timer
4003 } else {
4004 BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
4005 SET_CF();
4006 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4007 regs.u.r8.al--;
4008 }
4009
4010 break;
4011 }
4012
4013 case 0x87:
4014#if BX_CPU < 3
4015# error "Int15 function 87h not supported on < 80386"
4016#endif
4017 // +++ should probably have descriptor checks
4018 // +++ should have exception handlers
4019
4020 // turn off interrupts
4021ASM_START
4022 cli
4023ASM_END
4024
4025 prev_a20_enable = set_enable_a20(1); // enable A20 line
4026
4027 // 128K max of transfer on 386+ ???
4028 // source == destination ???
4029
4030 // ES:SI points to descriptor table
4031 // offset use initially comments
4032 // ==============================================
4033 // 00..07 Unused zeros Null descriptor
4034 // 08..0f GDT zeros filled in by BIOS
4035 // 10..17 source ssssssss source of data
4036 // 18..1f dest dddddddd destination of data
4037 // 20..27 CS zeros filled in by BIOS
4038 // 28..2f SS zeros filled in by BIOS
4039
4040 //es:si
4041 //eeee0
4042 //0ssss
4043 //-----
4044
4045// check for access rights of source & dest here
4046
4047 // Initialize GDT descriptor
4048 base15_00 = (ES << 4) + regs.u.r16.si;
4049 base23_16 = ES >> 12;
4050 if (base15_00 < (ES<<4))
4051 base23_16++;
4052 write_word(ES, regs.u.r16.si+0x08+0, 47); // limit 15:00 = 6 * 8bytes/descriptor
4053 write_word(ES, regs.u.r16.si+0x08+2, base15_00);// base 15:00
4054 write_byte(ES, regs.u.r16.si+0x08+4, base23_16);// base 23:16
4055 write_byte(ES, regs.u.r16.si+0x08+5, 0x93); // access
4056 write_word(ES, regs.u.r16.si+0x08+6, 0x0000); // base 31:24/reserved/limit 19:16
4057
4058 // Initialize CS descriptor
4059 write_word(ES, regs.u.r16.si+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
4060 write_word(ES, regs.u.r16.si+0x20+2, 0x0000);// base 15:00
4061 write_byte(ES, regs.u.r16.si+0x20+4, 0x000f);// base 23:16
4062 write_byte(ES, regs.u.r16.si+0x20+5, 0x9b); // access
4063 write_word(ES, regs.u.r16.si+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
4064
4065 // Initialize SS descriptor
4066 ss = get_SS();
4067 base15_00 = ss << 4;
4068 base23_16 = ss >> 12;
4069 write_word(ES, regs.u.r16.si+0x28+0, 0xffff); // limit 15:00 = normal 64K limit
4070 write_word(ES, regs.u.r16.si+0x28+2, base15_00);// base 15:00
4071 write_byte(ES, regs.u.r16.si+0x28+4, base23_16);// base 23:16
4072 write_byte(ES, regs.u.r16.si+0x28+5, 0x93); // access
4073 write_word(ES, regs.u.r16.si+0x28+6, 0x0000); // base 31:24/reserved/limit 19:16
4074
4075 CX = regs.u.r16.cx;
4076ASM_START
4077 // Compile generates locals offset info relative to SP.
4078 // Get CX (word count) from stack.
4079 mov bx, sp
4080 SEG SS
4081 mov cx, _int15_function.CX [bx]
4082
4083 // since we need to set SS:SP, save them to the BDA
4084 // for future restore
4085 push eax
4086 xor eax, eax
4087 mov ds, ax
4088 mov 0x0469, ss
4089 mov 0x0467, sp
4090
4091 SEG ES
4092 lgdt [si + 0x08]
4093 SEG CS
4094 lidt [pmode_IDT_info]
4095 ;; perhaps do something with IDT here
4096
4097 ;; set PE bit in CR0
4098 mov eax, cr0
4099 or al, #0x01
4100 mov cr0, eax
4101 ;; far jump to flush CPU queue after transition to protected mode
4102 JMP_AP(0x0020, protected_mode)
4103
4104protected_mode:
4105 ;; GDT points to valid descriptor table, now load SS, DS, ES
4106 mov ax, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
4107 mov ss, ax
4108 mov ax, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
4109 mov ds, ax
4110 mov ax, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
4111 mov es, ax
4112 xor si, si
4113 xor di, di
4114 cld
4115 rep
4116 movsw ;; move CX words from DS:SI to ES:DI
4117
4118 ;; make sure DS and ES limits are 64KB
4119 mov ax, #0x28
4120 mov ds, ax
4121 mov es, ax
4122
4123 ;; reset PG bit in CR0 ???
4124 mov eax, cr0
4125 and al, #0xFE
4126 mov cr0, eax
4127
4128 ;; far jump to flush CPU queue after transition to real mode
4129 JMP_AP(0xf000, real_mode)
4130
4131real_mode:
4132 ;; restore IDT to normal real-mode defaults
4133 SEG CS
4134 lidt [rmode_IDT_info]
4135
4136 // restore SS:SP from the BDA
4137 xor ax, ax
4138 mov ds, ax
4139 mov ss, 0x0469
4140 mov sp, 0x0467
4141 pop eax
4142ASM_END
4143
4144 set_enable_a20(prev_a20_enable);
4145
4146 // turn back on interrupts
4147ASM_START
4148 sti
4149ASM_END
4150
4151 regs.u.r8.ah = 0;
4152 CLEAR_CF();
4153 break;
4154
4155
4156 case 0x88:
4157 // Get the amount of extended memory (above 1M)
4158#if BX_CPU < 2
4159 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4160 SET_CF();
4161#else
4162 regs.u.r8.al = inb_cmos(0x30);
4163 regs.u.r8.ah = inb_cmos(0x31);
4164
4165 // According to Ralf Brown's interrupt the limit should be 15M,
4166 // but real machines mostly return max. 63M.
4167 if(regs.u.r16.ax > 0xffc0)
4168 regs.u.r16.ax = 0xffc0;
4169
4170 CLEAR_CF();
4171#endif
4172 break;
4173
4174#ifdef VBOX
4175 case 0x89:
4176 // Switch to Protected Mode.
4177 // ES:DI points to user-supplied GDT
4178 // BH/BL contains starting interrupt numbers for PIC0/PIC1
4179 // This subfunction does not return!
4180
4181// turn off interrupts
4182ASM_START
4183 cli
4184ASM_END
4185
4186 set_enable_a20(1); // enable A20 line; we're supposed to fail if that fails
4187
4188 // Initialize CS descriptor for BIOS
4189 write_word(ES, regs.u.r16.si+0x38+0, 0xffff);// limit 15:00 = normal 64K limit
4190 write_word(ES, regs.u.r16.si+0x38+2, 0x0000);// base 15:00
4191 write_byte(ES, regs.u.r16.si+0x38+4, 0x000f);// base 23:16 (hardcoded to f000:0000)
4192 write_byte(ES, regs.u.r16.si+0x38+5, 0x9b); // access
4193 write_word(ES, regs.u.r16.si+0x38+6, 0x0000);// base 31:24/reserved/limit 19:16
4194
4195 BX = regs.u.r16.bx;
4196ASM_START
4197 // Compiler generates locals offset info relative to SP.
4198 // Get BX (PIC offsets) from stack.
4199 mov bx, sp
4200 SEG SS
4201 mov bx, _int15_function.BX [bx]
4202
4203 // Program PICs
4204 mov al, #0x11 ; send initialisation commands
4205 out 0x20, al
4206 out 0xa0, al
4207 mov al, bh
4208 out 0x21, al
4209 mov al, bl
4210 out 0xa1, al
4211 mov al, #0x04
4212 out 0x21, al
4213 mov al, #0x02
4214 out 0xa1, al
4215 mov al, #0x01
4216 out 0x21, al
4217 out 0xa1, al
4218 mov al, #0xff ; mask all IRQs, user must re-enable
4219 out 0x21, al
4220 out 0xa1, al
4221
4222 // Load GDT and IDT from supplied data
4223 SEG ES
4224 lgdt [si + 0x08]
4225 SEG ES
4226 lidt [si + 0x10]
4227
4228 // set PE bit in CR0
4229 mov eax, cr0
4230 or al, #0x01
4231 mov cr0, eax
4232 // far jump to flush CPU queue after transition to protected mode
4233 JMP_AP(0x0038, protmode_switch)
4234
4235protmode_switch:
4236 ;; GDT points to valid descriptor table, now load SS, DS, ES
4237 mov ax, #0x28
4238 mov ss, ax
4239 mov ax, #0x18
4240 mov ds, ax
4241 mov ax, #0x20
4242 mov es, ax
4243
4244 // unwind the stack - this will break if calling sequence changes!
4245 mov sp,bp
4246 add sp,#4 ; skip return address
4247 popa ; restore regs
4248 pop ax ; skip saved es
4249 pop ax ; skip saved ds
4250 pop ax ; skip saved flags
4251
4252 // return to caller - note that we do not use IRET because
4253 // we cannot enable interrupts
4254 pop cx ; get return offset
4255 pop ax ; skip return segment
4256 pop ax ; skip flags
4257 mov ax, #0x30 ; ah must be 0 on successful exit
4258 push ax
4259 push cx ; re-create modified ret address on stack
4260 retf
4261
4262ASM_END
4263
4264 break;
4265#endif /* VBOX */
4266
4267 case 0x90:
4268 /* Device busy interrupt. Called by Int 16h when no key available */
4269 break;
4270
4271 case 0x91:
4272 /* Interrupt complete. Called by Int 16h when key becomes available */
4273 break;
4274
4275 case 0xbf:
4276 BX_INFO("*** int 15h function AH=bf not yet supported!\n");
4277 SET_CF();
4278 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4279 break;
4280
4281 case 0xC0:
4282#if 0
4283 SET_CF();
4284 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4285 break;
4286#endif
4287 CLEAR_CF();
4288 regs.u.r8.ah = 0;
4289 regs.u.r16.bx = BIOS_CONFIG_TABLE;
4290 ES = 0xF000;
4291 break;
4292
4293 case 0xc1:
4294 ES = ebda_seg;
4295 CLEAR_CF();
4296 break;
4297
4298 case 0xd8:
4299 bios_printf(BIOS_PRINTF_DEBUG, "EISA BIOS not present\n");
4300 SET_CF();
4301 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4302 break;
4303
4304#ifdef VBOX
4305 /* Make the BIOS warning for pretty much every Linux kernel start
4306 * disappear - it calls with ax=0xe980 to figure out SMI info. */
4307 case 0xe9: /* SMI functions (SpeedStep and similar things) */
4308 SET_CF();
4309 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4310 break;
4311 case 0xec: /* AMD64 target operating mode callback */
4312 if (regs.u.r8.al != 0)
4313 goto undecoded;
4314 regs.u.r8.ah = 0;
4315 if (regs.u.r8.bl >= 1 && regs.u.r8.bl <= 3)
4316 CLEAR_CF(); /* Accepted value. */
4317 else
4318 SET_CF(); /* Reserved, error. */
4319 break;
4320undecoded:
4321#endif /* VBOX */
4322 default:
4323 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4324 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4325 SET_CF();
4326 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4327 break;
4328 }
4329}
4330
4331#if BX_USE_PS2_MOUSE
4332 void
4333int15_function_mouse(regs, ES, DS, FLAGS)
4334 pusha_regs_t regs; // REGS pushed via pusha
4335 Bit16u ES, DS, FLAGS;
4336{
4337 Bit16u ebda_seg=read_word(0x0040,0x000E);
4338 Bit8u mouse_flags_1, mouse_flags_2;
4339 Bit16u mouse_driver_seg;
4340 Bit16u mouse_driver_offset;
4341 Bit8u mouse_cmd;
4342 Bit8u ret, mouse_data1, mouse_data2, mouse_data3;
4343
4344BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4345
4346 switch (regs.u.r8.ah) {
4347 case 0xC2:
4348 // Return Codes status in AH
4349 // =========================
4350 // 00: success
4351 // 01: invalid subfunction (AL > 7)
4352 // 02: invalid input value (out of allowable range)
4353 // 03: interface error
4354 // 04: resend command received from mouse controller,
4355 // device driver should attempt command again
4356 // 05: cannot enable mouse, since no far call has been installed
4357 // 80/86: mouse service not implemented
4358
4359 if (regs.u.r8.al > 7) {
4360BX_DEBUG_INT15("unsupported subfn\n");
4361 // invalid function
4362 SET_CF();
4363 regs.u.r8.ah = 1;
4364 break;
4365 }
4366
4367 // Valid subfn; disable AUX input and IRQ12, assume no error
4368 set_kbd_command_byte(0x65);
4369 CLEAR_CF();
4370 regs.u.r8.ah = 0;
4371
4372 switch (regs.u.r8.al) {
4373 case 0: // Disable/Enable Mouse
4374BX_DEBUG_INT15("case 0: ");
4375 if (regs.u.r8.bh > 1) {
4376 BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs.u.r8.bh);
4377 // invalid subfunction
4378 SET_CF();
4379 regs.u.r8.ah = 1;
4380 break;
4381 }
4382 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4383 if ( (mouse_flags_2 & 0x80) == 0 ) {
4384 BX_DEBUG_INT15("INT 15h C2 Enable/Disable Mouse, no far call handler\n");
4385 SET_CF();
4386 regs.u.r8.ah = 5; // no far call installed
4387 break;
4388 }
4389 if (regs.u.r8.bh == 0) {
4390BX_DEBUG_INT15("Disable Mouse\n");
4391 mouse_cmd = 0xF5; // disable mouse command
4392 } else {
4393BX_DEBUG_INT15("Enable Mouse\n");
4394 mouse_cmd = 0xF4; // enable mouse command
4395 }
4396
4397 ret = send_to_mouse_ctrl(mouse_cmd); // disable mouse command
4398 if (ret == 0) {
4399 ret = get_mouse_data(&mouse_data1);
4400 if ( (ret == 0) || (mouse_data1 == 0xFA) ) {
4401 // success
4402 break;
4403 }
4404 }
4405
4406 // interface error
4407 SET_CF();
4408 regs.u.r8.ah = 3;
4409 break;
4410
4411 case 5: // Initialize Mouse
4412 // Valid package sizes are 1 to 8
4413 if ( (regs.u.r8.bh < 1) || (regs.u.r8.bh > 8) ) {
4414 SET_CF();
4415 regs.u.r8.ah = 2; // invalid input
4416 break;
4417 }
4418 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4419 mouse_flags_2 = (mouse_flags_2 & 0xf8) | (regs.u.r8.bh - 1);
4420 write_byte(ebda_seg, 0x0027, mouse_flags_2);
4421 // fall through!
4422
4423 case 1: // Reset Mouse
4424BX_DEBUG_INT15("case 1 or 5:\n");
4425 // clear current package byte index
4426 mouse_flags_1 = read_byte(ebda_seg, 0x0026);
4427 mouse_flags_1 = mouse_flags_1 & 0xf8;
4428 write_byte(ebda_seg, 0x0026, mouse_flags_1);
4429 ret = send_to_mouse_ctrl(0xFF); // reset mouse command
4430 if (ret == 0) {
4431 ret = get_mouse_data(&mouse_data3);
4432 // if no mouse attached, it will return RESEND
4433 if (mouse_data3 == 0xfe) {
4434 SET_CF();
4435 regs.u.r8.ah = 4; // resend
4436 break;
4437 }
4438 if (mouse_data3 != 0xfa)
4439 BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3);
4440 if ( ret == 0 ) {
4441 ret = get_mouse_data(&mouse_data1);
4442 if ( ret == 0 ) {
4443 ret = get_mouse_data(&mouse_data2);
4444 if ( ret == 0 ) {
4445 // success
4446 regs.u.r8.bl = mouse_data1;
4447 regs.u.r8.bh = mouse_data2;
4448 break;
4449 }
4450 }
4451 }
4452 }
4453
4454 // interface error
4455 SET_CF();
4456 regs.u.r8.ah = 3;
4457 break;
4458
4459 case 2: // Set Sample Rate
4460BX_DEBUG_INT15("case 2:\n");
4461 switch (regs.u.r8.bh) {
4462 case 0: mouse_data1 = 10; break; // 10 reports/sec
4463 case 1: mouse_data1 = 20; break; // 20 reports/sec
4464 case 2: mouse_data1 = 40; break; // 40 reports/sec
4465 case 3: mouse_data1 = 60; break; // 60 reports/sec
4466 case 4: mouse_data1 = 80; break; // 80 reports/sec
4467 case 5: mouse_data1 = 100; break; // 100 reports/sec (default)
4468 case 6: mouse_data1 = 200; break; // 200 reports/sec
4469 default: mouse_data1 = 0;
4470 }
4471 if (mouse_data1 > 0) {
4472 ret = send_to_mouse_ctrl(0xF3); // set sample rate command
4473 if (ret == 0) {
4474 ret = get_mouse_data(&mouse_data2);
4475 ret = send_to_mouse_ctrl(mouse_data1);
4476 ret = get_mouse_data(&mouse_data2);
4477 // success
4478 } else {
4479 // interface error
4480 SET_CF();
4481 regs.u.r8.ah = 3;
4482 }
4483 } else {
4484 // invalid input
4485 SET_CF();
4486 regs.u.r8.ah = 2;
4487 }
4488 break;
4489
4490 case 3: // Set Resolution
4491BX_DEBUG_INT15("case 3:\n");
4492 // BX:
4493 // 0 = 25 dpi, 1 count per millimeter
4494 // 1 = 50 dpi, 2 counts per millimeter
4495 // 2 = 100 dpi, 4 counts per millimeter
4496 // 3 = 200 dpi, 8 counts per millimeter
4497 if (regs.u.r8.bh < 4) {
4498 ret = send_to_mouse_ctrl(0xE8); // set resolution command
4499 if (ret == 0) {
4500 ret = get_mouse_data(&mouse_data1);
4501 if (mouse_data1 != 0xfa)
4502 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4503 ret = send_to_mouse_ctrl(regs.u.r8.bh);
4504 ret = get_mouse_data(&mouse_data1);
4505 if (mouse_data1 != 0xfa)
4506 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4507 // success
4508 } else {
4509 // interface error
4510 SET_CF();
4511 regs.u.r8.ah = 3;
4512 }
4513 } else {
4514 // invalid input
4515 SET_CF();
4516 regs.u.r8.ah = 2;
4517 }
4518 break;
4519
4520 case 4: // Get Device ID
4521BX_DEBUG_INT15("case 4:\n");
4522 ret = send_to_mouse_ctrl(0xF2); // get mouse ID command
4523 if (ret == 0) {
4524 ret = get_mouse_data(&mouse_data1);
4525 ret = get_mouse_data(&mouse_data2);
4526 regs.u.r8.bh = mouse_data2;
4527 // success
4528 } else {
4529 // interface error
4530 SET_CF();
4531 regs.u.r8.ah = 3;
4532 }
4533 break;
4534
4535 case 6: // Return Status & Set Scaling Factor...
4536BX_DEBUG_INT15("case 6:\n");
4537 switch (regs.u.r8.bh) {
4538 case 0: // Return Status
4539 ret = send_to_mouse_ctrl(0xE9); // get mouse info command
4540 if (ret == 0) {
4541 ret = get_mouse_data(&mouse_data1);
4542 if (mouse_data1 != 0xfa)
4543 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4544 if (ret == 0) {
4545 ret = get_mouse_data(&mouse_data1);
4546 if ( ret == 0 ) {
4547 ret = get_mouse_data(&mouse_data2);
4548 if ( ret == 0 ) {
4549 ret = get_mouse_data(&mouse_data3);
4550 if ( ret == 0 ) {
4551 regs.u.r8.bl = mouse_data1;
4552 regs.u.r8.cl = mouse_data2;
4553 regs.u.r8.dl = mouse_data3;
4554 // success
4555 break;
4556 }
4557 }
4558 }
4559 }
4560 }
4561
4562 // interface error
4563 SET_CF();
4564 regs.u.r8.ah = 3;
4565 break;
4566
4567 case 1: // Set Scaling Factor to 1:1
4568 case 2: // Set Scaling Factor to 2:1
4569 if (regs.u.r8.bh == 1) {
4570 ret = send_to_mouse_ctrl(0xE6);
4571 } else {
4572 ret = send_to_mouse_ctrl(0xE7);
4573 }
4574 if (ret == 0) {
4575 get_mouse_data(&mouse_data1);
4576 ret = (mouse_data1 != 0xFA);
4577 }
4578 if (ret != 0) {
4579 // interface error
4580 SET_CF();
4581 regs.u.r8.ah = 3;
4582 }
4583 break;
4584
4585 default:
4586 BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs.u.r8.bh);
4587 // invalid subfunction
4588 SET_CF();
4589 regs.u.r8.ah = 1;
4590 }
4591 break;
4592
4593 case 7: // Set Mouse Handler Address
4594BX_DEBUG_INT15("case 7:\n");
4595 mouse_driver_seg = ES;
4596 mouse_driver_offset = regs.u.r16.bx;
4597 write_word(ebda_seg, 0x0022, mouse_driver_offset);
4598 write_word(ebda_seg, 0x0024, mouse_driver_seg);
4599 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4600 if (mouse_driver_offset == 0 && mouse_driver_seg == 0) {
4601 /* remove handler */
4602 if ( (mouse_flags_2 & 0x80) != 0 ) {
4603 mouse_flags_2 &= ~0x80;
4604 }
4605 }
4606 else {
4607 /* install handler */
4608 mouse_flags_2 |= 0x80;
4609 }
4610 write_byte(ebda_seg, 0x0027, mouse_flags_2);
4611 break;
4612
4613 default:
4614 BX_PANIC("INT 15h C2 default case entered\n");
4615 // invalid subfunction
4616 SET_CF();
4617 regs.u.r8.ah = 1;
4618 }
4619BX_DEBUG_INT15("returning cf = %u, ah = %02x\n", (unsigned)GET_CF(), (unsigned)regs.u.r8.ah);
4620 // Re-enable AUX input and IRQ12
4621 set_kbd_command_byte(0x47);
4622 break;
4623
4624 default:
4625 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4626 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4627 SET_CF();
4628 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4629 break;
4630 }
4631}
4632#endif // BX_USE_PS2_MOUSE
4633
4634
4635void set_e820_range(ES, DI, start, end, extra_start, extra_end, type)
4636 Bit16u ES;
4637 Bit16u DI;
4638 Bit32u start;
4639 Bit32u end;
4640 Bit8u extra_start;
4641 Bit8u extra_end;
4642 Bit16u type;
4643{
4644 write_word(ES, DI, start);
4645 write_word(ES, DI+2, start >> 16);
4646 write_word(ES, DI+4, extra_start);
4647 write_word(ES, DI+6, 0x00);
4648
4649 end -= start;
4650 extra_end -= extra_start;
4651 write_word(ES, DI+8, end);
4652 write_word(ES, DI+10, end >> 16);
4653 write_word(ES, DI+12, extra_end);
4654 write_word(ES, DI+14, 0x0000);
4655
4656 write_word(ES, DI+16, type);
4657 write_word(ES, DI+18, 0x0);
4658}
4659
4660 void
4661int15_function32(regs, ES, DS, FLAGS)
4662 pushad_regs_t regs; // REGS pushed via pushad
4663 Bit16u ES, DS, FLAGS;
4664{
4665 Bit32u extended_memory_size=0; // 64bits long
4666 Bit32u extra_lowbits_memory_size=0;
4667 Bit16u CX,DX;
4668 Bit8u extra_highbits_memory_size=0;
4669 Bit32u mcfgStart, mcfgSize;
4670
4671BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4672
4673 switch (regs.u.r8.ah) {
4674 case 0x86:
4675 // Wait for CX:DX microseconds. currently using the
4676 // refresh request port 0x61 bit4, toggling every 15usec
4677
4678 CX = regs.u.r16.cx;
4679 DX = regs.u.r16.dx;
4680
4681ASM_START
4682 sti
4683
4684 ;; Get the count in eax
4685 ;; VBOX: corrected _int15_function -> _int15_function32 here.
4686 mov bx, sp
4687 SEG SS
4688 mov ax, _int15_function32.CX [bx]
4689 shl eax, #16
4690 SEG SS
4691 mov ax, _int15_function32.DX [bx]
4692
4693 ;; convert to numbers of 15usec ticks
4694 mov ebx, #15
4695 xor edx, edx
4696 div eax, ebx
4697 mov ecx, eax
4698
4699 ;; wait for ecx number of refresh requests
4700 in al, #0x61
4701 and al,#0x10
4702 mov ah, al
4703
4704 or ecx, ecx
4705 je int1586_tick_end
4706int1586_tick:
4707 in al, #0x61
4708 and al,#0x10
4709 cmp al, ah
4710 je int1586_tick
4711 mov ah, al
4712 dec ecx
4713 jnz int1586_tick
4714int1586_tick_end:
4715ASM_END
4716
4717 break;
4718
4719 case 0xe8:
4720 switch(regs.u.r8.al)
4721 {
4722 case 0x20: // coded by osmaker aka K.J.
4723 if(regs.u.r32.edx == 0x534D4150)
4724 {
4725 extended_memory_size = inb_cmos(0x35);
4726 extended_memory_size <<= 8;
4727 extended_memory_size |= inb_cmos(0x34);
4728 extended_memory_size *= 64;
4729#ifndef VBOX /* The following excludes 0xf0000000 thru 0xffffffff. Trust DevPcBios.cpp to get this right. */
4730 // greater than EFF00000???
4731 if(extended_memory_size > 0x3bc000) {
4732 extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4733 }
4734#endif /* !VBOX */
4735 extended_memory_size *= 1024;
4736 extended_memory_size += (16L * 1024 * 1024);
4737
4738 if(extended_memory_size <= (16L * 1024 * 1024)) {
4739 extended_memory_size = inb_cmos(0x31);
4740 extended_memory_size <<= 8;
4741 extended_memory_size |= inb_cmos(0x30);
4742 extended_memory_size *= 1024;
4743 extended_memory_size += (1L * 1024 * 1024);
4744 }
4745
4746#ifdef VBOX /* We've already used the CMOS entries for SATA.
4747 BTW. This is the amount of memory above 4GB measured in 64KB units. */
4748 extra_lowbits_memory_size = inb_cmos(0x62);
4749 extra_lowbits_memory_size <<= 8;
4750 extra_lowbits_memory_size |= inb_cmos(0x61);
4751 extra_lowbits_memory_size <<= 16;
4752 extra_highbits_memory_size = inb_cmos(0x63);
4753 /* 0x64 and 0x65 can be used if we need to dig 1 TB or more at a later point. */
4754#else
4755 extra_lowbits_memory_size = inb_cmos(0x5c);
4756 extra_lowbits_memory_size <<= 8;
4757 extra_lowbits_memory_size |= inb_cmos(0x5b);
4758 extra_lowbits_memory_size *= 64;
4759 extra_lowbits_memory_size *= 1024;
4760 extra_highbits_memory_size = inb_cmos(0x5d);
4761#endif /* !VBOX */
4762
4763 mcfgStart = 0;
4764 mcfgSize = 0;
4765
4766 switch(regs.u.r16.bx)
4767 {
4768 case 0:
4769 set_e820_range(ES, regs.u.r16.di,
4770#ifndef VBOX /** @todo Upstream suggests the following, needs checking. (see next as well) */
4771 0x0000000L, 0x0009f000L, 0, 0, 1);
4772#else
4773 0x0000000L, 0x0009fc00L, 0, 0, 1);
4774#endif
4775 regs.u.r32.ebx = 1;
4776 break;
4777 case 1:
4778 set_e820_range(ES, regs.u.r16.di,
4779#ifndef VBOX /** @todo Upstream suggests the following, needs checking. (see next as well) */
4780 0x0009f000L, 0x000a0000L, 0, 0, 2);
4781#else
4782 0x0009fc00L, 0x000a0000L, 0, 0, 2);
4783#endif
4784 regs.u.r32.ebx = 2;
4785 break;
4786 case 2:
4787#ifdef VBOX
4788 /* Mark the BIOS as reserved. VBox doesn't currently
4789 * use the 0xe0000-0xeffff area. It does use the
4790 * 0xd0000-0xdffff area for the BIOS logo, but it's
4791 * not worth marking it as reserved. Note that various
4792 * Windows versions don't accept (read: in debug builds
4793 * they trigger the "Too many similar traps" assertion)
4794 * a single reserved range from 0xd0000 to 0xffffff.
4795 * A 128K area starting from 0xd0000 works. */
4796 set_e820_range(ES, regs.u.r16.di,
4797 0x000f0000L, 0x00100000L, 0, 0, 2);
4798#else /* !VBOX */
4799 set_e820_range(ES, regs.u.r16.di,
4800 0x000e8000L, 0x00100000L, 0, 0, 2);
4801#endif /* !VBOX */
4802 regs.u.r32.ebx = 3;
4803 break;
4804 case 3:
4805#if BX_ROMBIOS32 || defined(VBOX)
4806 set_e820_range(ES, regs.u.r16.di,
4807 0x00100000L,
4808 extended_memory_size - ACPI_DATA_SIZE, 0, 0, 1);
4809 regs.u.r32.ebx = 4;
4810#else
4811 set_e820_range(ES, regs.u.r16.di,
4812 0x00100000L,
4813 extended_memory_size, 1);
4814 regs.u.r32.ebx = 5;
4815#endif
4816 break;
4817 case 4:
4818 set_e820_range(ES, regs.u.r16.di,
4819 extended_memory_size - ACPI_DATA_SIZE,
4820 extended_memory_size, 0, 0, 3); // ACPI RAM
4821 regs.u.r32.ebx = 5;
4822 break;
4823 case 5:
4824 /* 256KB BIOS area at the end of 4 GB */
4825#ifdef VBOX
4826 /* We don't set the end to 1GB here and rely on the 32-bit
4827 unsigned wrap around effect (0-0xfffc0000L). */
4828#endif
4829 set_e820_range(ES, regs.u.r16.di,
4830 0xfffc0000L, 0x00000000L, 0, 0, 2);
4831 if (mcfgStart != 0)
4832 regs.u.r32.ebx = 6;
4833 else
4834 {
4835 if (extra_highbits_memory_size || extra_lowbits_memory_size)
4836 regs.u.r32.ebx = 7;
4837 else
4838 regs.u.r32.ebx = 0;
4839 }
4840 break;
4841 case 6:
4842 /* PCI MMIO config space (MCFG) */
4843 set_e820_range(ES, regs.u.r16.di,
4844 mcfgStart, mcfgStart + mcfgSize, 0, 0, 2);
4845
4846 if (extra_highbits_memory_size || extra_lowbits_memory_size)
4847 regs.u.r32.ebx = 7;
4848 else
4849 regs.u.r32.ebx = 0;
4850 break;
4851 case 7:
4852#ifdef VBOX /* Don't succeeded if no memory above 4 GB. */
4853 /* Mapping of memory above 4 GB if present.
4854 Note: set_e820_range needs do no borrowing in the
4855 subtraction because of the nice numbers. */
4856 if (extra_highbits_memory_size || extra_lowbits_memory_size)
4857 {
4858 set_e820_range(ES, regs.u.r16.di,
4859 0x00000000L, extra_lowbits_memory_size,
4860 1 /*GB*/, extra_highbits_memory_size + 1 /*GB*/, 1);
4861 regs.u.r32.ebx = 0;
4862 }
4863 break;
4864 /* fall thru */
4865#else /* !VBOX */
4866 /* Mapping of memory above 4 GB */
4867 set_e820_range(ES, regs.u.r16.di, 0x00000000L,
4868 extra_lowbits_memory_size, 1, extra_highbits_memory_size
4869 + 1, 1);
4870 regs.u.r32.ebx = 0;
4871 break;
4872#endif /* !VBOX */
4873 default: /* AX=E820, DX=534D4150, BX unrecognized */
4874 goto int15_unimplemented;
4875 break;
4876 }
4877 regs.u.r32.eax = 0x534D4150;
4878 regs.u.r32.ecx = 0x14;
4879 CLEAR_CF();
4880 } else {
4881 // if DX != 0x534D4150)
4882 goto int15_unimplemented;
4883 }
4884 break;
4885
4886 case 0x01:
4887 // do we have any reason to fail here ?
4888 CLEAR_CF();
4889
4890 // my real system sets ax and bx to 0
4891 // this is confirmed by Ralph Brown list
4892 // but syslinux v1.48 is known to behave
4893 // strangely if ax is set to 0
4894 // regs.u.r16.ax = 0;
4895 // regs.u.r16.bx = 0;
4896
4897 // Get the amount of extended memory (above 1M)
4898 regs.u.r8.cl = inb_cmos(0x30);
4899 regs.u.r8.ch = inb_cmos(0x31);
4900
4901 // limit to 15M
4902 if(regs.u.r16.cx > 0x3c00)
4903 {
4904 regs.u.r16.cx = 0x3c00;
4905 }
4906
4907 // Get the amount of extended memory above 16M in 64k blocs
4908 regs.u.r8.dl = inb_cmos(0x34);
4909 regs.u.r8.dh = inb_cmos(0x35);
4910
4911 // Set configured memory equal to extended memory
4912 regs.u.r16.ax = regs.u.r16.cx;
4913 regs.u.r16.bx = regs.u.r16.dx;
4914 break;
4915 default: /* AH=0xE8?? but not implemented */
4916 goto int15_unimplemented;
4917 }
4918 break;
4919 int15_unimplemented:
4920 // fall into the default
4921 default:
4922 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4923 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4924 SET_CF();
4925 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4926 break;
4927 }
4928}
4929
4930 void
4931int16_function(DI, SI, BP, SP, BX, DX, CX, AX, FLAGS)
4932 Bit16u DI, SI, BP, SP, BX, DX, CX, AX, FLAGS;
4933{
4934 Bit8u scan_code, ascii_code, shift_flags, led_flags, count;
4935 Bit16u kbd_code, max;
4936
4937 BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX, BX, CX, DX);
4938
4939 shift_flags = read_byte(0x0040, 0x17);
4940 led_flags = read_byte(0x0040, 0x97);
4941 if ((((shift_flags >> 4) & 0x07) ^ (led_flags & 0x07)) != 0) {
4942ASM_START
4943 cli
4944ASM_END
4945 outb(0x60, 0xed);
4946 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
4947 if ((inb(0x60) == 0xfa)) {
4948 led_flags &= 0xf8;
4949 led_flags |= ((shift_flags >> 4) & 0x07);
4950 outb(0x60, led_flags & 0x07);
4951 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
4952 inb(0x60);
4953 write_byte(0x0040, 0x97, led_flags);
4954 }
4955ASM_START
4956 sti
4957ASM_END
4958 }
4959
4960 switch (GET_AH()) {
4961 case 0x00: /* read keyboard input */
4962
4963 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4964 BX_PANIC("KBD: int16h: out of keyboard input\n");
4965 }
4966 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4967 else if (ascii_code == 0xE0) ascii_code = 0;
4968 AX = (scan_code << 8) | ascii_code;
4969 break;
4970
4971 case 0x01: /* check keyboard status */
4972 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4973 SET_ZF();
4974 return;
4975 }
4976 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4977 else if (ascii_code == 0xE0) ascii_code = 0;
4978 AX = (scan_code << 8) | ascii_code;
4979 CLEAR_ZF();
4980 break;
4981
4982 case 0x02: /* get shift flag status */
4983 shift_flags = read_byte(0x0040, 0x17);
4984 SET_AL(shift_flags);
4985 break;
4986
4987 case 0x05: /* store key-stroke into buffer */
4988 if ( !enqueue_key(GET_CH(), GET_CL()) ) {
4989 SET_AL(1);
4990 }
4991 else {
4992 SET_AL(0);
4993 }
4994 break;
4995
4996 case 0x09: /* GET KEYBOARD FUNCTIONALITY */
4997 // bit Bochs Description
4998 // 7 0 reserved
4999 // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
5000 // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
5001 // 4 1 INT 16/AH=0Ah supported
5002 // 3 0 INT 16/AX=0306h supported
5003 // 2 0 INT 16/AX=0305h supported
5004 // 1 0 INT 16/AX=0304h supported
5005 // 0 0 INT 16/AX=0300h supported
5006 //
5007 SET_AL(0x30);
5008 break;
5009
5010 case 0x0A: /* GET KEYBOARD ID */
5011 count = 2;
5012 kbd_code = 0x0;
5013 outb(0x60, 0xf2);
5014 /* Wait for data */
5015 max=0xffff;
5016 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
5017 if (max>0x0) {
5018 if ((inb(0x60) == 0xfa)) {
5019 do {
5020 max=0xffff;
5021 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
5022 if (max>0x0) {
5023 kbd_code >>= 8;
5024 kbd_code |= (inb(0x60) << 8);
5025 }
5026 } while (--count>0);
5027 }
5028 }
5029 BX=kbd_code;
5030 break;
5031
5032 case 0x10: /* read MF-II keyboard input */
5033
5034 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
5035 BX_PANIC("KBD: int16h: out of keyboard input\n");
5036 }
5037 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
5038 AX = (scan_code << 8) | ascii_code;
5039 break;
5040
5041 case 0x11: /* check MF-II keyboard status */
5042 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
5043 SET_ZF();
5044 return;
5045 }
5046 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
5047 AX = (scan_code << 8) | ascii_code;
5048 CLEAR_ZF();
5049 break;
5050
5051 case 0x12: /* get extended keyboard status */
5052 shift_flags = read_byte(0x0040, 0x17);
5053 SET_AL(shift_flags);
5054 shift_flags = read_byte(0x0040, 0x18) & 0x73;
5055 shift_flags |= read_byte(0x0040, 0x96) & 0x0c;
5056 SET_AH(shift_flags);
5057 BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX);
5058 break;
5059
5060 case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
5061 SET_AH(0x80); // function int16 ah=0x10-0x12 supported
5062 break;
5063
5064 case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
5065 // don't change AH : function int16 ah=0x20-0x22 NOT supported
5066 break;
5067
5068 case 0x6F:
5069 if (GET_AL() == 0x08)
5070 SET_AH(0x02); // unsupported, aka normal keyboard
5071
5072 default:
5073 BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
5074 }
5075}
5076
5077 unsigned int
5078dequeue_key(scan_code, ascii_code, incr)
5079 Bit8u *scan_code;
5080 Bit8u *ascii_code;
5081 unsigned int incr;
5082{
5083 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail;
5084 Bit16u ss;
5085 Bit8u acode, scode;
5086
5087#if BX_CPU < 2
5088 buffer_start = 0x001E;
5089 buffer_end = 0x003E;
5090#else
5091 buffer_start = read_word(0x0040, 0x0080);
5092 buffer_end = read_word(0x0040, 0x0082);
5093#endif
5094
5095 buffer_head = read_word(0x0040, 0x001a);
5096 buffer_tail = read_word(0x0040, 0x001c);
5097
5098 if (buffer_head != buffer_tail) {
5099 ss = get_SS();
5100 acode = read_byte(0x0040, buffer_head);
5101 scode = read_byte(0x0040, buffer_head+1);
5102 write_byte(ss, ascii_code, acode);
5103 write_byte(ss, scan_code, scode);
5104
5105 if (incr) {
5106 buffer_head += 2;
5107 if (buffer_head >= buffer_end)
5108 buffer_head = buffer_start;
5109 write_word(0x0040, 0x001a, buffer_head);
5110 }
5111 return(1);
5112 }
5113 else {
5114 return(0);
5115 }
5116}
5117
5118static char panic_msg_keyb_buffer_full[] = "%s: keyboard input buffer full\n";
5119
5120 Bit8u
5121send_to_mouse_ctrl(sendbyte)
5122 Bit8u sendbyte;
5123{
5124 Bit8u response;
5125
5126 // wait for chance to write to ctrl
5127 if ( inb(0x64) & 0x02 )
5128 BX_PANIC(panic_msg_keyb_buffer_full,"sendmouse");
5129 outb(0x64, 0xD4);
5130 outb(0x60, sendbyte);
5131 return(0);
5132}
5133
5134
5135 Bit8u
5136get_mouse_data(data)
5137 Bit8u *data;
5138{
5139 Bit8u response;
5140 Bit16u ss;
5141
5142 while ( (inb(0x64) & 0x21) != 0x21 ) {
5143 }
5144
5145 response = inb(0x60);
5146
5147 ss = get_SS();
5148 write_byte(ss, data, response);
5149 return(0);
5150}
5151
5152 void
5153set_kbd_command_byte(command_byte)
5154 Bit8u command_byte;
5155{
5156 if ( inb(0x64) & 0x02 )
5157 BX_PANIC(panic_msg_keyb_buffer_full,"setkbdcomm");
5158
5159 outb(0x64, 0x60); // write command byte
5160 outb(0x60, command_byte);
5161}
5162
5163 void
5164int09_function(DI, SI, BP, SP, BX, DX, CX, AX)
5165 Bit16u DI, SI, BP, SP, BX, DX, CX, AX;
5166{
5167 Bit8u scancode, asciicode, shift_flags;
5168 Bit8u mf2_flags, mf2_state;
5169
5170 //
5171 // DS has been set to F000 before call
5172 //
5173
5174
5175 scancode = GET_AL();
5176
5177 if (scancode == 0) {
5178 BX_INFO("KBD: int09 handler: AL=0\n");
5179 return;
5180 }
5181
5182
5183 shift_flags = read_byte(0x0040, 0x17);
5184 mf2_flags = read_byte(0x0040, 0x18);
5185 mf2_state = read_byte(0x0040, 0x96);
5186 asciicode = 0;
5187
5188 switch (scancode) {
5189 case 0x3a: /* Caps Lock press */
5190 shift_flags ^= 0x40;
5191 write_byte(0x0040, 0x17, shift_flags);
5192 mf2_flags |= 0x40;
5193 write_byte(0x0040, 0x18, mf2_flags);
5194 break;
5195 case 0xba: /* Caps Lock release */
5196 mf2_flags &= ~0x40;
5197 write_byte(0x0040, 0x18, mf2_flags);
5198 break;
5199
5200 case 0x2a: /* L Shift press */
5201 shift_flags |= 0x02;
5202 write_byte(0x0040, 0x17, shift_flags);
5203 break;
5204 case 0xaa: /* L Shift release */
5205 shift_flags &= ~0x02;
5206 write_byte(0x0040, 0x17, shift_flags);
5207 break;
5208
5209 case 0x36: /* R Shift press */
5210 shift_flags |= 0x01;
5211 write_byte(0x0040, 0x17, shift_flags);
5212 break;
5213 case 0xb6: /* R Shift release */
5214 shift_flags &= ~0x01;
5215 write_byte(0x0040, 0x17, shift_flags);
5216 break;
5217
5218 case 0x1d: /* Ctrl press */
5219 if ((mf2_state & 0x01) == 0) {
5220 shift_flags |= 0x04;
5221 write_byte(0x0040, 0x17, shift_flags);
5222 if (mf2_state & 0x02) {
5223 mf2_state |= 0x04;
5224 write_byte(0x0040, 0x96, mf2_state);
5225 } else {
5226 mf2_flags |= 0x01;
5227 write_byte(0x0040, 0x18, mf2_flags);
5228 }
5229 }
5230 break;
5231 case 0x9d: /* Ctrl release */
5232 if ((mf2_state & 0x01) == 0) {
5233 shift_flags &= ~0x04;
5234 write_byte(0x0040, 0x17, shift_flags);
5235 if (mf2_state & 0x02) {
5236 mf2_state &= ~0x04;
5237 write_byte(0x0040, 0x96, mf2_state);
5238 } else {
5239 mf2_flags &= ~0x01;
5240 write_byte(0x0040, 0x18, mf2_flags);
5241 }
5242 }
5243 break;
5244
5245 case 0x38: /* Alt press */
5246 shift_flags |= 0x08;
5247 write_byte(0x0040, 0x17, shift_flags);
5248 if (mf2_state & 0x02) {
5249 mf2_state |= 0x08;
5250 write_byte(0x0040, 0x96, mf2_state);
5251 } else {
5252 mf2_flags |= 0x02;
5253 write_byte(0x0040, 0x18, mf2_flags);
5254 }
5255 break;
5256 case 0xb8: /* Alt release */
5257 shift_flags &= ~0x08;
5258 write_byte(0x0040, 0x17, shift_flags);
5259 if (mf2_state & 0x02) {
5260 mf2_state &= ~0x08;
5261 write_byte(0x0040, 0x96, mf2_state);
5262 } else {
5263 mf2_flags &= ~0x02;
5264 write_byte(0x0040, 0x18, mf2_flags);
5265 }
5266 break;
5267
5268 case 0x45: /* Num Lock press */
5269 if ((mf2_state & 0x03) == 0) {
5270 mf2_flags |= 0x20;
5271 write_byte(0x0040, 0x18, mf2_flags);
5272 shift_flags ^= 0x20;
5273 write_byte(0x0040, 0x17, shift_flags);
5274 }
5275 break;
5276 case 0xc5: /* Num Lock release */
5277 if ((mf2_state & 0x03) == 0) {
5278 mf2_flags &= ~0x20;
5279 write_byte(0x0040, 0x18, mf2_flags);
5280 }
5281 break;
5282
5283 case 0x46: /* Scroll Lock press */
5284 mf2_flags |= 0x10;
5285 write_byte(0x0040, 0x18, mf2_flags);
5286 shift_flags ^= 0x10;
5287 write_byte(0x0040, 0x17, shift_flags);
5288 break;
5289
5290 case 0xc6: /* Scroll Lock release */
5291 mf2_flags &= ~0x10;
5292 write_byte(0x0040, 0x18, mf2_flags);
5293 break;
5294
5295#ifdef VBOX
5296 case 0x53: /* Del press */
5297 if ((shift_flags & 0x0f) == 0x0c)
5298 {
5299ASM_START
5300 /* Ctrl+Alt+Del => Reboot */
5301 jmp 0xf000:post
5302ASM_END
5303 }
5304 /* fall through */
5305#endif
5306
5307 default:
5308 if (scancode & 0x80) {
5309 break; /* toss key releases ... */
5310 }
5311 if (scancode > MAX_SCAN_CODE) {
5312 BX_INFO("KBD: int09h_handler(): unknown scancode read: 0x%02x!\n", scancode);
5313 return;
5314 }
5315 if (shift_flags & 0x08) { /* ALT */
5316 asciicode = scan_to_scanascii[scancode].alt;
5317 scancode = scan_to_scanascii[scancode].alt >> 8;
5318 } else if (shift_flags & 0x04) { /* CONTROL */
5319 asciicode = scan_to_scanascii[scancode].control;
5320 scancode = scan_to_scanascii[scancode].control >> 8;
5321 } else if (((mf2_state & 0x02) > 0) && ((scancode >= 0x47) && (scancode <= 0x53))) {
5322 /* extended keys handling */
5323 asciicode = 0xe0;
5324 scancode = scan_to_scanascii[scancode].normal >> 8;
5325 } else if (shift_flags & 0x03) { /* LSHIFT + RSHIFT */
5326 /* check if lock state should be ignored
5327 * because a SHIFT key are pressed */
5328
5329 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
5330 asciicode = scan_to_scanascii[scancode].normal;
5331 scancode = scan_to_scanascii[scancode].normal >> 8;
5332 } else {
5333 asciicode = scan_to_scanascii[scancode].shift;
5334 scancode = scan_to_scanascii[scancode].shift >> 8;
5335 }
5336 } else {
5337 /* check if lock is on */
5338 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
5339 asciicode = scan_to_scanascii[scancode].shift;
5340 scancode = scan_to_scanascii[scancode].shift >> 8;
5341 } else {
5342 asciicode = scan_to_scanascii[scancode].normal;
5343 scancode = scan_to_scanascii[scancode].normal >> 8;
5344 }
5345 }
5346 if (scancode==0 && asciicode==0) {
5347 BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
5348 }
5349 enqueue_key(scancode, asciicode);
5350 break;
5351 }
5352 if ((scancode & 0x7f) != 0x1d) {
5353 mf2_state &= ~0x01;
5354 }
5355 mf2_state &= ~0x02;
5356 write_byte(0x0040, 0x96, mf2_state);
5357}
5358
5359 unsigned int
5360enqueue_key(scan_code, ascii_code)
5361 Bit8u scan_code, ascii_code;
5362{
5363 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail, temp_tail;
5364
5365#if BX_CPU < 2
5366 buffer_start = 0x001E;
5367 buffer_end = 0x003E;
5368#else
5369 buffer_start = read_word(0x0040, 0x0080);
5370 buffer_end = read_word(0x0040, 0x0082);
5371#endif
5372
5373 buffer_head = read_word(0x0040, 0x001A);
5374 buffer_tail = read_word(0x0040, 0x001C);
5375
5376 temp_tail = buffer_tail;
5377 buffer_tail += 2;
5378 if (buffer_tail >= buffer_end)
5379 buffer_tail = buffer_start;
5380
5381 if (buffer_tail == buffer_head) {
5382 return(0);
5383 }
5384
5385 write_byte(0x0040, temp_tail, ascii_code);
5386 write_byte(0x0040, temp_tail+1, scan_code);
5387 write_word(0x0040, 0x001C, buffer_tail);
5388 return(1);
5389}
5390
5391
5392 void
5393int74_function(make_farcall, Z, Y, X, status)
5394 Bit16u make_farcall, Z, Y, X, status;
5395{
5396 Bit16u ebda_seg=read_word(0x0040,0x000E);
5397 Bit8u in_byte, index, package_count;
5398 Bit8u mouse_flags_1, mouse_flags_2;
5399
5400BX_DEBUG_INT74("entering int74_function\n");
5401 make_farcall = 0;
5402
5403 in_byte = inb(0x64);
5404 if ( (in_byte & 0x21) != 0x21 ) {
5405 return;
5406 }
5407 in_byte = inb(0x60);
5408BX_DEBUG_INT74("int74: read byte %02x\n", in_byte);
5409
5410 mouse_flags_1 = read_byte(ebda_seg, 0x0026);
5411 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
5412
5413 if ( (mouse_flags_2 & 0x80) != 0x80 ) {
5414 return;
5415 }
5416
5417 package_count = mouse_flags_2 & 0x07;
5418 index = mouse_flags_1 & 0x07;
5419 write_byte(ebda_seg, 0x28 + index, in_byte);
5420
5421 if ( index >= package_count ) {
5422BX_DEBUG_INT74("int74_function: make_farcall=1\n");
5423 status = read_byte(ebda_seg, 0x0028 + 0);
5424 X = read_byte(ebda_seg, 0x0028 + 1);
5425 Y = read_byte(ebda_seg, 0x0028 + 2);
5426 Z = 0;
5427 mouse_flags_1 = 0;
5428 // check if far call handler installed
5429 if (mouse_flags_2 & 0x80)
5430 make_farcall = 1;
5431 }
5432 else {
5433 mouse_flags_1++;
5434 }
5435 write_byte(ebda_seg, 0x0026, mouse_flags_1);
5436}
5437
5438#define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
5439
5440#if BX_USE_ATADRV
5441
5442 void
5443int13_harddisk(EHBX, EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5444 Bit16u EHBX, EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5445{
5446 Bit32u lba;
5447 Bit16u ebda_seg=read_word(0x0040,0x000E);
5448 Bit16u cylinder, head, sector;
5449 Bit16u segment, offset;
5450 Bit16u npc, nph, npspt, nlc, nlh, nlspt;
5451 Bit16u size, count;
5452 Bit8u device, status;
5453
5454 BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5455
5456 write_byte(0x0040, 0x008e, 0); // clear completion flag
5457
5458 // basic check : device has to be defined
5459 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_STORAGE_DEVICES) ) {
5460 BX_DEBUG("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5461 goto int13_fail;
5462 }
5463
5464 // Get the ata channel
5465 device=read_byte(ebda_seg,&EbdaData->ata.hdidmap[GET_ELDL()-0x80]);
5466
5467 // basic check : device has to be valid
5468 if (device >= BX_MAX_STORAGE_DEVICES) {
5469 BX_DEBUG("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5470 goto int13_fail;
5471 }
5472
5473 switch (GET_AH()) {
5474
5475 case 0x00: /* disk controller reset */
5476#ifdef VBOX_WITH_SCSI
5477 /* SCSI controller does not need a reset. */
5478 if (!VBOX_IS_SCSI_DEVICE(device))
5479#endif
5480 ata_reset (device);
5481 goto int13_success;
5482 break;
5483
5484 case 0x01: /* read disk status */
5485 status = read_byte(0x0040, 0x0074);
5486 SET_AH(status);
5487 SET_DISK_RET_STATUS(0);
5488 /* set CF if error status read */
5489 if (status) goto int13_fail_nostatus;
5490 else goto int13_success_noah;
5491 break;
5492
5493 case 0x02: // read disk sectors
5494 case 0x03: // write disk sectors
5495 case 0x04: // verify disk sectors
5496
5497 count = GET_AL();
5498 cylinder = GET_CH();
5499 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
5500 sector = (GET_CL() & 0x3f);
5501 head = GET_DH();
5502
5503 segment = ES;
5504 offset = BX;
5505
5506 if ( (count > 128) || (count == 0) ) {
5507 BX_INFO("int13_harddisk: function %02x, count out of range!\n",GET_AH());
5508 goto int13_fail;
5509 }
5510
5511#ifdef VBOX_WITH_SCSI
5512 if (!VBOX_IS_SCSI_DEVICE(device))
5513#endif
5514 {
5515 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
5516 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
5517 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
5518 }
5519#ifdef VBOX_WITH_SCSI
5520 else
5521 {
5522 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5523
5524 nlc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.cylinders);
5525 nlh = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.heads);
5526 nlspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.spt);
5527 }
5528#endif
5529
5530 // sanity check on cyl heads, sec
5531 if( (cylinder >= nlc) || (head >= nlh) || (sector > nlspt )) {
5532 BX_INFO("int13_harddisk: function %02x, disk %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), GET_DL(), cylinder, head, sector);
5533 goto int13_fail;
5534 }
5535
5536 // FIXME verify
5537 if ( GET_AH() == 0x04 ) goto int13_success;
5538
5539#ifdef VBOX_WITH_SCSI
5540 if (!VBOX_IS_SCSI_DEVICE(device))
5541#endif
5542 {
5543 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5544 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5545 }
5546#ifdef VBOX_WITH_SCSI
5547 else
5548 {
5549 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5550 nph = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.heads);
5551 npspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.spt);
5552 }
5553#endif
5554
5555 // if needed, translate lchs to lba, and execute command
5556#ifdef VBOX_WITH_SCSI
5557 if (( (nph != nlh) || (npspt != nlspt)) || VBOX_IS_SCSI_DEVICE(device)) {
5558 lba = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
5559 sector = 0; // this forces the command to be lba
5560 }
5561#else
5562 if (( (nph != nlh) || (npspt != nlspt)) ) {
5563 lba = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
5564 sector = 0; // this forces the command to be lba
5565 }
5566#endif
5567
5568 if ( GET_AH() == 0x02 )
5569 {
5570#ifdef VBOX_WITH_SCSI
5571 if (VBOX_IS_SCSI_DEVICE(device))
5572 status=scsi_read_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5573 else
5574#endif
5575 {
5576 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,count * 0x200);
5577 status=ata_cmd_data_in(device, ATA_CMD_READ_MULTIPLE, count, cylinder, head, sector, lba, segment, offset);
5578 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,0x200);
5579 }
5580 }
5581 else
5582 {
5583#ifdef VBOX_WITH_SCSI
5584 if (VBOX_IS_SCSI_DEVICE(device))
5585 status=scsi_write_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5586 else
5587#endif
5588 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, cylinder, head, sector, lba, segment, offset);
5589 }
5590
5591 // Set nb of sector transferred
5592 SET_AL(read_word(ebda_seg, &EbdaData->ata.trsfsectors));
5593
5594 if (status != 0) {
5595 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5596 SET_AH(0x0c);
5597 goto int13_fail_noah;
5598 }
5599
5600 goto int13_success;
5601 break;
5602
5603 case 0x05: /* format disk track */
5604 BX_INFO("format disk track called\n");
5605 goto int13_success;
5606 return;
5607 break;
5608
5609 case 0x08: /* read disk drive parameters */
5610
5611 // Get logical geometry from table
5612#ifdef VBOX_WITH_SCSI
5613 if (!VBOX_IS_SCSI_DEVICE(device))
5614#endif
5615 {
5616 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
5617 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
5618 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
5619 }
5620#ifdef VBOX_WITH_SCSI
5621 else
5622 {
5623 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5624 nlc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.cylinders);
5625 nlh = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.heads);
5626 nlspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.spt);
5627 }
5628#endif
5629
5630 count = read_byte(ebda_seg, &EbdaData->ata.hdcount);
5631#ifndef VBOX
5632 nlc = nlc - 2; /* 0 based , last sector not used */
5633#else /* VBOX */
5634 /* Maximum cylinder number is just one less than the number of cylinders. */
5635 nlc = nlc - 1; /* 0 based , last sector not used */
5636#endif /* VBOX */
5637 SET_AL(0);
5638 SET_CH(nlc & 0xff);
5639 SET_CL(((nlc >> 2) & 0xc0) | (nlspt & 0x3f));
5640 SET_DH(nlh - 1);
5641 SET_DL(count); /* FIXME returns 0, 1, or n hard drives */
5642
5643 // FIXME should set ES & DI
5644
5645 goto int13_success;
5646 break;
5647
5648 case 0x10: /* check drive ready */
5649 // should look at 40:8E also???
5650
5651 // Read the status from controller
5652 status = inb(read_word(ebda_seg, &EbdaData->ata.channels[device/2].iobase1) + ATA_CB_STAT);
5653 if ( (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY ) {
5654 goto int13_success;
5655 }
5656 else {
5657 SET_AH(0xAA);
5658 goto int13_fail_noah;
5659 }
5660 break;
5661
5662 case 0x15: /* read disk drive size */
5663
5664 // Get physical geometry from table
5665#ifdef VBOX_WITH_SCSI
5666 if (!VBOX_IS_SCSI_DEVICE(device))
5667#endif
5668 {
5669 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5670 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5671 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5672 }
5673#ifdef VBOX_WITH_SCSI
5674 else
5675 {
5676 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5677 npc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.cylinders);
5678 nph = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.heads);
5679 npspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.spt);
5680 }
5681#endif
5682
5683 // Compute sector count seen by int13
5684#ifndef VBOX
5685 lba = (Bit32u)(npc - 1) * (Bit32u)nph * (Bit32u)npspt;
5686#else /* VBOX */
5687 /* Is it so hard to multiply a couple of counts (without introducing
5688 * arbitrary off by one errors)? */
5689 lba = (Bit32u)npc * (Bit32u)nph * (Bit32u)npspt;
5690#endif /* VBOX */
5691 CX = lba >> 16;
5692 DX = lba & 0xffff;
5693
5694 SET_AH(3); // hard disk accessible
5695 goto int13_success_noah;
5696 break;
5697
5698 case 0x41: // IBM/MS installation check
5699 BX=0xaa55; // install check
5700 SET_AH(0x30); // EDD 3.0
5701 CX=0x0007; // ext disk access and edd, removable supported
5702 goto int13_success_noah;
5703 break;
5704
5705 case 0x42: // IBM/MS extended read
5706 case 0x43: // IBM/MS extended write
5707 case 0x44: // IBM/MS verify
5708 case 0x47: // IBM/MS extended seek
5709
5710 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5711 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5712 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5713
5714 // Can't use 64 bits lba
5715 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5716 if (lba != 0L) {
5717 BX_PANIC("int13_harddisk: function %02x. Can't use 64bits lba\n",GET_AH());
5718 goto int13_fail;
5719 }
5720
5721 // Get 32 bits lba and check
5722 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5723
5724#ifdef VBOX_WITH_SCSI
5725 if (VBOX_IS_SCSI_DEVICE(device))
5726 {
5727 if (lba >= read_dword(ebda_seg, &EbdaData->scsi.devices[VBOX_GET_SCSI_DEVICE(device)].device_info.sectors) ) {
5728 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5729 goto int13_fail;
5730 }
5731 }
5732 else
5733#endif
5734 if (lba >= read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors) ) {
5735 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5736 goto int13_fail;
5737 }
5738
5739
5740 // If verify or seek
5741 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5742 goto int13_success;
5743
5744 // Execute the command
5745 if ( GET_AH() == 0x42 )
5746#ifdef VBOX
5747 {
5748#ifdef VBOX_WITH_SCSI
5749 if (VBOX_IS_SCSI_DEVICE(device))
5750 status=scsi_read_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5751 else
5752#endif
5753 {
5754 if (lba + count >= 268435456)
5755 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS_EXT, count, 0, 0, 0, lba, segment, offset);
5756 else {
5757 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,count * 0x200);
5758 status=ata_cmd_data_in(device, ATA_CMD_READ_MULTIPLE, count, 0, 0, 0, lba, segment, offset);
5759 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,0x200);
5760 }
5761 }
5762 }
5763#else /* !VBOX */
5764 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba, segment, offset);
5765#endif /* VBOX */
5766 else
5767#ifdef VBOX
5768 {
5769#ifdef VBOX_WITH_SCSI
5770 if (VBOX_IS_SCSI_DEVICE(device))
5771 status=scsi_write_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5772 else
5773#endif
5774 {
5775 if (lba + count >= 268435456)
5776 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS_EXT, count, 0, 0, 0, lba, segment, offset);
5777 else
5778 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
5779 }
5780 }
5781#else /* !VBOX */
5782 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
5783#endif /* VBOX */
5784
5785 count=read_word(ebda_seg, &EbdaData->ata.trsfsectors);
5786 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5787
5788 if (status != 0) {
5789 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5790 SET_AH(0x0c);
5791 goto int13_fail_noah;
5792 }
5793
5794 goto int13_success;
5795 break;
5796
5797 case 0x45: // IBM/MS lock/unlock drive
5798 case 0x49: // IBM/MS extended media change
5799 goto int13_success; // Always success for HD
5800 break;
5801
5802 case 0x46: // IBM/MS eject media
5803 SET_AH(0xb2); // Volume Not Removable
5804 goto int13_fail_noah; // Always fail for HD
5805 break;
5806
5807 case 0x48: // IBM/MS get drive parameters
5808 size=read_word(DS,SI+(Bit16u)&Int13DPT->size);
5809
5810 // Buffer is too small
5811 if(size < 0x1a)
5812 goto int13_fail;
5813
5814 // EDD 1.x
5815 if(size >= 0x1a) {
5816 Bit16u blksize;
5817
5818#ifdef VBOX_WITH_SCSI
5819 if (!VBOX_IS_SCSI_DEVICE(device))
5820#endif
5821 {
5822 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5823 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5824 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5825 lba = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors);
5826 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5827 }
5828#ifdef VBOX_WITH_SCSI
5829 else
5830 {
5831 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5832 npc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.cylinders);
5833 nph = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.heads);
5834 npspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.spt);
5835 lba = read_dword(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.sectors);
5836 blksize = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.blksize);
5837 }
5838#endif
5839
5840 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5841 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x02); // geometry is valid
5842 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, (Bit32u)npc);
5843 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, (Bit32u)nph);
5844 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, (Bit32u)npspt);
5845 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, lba); // FIXME should be Bit64
5846 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0L);
5847 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5848 }
5849
5850 // EDD 2.x
5851 if(size >= 0x1e) {
5852 Bit8u channel, dev, irq, mode, checksum, i, translation;
5853 Bit16u iobase1, iobase2, options;
5854
5855 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5856
5857 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5858 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5859
5860 // Fill in dpte
5861 channel = device / 2;
5862 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5863 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5864 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5865 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5866 translation = read_byte(ebda_seg, &EbdaData->ata.devices[device].translation);
5867
5868 options = (translation==ATA_TRANSLATION_NONE?0:1<<3); // chs translation
5869 options |= (1<<4); // lba translation
5870 options |= (mode==ATA_MODE_PIO32?1:0<<7);
5871 options |= (translation==ATA_TRANSLATION_LBA?1:0<<9);
5872 options |= (translation==ATA_TRANSLATION_RECHS?3:0<<9);
5873
5874 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5875 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5876 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5877 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5878 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5879 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5880 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5881 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5882 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5883 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5884 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5885
5886 checksum=0;
5887 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5888 checksum = ~checksum;
5889 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5890 }
5891
5892 // EDD 3.x
5893 if(size >= 0x42) {
5894 Bit8u channel, iface, checksum, i;
5895 Bit16u iobase1;
5896
5897 channel = device / 2;
5898 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5899 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5900
5901 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5902 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5903 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5904 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5905 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5906
5907 if (iface==ATA_IFACE_ISA) {
5908 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5909 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5910 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5911 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5912 }
5913 else {
5914 // FIXME PCI
5915 }
5916 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5917 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5918 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5919 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5920
5921 if (iface==ATA_IFACE_ISA) {
5922 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5923 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5924 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5925 }
5926 else {
5927 // FIXME PCI
5928 }
5929 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5930 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5931 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5932 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5933
5934 checksum=0;
5935 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5936 checksum = ~checksum;
5937 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5938 }
5939
5940 goto int13_success;
5941 break;
5942
5943 case 0x4e: // // IBM/MS set hardware configuration
5944 // DMA, prefetch, PIO maximum not supported
5945 switch (GET_AL()) {
5946 case 0x01:
5947 case 0x03:
5948 case 0x04:
5949 case 0x06:
5950 goto int13_success;
5951 break;
5952 default :
5953 goto int13_fail;
5954 }
5955 break;
5956
5957 case 0x09: /* initialize drive parameters */
5958 case 0x0c: /* seek to specified cylinder */
5959 case 0x0d: /* alternate disk reset */
5960 case 0x11: /* recalibrate */
5961 case 0x14: /* controller internal diagnostic */
5962 BX_INFO("int13_harddisk: function %02xh unimplemented, returns success\n", GET_AH());
5963 goto int13_success;
5964 break;
5965
5966 case 0x0a: /* read disk sectors with ECC */
5967 case 0x0b: /* write disk sectors with ECC */
5968 case 0x18: // set media type for format
5969 case 0x50: // IBM/MS send packet command
5970 default:
5971 BX_INFO("int13_harddisk: function %02xh unsupported, returns fail\n", GET_AH());
5972 goto int13_fail;
5973 break;
5974 }
5975
5976int13_fail:
5977 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5978int13_fail_noah:
5979 SET_DISK_RET_STATUS(GET_AH());
5980int13_fail_nostatus:
5981 SET_CF(); // error occurred
5982 return;
5983
5984int13_success:
5985 SET_AH(0x00); // no error
5986int13_success_noah:
5987 SET_DISK_RET_STATUS(0x00);
5988 CLEAR_CF(); // no error
5989 return;
5990}
5991
5992// ---------------------------------------------------------------------------
5993// Start of int13 for cdrom
5994// ---------------------------------------------------------------------------
5995
5996 void
5997int13_cdrom(EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5998 Bit16u EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5999{
6000 Bit16u ebda_seg=read_word(0x0040,0x000E);
6001 Bit8u device, status, locks;
6002 Bit8u atacmd[12];
6003 Bit32u lba;
6004 Bit16u count, segment, offset, i, size;
6005
6006 BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6007
6008 SET_DISK_RET_STATUS(0x00);
6009
6010 /* basic check : device should be 0xE0+ */
6011 if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES) ) {
6012 BX_DEBUG("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
6013 goto int13_fail;
6014 }
6015
6016 // Get the ata channel
6017 device=read_byte(ebda_seg,&EbdaData->ata.cdidmap[GET_ELDL()-0xE0]);
6018
6019 /* basic check : device has to be valid */
6020 if (device >= BX_MAX_ATA_DEVICES) {
6021 BX_DEBUG("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
6022 goto int13_fail;
6023 }
6024
6025 switch (GET_AH()) {
6026
6027 // all those functions return SUCCESS
6028 case 0x00: /* disk controller reset */
6029 case 0x09: /* initialize drive parameters */
6030 case 0x0c: /* seek to specified cylinder */
6031 case 0x0d: /* alternate disk reset */
6032 case 0x10: /* check drive ready */
6033 case 0x11: /* recalibrate */
6034 case 0x14: /* controller internal diagnostic */
6035 case 0x16: /* detect disk change */
6036 goto int13_success;
6037 break;
6038
6039 // all those functions return disk write-protected
6040 case 0x03: /* write disk sectors */
6041 case 0x05: /* format disk track */
6042 case 0x43: // IBM/MS extended write
6043 SET_AH(0x03);
6044 goto int13_fail_noah;
6045 break;
6046
6047 case 0x01: /* read disk status */
6048 status = read_byte(0x0040, 0x0074);
6049 SET_AH(status);
6050 SET_DISK_RET_STATUS(0);
6051
6052 /* set CF if error status read */
6053 if (status) goto int13_fail_nostatus;
6054 else goto int13_success_noah;
6055 break;
6056
6057 case 0x15: /* read disk drive size */
6058 SET_AH(0x02);
6059 goto int13_fail_noah;
6060 break;
6061
6062 case 0x41: // IBM/MS installation check
6063 BX=0xaa55; // install check
6064 SET_AH(0x30); // EDD 2.1
6065 CX=0x0007; // ext disk access, removable and edd
6066 goto int13_success_noah;
6067 break;
6068
6069 case 0x42: // IBM/MS extended read
6070 case 0x44: // IBM/MS verify sectors
6071 case 0x47: // IBM/MS extended seek
6072
6073 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
6074 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
6075 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
6076
6077 // Can't use 64 bits lba
6078 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
6079 if (lba != 0L) {
6080 BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
6081 goto int13_fail;
6082 }
6083
6084 // Get 32 bits lba
6085 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
6086
6087 // If verify or seek
6088 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
6089 goto int13_success;
6090
6091 memsetb(get_SS(),atacmd,0,12);
6092 atacmd[0]=0x28; // READ command
6093 atacmd[7]=(count & 0xff00) >> 8; // Sectors
6094 atacmd[8]=(count & 0x00ff); // Sectors
6095 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
6096 atacmd[3]=(lba & 0x00ff0000) >> 16;
6097 atacmd[4]=(lba & 0x0000ff00) >> 8;
6098 atacmd[5]=(lba & 0x000000ff);
6099 status = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, count*2048L, ATA_DATA_IN, segment,offset);
6100
6101 count = (Bit16u)(read_dword(ebda_seg, &EbdaData->ata.trsfbytes) >> 11);
6102 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
6103
6104 if (status != 0) {
6105 BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status);
6106 SET_AH(0x0c);
6107 goto int13_fail_noah;
6108 }
6109
6110 goto int13_success;
6111 break;
6112
6113 case 0x45: // IBM/MS lock/unlock drive
6114 if (GET_AL() > 2) goto int13_fail;
6115
6116 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
6117
6118 switch (GET_AL()) {
6119 case 0 : // lock
6120 if (locks == 0xff) {
6121 SET_AH(0xb4);
6122 SET_AL(1);
6123 goto int13_fail_noah;
6124 }
6125 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, ++locks);
6126 SET_AL(1);
6127 break;
6128 case 1 : // unlock
6129 if (locks == 0x00) {
6130 SET_AH(0xb0);
6131 SET_AL(0);
6132 goto int13_fail_noah;
6133 }
6134 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, --locks);
6135 SET_AL(locks==0?0:1);
6136 break;
6137 case 2 : // status
6138 SET_AL(locks==0?0:1);
6139 break;
6140 }
6141 goto int13_success;
6142 break;
6143
6144 case 0x46: // IBM/MS eject media
6145 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
6146
6147 if (locks != 0) {
6148 SET_AH(0xb1); // media locked
6149 goto int13_fail_noah;
6150 }
6151 // FIXME should handle 0x31 no media in device
6152 // FIXME should handle 0xb5 valid request failed
6153
6154 // Call removable media eject
6155 ASM_START
6156 push bp
6157 mov bp, sp
6158
6159 mov ah, #0x52
6160 int #0x15
6161 mov _int13_cdrom.status + 2[bp], ah
6162 jnc int13_cdrom_rme_end
6163 mov _int13_cdrom.status, #1
6164int13_cdrom_rme_end:
6165 pop bp
6166 ASM_END
6167
6168 if (status != 0) {
6169 SET_AH(0xb1); // media locked
6170 goto int13_fail_noah;
6171 }
6172
6173 goto int13_success;
6174 break;
6175
6176 case 0x48: // IBM/MS get drive parameters
6177 size = read_word(DS,SI+(Bit16u)&Int13Ext->size);
6178
6179 // Buffer is too small
6180 if(size < 0x1a)
6181 goto int13_fail;
6182
6183 // EDD 1.x
6184 if(size >= 0x1a) {
6185 Bit16u cylinders, heads, spt, blksize;
6186
6187 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
6188
6189 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
6190 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x74); // removable, media change, lockable, max values
6191 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, 0xffffffff);
6192 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, 0xffffffff);
6193 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, 0xffffffff);
6194 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, 0xffffffff); // FIXME should be Bit64
6195 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0xffffffff);
6196 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
6197 }
6198
6199 // EDD 2.x
6200 if(size >= 0x1e) {
6201 Bit8u channel, dev, irq, mode, checksum, i;
6202 Bit16u iobase1, iobase2, options;
6203
6204 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
6205
6206 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
6207 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
6208
6209 // Fill in dpte
6210 channel = device / 2;
6211 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
6212 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
6213 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
6214 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
6215
6216 // FIXME atapi device
6217 options = (1<<4); // lba translation
6218 options |= (1<<5); // removable device
6219 options |= (1<<6); // atapi device
6220 options |= (mode==ATA_MODE_PIO32?1:0<<7);
6221
6222 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
6223 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
6224 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
6225 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
6226 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
6227 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
6228 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
6229 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
6230 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
6231 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
6232 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
6233
6234 checksum=0;
6235 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
6236 checksum = ~checksum;
6237 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
6238 }
6239
6240 // EDD 3.x
6241 if(size >= 0x42) {
6242 Bit8u channel, iface, checksum, i;
6243 Bit16u iobase1;
6244
6245 channel = device / 2;
6246 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
6247 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
6248
6249 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
6250 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
6251 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
6252 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
6253 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
6254
6255 if (iface==ATA_IFACE_ISA) {
6256 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
6257 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
6258 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
6259 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
6260 }
6261 else {
6262 // FIXME PCI
6263 }
6264 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
6265 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
6266 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
6267 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
6268
6269 if (iface==ATA_IFACE_ISA) {
6270 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
6271 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
6272 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
6273 }
6274 else {
6275 // FIXME PCI
6276 }
6277 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
6278 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
6279 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
6280 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
6281
6282 checksum=0;
6283 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
6284 checksum = ~checksum;
6285 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
6286 }
6287
6288 goto int13_success;
6289 break;
6290
6291 case 0x49: // IBM/MS extended media change
6292 // always send changed ??
6293 SET_AH(06);
6294 goto int13_fail_nostatus;
6295 break;
6296
6297 case 0x4e: // // IBM/MS set hardware configuration
6298 // DMA, prefetch, PIO maximum not supported
6299 switch (GET_AL()) {
6300 case 0x01:
6301 case 0x03:
6302 case 0x04:
6303 case 0x06:
6304 goto int13_success;
6305 break;
6306 default :
6307 goto int13_fail;
6308 }
6309 break;
6310
6311 // all those functions return unimplemented
6312 case 0x02: /* read sectors */
6313 case 0x04: /* verify sectors */
6314 case 0x08: /* read disk drive parameters */
6315 case 0x0a: /* read disk sectors with ECC */
6316 case 0x0b: /* write disk sectors with ECC */
6317 case 0x18: /* set media type for format */
6318 case 0x50: // ? - send packet command
6319 default:
6320 BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
6321 goto int13_fail;
6322 break;
6323 }
6324
6325int13_fail:
6326 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6327int13_fail_noah:
6328 SET_DISK_RET_STATUS(GET_AH());
6329int13_fail_nostatus:
6330 SET_CF(); // error occurred
6331 return;
6332
6333int13_success:
6334 SET_AH(0x00); // no error
6335int13_success_noah:
6336 SET_DISK_RET_STATUS(0x00);
6337 CLEAR_CF(); // no error
6338 return;
6339}
6340
6341// ---------------------------------------------------------------------------
6342// End of int13 for cdrom
6343// ---------------------------------------------------------------------------
6344
6345#if BX_ELTORITO_BOOT
6346// ---------------------------------------------------------------------------
6347// Start of int13 for eltorito functions
6348// ---------------------------------------------------------------------------
6349
6350 void
6351int13_eltorito(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
6352 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
6353{
6354 Bit16u ebda_seg=read_word(0x0040,0x000E);
6355
6356 BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6357 // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
6358
6359 switch (GET_AH()) {
6360
6361 // FIXME ElTorito Various. Should be implemented
6362 case 0x4a: // ElTorito - Initiate disk emu
6363 case 0x4c: // ElTorito - Initiate disk emu and boot
6364 case 0x4d: // ElTorito - Return Boot catalog
6365 BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX);
6366 goto int13_fail;
6367 break;
6368
6369 case 0x4b: // ElTorito - Terminate disk emu
6370 // FIXME ElTorito Hardcoded
6371 write_byte(DS,SI+0x00,0x13);
6372 write_byte(DS,SI+0x01,read_byte(ebda_seg,&EbdaData->cdemu.media));
6373 write_byte(DS,SI+0x02,read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
6374 write_byte(DS,SI+0x03,read_byte(ebda_seg,&EbdaData->cdemu.controller_index));
6375 write_dword(DS,SI+0x04,read_dword(ebda_seg,&EbdaData->cdemu.ilba));
6376 write_word(DS,SI+0x08,read_word(ebda_seg,&EbdaData->cdemu.device_spec));
6377 write_word(DS,SI+0x0a,read_word(ebda_seg,&EbdaData->cdemu.buffer_segment));
6378 write_word(DS,SI+0x0c,read_word(ebda_seg,&EbdaData->cdemu.load_segment));
6379 write_word(DS,SI+0x0e,read_word(ebda_seg,&EbdaData->cdemu.sector_count));
6380 write_byte(DS,SI+0x10,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.cylinders));
6381 write_byte(DS,SI+0x11,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.spt));
6382 write_byte(DS,SI+0x12,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.heads));
6383
6384 // If we have to terminate emulation
6385 if(GET_AL() == 0x00) {
6386 // FIXME ElTorito Various. Should be handled accordingly to spec
6387 write_byte(ebda_seg,&EbdaData->cdemu.active, 0x00); // bye bye
6388 }
6389
6390 goto int13_success;
6391 break;
6392
6393 default:
6394 BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
6395 goto int13_fail;
6396 break;
6397 }
6398
6399int13_fail:
6400 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6401 SET_DISK_RET_STATUS(GET_AH());
6402 SET_CF(); // error occurred
6403 return;
6404
6405int13_success:
6406 SET_AH(0x00); // no error
6407 SET_DISK_RET_STATUS(0x00);
6408 CLEAR_CF(); // no error
6409 return;
6410}
6411
6412// ---------------------------------------------------------------------------
6413// End of int13 for eltorito functions
6414// ---------------------------------------------------------------------------
6415
6416// ---------------------------------------------------------------------------
6417// Start of int13 when emulating a device from the cd
6418// ---------------------------------------------------------------------------
6419
6420 void
6421int13_cdemu(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
6422 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
6423{
6424 Bit16u ebda_seg=read_word(0x0040,0x000E);
6425 Bit8u device, status;
6426 Bit16u vheads, vspt, vcylinders;
6427 Bit16u head, sector, cylinder, nbsectors;
6428 Bit32u vlba, ilba, slba, elba;
6429 Bit16u before, segment, offset;
6430 Bit8u atacmd[12];
6431
6432 BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6433
6434 /* at this point, we are emulating a floppy/harddisk */
6435
6436 // Recompute the device number
6437 device = read_byte(ebda_seg,&EbdaData->cdemu.controller_index) * 2;
6438 device += read_byte(ebda_seg,&EbdaData->cdemu.device_spec);
6439
6440 SET_DISK_RET_STATUS(0x00);
6441
6442 /* basic checks : emulation should be active, dl should equal the emulated drive */
6443 if( (read_byte(ebda_seg,&EbdaData->cdemu.active) ==0 )
6444 || (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive ) != GET_DL())) {
6445 BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
6446 goto int13_fail;
6447 }
6448
6449 switch (GET_AH()) {
6450
6451 // all those functions return SUCCESS
6452 case 0x00: /* disk controller reset */
6453 case 0x09: /* initialize drive parameters */
6454 case 0x0c: /* seek to specified cylinder */
6455 case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
6456 case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
6457 case 0x11: /* recalibrate */
6458 case 0x14: /* controller internal diagnostic */
6459 case 0x16: /* detect disk change */
6460 goto int13_success;
6461 break;
6462
6463 // all those functions return disk write-protected
6464 case 0x03: /* write disk sectors */
6465 case 0x05: /* format disk track */
6466 SET_AH(0x03);
6467 goto int13_fail_noah;
6468 break;
6469
6470 case 0x01: /* read disk status */
6471 status=read_byte(0x0040, 0x0074);
6472 SET_AH(status);
6473 SET_DISK_RET_STATUS(0);
6474
6475 /* set CF if error status read */
6476 if (status) goto int13_fail_nostatus;
6477 else goto int13_success_noah;
6478 break;
6479
6480 case 0x02: // read disk sectors
6481 case 0x04: // verify disk sectors
6482 vspt = read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
6483 vcylinders = read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders);
6484 vheads = read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads);
6485
6486 ilba = read_dword(ebda_seg,&EbdaData->cdemu.ilba);
6487
6488 sector = GET_CL() & 0x003f;
6489 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
6490 head = GET_DH();
6491 nbsectors = GET_AL();
6492 segment = ES;
6493 offset = BX;
6494
6495 // no sector to read ?
6496 if(nbsectors==0) goto int13_success;
6497
6498 // sanity checks sco openserver needs this!
6499 if ((sector > vspt)
6500 || (cylinder >= vcylinders)
6501 || (head >= vheads)) {
6502 goto int13_fail;
6503 }
6504
6505 // After controls, verify do nothing
6506 if (GET_AH() == 0x04) goto int13_success;
6507
6508 segment = ES+(BX / 16);
6509 offset = BX % 16;
6510
6511 // calculate the virtual lba inside the image
6512 vlba=((((Bit32u)cylinder*(Bit32u)vheads)+(Bit32u)head)*(Bit32u)vspt)+((Bit32u)(sector-1));
6513
6514 // In advance so we don't loose the count
6515 SET_AL(nbsectors);
6516
6517 // start lba on cd
6518 slba = (Bit32u)vlba/4;
6519 before= (Bit16u)vlba%4;
6520
6521 // end lba on cd
6522 elba = (Bit32u)(vlba+nbsectors-1)/4;
6523
6524 memsetb(get_SS(),atacmd,0,12);
6525 atacmd[0]=0x28; // READ command
6526 atacmd[7]=((Bit16u)(elba-slba+1) & 0xff00) >> 8; // Sectors
6527 atacmd[8]=((Bit16u)(elba-slba+1) & 0x00ff); // Sectors
6528 atacmd[2]=(ilba+slba & 0xff000000) >> 24; // LBA
6529 atacmd[3]=(ilba+slba & 0x00ff0000) >> 16;
6530 atacmd[4]=(ilba+slba & 0x0000ff00) >> 8;
6531 atacmd[5]=(ilba+slba & 0x000000ff);
6532 if((status = ata_cmd_packet(device, 12, get_SS(), atacmd, before*512, nbsectors*512L, ATA_DATA_IN, segment,offset)) != 0) {
6533 BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status);
6534 SET_AH(0x02);
6535 SET_AL(0);
6536 goto int13_fail_noah;
6537 }
6538
6539 goto int13_success;
6540 break;
6541
6542 case 0x08: /* read disk drive parameters */
6543 vspt=read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
6544 vcylinders=read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders) - 1;
6545 vheads=read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads) - 1;
6546
6547 SET_AL( 0x00 );
6548 SET_BL( 0x00 );
6549 SET_CH( vcylinders & 0xff );
6550 SET_CL((( vcylinders >> 2) & 0xc0) | ( vspt & 0x3f ));
6551 SET_DH( vheads );
6552 SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2
6553 // FIXME ElTorito Harddisk. should send the HD count
6554
6555 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
6556 case 0x01: SET_BL( 0x02 ); break;
6557 case 0x02: SET_BL( 0x04 ); break;
6558 case 0x03: SET_BL( 0x06 ); break;
6559 }
6560
6561ASM_START
6562 push bp
6563 mov bp, sp
6564 mov ax, #diskette_param_table2
6565 mov _int13_cdemu.DI+2[bp], ax
6566 mov _int13_cdemu.ES+2[bp], cs
6567 pop bp
6568ASM_END
6569 goto int13_success;
6570 break;
6571
6572 case 0x15: /* read disk drive size */
6573 // FIXME ElTorito Harddisk. What geometry to send ?
6574 SET_AH(0x03);
6575 goto int13_success_noah;
6576 break;
6577
6578 // all those functions return unimplemented
6579 case 0x0a: /* read disk sectors with ECC */
6580 case 0x0b: /* write disk sectors with ECC */
6581 case 0x18: /* set media type for format */
6582 case 0x41: // IBM/MS installation check
6583 // FIXME ElTorito Harddisk. Darwin would like to use EDD
6584 case 0x42: // IBM/MS extended read
6585 case 0x43: // IBM/MS extended write
6586 case 0x44: // IBM/MS verify sectors
6587 case 0x45: // IBM/MS lock/unlock drive
6588 case 0x46: // IBM/MS eject media
6589 case 0x47: // IBM/MS extended seek
6590 case 0x48: // IBM/MS get drive parameters
6591 case 0x49: // IBM/MS extended media change
6592 case 0x4e: // ? - set hardware configuration
6593 case 0x50: // ? - send packet command
6594 default:
6595 BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
6596 goto int13_fail;
6597 break;
6598 }
6599
6600int13_fail:
6601 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6602int13_fail_noah:
6603 SET_DISK_RET_STATUS(GET_AH());
6604int13_fail_nostatus:
6605 SET_CF(); // error occurred
6606 return;
6607
6608int13_success:
6609 SET_AH(0x00); // no error
6610int13_success_noah:
6611 SET_DISK_RET_STATUS(0x00);
6612 CLEAR_CF(); // no error
6613 return;
6614}
6615
6616// ---------------------------------------------------------------------------
6617// End of int13 when emulating a device from the cd
6618// ---------------------------------------------------------------------------
6619
6620#endif // BX_ELTORITO_BOOT
6621
6622#else //BX_USE_ATADRV
6623
6624 void
6625outLBA(cylinder,hd_heads,head,hd_sectors,sector,dl)
6626 Bit16u cylinder;
6627 Bit16u hd_heads;
6628 Bit16u head;
6629 Bit16u hd_sectors;
6630 Bit16u sector;
6631 Bit16u dl;
6632{
6633ASM_START
6634 push bp
6635 mov bp, sp
6636 push eax
6637 push ebx
6638 push edx
6639 xor eax,eax
6640 mov ax,4[bp] // cylinder
6641 xor ebx,ebx
6642 mov bl,6[bp] // hd_heads
6643 imul ebx
6644
6645 mov bl,8[bp] // head
6646 add eax,ebx
6647 mov bl,10[bp] // hd_sectors
6648 imul ebx
6649 mov bl,12[bp] // sector
6650 add eax,ebx
6651
6652 dec eax
6653 mov dx,#0x1f3
6654 out dx,al
6655 mov dx,#0x1f4
6656 mov al,ah
6657 out dx,al
6658 shr eax,#16
6659 mov dx,#0x1f5
6660 out dx,al
6661 and ah,#0xf
6662 mov bl,14[bp] // dl
6663 and bl,#1
6664 shl bl,#4
6665 or ah,bl
6666 or ah,#0xe0
6667 mov al,ah
6668 mov dx,#0x01f6
6669 out dx,al
6670 pop edx
6671 pop ebx
6672 pop eax
6673 pop bp
6674ASM_END
6675}
6676
6677 void
6678int13_harddisk(EHBX, EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
6679 Bit16u EHBX, EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
6680{
6681 Bit8u drive, num_sectors, sector, head, status, mod;
6682 Bit8u drive_map;
6683 Bit8u n_drives;
6684 Bit16u cyl_mod, ax;
6685 Bit16u max_cylinder, cylinder, total_sectors;
6686 Bit16u hd_cylinders;
6687 Bit8u hd_heads, hd_sectors;
6688 Bit16u val16;
6689 Bit8u sector_count;
6690 unsigned int i;
6691 Bit16u tempbx;
6692 Bit16u dpsize;
6693
6694 Bit16u count, segment, offset;
6695 Bit32u lba;
6696 Bit16u error;
6697
6698 BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6699
6700 write_byte(0x0040, 0x008e, 0); // clear completion flag
6701
6702 /* at this point, DL is >= 0x80 to be passed from the floppy int13h
6703 handler code */
6704 /* check how many disks first (cmos reg 0x12), return an error if
6705 drive not present */
6706 drive_map = inb_cmos(0x12);
6707 drive_map = (((drive_map & 0xf0)==0) ? 0 : 1) |
6708 (((drive_map & 0x0f)==0) ? 0 : 2);
6709 n_drives = (drive_map==0) ? 0 :
6710 ((drive_map==3) ? 2 : 1);
6711
6712 if (!(drive_map & (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
6713 SET_AH(0x01);
6714 SET_DISK_RET_STATUS(0x01);
6715 SET_CF(); /* error occurred */
6716 return;
6717 }
6718
6719 switch (GET_AH()) {
6720
6721 case 0x00: /* disk controller reset */
6722BX_DEBUG_INT13_HD("int13_f00\n");
6723
6724 SET_AH(0);
6725 SET_DISK_RET_STATUS(0);
6726 set_diskette_ret_status(0);
6727 set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
6728 set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
6729 CLEAR_CF(); /* successful */
6730 return;
6731 break;
6732
6733 case 0x01: /* read disk status */
6734BX_DEBUG_INT13_HD("int13_f01\n");
6735 status = read_byte(0x0040, 0x0074);
6736 SET_AH(status);
6737 SET_DISK_RET_STATUS(0);
6738 /* set CF if error status read */
6739 if (status) SET_CF();
6740 else CLEAR_CF();
6741 return;
6742 break;
6743
6744 case 0x04: // verify disk sectors
6745 case 0x02: // read disk sectors
6746 drive = GET_ELDL();
6747 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6748
6749 num_sectors = GET_AL();
6750 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
6751 sector = (GET_CL() & 0x3f);
6752 head = GET_DH();
6753
6754
6755 if (hd_cylinders > 1024) {
6756 if (hd_cylinders <= 2048) {
6757 cylinder <<= 1;
6758 }
6759 else if (hd_cylinders <= 4096) {
6760 cylinder <<= 2;
6761 }
6762 else if (hd_cylinders <= 8192) {
6763 cylinder <<= 3;
6764 }
6765 else { // hd_cylinders <= 16384
6766 cylinder <<= 4;
6767 }
6768
6769 ax = head / hd_heads;
6770 cyl_mod = ax & 0xff;
6771 head = ax >> 8;
6772 cylinder |= cyl_mod;
6773 }
6774
6775 if ( (cylinder >= hd_cylinders) ||
6776 (sector > hd_sectors) ||
6777 (head >= hd_heads) ) {
6778 SET_AH(1);
6779 SET_DISK_RET_STATUS(1);
6780 SET_CF(); /* error occurred */
6781 return;
6782 }
6783
6784 if ( (num_sectors > 128) || (num_sectors == 0) )
6785 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6786
6787 if (head > 15)
6788 BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
6789
6790 if ( GET_AH() == 0x04 ) {
6791 SET_AH(0);
6792 SET_DISK_RET_STATUS(0);
6793 CLEAR_CF();
6794 return;
6795 }
6796
6797 status = inb(0x1f7);
6798 if (status & 0x80) {
6799 BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
6800 }
6801 outb(0x01f2, num_sectors);
6802 /* activate LBA? (tomv) */
6803 if (hd_heads > 16) {
6804BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder, head, sector);
6805 outLBA(cylinder,hd_heads,head,hd_sectors,sector,drive);
6806 }
6807 else {
6808 outb(0x01f3, sector);
6809 outb(0x01f4, cylinder & 0x00ff);
6810 outb(0x01f5, cylinder >> 8);
6811 outb(0x01f6, 0xa0 | ((drive & 0x01)<<4) | (head & 0x0f));
6812 }
6813 outb(0x01f7, 0x20);
6814
6815 while (1) {
6816 status = inb(0x1f7);
6817 if ( !(status & 0x80) ) break;
6818 }
6819
6820 if (status & 0x01) {
6821 BX_PANIC("hard drive BIOS:(read/verify) read error\n");
6822 } else if ( !(status & 0x08) ) {
6823 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6824 BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
6825 }
6826
6827 sector_count = 0;
6828 tempbx = BX;
6829
6830ASM_START
6831 sti ;; enable higher priority interrupts
6832ASM_END
6833
6834 while (1) {
6835ASM_START
6836 ;; store temp bx in real DI register
6837 push bp
6838 mov bp, sp
6839 mov di, _int13_harddisk.tempbx + 2 [bp]
6840 pop bp
6841
6842 ;; adjust if there will be an overrun
6843 cmp di, #0xfe00
6844 jbe i13_f02_no_adjust
6845i13_f02_adjust:
6846 sub di, #0x0200 ; sub 512 bytes from offset
6847 mov ax, es
6848 add ax, #0x0020 ; add 512 to segment
6849 mov es, ax
6850
6851i13_f02_no_adjust:
6852 mov cx, #0x0100 ;; counter (256 words = 512b)
6853 mov dx, #0x01f0 ;; AT data read port
6854
6855 rep
6856 insw ;; CX words transferred from port(DX) to ES:[DI]
6857
6858i13_f02_done:
6859 ;; store real DI register back to temp bx
6860 push bp
6861 mov bp, sp
6862 mov _int13_harddisk.tempbx + 2 [bp], di
6863 pop bp
6864ASM_END
6865
6866 sector_count++;
6867 num_sectors--;
6868 if (num_sectors == 0) {
6869 status = inb(0x1f7);
6870 if ( (status & 0xc9) != 0x40 )
6871 BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status);
6872 break;
6873 }
6874 else {
6875 status = inb(0x1f7);
6876 if ( (status & 0xc9) != 0x48 )
6877 BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status);
6878 continue;
6879 }
6880 }
6881
6882 SET_AH(0);
6883 SET_DISK_RET_STATUS(0);
6884 SET_AL(sector_count);
6885 CLEAR_CF(); /* successful */
6886 return;
6887 break;
6888
6889
6890 case 0x03: /* write disk sectors */
6891BX_DEBUG_INT13_HD("int13_f03\n");
6892 drive = GET_ELDL ();
6893 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6894
6895 num_sectors = GET_AL();
6896 cylinder = GET_CH();
6897 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
6898 sector = (GET_CL() & 0x3f);
6899 head = GET_DH();
6900
6901 if (hd_cylinders > 1024) {
6902 if (hd_cylinders <= 2048) {
6903 cylinder <<= 1;
6904 }
6905 else if (hd_cylinders <= 4096) {
6906 cylinder <<= 2;
6907 }
6908 else if (hd_cylinders <= 8192) {
6909 cylinder <<= 3;
6910 }
6911 else { // hd_cylinders <= 16384
6912 cylinder <<= 4;
6913 }
6914
6915 ax = head / hd_heads;
6916 cyl_mod = ax & 0xff;
6917 head = ax >> 8;
6918 cylinder |= cyl_mod;
6919 }
6920
6921 if ( (cylinder >= hd_cylinders) ||
6922 (sector > hd_sectors) ||
6923 (head >= hd_heads) ) {
6924 SET_AH( 1);
6925 SET_DISK_RET_STATUS(1);
6926 SET_CF(); /* error occurred */
6927 return;
6928 }
6929
6930 if ( (num_sectors > 128) || (num_sectors == 0) )
6931 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6932
6933 if (head > 15)
6934 BX_PANIC("hard drive BIOS:(read) head > 15\n");
6935
6936 status = inb(0x1f7);
6937 if (status & 0x80) {
6938 BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
6939 }
6940// should check for Drive Ready Bit also in status reg
6941 outb(0x01f2, num_sectors);
6942
6943 /* activate LBA? (tomv) */
6944 if (hd_heads > 16) {
6945BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder, head, sector);
6946 outLBA(cylinder,hd_heads,head,hd_sectors,sector,GET_ELDL());
6947 }
6948 else {
6949 outb(0x01f3, sector);
6950 outb(0x01f4, cylinder & 0x00ff);
6951 outb(0x01f5, cylinder >> 8);
6952 outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head & 0x0f));
6953 }
6954 outb(0x01f7, 0x30);
6955
6956 // wait for busy bit to turn off after seeking
6957 while (1) {
6958 status = inb(0x1f7);
6959 if ( !(status & 0x80) ) break;
6960 }
6961
6962 if ( !(status & 0x08) ) {
6963 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6964 BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
6965 }
6966
6967 sector_count = 0;
6968 tempbx = BX;
6969
6970ASM_START
6971 sti ;; enable higher priority interrupts
6972ASM_END
6973
6974 while (1) {
6975ASM_START
6976 ;; store temp bx in real SI register
6977 push bp
6978 mov bp, sp
6979 mov si, _int13_harddisk.tempbx + 2 [bp]
6980 pop bp
6981
6982 ;; adjust if there will be an overrun
6983 cmp si, #0xfe00
6984 jbe i13_f03_no_adjust
6985i13_f03_adjust:
6986 sub si, #0x0200 ; sub 512 bytes from offset
6987 mov ax, es
6988 add ax, #0x0020 ; add 512 to segment
6989 mov es, ax
6990
6991i13_f03_no_adjust:
6992 mov cx, #0x0100 ;; counter (256 words = 512b)
6993 mov dx, #0x01f0 ;; AT data read port
6994
6995 seg ES
6996 rep
6997 outsw ;; CX words transferred from ES:[SI] to port(DX)
6998
6999 ;; store real SI register back to temp bx
7000 push bp
7001 mov bp, sp
7002 mov _int13_harddisk.tempbx + 2 [bp], si
7003 pop bp
7004ASM_END
7005
7006 sector_count++;
7007 num_sectors--;
7008 if (num_sectors == 0) {
7009 status = inb(0x1f7);
7010 if ( (status & 0xe9) != 0x40 )
7011 BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status);
7012 break;
7013 }
7014 else {
7015 status = inb(0x1f7);
7016 if ( (status & 0xc9) != 0x48 )
7017 BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status);
7018 continue;
7019 }
7020 }
7021
7022 SET_AH(0);
7023 SET_DISK_RET_STATUS(0);
7024 SET_AL(sector_count);
7025 CLEAR_CF(); /* successful */
7026 return;
7027 break;
7028
7029 case 0x05: /* format disk track */
7030BX_DEBUG_INT13_HD("int13_f05\n");
7031 BX_PANIC("format disk track called\n");
7032 /* nop */
7033 SET_AH(0);
7034 SET_DISK_RET_STATUS(0);
7035 CLEAR_CF(); /* successful */
7036 return;
7037 break;
7038
7039 case 0x08: /* read disk drive parameters */
7040BX_DEBUG_INT13_HD("int13_f08\n");
7041
7042 drive = GET_ELDL ();
7043 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
7044
7045 // translate CHS
7046 //
7047 if (hd_cylinders <= 1024) {
7048 // hd_cylinders >>= 0;
7049 // hd_heads <<= 0;
7050 }
7051 else if (hd_cylinders <= 2048) {
7052 hd_cylinders >>= 1;
7053 hd_heads <<= 1;
7054 }
7055 else if (hd_cylinders <= 4096) {
7056 hd_cylinders >>= 2;
7057 hd_heads <<= 2;
7058 }
7059 else if (hd_cylinders <= 8192) {
7060 hd_cylinders >>= 3;
7061 hd_heads <<= 3;
7062 }
7063 else { // hd_cylinders <= 16384
7064 hd_cylinders >>= 4;
7065 hd_heads <<= 4;
7066 }
7067
7068 max_cylinder = hd_cylinders - 2; /* 0 based */
7069 SET_AL(0);
7070 SET_CH(max_cylinder & 0xff);
7071 SET_CL(((max_cylinder >> 2) & 0xc0) | (hd_sectors & 0x3f));
7072 SET_DH(hd_heads - 1);
7073 SET_DL(n_drives); /* returns 0, 1, or 2 hard drives */
7074 SET_AH(0);
7075 SET_DISK_RET_STATUS(0);
7076 CLEAR_CF(); /* successful */
7077
7078 return;
7079 break;
7080
7081 case 0x09: /* initialize drive parameters */
7082BX_DEBUG_INT13_HD("int13_f09\n");
7083 SET_AH(0);
7084 SET_DISK_RET_STATUS(0);
7085 CLEAR_CF(); /* successful */
7086 return;
7087 break;
7088
7089 case 0x0a: /* read disk sectors with ECC */
7090BX_DEBUG_INT13_HD("int13_f0a\n");
7091 case 0x0b: /* write disk sectors with ECC */
7092BX_DEBUG_INT13_HD("int13_f0b\n");
7093 BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
7094 return;
7095 break;
7096
7097 case 0x0c: /* seek to specified cylinder */
7098BX_DEBUG_INT13_HD("int13_f0c\n");
7099 BX_INFO("int13h function 0ch (seek) not implemented!\n");
7100 SET_AH(0);
7101 SET_DISK_RET_STATUS(0);
7102 CLEAR_CF(); /* successful */
7103 return;
7104 break;
7105
7106 case 0x0d: /* alternate disk reset */
7107BX_DEBUG_INT13_HD("int13_f0d\n");
7108 SET_AH(0);
7109 SET_DISK_RET_STATUS(0);
7110 CLEAR_CF(); /* successful */
7111 return;
7112 break;
7113
7114 case 0x10: /* check drive ready */
7115BX_DEBUG_INT13_HD("int13_f10\n");
7116 //SET_AH(0);
7117 //SET_DISK_RET_STATUS(0);
7118 //CLEAR_CF(); /* successful */
7119 //return;
7120 //break;
7121
7122 // should look at 40:8E also???
7123 status = inb(0x01f7);
7124 if ( (status & 0xc0) == 0x40 ) {
7125 SET_AH(0);
7126 SET_DISK_RET_STATUS(0);
7127 CLEAR_CF(); // drive ready
7128 return;
7129 }
7130 else {
7131 SET_AH(0xAA);
7132 SET_DISK_RET_STATUS(0xAA);
7133 SET_CF(); // not ready
7134 return;
7135 }
7136 break;
7137
7138 case 0x11: /* recalibrate */
7139BX_DEBUG_INT13_HD("int13_f11\n");
7140 SET_AH(0);
7141 SET_DISK_RET_STATUS(0);
7142 CLEAR_CF(); /* successful */
7143 return;
7144 break;
7145
7146 case 0x14: /* controller internal diagnostic */
7147BX_DEBUG_INT13_HD("int13_f14\n");
7148 SET_AH(0);
7149 SET_DISK_RET_STATUS(0);
7150 CLEAR_CF(); /* successful */
7151 SET_AL(0);
7152 return;
7153 break;
7154
7155 case 0x15: /* read disk drive size */
7156 drive = GET_ELDL();
7157 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
7158ASM_START
7159 push bp
7160 mov bp, sp
7161 mov al, _int13_harddisk.hd_heads + 2 [bp]
7162 mov ah, _int13_harddisk.hd_sectors + 2 [bp]
7163 mul al, ah ;; ax = heads * sectors
7164 mov bx, _int13_harddisk.hd_cylinders + 2 [bp]
7165 dec bx ;; use (cylinders - 1) ???
7166 mul ax, bx ;; dx:ax = (cylinders -1) * (heads * sectors)
7167 ;; now we need to move the 32bit result dx:ax to what the
7168 ;; BIOS wants which is cx:dx.
7169 ;; and then into CX:DX on the stack
7170 mov _int13_harddisk.CX + 2 [bp], dx
7171 mov _int13_harddisk.DX + 2 [bp], ax
7172 pop bp
7173ASM_END
7174 SET_AH(3); // hard disk accessible
7175 SET_DISK_RET_STATUS(0); // ??? should this be 0
7176 CLEAR_CF(); // successful
7177 return;
7178 break;
7179
7180 case 0x18: // set media type for format
7181 case 0x41: // IBM/MS
7182 case 0x42: // IBM/MS
7183 case 0x43: // IBM/MS
7184 case 0x44: // IBM/MS
7185 case 0x45: // IBM/MS lock/unlock drive
7186 case 0x46: // IBM/MS eject media
7187 case 0x47: // IBM/MS extended seek
7188 case 0x49: // IBM/MS extended media change
7189 case 0x50: // IBM/MS send packet command
7190 default:
7191 BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
7192
7193 SET_AH(1); // code=invalid function in AH or invalid parameter
7194 SET_DISK_RET_STATUS(1);
7195 SET_CF(); /* unsuccessful */
7196 return;
7197 break;
7198 }
7199}
7200
7201static char panic_msg_reg12h[] = "HD%d cmos reg 12h not type F\n";
7202static char panic_msg_reg19h[] = "HD%d cmos reg %02xh not user definable type 47\n";
7203
7204 void
7205get_hd_geometry(drive, hd_cylinders, hd_heads, hd_sectors)
7206 Bit8u drive;
7207 Bit16u *hd_cylinders;
7208 Bit8u *hd_heads;
7209 Bit8u *hd_sectors;
7210{
7211 Bit8u hd_type;
7212 Bit16u ss;
7213 Bit16u cylinders;
7214 Bit8u iobase;
7215
7216 ss = get_SS();
7217 if (drive == 0x80) {
7218 hd_type = inb_cmos(0x12) & 0xf0;
7219 if (hd_type != 0xf0)
7220 BX_INFO(panic_msg_reg12h,0);
7221 hd_type = inb_cmos(0x19); // HD0: extended type
7222 if (hd_type != 47)
7223 BX_INFO(panic_msg_reg19h,0,0x19);
7224 iobase = 0x1b;
7225 } else {
7226 hd_type = inb_cmos(0x12) & 0x0f;
7227 if (hd_type != 0x0f)
7228 BX_INFO(panic_msg_reg12h,1);
7229 hd_type = inb_cmos(0x1a); // HD1: extended type
7230 if (hd_type != 47)
7231 BX_INFO(panic_msg_reg19h,0,0x1a);
7232 iobase = 0x24;
7233 }
7234
7235 // cylinders
7236 cylinders = inb_cmos(iobase) | (inb_cmos(iobase+1) << 8);
7237 write_word(ss, hd_cylinders, cylinders);
7238
7239 // heads
7240 write_byte(ss, hd_heads, inb_cmos(iobase+2));
7241
7242 // sectors per track
7243 write_byte(ss, hd_sectors, inb_cmos(iobase+8));
7244}
7245
7246#endif //else BX_USE_ATADRV
7247
7248#if BX_SUPPORT_FLOPPY
7249
7250//////////////////////
7251// FLOPPY functions //
7252//////////////////////
7253
7254void floppy_reset_controller()
7255{
7256 Bit8u val8;
7257
7258 // Reset controller
7259 val8 = inb(0x03f2);
7260 outb(0x03f2, val8 & ~0x04);
7261 outb(0x03f2, val8 | 0x04);
7262
7263 // Wait for controller to come out of reset
7264 do {
7265 val8 = inb(0x3f4);
7266 } while ( (val8 & 0xc0) != 0x80 );
7267}
7268
7269void floppy_prepare_controller(drive)
7270 Bit16u drive;
7271{
7272 Bit8u val8, dor, prev_reset;
7273
7274 // set 40:3e bit 7 to 0
7275 val8 = read_byte(0x0040, 0x003e);
7276 val8 &= 0x7f;
7277 write_byte(0x0040, 0x003e, val8);
7278
7279 // turn on motor of selected drive, DMA & int enabled, normal operation
7280 prev_reset = inb(0x03f2) & 0x04;
7281 if (drive)
7282 dor = 0x20;
7283 else
7284 dor = 0x10;
7285 dor |= 0x0c;
7286 dor |= drive;
7287 outb(0x03f2, dor);
7288
7289 // reset the disk motor timeout value of INT 08
7290 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
7291
7292#ifdef VBOX
7293 // program data rate
7294 val8 = read_byte(0x0040, 0x008b);
7295 val8 >>= 6;
7296 outb(0x03f7, val8);
7297#endif
7298
7299 // wait for drive readiness
7300 do {
7301 val8 = inb(0x3f4);
7302 } while ( (val8 & 0xc0) != 0x80 );
7303
7304 if (prev_reset == 0) {
7305 // turn on interrupts
7306ASM_START
7307 sti
7308ASM_END
7309 // wait on 40:3e bit 7 to become 1
7310 do {
7311 val8 = read_byte(0x0040, 0x003e);
7312 } while ( (val8 & 0x80) == 0 );
7313 val8 &= 0x7f;
7314ASM_START
7315 cli
7316ASM_END
7317 write_byte(0x0040, 0x003e, val8);
7318 }
7319}
7320
7321 bx_bool
7322floppy_media_known(drive)
7323 Bit16u drive;
7324{
7325 Bit8u val8;
7326 Bit16u media_state_offset;
7327
7328 val8 = read_byte(0x0040, 0x003e); // diskette recal status
7329 if (drive)
7330 val8 >>= 1;
7331 val8 &= 0x01;
7332 if (val8 == 0)
7333 return(0);
7334
7335 media_state_offset = 0x0090;
7336 if (drive)
7337 media_state_offset += 1;
7338
7339 val8 = read_byte(0x0040, media_state_offset);
7340 val8 = (val8 >> 4) & 0x01;
7341 if (val8 == 0)
7342 return(0);
7343
7344 // check pass, return KNOWN
7345 return(1);
7346}
7347
7348 bx_bool
7349floppy_read_id(drive)
7350 Bit16u drive;
7351{
7352 Bit8u val8;
7353 Bit8u return_status[7];
7354
7355 floppy_prepare_controller(drive);
7356
7357 // send Read ID command (2 bytes) to controller
7358 outb(0x03f5, 0x4a); // 4a: Read ID (MFM)
7359 outb(0x03f5, drive); // 0=drive0, 1=drive1, head always 0
7360
7361 // turn on interrupts
7362ASM_START
7363 sti
7364ASM_END
7365
7366 // wait on 40:3e bit 7 to become 1
7367 do {
7368 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7369 } while ( val8 == 0 );
7370
7371 val8 = 0; // separate asm from while() loop
7372 // turn off interrupts
7373ASM_START
7374 cli
7375ASM_END
7376
7377 // read 7 return status bytes from controller
7378 return_status[0] = inb(0x3f5);
7379 return_status[1] = inb(0x3f5);
7380 return_status[2] = inb(0x3f5);
7381 return_status[3] = inb(0x3f5);
7382 return_status[4] = inb(0x3f5);
7383 return_status[5] = inb(0x3f5);
7384 return_status[6] = inb(0x3f5);
7385
7386 if ( (return_status[0] & 0xc0) != 0 )
7387 return(0);
7388 else
7389 return(1);
7390}
7391
7392 bx_bool
7393floppy_media_sense(drive)
7394 Bit16u drive;
7395{
7396 bx_bool retval;
7397 Bit16u media_state_offset;
7398 Bit8u drive_type, config_data, media_state;
7399
7400 if (floppy_drive_recal(drive) == 0) {
7401 return(0);
7402 }
7403
7404 // Try the diskette data rates in the following order:
7405 // 1 Mbps -> 500 Kbps -> 300 Kbps -> 250 Kbps
7406 // The 1 Mbps rate is only tried for 2.88M drives.
7407
7408 // ** config_data **
7409 // Bitfields for diskette media control:
7410 // Bit(s) Description (Table M0028)
7411 // 7-6 last data rate set by controller
7412 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
7413 // 5-4 last diskette drive step rate selected
7414 // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
7415 // 3-2 {data rate at start of operation}
7416 // 1-0 reserved
7417
7418 // ** media_state **
7419 // Bitfields for diskette drive media state:
7420 // Bit(s) Description (Table M0030)
7421 // 7-6 data rate
7422 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
7423 // 5 double stepping required (e.g. 360kB in 1.2MB)
7424 // 4 media type established
7425 // 3 drive capable of supporting 4MB media
7426 // 2-0 on exit from BIOS, contains
7427 // 000 trying 360kB in 360kB
7428 // 001 trying 360kB in 1.2MB
7429 // 010 trying 1.2MB in 1.2MB
7430 // 011 360kB in 360kB established
7431 // 100 360kB in 1.2MB established
7432 // 101 1.2MB in 1.2MB established
7433 // 110 reserved
7434 // 111 all other formats/drives
7435
7436 drive_type = inb_cmos(0x10);
7437 if (drive == 0)
7438 drive_type >>= 4;
7439 else
7440 drive_type &= 0x0f;
7441 if ( drive_type == 1 ) {
7442 // 360K 5.25" drive
7443 config_data = 0x00; // 0000 0000
7444 media_state = 0x25; // 0010 0101
7445 retval = 1;
7446 }
7447 else if ( drive_type == 2 ) {
7448 // 1.2 MB 5.25" drive
7449 config_data = 0x00; // 0000 0000
7450 media_state = 0x25; // 0010 0101 // need double stepping??? (bit 5)
7451 retval = 1;
7452 }
7453 else if ( drive_type == 3 ) {
7454 // 720K 3.5" drive
7455 config_data = 0x00; // 0000 0000 ???
7456 media_state = 0x17; // 0001 0111
7457 retval = 1;
7458 }
7459 else if ( drive_type == 4 ) {
7460 // 1.44 MB 3.5" drive
7461 config_data = 0x00; // 0000 0000
7462 media_state = 0x17; // 0001 0111
7463 retval = 1;
7464 }
7465 else if ( drive_type == 5 ) {
7466 // 2.88 MB 3.5" drive
7467 config_data = 0xCC; // 1100 1100
7468 media_state = 0xD7; // 1101 0111
7469 retval = 1;
7470 }
7471 //
7472 // Extended floppy size uses special cmos setting
7473 else if ( drive_type == 6 ) {
7474 // 160k 5.25" drive
7475 config_data = 0x00; // 0000 0000
7476 media_state = 0x27; // 0010 0111
7477 retval = 1;
7478 }
7479 else if ( drive_type == 7 ) {
7480 // 180k 5.25" drive
7481 config_data = 0x00; // 0000 0000
7482 media_state = 0x27; // 0010 0111
7483 retval = 1;
7484 }
7485 else if ( drive_type == 8 ) {
7486 // 320k 5.25" drive
7487 config_data = 0x00; // 0000 0000
7488 media_state = 0x27; // 0010 0111
7489 retval = 1;
7490 }
7491
7492 else {
7493 // not recognized
7494 config_data = 0x00; // 0000 0000
7495 media_state = 0x00; // 0000 0000
7496 retval = 0;
7497 }
7498
7499 write_byte(0x0040, 0x008B, config_data);
7500 while (!floppy_read_id(drive)) {
7501 if ((config_data & 0xC0) == 0x80) {
7502 // If even 250 Kbps failed, we can't do much
7503 break;
7504 }
7505 switch (config_data & 0xC0) {
7506 case 0xC0: // 1 Mbps
7507 config_data = config_data & 0x3F | 0x00;
7508 break;
7509 case 0x00: // 500 Kbps
7510 config_data = config_data & 0x3F | 0x40;
7511 break;
7512 case 0x40: // 300 Kbps
7513 config_data = config_data & 0x3F | 0x80;
7514 break;
7515 }
7516 write_byte(0x0040, 0x008B, config_data);
7517 }
7518
7519 if (drive == 0)
7520 media_state_offset = 0x90;
7521 else
7522 media_state_offset = 0x91;
7523 write_byte(0x0040, 0x008B, config_data);
7524 write_byte(0x0040, media_state_offset, media_state);
7525
7526 return(retval);
7527}
7528
7529 bx_bool
7530floppy_drive_recal(drive)
7531 Bit16u drive;
7532{
7533 Bit8u val8;
7534 Bit16u curr_cyl_offset;
7535
7536 floppy_prepare_controller(drive);
7537
7538 // send Recalibrate command (2 bytes) to controller
7539 outb(0x03f5, 0x07); // 07: Recalibrate
7540 outb(0x03f5, drive); // 0=drive0, 1=drive1
7541
7542 // turn on interrupts
7543ASM_START
7544 sti
7545ASM_END
7546
7547 // wait on 40:3e bit 7 to become 1
7548 do {
7549 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7550 } while ( val8 == 0 );
7551
7552 val8 = 0; // separate asm from while() loop
7553 // turn off interrupts
7554ASM_START
7555 cli
7556ASM_END
7557
7558 // set 40:3e bit 7 to 0, and calibrated bit
7559 val8 = read_byte(0x0040, 0x003e);
7560 val8 &= 0x7f;
7561 if (drive) {
7562 val8 |= 0x02; // Drive 1 calibrated
7563 curr_cyl_offset = 0x0095;
7564 } else {
7565 val8 |= 0x01; // Drive 0 calibrated
7566 curr_cyl_offset = 0x0094;
7567 }
7568 write_byte(0x0040, 0x003e, val8);
7569 write_byte(0x0040, curr_cyl_offset, 0); // current cylinder is 0
7570
7571 return(1);
7572}
7573
7574
7575
7576 bx_bool
7577floppy_drive_exists(drive)
7578 Bit16u drive;
7579{
7580 Bit8u drive_type;
7581
7582 // check CMOS to see if drive exists
7583 drive_type = inb_cmos(0x10);
7584 if (drive == 0)
7585 drive_type >>= 4;
7586 else
7587 drive_type &= 0x0f;
7588 if ( drive_type == 0 )
7589 return(0);
7590 else
7591 return(1);
7592}
7593
7594 void
7595int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
7596 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
7597{
7598 Bit8u drive, num_sectors, track, sector, head, status;
7599 Bit16u base_address, base_count, base_es;
7600 Bit8u page, mode_register, val8, dor;
7601 Bit8u return_status[7];
7602 Bit8u drive_type, num_floppies, ah;
7603 Bit16u es, last_addr;
7604
7605 BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
7606
7607 ah = GET_AH();
7608
7609 switch ( ah ) {
7610 case 0x00: // diskette controller reset
7611BX_DEBUG_INT13_FL("floppy f00\n");
7612 drive = GET_ELDL();
7613 if (drive > 1) {
7614 SET_AH(1); // invalid param
7615 set_diskette_ret_status(1);
7616 SET_CF();
7617 return;
7618 }
7619 drive_type = inb_cmos(0x10);
7620
7621 if (drive == 0)
7622 drive_type >>= 4;
7623 else
7624 drive_type &= 0x0f;
7625 if (drive_type == 0) {
7626 SET_AH(0x80); // drive not responding
7627 set_diskette_ret_status(0x80);
7628 SET_CF();
7629 return;
7630 }
7631
7632 // force re-calibration etc.
7633 write_byte(0x0040, 0x003e, 0);
7634
7635 SET_AH(0);
7636 set_diskette_ret_status(0);
7637 CLEAR_CF(); // successful
7638 set_diskette_current_cyl(drive, 0); // current cylinder
7639 return;
7640
7641 case 0x01: // Read Diskette Status
7642 CLEAR_CF();
7643 val8 = read_byte(0x0000, 0x0441);
7644 SET_AH(val8);
7645 if (val8) {
7646 SET_CF();
7647 }
7648 return;
7649
7650 case 0x02: // Read Diskette Sectors
7651 case 0x03: // Write Diskette Sectors
7652 case 0x04: // Verify Diskette Sectors
7653 num_sectors = GET_AL();
7654 track = GET_CH();
7655 sector = GET_CL();
7656 head = GET_DH();
7657 drive = GET_ELDL();
7658
7659 if ( (drive > 1) || (head > 1) ||
7660 (num_sectors == 0) || (num_sectors > 72) ) {
7661BX_INFO("floppy: drive>1 || head>1 ...\n");
7662 SET_AH(1);
7663 set_diskette_ret_status(1);
7664 SET_AL(0); // no sectors read
7665 SET_CF(); // error occurred
7666 return;
7667 }
7668
7669 // see if drive exists
7670 if (floppy_drive_exists(drive) == 0) {
7671 SET_AH(0x80); // not responding
7672 set_diskette_ret_status(0x80);
7673 SET_AL(0); // no sectors read
7674 SET_CF(); // error occurred
7675 return;
7676 }
7677
7678 // see if media in drive, and type is known
7679 if (floppy_media_known(drive) == 0) {
7680 if (floppy_media_sense(drive) == 0) {
7681 SET_AH(0x0C); // Media type not found
7682 set_diskette_ret_status(0x0C);
7683 SET_AL(0); // no sectors read
7684 SET_CF(); // error occurred
7685 return;
7686 }
7687 }
7688
7689 if (ah == 0x02) {
7690 // Read Diskette Sectors
7691
7692 //-----------------------------------
7693 // set up DMA controller for transfer
7694 //-----------------------------------
7695
7696 // es:bx = pointer to where to place information from diskette
7697 // port 04: DMA-1 base and current address, channel 2
7698 // port 05: DMA-1 base and current count, channel 2
7699 page = (ES >> 12); // upper 4 bits
7700 base_es = (ES << 4); // lower 16bits contributed by ES
7701 base_address = base_es + BX; // lower 16 bits of address
7702 // contributed by ES:BX
7703 if ( base_address < base_es ) {
7704 // in case of carry, adjust page by 1
7705 page++;
7706 }
7707 base_count = (num_sectors * 512) - 1;
7708
7709 // check for 64K boundary overrun
7710 last_addr = base_address + base_count;
7711 if (last_addr < base_address) {
7712 SET_AH(0x09);
7713 set_diskette_ret_status(0x09);
7714 SET_AL(0); // no sectors read
7715 SET_CF(); // error occurred
7716 return;
7717 }
7718
7719 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7720 outb(0x000a, 0x06);
7721
7722 BX_DEBUG_INT13_FL("clear flip-flop\n");
7723 outb(0x000c, 0x00); // clear flip-flop
7724 outb(0x0004, base_address);
7725 outb(0x0004, base_address>>8);
7726 BX_DEBUG_INT13_FL("clear flip-flop\n");
7727 outb(0x000c, 0x00); // clear flip-flop
7728 outb(0x0005, base_count);
7729 outb(0x0005, base_count>>8);
7730
7731 // port 0b: DMA-1 Mode Register
7732 mode_register = 0x46; // single mode, increment, autoinit disable,
7733 // transfer type=write, channel 2
7734 BX_DEBUG_INT13_FL("setting mode register\n");
7735 outb(0x000b, mode_register);
7736
7737 BX_DEBUG_INT13_FL("setting page register\n");
7738 // port 81: DMA-1 Page Register, channel 2
7739 outb(0x0081, page);
7740
7741 BX_DEBUG_INT13_FL("unmask chan 2\n");
7742 outb(0x000a, 0x02); // unmask channel 2
7743
7744 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7745 outb(0x000a, 0x02);
7746
7747 //--------------------------------------
7748 // set up floppy controller for transfer
7749 //--------------------------------------
7750 floppy_prepare_controller(drive);
7751
7752 // send read-normal-data command (9 bytes) to controller
7753 outb(0x03f5, 0xe6); // e6: read normal data
7754 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7755 outb(0x03f5, track);
7756 outb(0x03f5, head);
7757 outb(0x03f5, sector);
7758 outb(0x03f5, 2); // 512 byte sector size
7759 outb(0x03f5, sector + num_sectors - 1); // last sector to read on track
7760 outb(0x03f5, 0); // Gap length
7761 outb(0x03f5, 0xff); // Gap length
7762
7763 // turn on interrupts
7764 ASM_START
7765 sti
7766 ASM_END
7767
7768 // wait on 40:3e bit 7 to become 1
7769 do {
7770 val8 = read_byte(0x0040, 0x0040);
7771 if (val8 == 0) {
7772 floppy_reset_controller();
7773 SET_AH(0x80); // drive not ready (timeout)
7774 set_diskette_ret_status(0x80);
7775 SET_AL(0); // no sectors read
7776 SET_CF(); // error occurred
7777 return;
7778 }
7779 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7780 } while ( val8 == 0 );
7781
7782 val8 = 0; // separate asm from while() loop
7783 // turn off interrupts
7784 ASM_START
7785 cli
7786 ASM_END
7787
7788 // set 40:3e bit 7 to 0
7789 val8 = read_byte(0x0040, 0x003e);
7790 val8 &= 0x7f;
7791 write_byte(0x0040, 0x003e, val8);
7792
7793 // check port 3f4 for accessibility to status bytes
7794 val8 = inb(0x3f4);
7795 if ( (val8 & 0xc0) != 0xc0 )
7796 BX_PANIC("int13_diskette: ctrl not ready\n");
7797
7798 // read 7 return status bytes from controller
7799 // using loop index broken, have to unroll...
7800 return_status[0] = inb(0x3f5);
7801 return_status[1] = inb(0x3f5);
7802 return_status[2] = inb(0x3f5);
7803 return_status[3] = inb(0x3f5);
7804 return_status[4] = inb(0x3f5);
7805 return_status[5] = inb(0x3f5);
7806 return_status[6] = inb(0x3f5);
7807 // record in BIOS Data Area
7808 write_byte(0x0040, 0x0042, return_status[0]);
7809 write_byte(0x0040, 0x0043, return_status[1]);
7810 write_byte(0x0040, 0x0044, return_status[2]);
7811 write_byte(0x0040, 0x0045, return_status[3]);
7812 write_byte(0x0040, 0x0046, return_status[4]);
7813 write_byte(0x0040, 0x0047, return_status[5]);
7814 write_byte(0x0040, 0x0048, return_status[6]);
7815
7816 if ( (return_status[0] & 0xc0) != 0 ) {
7817 SET_AH(0x20);
7818 set_diskette_ret_status(0x20);
7819 SET_AL(0); // no sectors read
7820 SET_CF(); // error occurred
7821 return;
7822 }
7823
7824 // ??? should track be new val from return_status[3] ?
7825 set_diskette_current_cyl(drive, track);
7826 // AL = number of sectors read (same value as passed)
7827 SET_AH(0x00); // success
7828 CLEAR_CF(); // success
7829 return;
7830 } else if (ah == 0x03) {
7831 // Write Diskette Sectors
7832
7833 //-----------------------------------
7834 // set up DMA controller for transfer
7835 //-----------------------------------
7836
7837 // es:bx = pointer to where to place information from diskette
7838 // port 04: DMA-1 base and current address, channel 2
7839 // port 05: DMA-1 base and current count, channel 2
7840 page = (ES >> 12); // upper 4 bits
7841 base_es = (ES << 4); // lower 16bits contributed by ES
7842 base_address = base_es + BX; // lower 16 bits of address
7843 // contributed by ES:BX
7844 if ( base_address < base_es ) {
7845 // in case of carry, adjust page by 1
7846 page++;
7847 }
7848 base_count = (num_sectors * 512) - 1;
7849
7850 // check for 64K boundary overrun
7851 last_addr = base_address + base_count;
7852 if (last_addr < base_address) {
7853 SET_AH(0x09);
7854 set_diskette_ret_status(0x09);
7855 SET_AL(0); // no sectors read
7856 SET_CF(); // error occurred
7857 return;
7858 }
7859
7860 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7861 outb(0x000a, 0x06);
7862
7863 outb(0x000c, 0x00); // clear flip-flop
7864 outb(0x0004, base_address);
7865 outb(0x0004, base_address>>8);
7866 outb(0x000c, 0x00); // clear flip-flop
7867 outb(0x0005, base_count);
7868 outb(0x0005, base_count>>8);
7869
7870 // port 0b: DMA-1 Mode Register
7871 mode_register = 0x4a; // single mode, increment, autoinit disable,
7872 // transfer type=read, channel 2
7873 outb(0x000b, mode_register);
7874
7875 // port 81: DMA-1 Page Register, channel 2
7876 outb(0x0081, page);
7877
7878 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7879 outb(0x000a, 0x02);
7880
7881 //--------------------------------------
7882 // set up floppy controller for transfer
7883 //--------------------------------------
7884 floppy_prepare_controller(drive);
7885
7886 // send write-normal-data command (9 bytes) to controller
7887 outb(0x03f5, 0xc5); // c5: write normal data
7888 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7889 outb(0x03f5, track);
7890 outb(0x03f5, head);
7891 outb(0x03f5, sector);
7892 outb(0x03f5, 2); // 512 byte sector size
7893 outb(0x03f5, sector + num_sectors - 1); // last sector to write on track
7894 outb(0x03f5, 0); // Gap length
7895 outb(0x03f5, 0xff); // Gap length
7896
7897 // turn on interrupts
7898 ASM_START
7899 sti
7900 ASM_END
7901
7902 // wait on 40:3e bit 7 to become 1
7903 do {
7904 val8 = read_byte(0x0040, 0x0040);
7905 if (val8 == 0) {
7906 floppy_reset_controller();
7907 SET_AH(0x80); // drive not ready (timeout)
7908 set_diskette_ret_status(0x80);
7909 SET_AL(0); // no sectors written
7910 SET_CF(); // error occurred
7911 return;
7912 }
7913 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7914 } while ( val8 == 0 );
7915
7916 val8 = 0; // separate asm from while() loop
7917 // turn off interrupts
7918 ASM_START
7919 cli
7920 ASM_END
7921
7922 // set 40:3e bit 7 to 0
7923 val8 = read_byte(0x0040, 0x003e);
7924 val8 &= 0x7f;
7925 write_byte(0x0040, 0x003e, val8);
7926
7927 // check port 3f4 for accessibility to status bytes
7928 val8 = inb(0x3f4);
7929 if ( (val8 & 0xc0) != 0xc0 )
7930 BX_PANIC("int13_diskette: ctrl not ready\n");
7931
7932 // read 7 return status bytes from controller
7933 // using loop index broken, have to unroll...
7934 return_status[0] = inb(0x3f5);
7935 return_status[1] = inb(0x3f5);
7936 return_status[2] = inb(0x3f5);
7937 return_status[3] = inb(0x3f5);
7938 return_status[4] = inb(0x3f5);
7939 return_status[5] = inb(0x3f5);
7940 return_status[6] = inb(0x3f5);
7941 // record in BIOS Data Area
7942 write_byte(0x0040, 0x0042, return_status[0]);
7943 write_byte(0x0040, 0x0043, return_status[1]);
7944 write_byte(0x0040, 0x0044, return_status[2]);
7945 write_byte(0x0040, 0x0045, return_status[3]);
7946 write_byte(0x0040, 0x0046, return_status[4]);
7947 write_byte(0x0040, 0x0047, return_status[5]);
7948 write_byte(0x0040, 0x0048, return_status[6]);
7949
7950 if ( (return_status[0] & 0xc0) != 0 ) {
7951 if ( (return_status[1] & 0x02) != 0 ) {
7952 // diskette not writable.
7953 // AH=status code=0x03 (tried to write on write-protected disk)
7954 // AL=number of sectors written=0
7955 AX = 0x0300;
7956 SET_CF();
7957 return;
7958 } else {
7959 BX_PANIC("int13_diskette_function: read error\n");
7960 }
7961 }
7962
7963 // ??? should track be new val from return_status[3] ?
7964 set_diskette_current_cyl(drive, track);
7965 // AL = number of sectors read (same value as passed)
7966 SET_AH(0x00); // success
7967 CLEAR_CF(); // success
7968 return;
7969 } else { // if (ah == 0x04)
7970 // Verify Diskette Sectors
7971
7972 // ??? should track be new val from return_status[3] ?
7973 set_diskette_current_cyl(drive, track);
7974 // AL = number of sectors verified (same value as passed)
7975 CLEAR_CF(); // success
7976 SET_AH(0x00); // success
7977 return;
7978 }
7979 break;
7980
7981 case 0x05: // format diskette track
7982BX_DEBUG_INT13_FL("floppy f05\n");
7983
7984 num_sectors = GET_AL();
7985 track = GET_CH();
7986 head = GET_DH();
7987 drive = GET_ELDL();
7988
7989 if ((drive > 1) || (head > 1) || (track > 79) ||
7990 (num_sectors == 0) || (num_sectors > 18)) {
7991 SET_AH(1);
7992 set_diskette_ret_status(1);
7993 SET_CF(); // error occurred
7994 }
7995
7996 // see if drive exists
7997 if (floppy_drive_exists(drive) == 0) {
7998 SET_AH(0x80); // drive not responding
7999 set_diskette_ret_status(0x80);
8000 SET_CF(); // error occurred
8001 return;
8002 }
8003
8004 // see if media in drive, and type is known
8005 if (floppy_media_known(drive) == 0) {
8006 if (floppy_media_sense(drive) == 0) {
8007 SET_AH(0x0C); // Media type not found
8008 set_diskette_ret_status(0x0C);
8009 SET_AL(0); // no sectors read
8010 SET_CF(); // error occurred
8011 return;
8012 }
8013 }
8014
8015 // set up DMA controller for transfer
8016 page = (ES >> 12); // upper 4 bits
8017 base_es = (ES << 4); // lower 16bits contributed by ES
8018 base_address = base_es + BX; // lower 16 bits of address
8019 // contributed by ES:BX
8020 if ( base_address < base_es ) {
8021 // in case of carry, adjust page by 1
8022 page++;
8023 }
8024 base_count = (num_sectors * 4) - 1;
8025
8026 // check for 64K boundary overrun
8027 last_addr = base_address + base_count;
8028 if (last_addr < base_address) {
8029 SET_AH(0x09);
8030 set_diskette_ret_status(0x09);
8031 SET_AL(0); // no sectors read
8032 SET_CF(); // error occurred
8033 return;
8034 }
8035
8036 outb(0x000a, 0x06);
8037 outb(0x000c, 0x00); // clear flip-flop
8038 outb(0x0004, base_address);
8039 outb(0x0004, base_address>>8);
8040 outb(0x000c, 0x00); // clear flip-flop
8041 outb(0x0005, base_count);
8042 outb(0x0005, base_count>>8);
8043 mode_register = 0x4a; // single mode, increment, autoinit disable,
8044 // transfer type=read, channel 2
8045 outb(0x000b, mode_register);
8046 // port 81: DMA-1 Page Register, channel 2
8047 outb(0x0081, page);
8048 outb(0x000a, 0x02);
8049
8050 // set up floppy controller for transfer
8051 floppy_prepare_controller(drive);
8052
8053 // send format-track command (6 bytes) to controller
8054 outb(0x03f5, 0x4d); // 4d: format track
8055 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
8056 outb(0x03f5, 2); // 512 byte sector size
8057 outb(0x03f5, num_sectors); // number of sectors per track
8058 outb(0x03f5, 0); // Gap length
8059 outb(0x03f5, 0xf6); // Fill byte
8060 // turn on interrupts
8061 ASM_START
8062 sti
8063 ASM_END
8064
8065 // wait on 40:3e bit 7 to become 1
8066 do {
8067 val8 = read_byte(0x0040, 0x0040);
8068 if (val8 == 0) {
8069 floppy_reset_controller();
8070 SET_AH(0x80); // drive not ready (timeout)
8071 set_diskette_ret_status(0x80);
8072 SET_CF(); // error occurred
8073 return;
8074 }
8075 val8 = (read_byte(0x0040, 0x003e) & 0x80);
8076 } while ( val8 == 0 );
8077
8078 val8 = 0; // separate asm from while() loop
8079 // turn off interrupts
8080 ASM_START
8081 cli
8082 ASM_END
8083 // set 40:3e bit 7 to 0
8084 val8 = read_byte(0x0040, 0x003e);
8085 val8 &= 0x7f;
8086 write_byte(0x0040, 0x003e, val8);
8087 // check port 3f4 for accessibility to status bytes
8088 val8 = inb(0x3f4);
8089 if ( (val8 & 0xc0) != 0xc0 )
8090 BX_PANIC("int13_diskette: ctrl not ready\n");
8091
8092 // read 7 return status bytes from controller
8093 // using loop index broken, have to unroll...
8094 return_status[0] = inb(0x3f5);
8095 return_status[1] = inb(0x3f5);
8096 return_status[2] = inb(0x3f5);
8097 return_status[3] = inb(0x3f5);
8098 return_status[4] = inb(0x3f5);
8099 return_status[5] = inb(0x3f5);
8100 return_status[6] = inb(0x3f5);
8101 // record in BIOS Data Area
8102 write_byte(0x0040, 0x0042, return_status[0]);
8103 write_byte(0x0040, 0x0043, return_status[1]);
8104 write_byte(0x0040, 0x0044, return_status[2]);
8105 write_byte(0x0040, 0x0045, return_status[3]);
8106 write_byte(0x0040, 0x0046, return_status[4]);
8107 write_byte(0x0040, 0x0047, return_status[5]);
8108 write_byte(0x0040, 0x0048, return_status[6]);
8109
8110 if ( (return_status[0] & 0xc0) != 0 ) {
8111 if ( (return_status[1] & 0x02) != 0 ) {
8112 // diskette not writable.
8113 // AH=status code=0x03 (tried to write on write-protected disk)
8114 // AL=number of sectors written=0
8115 AX = 0x0300;
8116 SET_CF();
8117 return;
8118 } else {
8119 BX_PANIC("int13_diskette_function: write error\n");
8120 }
8121 }
8122
8123 SET_AH(0);
8124 set_diskette_ret_status(0);
8125 set_diskette_current_cyl(drive, 0);
8126 CLEAR_CF(); // successful
8127 return;
8128
8129
8130 case 0x08: // read diskette drive parameters
8131BX_DEBUG_INT13_FL("floppy f08\n");
8132 drive = GET_ELDL();
8133
8134 if (drive > 1) {
8135 AX = 0;
8136 BX = 0;
8137 CX = 0;
8138 DX = 0;
8139 ES = 0;
8140 DI = 0;
8141 SET_DL(num_floppies);
8142 SET_CF();
8143 return;
8144 }
8145
8146 drive_type = inb_cmos(0x10);
8147 num_floppies = 0;
8148 if (drive_type & 0xf0)
8149 num_floppies++;
8150 if (drive_type & 0x0f)
8151 num_floppies++;
8152
8153 if (drive == 0)
8154 drive_type >>= 4;
8155 else
8156 drive_type &= 0x0f;
8157
8158 SET_BH(0);
8159 SET_BL(drive_type);
8160 SET_AH(0);
8161 SET_AL(0);
8162 SET_DL(num_floppies);
8163
8164 switch (drive_type) {
8165 case 0: // none
8166 CX = 0;
8167 SET_DH(0); // max head #
8168 break;
8169
8170 case 1: // 360KB, 5.25"
8171 CX = 0x2709; // 40 tracks, 9 sectors
8172 SET_DH(1); // max head #
8173 break;
8174
8175 case 2: // 1.2MB, 5.25"
8176 CX = 0x4f0f; // 80 tracks, 15 sectors
8177 SET_DH(1); // max head #
8178 break;
8179
8180 case 3: // 720KB, 3.5"
8181 CX = 0x4f09; // 80 tracks, 9 sectors
8182 SET_DH(1); // max head #
8183 break;
8184
8185 case 4: // 1.44MB, 3.5"
8186 CX = 0x4f12; // 80 tracks, 18 sectors
8187 SET_DH(1); // max head #
8188 break;
8189
8190 case 5: // 2.88MB, 3.5"
8191 CX = 0x4f24; // 80 tracks, 36 sectors
8192 SET_DH(1); // max head #
8193 break;
8194
8195 case 6: // 160k, 5.25"
8196 CX = 0x2708; // 40 tracks, 8 sectors
8197 SET_DH(0); // max head #
8198 break;
8199
8200 case 7: // 180k, 5.25"
8201 CX = 0x2709; // 40 tracks, 9 sectors
8202 SET_DH(0); // max head #
8203 break;
8204
8205 case 8: // 320k, 5.25"
8206 CX = 0x2708; // 40 tracks, 8 sectors
8207 SET_DH(1); // max head #
8208 break;
8209
8210 default: // ?
8211 BX_PANIC("floppy: int13: bad floppy type\n");
8212 }
8213
8214 /* set es & di to point to 11 byte diskette param table in ROM */
8215ASM_START
8216 push bp
8217 mov bp, sp
8218 mov ax, #diskette_param_table2
8219 mov _int13_diskette_function.DI+2[bp], ax
8220 mov _int13_diskette_function.ES+2[bp], cs
8221 pop bp
8222ASM_END
8223 CLEAR_CF(); // success
8224 /* disk status not changed upon success */
8225 return;
8226
8227
8228 case 0x15: // read diskette drive type
8229BX_DEBUG_INT13_FL("floppy f15\n");
8230 drive = GET_ELDL();
8231 if (drive > 1) {
8232 SET_AH(0); // only 2 drives supported
8233 // set_diskette_ret_status here ???
8234 SET_CF();
8235 return;
8236 }
8237 drive_type = inb_cmos(0x10);
8238
8239 if (drive == 0)
8240 drive_type >>= 4;
8241 else
8242 drive_type &= 0x0f;
8243 CLEAR_CF(); // successful, not present
8244 if (drive_type==0) {
8245 SET_AH(0); // drive not present
8246 }
8247 else {
8248 SET_AH(1); // drive present, does not support change line
8249 }
8250
8251 return;
8252
8253 case 0x16: // get diskette change line status
8254BX_DEBUG_INT13_FL("floppy f16\n");
8255 drive = GET_ELDL();
8256 if (drive > 1) {
8257 SET_AH(0x01); // invalid drive
8258 set_diskette_ret_status(0x01);
8259 SET_CF();
8260 return;
8261 }
8262
8263 SET_AH(0x06); // change line not supported
8264 set_diskette_ret_status(0x06);
8265 SET_CF();
8266 return;
8267
8268 case 0x17: // set diskette type for format(old)
8269BX_DEBUG_INT13_FL("floppy f17\n");
8270 /* not used for 1.44M floppies */
8271 SET_AH(0x01); // not supported
8272 set_diskette_ret_status(1); /* not supported */
8273 SET_CF();
8274 return;
8275
8276 case 0x18: // set diskette type for format(new)
8277BX_DEBUG_INT13_FL("floppy f18\n");
8278 SET_AH(0x01); // do later
8279 set_diskette_ret_status(1);
8280 SET_CF();
8281 return;
8282
8283 default:
8284 BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
8285
8286 // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
8287 SET_AH(0x01); // ???
8288 set_diskette_ret_status(1);
8289 SET_CF();
8290 return;
8291 // }
8292 }
8293}
8294#else // #if BX_SUPPORT_FLOPPY
8295 void
8296int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
8297 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
8298{
8299 Bit8u val8;
8300
8301 switch ( GET_AH() ) {
8302
8303 case 0x01: // Read Diskette Status
8304 CLEAR_CF();
8305 val8 = read_byte(0x0000, 0x0441);
8306 SET_AH(val8);
8307 if (val8) {
8308 SET_CF();
8309 }
8310 return;
8311
8312 default:
8313 SET_CF();
8314 write_byte(0x0000, 0x0441, 0x01);
8315 SET_AH(0x01);
8316 }
8317}
8318#endif // #if BX_SUPPORT_FLOPPY
8319
8320 void
8321set_diskette_ret_status(value)
8322 Bit8u value;
8323{
8324 write_byte(0x0040, 0x0041, value);
8325}
8326
8327 void
8328set_diskette_current_cyl(drive, cyl)
8329 Bit8u drive;
8330 Bit8u cyl;
8331{
8332 if (drive > 1)
8333 BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
8334 write_byte(0x0040, 0x0094+drive, cyl);
8335}
8336
8337 void
8338determine_floppy_media(drive)
8339 Bit16u drive;
8340{
8341#if 0
8342 Bit8u val8, DOR, ctrl_info;
8343
8344 ctrl_info = read_byte(0x0040, 0x008F);
8345 if (drive==1)
8346 ctrl_info >>= 4;
8347 else
8348 ctrl_info &= 0x0f;
8349
8350#if 0
8351 if (drive == 0) {
8352 DOR = 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
8353 }
8354 else {
8355 DOR = 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
8356 }
8357#endif
8358
8359 if ( (ctrl_info & 0x04) != 0x04 ) {
8360 // Drive not determined means no drive exists, done.
8361 return;
8362 }
8363
8364#if 0
8365 // check Main Status Register for readiness
8366 val8 = inb(0x03f4) & 0x80; // Main Status Register
8367 if (val8 != 0x80)
8368 BX_PANIC("d_f_m: MRQ bit not set\n");
8369
8370 // change line
8371
8372 // existing BDA values
8373
8374 // turn on drive motor
8375 outb(0x03f2, DOR); // Digital Output Register
8376 //
8377#endif
8378 BX_PANIC("d_f_m: OK so far\n");
8379#endif
8380}
8381
8382 void
8383int17_function(regs, ds, iret_addr)
8384 pusha_regs_t regs; // regs pushed from PUSHA instruction
8385 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8386 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8387{
8388 Bit16u addr,timeout;
8389 Bit8u val8;
8390
8391 ASM_START
8392 sti
8393 ASM_END
8394
8395 addr = read_word(0x0040, (regs.u.r16.dx << 1) + 8);
8396 if ((regs.u.r8.ah < 3) && (regs.u.r16.dx < 3) && (addr > 0)) {
8397 timeout = read_byte(0x0040, 0x0078 + regs.u.r16.dx) << 8;
8398 if (regs.u.r8.ah == 0) {
8399 outb(addr, regs.u.r8.al);
8400 val8 = inb(addr+2);
8401 outb(addr+2, val8 | 0x01); // send strobe
8402 ASM_START
8403 nop
8404 ASM_END
8405 outb(addr+2, val8 & ~0x01);
8406 while (((inb(addr+1) & 0x40) == 0x40) && (timeout)) {
8407 timeout--;
8408 }
8409 }
8410 if (regs.u.r8.ah == 1) {
8411 val8 = inb(addr+2);
8412 outb(addr+2, val8 & ~0x04); // send init
8413 ASM_START
8414 nop
8415 ASM_END
8416 outb(addr+2, val8 | 0x04);
8417 }
8418 val8 = inb(addr+1);
8419 regs.u.r8.ah = (val8 ^ 0x48);
8420 if (!timeout) regs.u.r8.ah |= 0x01;
8421 ClearCF(iret_addr.flags);
8422 } else {
8423 SetCF(iret_addr.flags); // Unsupported
8424 }
8425}
8426
8427// returns bootsegment in ax, drive in bl
8428 Bit32u
8429int19_function(bseqnr)
8430Bit8u bseqnr;
8431{
8432 Bit16u ebda_seg=read_word(0x0040,0x000E);
8433 Bit16u bootseq;
8434 Bit8u bootdrv;
8435 Bit8u bootcd;
8436#ifdef VBOX
8437 Bit8u bootlan;
8438#endif /* VBOX */
8439 Bit8u bootchk;
8440 Bit16u bootseg;
8441 Bit16u status;
8442 Bit8u lastdrive=0;
8443
8444 // if BX_ELTORITO_BOOT is not defined, old behavior
8445 // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
8446 // in preparation for the initial INT 13h (0=floppy A:, 0x80=C:)
8447 // 0: system boot sequence, first drive C: then A:
8448 // 1: system boot sequence, first drive A: then C:
8449 // else BX_ELTORITO_BOOT is defined
8450 // CMOS regs 0x3D and 0x38 contain the boot sequence:
8451 // CMOS reg 0x3D & 0x0f : 1st boot device
8452 // CMOS reg 0x3D & 0xf0 : 2nd boot device
8453 // CMOS reg 0x38 & 0xf0 : 3rd boot device
8454#ifdef VBOX
8455 // CMOS reg 0x3C & 0x0f : 4th boot device
8456#endif /* VBOX */
8457 // boot device codes:
8458 // 0x00 : not defined
8459 // 0x01 : first floppy
8460 // 0x02 : first harddrive
8461 // 0x03 : first cdrom
8462#ifdef VBOX
8463 // 0x04 : local area network
8464#endif /* VBOX */
8465 // else : boot failure
8466
8467 // Get the boot sequence
8468#if BX_ELTORITO_BOOT
8469 bootseq=inb_cmos(0x3d);
8470 bootseq|=((inb_cmos(0x38) & 0xf0) << 4);
8471#ifdef VBOX
8472 bootseq|=((inb_cmos(0x3c) & 0x0f) << 12);
8473 if (read_byte(ebda_seg, &EbdaData->uForceBootDevice))
8474 bootseq = read_byte(ebda_seg, &EbdaData->uForceBootDevice);
8475 /* Boot delay hack. */
8476 if (bseqnr == 1)
8477 delay_boot((inb_cmos(0x3c) & 0xf0) >> 4); /* Implemented in logo.c */
8478#endif /* VBOX */
8479
8480 if (bseqnr==2) bootseq >>= 4;
8481 if (bseqnr==3) bootseq >>= 8;
8482#ifdef VBOX
8483 if (bseqnr==4) bootseq >>= 12;
8484#endif /* VBOX */
8485 if (bootseq<0x10) lastdrive = 1;
8486 bootdrv=0x00; bootcd=0;
8487#ifdef VBOX
8488 bootlan=0;
8489#endif /* VBOX */
8490
8491 switch(bootseq & 0x0f) {
8492 case 0x01:
8493 bootdrv=0x00;
8494 bootcd=0;
8495 break;
8496 case 0x02:
8497 {
8498 // Get the Boot drive.
8499 Bit8u boot_drive = read_byte(ebda_seg, &EbdaData->uForceBootDrive);
8500
8501 bootdrv = boot_drive + 0x80;
8502 bootcd=0;
8503 break;
8504 }
8505 case 0x03:
8506 bootdrv=0x00;
8507 bootcd=1;
8508 break;
8509#ifdef VBOX
8510 case 0x04: bootlan=1; break;
8511#endif /* VBOX */
8512 default: return 0x00000000;
8513 }
8514#else
8515 bootseq=inb_cmos(0x2d);
8516
8517 if (bseqnr==2) {
8518 bootseq ^= 0x20;
8519 lastdrive = 1;
8520 }
8521 bootdrv=0x00; bootcd=0;
8522 if((bootseq&0x20)==0) bootdrv=0x80;
8523#endif // BX_ELTORITO_BOOT
8524
8525#if BX_ELTORITO_BOOT
8526 // We have to boot from cd
8527 if (bootcd != 0) {
8528 status = cdrom_boot();
8529
8530 // If failure
8531 if ( (status & 0x00ff) !=0 ) {
8532 print_cdromboot_failure(status);
8533#ifdef VBOX
8534 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
8535#else /* !VBOX */
8536 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
8537#endif /* !VBOX */
8538 return 0x00000000;
8539 }
8540
8541 bootseg = read_word(ebda_seg,&EbdaData->cdemu.load_segment);
8542 bootdrv = (Bit8u)(status>>8);
8543 }
8544
8545#endif // BX_ELTORITO_BOOT
8546
8547#ifdef VBOX
8548 // Check for boot from LAN first
8549 if (bootlan == 1) {
8550 if (read_word(VBOX_LANBOOT_SEG,0) == 0xaa55) {
8551 Bit16u pnpoff;
8552 Bit32u manuf;
8553 // This is NOT a generic PnP implementation, but an Etherboot-specific hack.
8554 pnpoff = read_word(VBOX_LANBOOT_SEG,0x1a);
8555 if (read_dword(VBOX_LANBOOT_SEG,pnpoff) == 0x506e5024) {
8556 // Found PnP signature
8557 manuf = read_dword(VBOX_LANBOOT_SEG,read_word(VBOX_LANBOOT_SEG,pnpoff+0xe));
8558 if (manuf == 0x65687445) {
8559 // Found Etherboot ROM
8560 print_boot_device(bootcd, bootlan, bootdrv);
8561ASM_START
8562 push ds
8563 push es
8564 pusha
8565 calli 0x0006,VBOX_LANBOOT_SEG
8566 popa
8567 pop es
8568 pop ds
8569ASM_END
8570 } else if (manuf == 0x65746E49) {
8571 // Found Intel PXE ROM
8572 print_boot_device(bootcd, bootlan, bootdrv);
8573ASM_START
8574 push ds
8575 push es
8576 pusha
8577 sti ; Why are interrupts disabled now? Because we were called through an INT!
8578 push #VBOX_LANBOOT_SEG
8579 pop ds
8580 mov bx,#0x1a ; PnP header offset
8581 mov bx,[bx]
8582 add bx,#0x1a ; BEV offset in PnP header
8583 mov ax,[bx]
8584 test ax,ax
8585 jz no_rom
8586bev_jump:
8587 push cs
8588 push #no_rom
8589 push #VBOX_LANBOOT_SEG
8590 push ax
8591 retf ; call Boot Entry Vector
8592no_rom:
8593 popa
8594 pop es
8595 pop ds
8596ASM_END
8597 }
8598 }
8599 }
8600
8601 // boot from LAN will not return if successful.
8602 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
8603 return 0x00000000;
8604 }
8605#endif /* VBOX */
8606 // We have to boot from harddisk or floppy
8607#ifdef VBOX
8608 if (bootcd == 0 && bootlan == 0) {
8609#else /* !VBOX */
8610 if (bootcd == 0) {
8611#endif /* !VBOX */
8612 bootseg=0x07c0;
8613
8614ASM_START
8615 push bp
8616 mov bp, sp
8617
8618 xor ax, ax
8619 mov _int19_function.status + 2[bp], ax
8620 mov dl, _int19_function.bootdrv + 2[bp]
8621 mov ax, _int19_function.bootseg + 2[bp]
8622 mov es, ax ;; segment
8623 xor bx, bx ;; offset
8624 mov ah, #0x02 ;; function 2, read diskette sector
8625 mov al, #0x01 ;; read 1 sector
8626 mov ch, #0x00 ;; track 0
8627 mov cl, #0x01 ;; sector 1
8628 mov dh, #0x00 ;; head 0
8629 int #0x13 ;; read sector
8630 jnc int19_load_done
8631 mov ax, #0x0001
8632 mov _int19_function.status + 2[bp], ax
8633
8634int19_load_done:
8635 pop bp
8636ASM_END
8637
8638 if (status != 0) {
8639#ifdef VBOX
8640 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
8641#else /* !VBOX */
8642 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
8643#endif /* !VBOX */
8644 return 0x00000000;
8645 }
8646 }
8647
8648#ifdef VBOX
8649 // Don't check boot sectors on floppies and don't read CMOS - byte
8650 // 0x38 in CMOS always has the low bit clear.
8651 // There is *no* requirement whatsoever for a valid boot sector to
8652 // have a 55AAh signature. UNIX boot floppies typically have no such
8653 // signature. In general, it is impossible to tell a valid bootsector
8654 // from an invalid one.
8655 // NB: It is somewhat common for failed OS installs to have the
8656 // 0x55AA signature and a valid partition table but zeros in the
8657 // rest of the boot sector. We do a quick check by comparing the first
8658 // two words of boot sector; if identical, the boot sector is
8659 // extremely unlikely to be valid.
8660#endif
8661 // check signature if instructed by cmos reg 0x38, only for floppy
8662 // bootchk = 1 : signature check disabled
8663 // bootchk = 0 : signature check enabled
8664 if (bootdrv != 0) bootchk = 0;
8665#ifdef VBOX
8666 else bootchk = 1; /* disable 0x55AA signature check on drive A: */
8667#else
8668 else bootchk = inb_cmos(0x38) & 0x01;
8669#endif
8670
8671#if BX_ELTORITO_BOOT
8672 // if boot from cd, no signature check
8673 if (bootcd != 0)
8674 bootchk = 1;
8675#endif // BX_ELTORITO_BOOT
8676
8677 if (bootchk == 0) {
8678 if (read_word(bootseg,0x1fe) != 0xaa55 ||
8679 read_word(bootseg,0) == read_word(bootseg,2)) {
8680#ifdef VBOX
8681 print_boot_failure(bootcd, bootlan, bootdrv, 0, lastdrive);
8682#else /* !VBOX */
8683 print_boot_failure(bootcd, bootdrv, 0, lastdrive);
8684#endif /* VBOX */
8685 return 0x00000000;
8686 }
8687 }
8688
8689#if BX_ELTORITO_BOOT
8690 // Print out the boot string
8691#ifdef VBOX
8692 print_boot_device(bootcd, bootlan, bootdrv);
8693#else /* !VBOX */
8694 print_boot_device(bootcd, bootdrv);
8695#endif /* !VBOX */
8696#else // BX_ELTORITO_BOOT
8697#ifdef VBOX
8698 print_boot_device(0, bootlan, bootdrv);
8699#else /* !VBOX */
8700 print_boot_device(0, bootdrv);
8701#endif /* !VBOX */
8702#endif // BX_ELTORITO_BOOT
8703
8704 // return the boot segment
8705 return (((Bit32u)bootdrv) << 16) + bootseg;
8706}
8707
8708 void
8709int1a_function(regs, ds, iret_addr)
8710 pusha_regs_t regs; // regs pushed from PUSHA instruction
8711 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8712 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8713{
8714 Bit8u val8;
8715
8716 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);
8717
8718 ASM_START
8719 sti
8720 ASM_END
8721
8722 switch (regs.u.r8.ah) {
8723 case 0: // get current clock count
8724 ASM_START
8725 cli
8726 ASM_END
8727 regs.u.r16.cx = BiosData->ticks_high;
8728 regs.u.r16.dx = BiosData->ticks_low;
8729 regs.u.r8.al = BiosData->midnight_flag;
8730 BiosData->midnight_flag = 0; // reset flag
8731 ASM_START
8732 sti
8733 ASM_END
8734 // AH already 0
8735 ClearCF(iret_addr.flags); // OK
8736 break;
8737
8738 case 1: // Set Current Clock Count
8739 ASM_START
8740 cli
8741 ASM_END
8742 BiosData->ticks_high = regs.u.r16.cx;
8743 BiosData->ticks_low = regs.u.r16.dx;
8744 BiosData->midnight_flag = 0; // reset flag
8745 ASM_START
8746 sti
8747 ASM_END
8748 regs.u.r8.ah = 0;
8749 ClearCF(iret_addr.flags); // OK
8750 break;
8751
8752
8753 case 2: // Read CMOS Time
8754 if (rtc_updating()) {
8755 SetCF(iret_addr.flags);
8756 break;
8757 }
8758
8759 regs.u.r8.dh = inb_cmos(0x00); // Seconds
8760 regs.u.r8.cl = inb_cmos(0x02); // Minutes
8761 regs.u.r8.ch = inb_cmos(0x04); // Hours
8762 regs.u.r8.dl = inb_cmos(0x0b) & 0x01; // Stat Reg B
8763 regs.u.r8.ah = 0;
8764 regs.u.r8.al = regs.u.r8.ch;
8765 ClearCF(iret_addr.flags); // OK
8766 break;
8767
8768 case 3: // Set CMOS Time
8769 // Using a debugger, I notice the following masking/setting
8770 // of bits in Status Register B, by setting Reg B to
8771 // a few values and getting its value after INT 1A was called.
8772 //
8773 // try#1 try#2 try#3
8774 // before 1111 1101 0111 1101 0000 0000
8775 // after 0110 0010 0110 0010 0000 0010
8776 //
8777 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8778 // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
8779 if (rtc_updating()) {
8780 init_rtc();
8781 // fall through as if an update were not in progress
8782 }
8783 outb_cmos(0x00, regs.u.r8.dh); // Seconds
8784 outb_cmos(0x02, regs.u.r8.cl); // Minutes
8785 outb_cmos(0x04, regs.u.r8.ch); // Hours
8786 // Set Daylight Savings time enabled bit to requested value
8787 val8 = (inb_cmos(0x0b) & 0x60) | 0x02 | (regs.u.r8.dl & 0x01);
8788 // (reg B already selected)
8789 outb_cmos(0x0b, val8);
8790 regs.u.r8.ah = 0;
8791 regs.u.r8.al = val8; // val last written to Reg B
8792 ClearCF(iret_addr.flags); // OK
8793 break;
8794
8795 case 4: // Read CMOS Date
8796 regs.u.r8.ah = 0;
8797 if (rtc_updating()) {
8798 SetCF(iret_addr.flags);
8799 break;
8800 }
8801 regs.u.r8.cl = inb_cmos(0x09); // Year
8802 regs.u.r8.dh = inb_cmos(0x08); // Month
8803 regs.u.r8.dl = inb_cmos(0x07); // Day of Month
8804 regs.u.r8.ch = inb_cmos(0x32); // Century
8805 regs.u.r8.al = regs.u.r8.ch;
8806 ClearCF(iret_addr.flags); // OK
8807 break;
8808
8809 case 5: // Set CMOS Date
8810 // Using a debugger, I notice the following masking/setting
8811 // of bits in Status Register B, by setting Reg B to
8812 // a few values and getting its value after INT 1A was called.
8813 //
8814 // try#1 try#2 try#3 try#4
8815 // before 1111 1101 0111 1101 0000 0010 0000 0000
8816 // after 0110 1101 0111 1101 0000 0010 0000 0000
8817 //
8818 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8819 // My assumption: RegB = (RegB & 01111111b)
8820 if (rtc_updating()) {
8821 init_rtc();
8822 SetCF(iret_addr.flags);
8823 break;
8824 }
8825 outb_cmos(0x09, regs.u.r8.cl); // Year
8826 outb_cmos(0x08, regs.u.r8.dh); // Month
8827 outb_cmos(0x07, regs.u.r8.dl); // Day of Month
8828 outb_cmos(0x32, regs.u.r8.ch); // Century
8829 val8 = inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
8830 outb_cmos(0x0b, val8);
8831 regs.u.r8.ah = 0;
8832 regs.u.r8.al = val8; // AL = val last written to Reg B
8833 ClearCF(iret_addr.flags); // OK
8834 break;
8835
8836 case 6: // Set Alarm Time in CMOS
8837 // Using a debugger, I notice the following masking/setting
8838 // of bits in Status Register B, by setting Reg B to
8839 // a few values and getting its value after INT 1A was called.
8840 //
8841 // try#1 try#2 try#3
8842 // before 1101 1111 0101 1111 0000 0000
8843 // after 0110 1111 0111 1111 0010 0000
8844 //
8845 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8846 // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
8847 val8 = inb_cmos(0x0b); // Get Status Reg B
8848 regs.u.r16.ax = 0;
8849 if (val8 & 0x20) {
8850 // Alarm interrupt enabled already
8851 SetCF(iret_addr.flags); // Error: alarm in use
8852 break;
8853 }
8854 if (rtc_updating()) {
8855 init_rtc();
8856 // fall through as if an update were not in progress
8857 }
8858 outb_cmos(0x01, regs.u.r8.dh); // Seconds alarm
8859 outb_cmos(0x03, regs.u.r8.cl); // Minutes alarm
8860 outb_cmos(0x05, regs.u.r8.ch); // Hours alarm
8861 outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
8862 // enable Status Reg B alarm bit, clear halt clock bit
8863 outb_cmos(0x0b, (val8 & 0x7f) | 0x20);
8864 ClearCF(iret_addr.flags); // OK
8865 break;
8866
8867 case 7: // Turn off Alarm
8868 // Using a debugger, I notice the following masking/setting
8869 // of bits in Status Register B, by setting Reg B to
8870 // a few values and getting its value after INT 1A was called.
8871 //
8872 // try#1 try#2 try#3 try#4
8873 // before 1111 1101 0111 1101 0010 0000 0010 0010
8874 // after 0100 0101 0101 0101 0000 0000 0000 0010
8875 //
8876 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8877 // My assumption: RegB = (RegB & 01010111b)
8878 val8 = inb_cmos(0x0b); // Get Status Reg B
8879 // clear clock-halt bit, disable alarm bit
8880 outb_cmos(0x0b, val8 & 0x57); // disable alarm bit
8881 regs.u.r8.ah = 0;
8882 regs.u.r8.al = val8; // val last written to Reg B
8883 ClearCF(iret_addr.flags); // OK
8884 break;
8885#if BX_PCIBIOS
8886 case 0xb1:
8887 // real mode PCI BIOS functions now handled in assembler code
8888 // this C code handles the error code for information only
8889 if (regs.u.r8.bl == 0xff) {
8890 BX_INFO("PCI BIOS: PCI not present\n");
8891 } else if (regs.u.r8.bl == 0x81) {
8892 BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs.u.r8.al);
8893 } else if (regs.u.r8.bl == 0x83) {
8894 BX_INFO("bad PCI vendor ID %04x\n", regs.u.r16.dx);
8895 } else if (regs.u.r8.bl == 0x86) {
8896 if (regs.u.r8.al == 0x02) {
8897 BX_INFO("PCI device %04x:%04x not found at index %d\n", regs.u.r16.dx, regs.u.r16.cx, regs.u.r16.si);
8898 } else {
8899 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);
8900 }
8901 }
8902 regs.u.r8.ah = regs.u.r8.bl;
8903 SetCF(iret_addr.flags);
8904 break;
8905#endif
8906
8907 default:
8908 SetCF(iret_addr.flags); // Unsupported
8909 }
8910}
8911
8912 void
8913int70_function(regs, ds, iret_addr)
8914 pusha_regs_t regs; // regs pushed from PUSHA instruction
8915 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8916 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8917{
8918 // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
8919 Bit8u registerB = 0, registerC = 0;
8920
8921 // Check which modes are enabled and have occurred.
8922 registerB = inb_cmos( 0xB );
8923 registerC = inb_cmos( 0xC );
8924
8925 if( ( registerB & 0x60 ) != 0 ) {
8926 if( ( registerC & 0x20 ) != 0 ) {
8927 // Handle Alarm Interrupt.
8928ASM_START
8929 sti
8930 int #0x4a
8931 cli
8932ASM_END
8933 }
8934 if( ( registerC & 0x40 ) != 0 ) {
8935 // Handle Periodic Interrupt.
8936
8937 if( read_byte( 0x40, 0xA0 ) != 0 ) {
8938 // Wait Interval (Int 15, AH=83) active.
8939 Bit32u time, toggle;
8940
8941 time = read_dword( 0x40, 0x9C ); // Time left in microseconds.
8942 if( time < 0x3D1 ) {
8943 // Done waiting.
8944 Bit16u segment, offset;
8945
8946 segment = read_word( 0x40, 0x98 );
8947 offset = read_word( 0x40, 0x9A );
8948 write_byte( 0x40, 0xA0, 0 ); // Turn of status byte.
8949 outb_cmos( 0xB, registerB & 0x37 ); // Clear the Periodic Interrupt.
8950 write_byte(segment, offset, read_byte(segment, offset) | 0x80 ); // Write to specified flag byte.
8951 } else {
8952 // Continue waiting.
8953 time -= 0x3D1;
8954 write_dword( 0x40, 0x9C, time );
8955 }
8956 }
8957 }
8958 }
8959
8960ASM_START
8961 call eoi_both_pics
8962ASM_END
8963}
8964
8965 void
8966dummy_isr_function(regs, ds, iret_addr)
8967 pusha_regs_t regs; // regs pushed from PUSHA instruction
8968 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8969 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8970{
8971 // Interrupt handler for unexpected hardware interrupts. We have to clear
8972 // the PIC because if we don't, the next EOI will clear the wrong interrupt
8973 // and all hell will break loose! This routine also masks the unexpected
8974 // interrupt so it will generally be called only once for each unexpected
8975 // interrupt level.
8976 Bit8u isrA, isrB, imr, last_int = 0xFF;
8977
8978 outb( 0x20, 0x0B );
8979 isrA = inb( 0x20 );
8980 if (isrA) {
8981 outb( 0xA0, 0x0B );
8982 isrB = inb( 0xA0 );
8983 if (isrB) {
8984 imr = inb( 0xA1 );
8985 outb( 0xA1, imr | isrB ); // Mask this interrupt
8986 outb( 0xA0, 0x20 ); // Send EOI on slave PIC
8987 } else {
8988 imr = inb( 0x21 );
8989 isrA &= 0xFB; // Never mask the cascade interrupt
8990 outb( 0x21, imr | isrA); // Mask this interrupt
8991 }
8992 outb( 0x20, 0x20 ); // Send EOI on master PIC
8993 last_int = isrA;
8994 }
8995 write_byte( 0x40, 0x6B, last_int ); // Write INTR_FLAG
8996}
8997
8998ASM_START
8999;------------------------------------------
9000;- INT74h : PS/2 mouse hardware interrupt -
9001;------------------------------------------
9002int74_handler:
9003 sti
9004 pusha
9005 push ds ;; save DS
9006 push #0x00 ;; placeholder for status
9007 push #0x00 ;; placeholder for X
9008 push #0x00 ;; placeholder for Y
9009 push #0x00 ;; placeholder for Z
9010 push #0x00 ;; placeholder for make_far_call boolean
9011 call _int74_function
9012 pop cx ;; remove make_far_call from stack
9013 jcxz int74_done
9014
9015 ;; make far call to EBDA:0022
9016 push #0x00
9017 pop ds
9018 push 0x040E ;; push 0000:040E (opcodes 0xff, 0x36, 0x0E, 0x04)
9019 pop ds
9020 //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
9021 call far ptr[0x22]
9022int74_done:
9023 cli
9024 call eoi_both_pics
9025 add sp, #8 ;; pop status, x, y, z
9026
9027 pop ds ;; restore DS
9028 popa
9029 iret
9030
9031
9032;; This will perform an IRET, but will retain value of current CF
9033;; by altering flags on stack. Better than RETF #02.
9034iret_modify_cf:
9035 jc carry_set
9036 push bp
9037 mov bp, sp
9038 and BYTE [bp + 0x06], #0xfe
9039 pop bp
9040 iret
9041carry_set:
9042 push bp
9043 mov bp, sp
9044 or BYTE [bp + 0x06], #0x01
9045 pop bp
9046 iret
9047
9048
9049;----------------------
9050;- INT13h (relocated) -
9051;----------------------
9052;
9053; int13_relocated is a little bit messed up since I played with it
9054; I have to rewrite it:
9055; - call a function that detect which function to call
9056; - make all called C function get the same parameters list
9057;
9058int13_relocated:
9059 cld ;; we will be doing some string I/O
9060
9061#if BX_ELTORITO_BOOT
9062 ;; check for an eltorito function
9063 cmp ah,#0x4a
9064 jb int13_not_eltorito
9065 cmp ah,#0x4d
9066 ja int13_not_eltorito
9067
9068 pusha
9069 push es
9070 push ds
9071 push ss
9072 pop ds
9073
9074 push #int13_out
9075 jmp _int13_eltorito ;; ELDX not used
9076
9077int13_not_eltorito:
9078 push ax
9079 push bx
9080 push cx
9081 push dx
9082
9083 ;; check if emulation active
9084 call _cdemu_isactive
9085 cmp al,#0x00
9086 je int13_cdemu_inactive
9087
9088 ;; check if access to the emulated drive
9089 call _cdemu_emulated_drive
9090 pop dx
9091 push dx
9092 cmp al,dl ;; int13 on emulated drive
9093 jne int13_nocdemu
9094
9095 pop dx
9096 pop cx
9097 pop bx
9098 pop ax
9099
9100 pusha
9101 push es
9102 push ds
9103 push ss
9104 pop ds
9105
9106 push #int13_out
9107 jmp _int13_cdemu ;; ELDX not used
9108
9109int13_nocdemu:
9110 and dl,#0xE0 ;; mask to get device class, including cdroms
9111 cmp al,dl ;; al is 0x00 or 0x80
9112 jne int13_cdemu_inactive ;; inactive for device class
9113
9114 pop dx
9115 pop cx
9116 pop bx
9117 pop ax
9118
9119 push ax
9120 push cx
9121 push dx
9122 push bx
9123
9124 dec dl ;; real drive is dl - 1
9125 jmp int13_legacy
9126
9127int13_cdemu_inactive:
9128 pop dx
9129 pop cx
9130 pop bx
9131 pop ax
9132
9133#endif // BX_ELTORITO_BOOT
9134
9135int13_noeltorito:
9136
9137 push ax
9138 push cx
9139 push dx
9140 push bx
9141
9142int13_legacy:
9143
9144 push dx ;; push eltorito value of dx instead of sp
9145
9146 push bp
9147 push si
9148 push di
9149
9150 push es
9151 push ds
9152 push ss
9153 pop ds
9154
9155 ;; now the 16-bit registers can be restored with:
9156 ;; pop ds; pop es; popa; iret
9157 ;; arguments passed to functions should be
9158 ;; DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS
9159
9160 test dl, #0x80
9161 jnz int13_notfloppy
9162
9163 push #int13_out
9164 jmp _int13_diskette_function
9165
9166int13_notfloppy:
9167
9168#if BX_USE_ATADRV
9169
9170 cmp dl, #0xE0
9171 jb int13_notcdrom
9172
9173 // ebx is modified: BSD 5.2.1 boot loader problem
9174 // someone should figure out which 32 bit register that actually are used
9175
9176 shr ebx, #16
9177 push bx
9178
9179 call _int13_cdrom
9180
9181 pop bx
9182 shl ebx, #16
9183
9184 jmp int13_out
9185
9186int13_notcdrom:
9187
9188#endif
9189
9190int13_disk:
9191 ;; int13_harddisk modifies high word of EAX and EBX
9192 shr eax, #16
9193 push ax
9194 shr ebx, #16
9195 push bx
9196 call _int13_harddisk
9197 pop bx
9198 shl ebx, #16
9199 pop ax
9200 shl eax, #16
9201
9202int13_out:
9203 pop ds
9204 pop es
9205 popa
9206 iret
9207
9208;----------
9209;- INT18h -
9210;----------
9211int18_handler: ;; Boot Failure routing
9212 call _int18_panic_msg
9213 hlt
9214 iret
9215
9216;----------
9217;- INT19h -
9218;----------
9219int19_relocated: ;; Boot function, relocated
9220
9221#ifdef VBOX
9222 // If an already booted OS calls int 0x19 to reboot, it is not sufficient
9223 // just to try booting from the configured drives. All BIOS variables and
9224 // interrupt vectors need to be reset, otherwise strange things may happen.
9225 // The approach used is faking a warm reboot (which just skips showing the
9226 // logo), which is a bit more than what we need, but hey, it's fast.
9227 mov bp, sp
9228 mov ax, 2[bp]
9229 cmp ax, #0xf000
9230 jz bios_initiated_boot
9231 xor ax, ax
9232 mov ds, ax
9233 mov ax, #0x1234
9234 mov 0x472, ax
9235 jmp post
9236bios_initiated_boot:
9237#endif /* VBOX */
9238
9239 ;; int19 was beginning to be really complex, so now it
9240 ;; just calls a C function that does the work
9241 ;; it returns in BL the boot drive, and in AX the boot segment
9242 ;; the boot segment will be 0x0000 if something has failed
9243
9244 push bp
9245 mov bp, sp
9246
9247 ;; drop ds
9248 xor ax, ax
9249 mov ds, ax
9250
9251 ;; 1st boot device
9252 mov ax, #0x0001
9253 push ax
9254 call _int19_function
9255 inc sp
9256 inc sp
9257 ;; bl contains the boot drive
9258 ;; ax contains the boot segment or 0 if failure
9259
9260 test ax, ax ;; if ax is 0 try next boot device
9261 jnz boot_setup
9262
9263 ;; 2nd boot device
9264 mov ax, #0x0002
9265 push ax
9266 call _int19_function
9267 inc sp
9268 inc sp
9269 test ax, ax ;; if ax is 0 try next boot device
9270 jnz boot_setup
9271
9272 ;; 3rd boot device
9273 mov ax, #0x0003
9274 push ax
9275 call _int19_function
9276 inc sp
9277 inc sp
9278#ifdef VBOX
9279 test ax, ax ;; if ax is 0 try next boot device
9280 jnz boot_setup
9281
9282 ;; 4th boot device
9283 mov ax, #0x0004
9284 push ax
9285 call _int19_function
9286 inc sp
9287 inc sp
9288#endif /* VBOX */
9289 test ax, ax ;; if ax is 0 call int18
9290 jz int18_handler
9291
9292boot_setup:
9293 mov dl, bl ;; set drive so guest os find it
9294 shl eax, #0x04 ;; convert seg to ip
9295 mov 2[bp], ax ;; set ip
9296
9297 shr eax, #0x04 ;; get cs back
9298 and ax, #0xF000 ;; remove what went in ip
9299 mov 4[bp], ax ;; set cs
9300 xor ax, ax
9301 mov es, ax ;; set es to zero fixes [ 549815 ]
9302 mov [bp], ax ;; set bp to zero
9303 mov ax, #0xaa55 ;; set ok flag
9304
9305 pop bp
9306 iret ;; Beam me up Scotty
9307
9308;----------
9309;- INT1Ch -
9310;----------
9311int1c_handler: ;; User Timer Tick
9312 iret
9313
9314
9315;----------------------
9316;- POST: Floppy Drive -
9317;----------------------
9318floppy_drive_post:
9319 xor ax, ax
9320 mov ds, ax
9321
9322 mov al, #0x00
9323 mov 0x043e, al ;; drive 0 & 1 uncalibrated, no interrupt has occurred
9324
9325 mov 0x043f, al ;; diskette motor status: read op, drive0, motors off
9326
9327 mov 0x0440, al ;; diskette motor timeout counter: not active
9328 mov 0x0441, al ;; diskette controller status return code
9329
9330 mov 0x0442, al ;; disk & diskette controller status register 0
9331 mov 0x0443, al ;; diskette controller status register 1
9332 mov 0x0444, al ;; diskette controller status register 2
9333 mov 0x0445, al ;; diskette controller cylinder number
9334 mov 0x0446, al ;; diskette controller head number
9335 mov 0x0447, al ;; diskette controller sector number
9336 mov 0x0448, al ;; diskette controller bytes written
9337
9338 mov 0x048b, al ;; diskette configuration data
9339
9340 ;; -----------------------------------------------------------------
9341 ;; (048F) diskette controller information
9342 ;;
9343 mov al, #0x10 ;; get CMOS diskette drive type
9344 out 0x70, AL
9345 in AL, 0x71
9346 mov ah, al ;; save byte to AH
9347
9348look_drive0:
9349 shr al, #4 ;; look at top 4 bits for drive 0
9350 jz f0_missing ;; jump if no drive0
9351 mov bl, #0x07 ;; drive0 determined, multi-rate, has changed line
9352 jmp look_drive1
9353f0_missing:
9354 mov bl, #0x00 ;; no drive0
9355
9356look_drive1:
9357 mov al, ah ;; restore from AH
9358 and al, #0x0f ;; look at bottom 4 bits for drive 1
9359 jz f1_missing ;; jump if no drive1
9360 or bl, #0x70 ;; drive1 determined, multi-rate, has changed line
9361f1_missing:
9362 ;; leave high bits in BL zerod
9363 mov 0x048f, bl ;; put new val in BDA (diskette controller information)
9364 ;; -----------------------------------------------------------------
9365
9366 mov al, #0x00
9367 mov 0x0490, al ;; diskette 0 media state
9368 mov 0x0491, al ;; diskette 1 media state
9369
9370 ;; diskette 0,1 operational starting state
9371 ;; drive type has not been determined,
9372 ;; has no changed detection line
9373 mov 0x0492, al
9374 mov 0x0493, al
9375
9376 mov 0x0494, al ;; diskette 0 current cylinder
9377 mov 0x0495, al ;; diskette 1 current cylinder
9378
9379 mov al, #0x02
9380 out #0x0a, al ;; clear DMA-1 channel 2 mask bit
9381
9382 SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
9383 SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
9384 SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
9385
9386 ret
9387
9388
9389;--------------------
9390;- POST: HARD DRIVE -
9391;--------------------
9392; relocated here because the primary POST area isnt big enough.
9393hard_drive_post:
9394 // IRQ 14 = INT 76h
9395 // INT 76h calls INT 15h function ax=9100
9396
9397 mov al, #0x0a ; 0000 1010 = reserved, disable IRQ 14
9398 mov dx, #0x03f6
9399 out dx, al
9400
9401 xor ax, ax
9402 mov ds, ax
9403 mov 0x0474, al /* hard disk status of last operation */
9404 mov 0x0477, al /* hard disk port offset (XT only ???) */
9405 mov 0x048c, al /* hard disk status register */
9406 mov 0x048d, al /* hard disk error register */
9407 mov 0x048e, al /* hard disk task complete flag */
9408 mov al, #0x01
9409 mov 0x0475, al /* hard disk number attached */
9410 mov al, #0xc0
9411 mov 0x0476, al /* hard disk control byte */
9412 SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
9413 SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
9414 ;; INT 41h: hard disk 0 configuration pointer
9415 ;; INT 46h: hard disk 1 configuration pointer
9416 SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D)
9417 SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D)
9418
9419#ifndef VBOX /* This is done later (and the CMOS format is now different). */
9420 ;; move disk geometry data from CMOS to EBDA disk parameter table(s)
9421 mov al, #0x12
9422 out #0x70, al
9423 in al, #0x71
9424 and al, #0xf0
9425 cmp al, #0xf0
9426 je post_d0_extended
9427 jmp check_for_hd1
9428post_d0_extended:
9429 mov al, #0x19
9430 out #0x70, al
9431 in al, #0x71
9432 cmp al, #47 ;; decimal 47 - user definable
9433 je post_d0_type47
9434 HALT(__LINE__)
9435post_d0_type47:
9436 ;; CMOS purpose param table offset
9437 ;; 1b cylinders low 0
9438 ;; 1c cylinders high 1
9439 ;; 1d heads 2
9440 ;; 1e write pre-comp low 5
9441 ;; 1f write pre-comp high 6
9442 ;; 20 retries/bad map/heads>8 8
9443 ;; 21 landing zone low C
9444 ;; 22 landing zone high D
9445 ;; 23 sectors/track E
9446
9447 mov ax, #EBDA_SEG
9448 mov ds, ax
9449
9450 ;;; Filling EBDA table for hard disk 0.
9451 mov al, #0x1f
9452 out #0x70, al
9453 in al, #0x71
9454 mov ah, al
9455 mov al, #0x1e
9456 out #0x70, al
9457 in al, #0x71
9458 mov (0x003d + 0x05), ax ;; write precomp word
9459
9460 mov al, #0x20
9461 out #0x70, al
9462 in al, #0x71
9463 mov (0x003d + 0x08), al ;; drive control byte
9464
9465 mov al, #0x22
9466 out #0x70, al
9467 in al, #0x71
9468 mov ah, al
9469 mov al, #0x21
9470 out #0x70, al
9471 in al, #0x71
9472 mov (0x003d + 0x0C), ax ;; landing zone word
9473
9474 mov al, #0x1c ;; get cylinders word in AX
9475 out #0x70, al
9476 in al, #0x71 ;; high byte
9477 mov ah, al
9478 mov al, #0x1b
9479 out #0x70, al
9480 in al, #0x71 ;; low byte
9481 mov bx, ax ;; BX = cylinders
9482
9483 mov al, #0x1d
9484 out #0x70, al
9485 in al, #0x71
9486 mov cl, al ;; CL = heads
9487
9488 mov al, #0x23
9489 out #0x70, al
9490 in al, #0x71
9491 mov dl, al ;; DL = sectors
9492
9493 cmp bx, #1024
9494 jnbe hd0_post_logical_chs ;; if cylinders > 1024, use translated style CHS
9495
9496hd0_post_physical_chs:
9497 ;; no logical CHS mapping used, just physical CHS
9498 ;; use Standard Fixed Disk Parameter Table (FDPT)
9499 mov (0x003d + 0x00), bx ;; number of physical cylinders
9500 mov (0x003d + 0x02), cl ;; number of physical heads
9501 mov (0x003d + 0x0E), dl ;; number of physical sectors
9502 jmp check_for_hd1
9503
9504hd0_post_logical_chs:
9505 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
9506 mov (0x003d + 0x09), bx ;; number of physical cylinders
9507 mov (0x003d + 0x0b), cl ;; number of physical heads
9508 mov (0x003d + 0x04), dl ;; number of physical sectors
9509 mov (0x003d + 0x0e), dl ;; number of logical sectors (same)
9510 mov al, #0xa0
9511 mov (0x003d + 0x03), al ;; A0h signature, indicates translated table
9512
9513 cmp bx, #2048
9514 jnbe hd0_post_above_2048
9515 ;; 1024 < c <= 2048 cylinders
9516 shr bx, #0x01
9517 shl cl, #0x01
9518 jmp hd0_post_store_logical
9519
9520hd0_post_above_2048:
9521 cmp bx, #4096
9522 jnbe hd0_post_above_4096
9523 ;; 2048 < c <= 4096 cylinders
9524 shr bx, #0x02
9525 shl cl, #0x02
9526 jmp hd0_post_store_logical
9527
9528hd0_post_above_4096:
9529 cmp bx, #8192
9530 jnbe hd0_post_above_8192
9531 ;; 4096 < c <= 8192 cylinders
9532 shr bx, #0x03
9533 shl cl, #0x03
9534 jmp hd0_post_store_logical
9535
9536hd0_post_above_8192:
9537 ;; 8192 < c <= 16384 cylinders
9538 shr bx, #0x04
9539 shl cl, #0x04
9540
9541hd0_post_store_logical:
9542 mov (0x003d + 0x00), bx ;; number of physical cylinders
9543 mov (0x003d + 0x02), cl ;; number of physical heads
9544 ;; checksum
9545 mov cl, #0x0f ;; repeat count
9546 mov si, #0x003d ;; offset to disk0 FDPT
9547 mov al, #0x00 ;; sum
9548hd0_post_checksum_loop:
9549 add al, [si]
9550 inc si
9551 dec cl
9552 jnz hd0_post_checksum_loop
9553 not al ;; now take 2s complement
9554 inc al
9555 mov [si], al
9556;;; Done filling EBDA table for hard disk 0.
9557
9558
9559check_for_hd1:
9560 ;; is there really a second hard disk? if not, return now
9561 mov al, #0x12
9562 out #0x70, al
9563 in al, #0x71
9564 and al, #0x0f
9565 jnz post_d1_exists
9566 ret
9567post_d1_exists:
9568 ;; check that the hd type is really 0x0f.
9569 cmp al, #0x0f
9570 jz post_d1_extended
9571 HALT(__LINE__)
9572post_d1_extended:
9573 ;; check that the extended type is 47 - user definable
9574 mov al, #0x1a
9575 out #0x70, al
9576 in al, #0x71
9577 cmp al, #47 ;; decimal 47 - user definable
9578 je post_d1_type47
9579 HALT(__LINE__)
9580post_d1_type47:
9581 ;; Table for disk1.
9582 ;; CMOS purpose param table offset
9583 ;; 0x24 cylinders low 0
9584 ;; 0x25 cylinders high 1
9585 ;; 0x26 heads 2
9586 ;; 0x27 write pre-comp low 5
9587 ;; 0x28 write pre-comp high 6
9588 ;; 0x29 heads>8 8
9589 ;; 0x2a landing zone low C
9590 ;; 0x2b landing zone high D
9591 ;; 0x2c sectors/track E
9592;;; Fill EBDA table for hard disk 1.
9593 mov ax, #EBDA_SEG
9594 mov ds, ax
9595 mov al, #0x28
9596 out #0x70, al
9597 in al, #0x71
9598 mov ah, al
9599 mov al, #0x27
9600 out #0x70, al
9601 in al, #0x71
9602 mov (0x004d + 0x05), ax ;; write precomp word
9603
9604 mov al, #0x29
9605 out #0x70, al
9606 in al, #0x71
9607 mov (0x004d + 0x08), al ;; drive control byte
9608
9609 mov al, #0x2b
9610 out #0x70, al
9611 in al, #0x71
9612 mov ah, al
9613 mov al, #0x2a
9614 out #0x70, al
9615 in al, #0x71
9616 mov (0x004d + 0x0C), ax ;; landing zone word
9617
9618 mov al, #0x25 ;; get cylinders word in AX
9619 out #0x70, al
9620 in al, #0x71 ;; high byte
9621 mov ah, al
9622 mov al, #0x24
9623 out #0x70, al
9624 in al, #0x71 ;; low byte
9625 mov bx, ax ;; BX = cylinders
9626
9627 mov al, #0x26
9628 out #0x70, al
9629 in al, #0x71
9630 mov cl, al ;; CL = heads
9631
9632 mov al, #0x2c
9633 out #0x70, al
9634 in al, #0x71
9635 mov dl, al ;; DL = sectors
9636
9637 cmp bx, #1024
9638 jnbe hd1_post_logical_chs ;; if cylinders > 1024, use translated style CHS
9639
9640hd1_post_physical_chs:
9641 ;; no logical CHS mapping used, just physical CHS
9642 ;; use Standard Fixed Disk Parameter Table (FDPT)
9643 mov (0x004d + 0x00), bx ;; number of physical cylinders
9644 mov (0x004d + 0x02), cl ;; number of physical heads
9645 mov (0x004d + 0x0E), dl ;; number of physical sectors
9646 ret
9647
9648hd1_post_logical_chs:
9649 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
9650 mov (0x004d + 0x09), bx ;; number of physical cylinders
9651 mov (0x004d + 0x0b), cl ;; number of physical heads
9652 mov (0x004d + 0x04), dl ;; number of physical sectors
9653 mov (0x004d + 0x0e), dl ;; number of logical sectors (same)
9654 mov al, #0xa0
9655 mov (0x004d + 0x03), al ;; A0h signature, indicates translated table
9656
9657 cmp bx, #2048
9658 jnbe hd1_post_above_2048
9659 ;; 1024 < c <= 2048 cylinders
9660 shr bx, #0x01
9661 shl cl, #0x01
9662 jmp hd1_post_store_logical
9663
9664hd1_post_above_2048:
9665 cmp bx, #4096
9666 jnbe hd1_post_above_4096
9667 ;; 2048 < c <= 4096 cylinders
9668 shr bx, #0x02
9669 shl cl, #0x02
9670 jmp hd1_post_store_logical
9671
9672hd1_post_above_4096:
9673 cmp bx, #8192
9674 jnbe hd1_post_above_8192
9675 ;; 4096 < c <= 8192 cylinders
9676 shr bx, #0x03
9677 shl cl, #0x03
9678 jmp hd1_post_store_logical
9679
9680hd1_post_above_8192:
9681 ;; 8192 < c <= 16384 cylinders
9682 shr bx, #0x04
9683 shl cl, #0x04
9684
9685hd1_post_store_logical:
9686 mov (0x004d + 0x00), bx ;; number of physical cylinders
9687 mov (0x004d + 0x02), cl ;; number of physical heads
9688 ;; checksum
9689 mov cl, #0x0f ;; repeat count
9690 mov si, #0x004d ;; offset to disk0 FDPT
9691 mov al, #0x00 ;; sum
9692hd1_post_checksum_loop:
9693 add al, [si]
9694 inc si
9695 dec cl
9696 jnz hd1_post_checksum_loop
9697 not al ;; now take 2s complement
9698 inc al
9699 mov [si], al
9700;;; Done filling EBDA table for hard disk 1.
9701#endif /* !VBOX */
9702
9703 ret
9704
9705;--------------------
9706;- POST: EBDA segment
9707;--------------------
9708; relocated here because the primary POST area isnt big enough.
9709; the SET_INT_VECTORs have nothing to do with EBDA but do not
9710; fit into the primary POST area either
9711ebda_post:
9712 SET_INT_VECTOR(0x0D, #0xF000, #dummy_isr); IRQ 5
9713 SET_INT_VECTOR(0x0F, #0xF000, #dummy_isr); IRQ 7
9714 SET_INT_VECTOR(0x72, #0xF000, #dummy_isr); IRQ 11
9715 SET_INT_VECTOR(0x77, #0xF000, #dummy_isr); IRQ 15
9716
9717#if BX_USE_EBDA
9718 mov ax, #EBDA_SEG
9719 mov ds, ax
9720 mov byte ptr [0x0], #EBDA_SIZE
9721#endif
9722 xor ax, ax ; mov EBDA seg into 40E
9723 mov ds, ax
9724 mov word ptr [0x40E], #EBDA_SEG
9725 ret;;
9726
9727;--------------------
9728;- POST: EOI + jmp via [0x40:67)
9729;--------------------
9730; relocated here because the primary POST area isnt big enough.
9731eoi_jmp_post:
9732 call eoi_both_pics
9733
9734 xor ax, ax
9735 mov ds, ax
9736
9737 jmp far ptr [0x467]
9738
9739
9740;--------------------
9741eoi_both_pics:
9742 mov al, #0x20
9743 out #0xA0, al ;; slave PIC EOI
9744eoi_master_pic:
9745 mov al, #0x20
9746 out #0x20, al ;; master PIC EOI
9747 ret
9748
9749;--------------------
9750BcdToBin:
9751 ;; in: AL in BCD format
9752 ;; out: AL in binary format, AH will always be 0
9753 ;; trashes BX
9754 mov bl, al
9755 and bl, #0x0f ;; bl has low digit
9756 shr al, #4 ;; al has high digit
9757 mov bh, #10
9758 mul al, bh ;; multiply high digit by 10 (result in AX)
9759 add al, bl ;; then add low digit
9760 ret
9761
9762;--------------------
9763timer_tick_post:
9764 ;; Setup the Timer Ticks Count (0x46C:dword) and
9765 ;; Timer Ticks Roller Flag (0x470:byte)
9766 ;; The Timer Ticks Count needs to be set according to
9767 ;; the current CMOS time, as if ticks have been occurring
9768 ;; at 18.2hz since midnight up to this point. Calculating
9769 ;; this is a little complicated. Here are the factors I gather
9770 ;; regarding this. 14,318,180 hz was the original clock speed,
9771 ;; chosen so it could be divided by either 3 to drive the 5Mhz CPU
9772 ;; at the time, or 4 to drive the CGA video adapter. The div3
9773 ;; source was divided again by 4 to feed a 1.193Mhz signal to
9774 ;; the timer. With a maximum 16bit timer count, this is again
9775 ;; divided down by 65536 to 18.2hz.
9776 ;;
9777 ;; 14,318,180 Hz clock
9778 ;; /3 = 4,772,726 Hz fed to original 5Mhz CPU
9779 ;; /4 = 1,193,181 Hz fed to timer
9780 ;; /65536 (maximum timer count) = 18.20650736 ticks/second
9781 ;; 1 second = 18.20650736 ticks
9782 ;; 1 minute = 1092.390442 ticks
9783 ;; 1 hour = 65543.42651 ticks
9784 ;;
9785 ;; Given the values in the CMOS clock, one could calculate
9786 ;; the number of ticks by the following:
9787 ;; ticks = (BcdToBin(seconds) * 18.206507) +
9788 ;; (BcdToBin(minutes) * 1092.3904)
9789 ;; (BcdToBin(hours) * 65543.427)
9790 ;; To get a little more accuracy, since Im using integer
9791 ;; arithmetic, I use:
9792 ;; ticks = (BcdToBin(seconds) * 18206507) / 1000000 +
9793 ;; (BcdToBin(minutes) * 10923904) / 10000 +
9794 ;; (BcdToBin(hours) * 65543427) / 1000
9795
9796 ;; assuming DS=0000
9797
9798 ;; get CMOS seconds
9799 xor eax, eax ;; clear EAX
9800 mov al, #0x00
9801 out #0x70, al
9802 in al, #0x71 ;; AL has CMOS seconds in BCD
9803 call BcdToBin ;; EAX now has seconds in binary
9804 mov edx, #18206507
9805 mul eax, edx
9806 mov ebx, #1000000
9807 xor edx, edx
9808 div eax, ebx
9809 mov ecx, eax ;; ECX will accumulate total ticks
9810
9811 ;; get CMOS minutes
9812 xor eax, eax ;; clear EAX
9813 mov al, #0x02
9814 out #0x70, al
9815 in al, #0x71 ;; AL has CMOS minutes in BCD
9816 call BcdToBin ;; EAX now has minutes in binary
9817 mov edx, #10923904
9818 mul eax, edx
9819 mov ebx, #10000
9820 xor edx, edx
9821 div eax, ebx
9822 add ecx, eax ;; add to total ticks
9823
9824 ;; get CMOS hours
9825 xor eax, eax ;; clear EAX
9826 mov al, #0x04
9827 out #0x70, al
9828 in al, #0x71 ;; AL has CMOS hours in BCD
9829 call BcdToBin ;; EAX now has hours in binary
9830 mov edx, #65543427
9831 mul eax, edx
9832 mov ebx, #1000
9833 xor edx, edx
9834 div eax, ebx
9835 add ecx, eax ;; add to total ticks
9836
9837 mov 0x46C, ecx ;; Timer Ticks Count
9838 xor al, al
9839 mov 0x470, al ;; Timer Ticks Rollover Flag
9840 ret
9841
9842;--------------------
9843int76_handler:
9844 ;; record completion in BIOS task complete flag
9845 push ax
9846 push ds
9847 mov ax, #0x0040
9848 mov ds, ax
9849 mov 0x008E, #0xff
9850 call eoi_both_pics
9851 pop ds
9852 pop ax
9853 iret
9854
9855
9856;--------------------
9857#ifdef VBOX
9858init_pic:
9859 ;; init PIC
9860 mov al, #0x11 ; send initialisation commands
9861 out 0x20, al
9862 out 0xa0, al
9863 mov al, #0x08
9864 out 0x21, al
9865 mov al, #0x70
9866 out 0xa1, al
9867 mov al, #0x04
9868 out 0x21, al
9869 mov al, #0x02
9870 out 0xa1, al
9871 mov al, #0x01
9872 out 0x21, al
9873 out 0xa1, al
9874 mov al, #0xb8
9875 out 0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6
9876#if BX_USE_PS2_MOUSE
9877 mov al, #0x8f
9878#else
9879 mov al, #0x9f
9880#endif
9881 out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14
9882 ret
9883#endif /* VBOX */
9884
9885;--------------------
9886#if BX_APM
9887
9888use32 386
9889#define APM_PROT32
9890#include "apmbios.S"
9891
9892use16 386
9893#define APM_PROT16
9894#include "apmbios.S"
9895
9896#define APM_REAL
9897#include "apmbios.S"
9898
9899#endif
9900
9901;--------------------
9902#if BX_PCIBIOS
9903use32 386
9904.align 16
9905bios32_structure:
9906 db 0x5f, 0x33, 0x32, 0x5f ;; "_32_" signature
9907 dw bios32_entry_point, 0xf ;; 32 bit physical address
9908 db 0 ;; revision level
9909 ;; length in paragraphs and checksum stored in a word to prevent errors
9910 dw (~(((bios32_entry_point >> 8) + (bios32_entry_point & 0xff) + 0x32) \
9911 & 0xff) << 8) + 0x01
9912 db 0,0,0,0,0 ;; reserved
9913
9914.align 16
9915bios32_entry_point:
9916 pushfd
9917 cmp eax, #0x49435024 ;; "$PCI"
9918 jne unknown_service
9919
9920#ifdef PCI_FIXED_HOST_BRIDGE_1
9921 mov eax, #0x80000000
9922 mov dx, #0x0cf8
9923 out dx, eax
9924 mov dx, #0x0cfc
9925 in eax, dx
9926 cmp eax, #PCI_FIXED_HOST_BRIDGE_1
9927 je device_ok
9928#endif
9929
9930#ifdef PCI_FIXED_HOST_BRIDGE_2
9931 /* 0x1e << 11 */
9932 mov eax, #0x8000f000
9933 mov dx, #0x0cf8
9934 out dx, eax
9935 mov dx, #0x0cfc
9936 in eax, dx
9937 cmp eax, #PCI_FIXED_HOST_BRIDGE_2
9938 je device_ok
9939#endif
9940 jmp unknown_service
9941device_ok:
9942 mov ebx, #0x000f0000
9943 mov ecx, #0
9944 mov edx, #pcibios_protected
9945 xor al, al
9946 jmp bios32_end
9947unknown_service:
9948 mov al, #0x80
9949bios32_end:
9950#ifdef BX_QEMU
9951 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
9952#endif
9953 popfd
9954 retf
9955
9956.align 16
9957pcibios_protected:
9958 pushfd
9959 cli
9960 push esi
9961 push edi
9962 cmp al, #0x01 ;; installation check
9963 jne pci_pro_f02
9964 mov bx, #0x0210
9965 mov cx, #0
9966 mov edx, #0x20494350 ;; "PCI "
9967 mov al, #0x01
9968 jmp pci_pro_ok
9969pci_pro_f02: ;; find pci device
9970 cmp al, #0x02
9971 jne pci_pro_f03
9972 shl ecx, #16
9973 mov cx, dx
9974 xor ebx, ebx
9975 mov di, #0x00
9976pci_pro_devloop:
9977 call pci_pro_select_reg
9978 mov dx, #0x0cfc
9979 in eax, dx
9980 cmp eax, ecx
9981 jne pci_pro_nextdev
9982 cmp si, #0
9983 je pci_pro_ok
9984 dec si
9985pci_pro_nextdev:
9986 inc ebx
9987 cmp ebx, #0x10000
9988 jne pci_pro_devloop
9989 mov ah, #0x86
9990 jmp pci_pro_fail
9991pci_pro_f03: ;; find class code
9992 cmp al, #0x03
9993 jne pci_pro_f08
9994 xor ebx, ebx
9995 mov di, #0x08
9996pci_pro_devloop2:
9997 call pci_pro_select_reg
9998 mov dx, #0x0cfc
9999 in eax, dx
10000 shr eax, #8
10001 cmp eax, ecx
10002 jne pci_pro_nextdev2
10003 cmp si, #0
10004 je pci_pro_ok
10005 dec si
10006pci_pro_nextdev2:
10007 inc ebx
10008 cmp ebx, #0x10000
10009 jne pci_pro_devloop2
10010 mov ah, #0x86
10011 jmp pci_pro_fail
10012pci_pro_f08: ;; read configuration byte
10013 cmp al, #0x08
10014 jne pci_pro_f09
10015 call pci_pro_select_reg
10016 push edx
10017 mov dx, di
10018 and dx, #0x03
10019 add dx, #0x0cfc
10020 in al, dx
10021 pop edx
10022 mov cl, al
10023 jmp pci_pro_ok
10024pci_pro_f09: ;; read configuration word
10025 cmp al, #0x09
10026 jne pci_pro_f0a
10027 call pci_pro_select_reg
10028 push edx
10029 mov dx, di
10030 and dx, #0x02
10031 add dx, #0x0cfc
10032 in ax, dx
10033 pop edx
10034 mov cx, ax
10035 jmp pci_pro_ok
10036pci_pro_f0a: ;; read configuration dword
10037 cmp al, #0x0a
10038 jne pci_pro_f0b
10039 call pci_pro_select_reg
10040 push edx
10041 mov dx, #0x0cfc
10042 in eax, dx
10043 pop edx
10044 mov ecx, eax
10045 jmp pci_pro_ok
10046pci_pro_f0b: ;; write configuration byte
10047 cmp al, #0x0b
10048 jne pci_pro_f0c
10049 call pci_pro_select_reg
10050 push edx
10051 mov dx, di
10052 and dx, #0x03
10053 add dx, #0x0cfc
10054 mov al, cl
10055 out dx, al
10056 pop edx
10057 jmp pci_pro_ok
10058pci_pro_f0c: ;; write configuration word
10059 cmp al, #0x0c
10060 jne pci_pro_f0d
10061 call pci_pro_select_reg
10062 push edx
10063 mov dx, di
10064 and dx, #0x02
10065 add dx, #0x0cfc
10066 mov ax, cx
10067 out dx, ax
10068 pop edx
10069 jmp pci_pro_ok
10070pci_pro_f0d: ;; write configuration dword
10071 cmp al, #0x0d
10072 jne pci_pro_unknown
10073 call pci_pro_select_reg
10074 push edx
10075 mov dx, #0x0cfc
10076 mov eax, ecx
10077 out dx, eax
10078 pop edx
10079 jmp pci_pro_ok
10080pci_pro_unknown:
10081 mov ah, #0x81
10082pci_pro_fail:
10083 pop edi
10084 pop esi
10085#ifdef BX_QEMU
10086 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
10087#endif
10088 popfd
10089 stc
10090 retf
10091pci_pro_ok:
10092 xor ah, ah
10093 pop edi
10094 pop esi
10095#ifdef BX_QEMU
10096 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
10097#endif
10098 popfd
10099 clc
10100 retf
10101
10102pci_pro_select_reg:
10103 push edx
10104 mov eax, #0x800000
10105 mov ax, bx
10106 shl eax, #8
10107 and di, #0xff
10108 or ax, di
10109 and al, #0xfc
10110 mov dx, #0x0cf8
10111 out dx, eax
10112 pop edx
10113 ret
10114
10115use16 386
10116
10117pcibios_real:
10118 push eax
10119 push dx
10120#ifdef PCI_FIXED_HOST_BRIDGE_1
10121 mov eax, #0x80000000
10122 mov dx, #0x0cf8
10123 out dx, eax
10124 mov dx, #0x0cfc
10125 in eax, dx
10126 cmp eax, #PCI_FIXED_HOST_BRIDGE_1
10127 je pci_present
10128#endif
10129
10130#ifdef PCI_FIXED_HOST_BRIDGE_2
10131 /* 0x1e << 11 */
10132 mov eax, #0x8000f000
10133 mov dx, #0x0cf8
10134 out dx, eax
10135 mov dx, #0x0cfc
10136 in eax, dx
10137 cmp eax, #PCI_FIXED_HOST_BRIDGE_2
10138 je pci_present
10139#endif
10140 pop dx
10141 pop eax
10142 mov ah, #0xff
10143 stc
10144 ret
10145pci_present:
10146 pop dx
10147 pop eax
10148 cmp al, #0x01 ;; installation check
10149 jne pci_real_f02
10150 mov ax, #0x0001
10151 mov bx, #0x0210
10152 mov cx, #0
10153 mov edx, #0x20494350 ;; "PCI "
10154 mov edi, #0xf0000
10155 mov di, #pcibios_protected
10156 clc
10157 ret
10158pci_real_f02: ;; find pci device
10159 push esi
10160 push edi
10161 push edx
10162 cmp al, #0x02
10163 jne pci_real_f03
10164 shl ecx, #16
10165 mov cx, dx
10166 xor ebx, ebx
10167 mov di, #0x00
10168pci_real_devloop:
10169 call pci_real_select_reg
10170 mov dx, #0x0cfc
10171 in eax, dx
10172 cmp eax, ecx
10173 jne pci_real_nextdev
10174 cmp si, #0
10175 je pci_real_ok
10176 dec si
10177pci_real_nextdev:
10178 inc ebx
10179 cmp ebx, #0x10000
10180 jne pci_real_devloop
10181 mov dx, cx
10182 shr ecx, #16
10183 mov ax, #0x8602
10184 jmp pci_real_fail
10185pci_real_f03: ;; find class code
10186 cmp al, #0x03
10187 jne pci_real_f08
10188 xor ebx, ebx
10189 mov di, #0x08
10190pci_real_devloop2:
10191 call pci_real_select_reg
10192 mov dx, #0x0cfc
10193 in eax, dx
10194 shr eax, #8
10195 cmp eax, ecx
10196 jne pci_real_nextdev2
10197 cmp si, #0
10198 je pci_real_ok
10199 dec si
10200pci_real_nextdev2:
10201 inc ebx
10202 cmp ebx, #0x10000
10203 jne pci_real_devloop2
10204 mov ax, #0x8603
10205 jmp pci_real_fail
10206pci_real_f08: ;; read configuration byte
10207 cmp al, #0x08
10208 jne pci_real_f09
10209 call pci_real_select_reg
10210 push dx
10211 mov dx, di
10212 and dx, #0x03
10213 add dx, #0x0cfc
10214 in al, dx
10215 pop dx
10216 mov cl, al
10217 jmp pci_real_ok
10218pci_real_f09: ;; read configuration word
10219 cmp al, #0x09
10220 jne pci_real_f0a
10221 call pci_real_select_reg
10222 push dx
10223 mov dx, di
10224 and dx, #0x02
10225 add dx, #0x0cfc
10226 in ax, dx
10227 pop dx
10228 mov cx, ax
10229 jmp pci_real_ok
10230pci_real_f0a: ;; read configuration dword
10231 cmp al, #0x0a
10232 jne pci_real_f0b
10233 call pci_real_select_reg
10234 push dx
10235 mov dx, #0x0cfc
10236 in eax, dx
10237 pop dx
10238 mov ecx, eax
10239 jmp pci_real_ok
10240pci_real_f0b: ;; write configuration byte
10241 cmp al, #0x0b
10242 jne pci_real_f0c
10243 call pci_real_select_reg
10244 push dx
10245 mov dx, di
10246 and dx, #0x03
10247 add dx, #0x0cfc
10248 mov al, cl
10249 out dx, al
10250 pop dx
10251 jmp pci_real_ok
10252pci_real_f0c: ;; write configuration word
10253 cmp al, #0x0c
10254 jne pci_real_f0d
10255 call pci_real_select_reg
10256 push dx
10257 mov dx, di
10258 and dx, #0x02
10259 add dx, #0x0cfc
10260 mov ax, cx
10261 out dx, ax
10262 pop dx
10263 jmp pci_real_ok
10264pci_real_f0d: ;; write configuration dword
10265 cmp al, #0x0d
10266 jne pci_real_f0e
10267 call pci_real_select_reg
10268 push dx
10269 mov dx, #0x0cfc
10270 mov eax, ecx
10271 out dx, eax
10272 pop dx
10273 jmp pci_real_ok
10274pci_real_f0e: ;; get irq routing options
10275 cmp al, #0x0e
10276 jne pci_real_unknown
10277 SEG ES
10278 cmp word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
10279 jb pci_real_too_small
10280 SEG ES
10281 mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
10282 pushf
10283 push ds
10284 push es
10285 push cx
10286 push si
10287 push di
10288 cld
10289 mov si, #pci_routing_table_structure_start
10290 push cs
10291 pop ds
10292 SEG ES
10293 mov cx, [di+2]
10294 SEG ES
10295 mov es, [di+4]
10296 mov di, cx
10297 mov cx, #pci_routing_table_structure_end - pci_routing_table_structure_start
10298 rep
10299 movsb
10300 pop di
10301 pop si
10302 pop cx
10303 pop es
10304 pop ds
10305 popf
10306 mov bx, #(1 << 9) | (1 << 11) ;; irq 9 and 11 are used
10307 jmp pci_real_ok
10308pci_real_too_small:
10309 SEG ES
10310 mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
10311 mov ah, #0x89
10312 jmp pci_real_fail
10313
10314pci_real_unknown:
10315 mov ah, #0x81
10316pci_real_fail:
10317 pop edx
10318 pop edi
10319 pop esi
10320 stc
10321 ret
10322pci_real_ok:
10323 xor ah, ah
10324 pop edx
10325 pop edi
10326 pop esi
10327 clc
10328 ret
10329
10330;; prepare from reading the PCI config space; on input:
10331;; bx = bus/dev/fn
10332;; di = offset into config space header
10333;; destroys eax and may modify di
10334pci_real_select_reg:
10335 push dx
10336 mov eax, #0x800000
10337 mov ax, bx
10338 shl eax, #8
10339 and di, #0xff
10340 or ax, di
10341 and al, #0xfc
10342 mov dx, #0x0cf8
10343 out dx, eax
10344 pop dx
10345 ret
10346
10347.align 16
10348pci_routing_table_structure:
10349 db 0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature
10350 db 0, 1 ;; version
10351#ifdef VBOX
10352 dw 32 + (30 * 16) ;; table size
10353#else /* !VBOX */
10354 dw 32 + (6 * 16) ;; table size
10355#endif /* !VBOX */
10356 db 0 ;; PCI interrupt router bus
10357 db 0x08 ;; PCI interrupt router DevFunc
10358 dw 0x0000 ;; PCI exclusive IRQs
10359 dw 0x8086 ;; compatible PCI interrupt router vendor ID
10360 dw 0x7000 ;; compatible PCI interrupt router device ID
10361 dw 0,0 ;; Miniport data
10362 db 0,0,0,0,0,0,0,0,0,0,0 ;; reserved
10363#ifdef VBOX
10364 db 0x00 ;; checksum (set by biossums)
10365#else /* !VBOX */
10366 db 0x07 ;; checksum
10367#endif /* !VBOX */
10368pci_routing_table_structure_start:
10369 ;; first slot entry PCI-to-ISA (embedded)
10370 db 0 ;; pci bus number
10371 db 0x08 ;; pci device number (bit 7-3)
10372 db 0x60 ;; link value INTA#: pointer into PCI2ISA config space
10373 dw 0xdef8 ;; IRQ bitmap INTA#
10374 db 0x61 ;; link value INTB#
10375 dw 0xdef8 ;; IRQ bitmap INTB#
10376 db 0x62 ;; link value INTC#
10377 dw 0xdef8 ;; IRQ bitmap INTC#
10378 db 0x63 ;; link value INTD#
10379 dw 0xdef8 ;; IRQ bitmap INTD#
10380 db 0 ;; physical slot (0 = embedded)
10381 db 0 ;; reserved
10382 ;; second slot entry: 1st PCI slot
10383 db 0 ;; pci bus number
10384 db 0x10 ;; pci device number (bit 7-3)
10385 db 0x61 ;; link value INTA#
10386 dw 0xdef8 ;; IRQ bitmap INTA#
10387 db 0x62 ;; link value INTB#
10388 dw 0xdef8 ;; IRQ bitmap INTB#
10389 db 0x63 ;; link value INTC#
10390 dw 0xdef8 ;; IRQ bitmap INTC#
10391 db 0x60 ;; link value INTD#
10392 dw 0xdef8 ;; IRQ bitmap INTD#
10393 db 1 ;; physical slot (0 = embedded)
10394 db 0 ;; reserved
10395 ;; third slot entry: 2nd PCI slot
10396 db 0 ;; pci bus number
10397 db 0x18 ;; pci device number (bit 7-3)
10398 db 0x62 ;; link value INTA#
10399 dw 0xdef8 ;; IRQ bitmap INTA#
10400 db 0x63 ;; link value INTB#
10401 dw 0xdef8 ;; IRQ bitmap INTB#
10402 db 0x60 ;; link value INTC#
10403 dw 0xdef8 ;; IRQ bitmap INTC#
10404 db 0x61 ;; link value INTD#
10405 dw 0xdef8 ;; IRQ bitmap INTD#
10406 db 2 ;; physical slot (0 = embedded)
10407 db 0 ;; reserved
10408 ;; 4th slot entry: 3rd PCI slot
10409 db 0 ;; pci bus number
10410 db 0x20 ;; pci device number (bit 7-3)
10411 db 0x63 ;; link value INTA#
10412 dw 0xdef8 ;; IRQ bitmap INTA#
10413 db 0x60 ;; link value INTB#
10414 dw 0xdef8 ;; IRQ bitmap INTB#
10415 db 0x61 ;; link value INTC#
10416 dw 0xdef8 ;; IRQ bitmap INTC#
10417 db 0x62 ;; link value INTD#
10418 dw 0xdef8 ;; IRQ bitmap INTD#
10419 db 3 ;; physical slot (0 = embedded)
10420 db 0 ;; reserved
10421 ;; 5th slot entry: 4rd PCI slot
10422 db 0 ;; pci bus number
10423 db 0x28 ;; pci device number (bit 7-3)
10424 db 0x60 ;; link value INTA#
10425 dw 0xdef8 ;; IRQ bitmap INTA#
10426 db 0x61 ;; link value INTB#
10427 dw 0xdef8 ;; IRQ bitmap INTB#
10428 db 0x62 ;; link value INTC#
10429 dw 0xdef8 ;; IRQ bitmap INTC#
10430 db 0x63 ;; link value INTD#
10431 dw 0xdef8 ;; IRQ bitmap INTD#
10432 db 4 ;; physical slot (0 = embedded)
10433 db 0 ;; reserved
10434 ;; 6th slot entry: 5rd PCI slot
10435 db 0 ;; pci bus number
10436 db 0x30 ;; pci device number (bit 7-3)
10437 db 0x61 ;; link value INTA#
10438 dw 0xdef8 ;; IRQ bitmap INTA#
10439 db 0x62 ;; link value INTB#
10440 dw 0xdef8 ;; IRQ bitmap INTB#
10441 db 0x63 ;; link value INTC#
10442 dw 0xdef8 ;; IRQ bitmap INTC#
10443 db 0x60 ;; link value INTD#
10444 dw 0xdef8 ;; IRQ bitmap INTD#
10445 db 5 ;; physical slot (0 = embedded)
10446 db 0 ;; reserved
10447#ifdef VBOX
10448 ;; 7th slot entry: 6th PCI slot
10449 db 0 ;; pci bus number
10450 db 0x38 ;; pci device number (bit 7-3)
10451 db 0x62 ;; link value INTA#
10452 dw 0xdef8 ;; IRQ bitmap INTA#
10453 db 0x63 ;; link value INTB#
10454 dw 0xdef8 ;; IRQ bitmap INTB#
10455 db 0x60 ;; link value INTC#
10456 dw 0xdef8 ;; IRQ bitmap INTC#
10457 db 0x61 ;; link value INTD#
10458 dw 0xdef8 ;; IRQ bitmap INTD#
10459 db 6 ;; physical slot (0 = embedded)
10460 db 0 ;; reserved
10461 ;; 8th slot entry: 7th PCI slot
10462 db 0 ;; pci bus number
10463 db 0x40 ;; pci device number (bit 7-3)
10464 db 0x63 ;; link value INTA#
10465 dw 0xdef8 ;; IRQ bitmap INTA#
10466 db 0x60 ;; link value INTB#
10467 dw 0xdef8 ;; IRQ bitmap INTB#
10468 db 0x61 ;; link value INTC#
10469 dw 0xdef8 ;; IRQ bitmap INTC#
10470 db 0x62 ;; link value INTD#
10471 dw 0xdef8 ;; IRQ bitmap INTD#
10472 db 7 ;; physical slot (0 = embedded)
10473 db 0 ;; reserved
10474 ;; 9th slot entry: 8th PCI slot
10475 db 0 ;; pci bus number
10476 db 0x48 ;; pci device number (bit 7-3)
10477 db 0x60 ;; link value INTA#
10478 dw 0xdef8 ;; IRQ bitmap INTA#
10479 db 0x61 ;; link value INTB#
10480 dw 0xdef8 ;; IRQ bitmap INTB#
10481 db 0x62 ;; link value INTC#
10482 dw 0xdef8 ;; IRQ bitmap INTC#
10483 db 0x63 ;; link value INTD#
10484 dw 0xdef8 ;; IRQ bitmap INTD#
10485 db 8 ;; physical slot (0 = embedded)
10486 db 0 ;; reserved
10487 ;; 10th slot entry: 9th PCI slot
10488 db 0 ;; pci bus number
10489 db 0x50 ;; pci device number (bit 7-3)
10490 db 0x61 ;; link value INTA#
10491 dw 0xdef8 ;; IRQ bitmap INTA#
10492 db 0x62 ;; link value INTB#
10493 dw 0xdef8 ;; IRQ bitmap INTB#
10494 db 0x63 ;; link value INTC#
10495 dw 0xdef8 ;; IRQ bitmap INTC#
10496 db 0x60 ;; link value INTD#
10497 dw 0xdef8 ;; IRQ bitmap INTD#
10498 db 9 ;; physical slot (0 = embedded)
10499 db 0 ;; reserved
10500 ;; 11th slot entry: 10th PCI slot
10501 db 0 ;; pci bus number
10502 db 0x58 ;; pci device number (bit 7-3)
10503 db 0x62 ;; link value INTA#
10504 dw 0xdef8 ;; IRQ bitmap INTA#
10505 db 0x63 ;; link value INTB#
10506 dw 0xdef8 ;; IRQ bitmap INTB#
10507 db 0x60 ;; link value INTC#
10508 dw 0xdef8 ;; IRQ bitmap INTC#
10509 db 0x61 ;; link value INTD#
10510 dw 0xdef8 ;; IRQ bitmap INTD#
10511 db 10 ;; physical slot (0 = embedded)
10512 db 0 ;; reserved
10513 ;; 12th slot entry: 11th PCI slot
10514 db 0 ;; pci bus number
10515 db 0x60 ;; pci device number (bit 7-3)
10516 db 0x63 ;; link value INTA#
10517 dw 0xdef8 ;; IRQ bitmap INTA#
10518 db 0x60 ;; link value INTB#
10519 dw 0xdef8 ;; IRQ bitmap INTB#
10520 db 0x61 ;; link value INTC#
10521 dw 0xdef8 ;; IRQ bitmap INTC#
10522 db 0x62 ;; link value INTD#
10523 dw 0xdef8 ;; IRQ bitmap INTD#
10524 db 11 ;; physical slot (0 = embedded)
10525 db 0 ;; reserved
10526 ;; 13th slot entry: 12th PCI slot
10527 db 0 ;; pci bus number
10528 db 0x68 ;; pci device number (bit 7-3)
10529 db 0x60 ;; link value INTA#
10530 dw 0xdef8 ;; IRQ bitmap INTA#
10531 db 0x61 ;; link value INTB#
10532 dw 0xdef8 ;; IRQ bitmap INTB#
10533 db 0x62 ;; link value INTC#
10534 dw 0xdef8 ;; IRQ bitmap INTC#
10535 db 0x63 ;; link value INTD#
10536 dw 0xdef8 ;; IRQ bitmap INTD#
10537 db 12 ;; physical slot (0 = embedded)
10538 db 0 ;; reserved
10539 ;; 14th slot entry: 13th PCI slot
10540 db 0 ;; pci bus number
10541 db 0x70 ;; pci device number (bit 7-3)
10542 db 0x61 ;; link value INTA#
10543 dw 0xdef8 ;; IRQ bitmap INTA#
10544 db 0x62 ;; link value INTB#
10545 dw 0xdef8 ;; IRQ bitmap INTB#
10546 db 0x63 ;; link value INTC#
10547 dw 0xdef8 ;; IRQ bitmap INTC#
10548 db 0x60 ;; link value INTD#
10549 dw 0xdef8 ;; IRQ bitmap INTD#
10550 db 13 ;; physical slot (0 = embedded)
10551 db 0 ;; reserved
10552 ;; 15th slot entry: 14th PCI slot
10553 db 0 ;; pci bus number
10554 db 0x78 ;; pci device number (bit 7-3)
10555 db 0x62 ;; link value INTA#
10556 dw 0xdef8 ;; IRQ bitmap INTA#
10557 db 0x63 ;; link value INTB#
10558 dw 0xdef8 ;; IRQ bitmap INTB#
10559 db 0x60 ;; link value INTC#
10560 dw 0xdef8 ;; IRQ bitmap INTC#
10561 db 0x61 ;; link value INTD#
10562 dw 0xdef8 ;; IRQ bitmap INTD#
10563 db 14 ;; physical slot (0 = embedded)
10564 db 0 ;; reserved
10565 ;; 16th slot entry: 15th PCI slot
10566 db 0 ;; pci bus number
10567 db 0x80 ;; pci device number (bit 7-3)
10568 db 0x63 ;; link value INTA#
10569 dw 0xdef8 ;; IRQ bitmap INTA#
10570 db 0x60 ;; link value INTB#
10571 dw 0xdef8 ;; IRQ bitmap INTB#
10572 db 0x61 ;; link value INTC#
10573 dw 0xdef8 ;; IRQ bitmap INTC#
10574 db 0x62 ;; link value INTD#
10575 dw 0xdef8 ;; IRQ bitmap INTD#
10576 db 15 ;; physical slot (0 = embedded)
10577 db 0 ;; reserved
10578 ;; 17th slot entry: 16th PCI slot
10579 db 0 ;; pci bus number
10580 db 0x88 ;; pci device number (bit 7-3)
10581 db 0x60 ;; link value INTA#
10582 dw 0xdef8 ;; IRQ bitmap INTA#
10583 db 0x61 ;; link value INTB#
10584 dw 0xdef8 ;; IRQ bitmap INTB#
10585 db 0x62 ;; link value INTC#
10586 dw 0xdef8 ;; IRQ bitmap INTC#
10587 db 0x63 ;; link value INTD#
10588 dw 0xdef8 ;; IRQ bitmap INTD#
10589 db 16 ;; physical slot (0 = embedded)
10590 db 0 ;; reserved
10591 ;; 18th slot entry: 17th PCI slot
10592 db 0 ;; pci bus number
10593 db 0x90 ;; pci device number (bit 7-3)
10594 db 0x61 ;; link value INTA#
10595 dw 0xdef8 ;; IRQ bitmap INTA#
10596 db 0x62 ;; link value INTB#
10597 dw 0xdef8 ;; IRQ bitmap INTB#
10598 db 0x63 ;; link value INTC#
10599 dw 0xdef8 ;; IRQ bitmap INTC#
10600 db 0x60 ;; link value INTD#
10601 dw 0xdef8 ;; IRQ bitmap INTD#
10602 db 17 ;; physical slot (0 = embedded)
10603 db 0 ;; reserved
10604 ;; 19th slot entry: 18th PCI slot
10605 db 0 ;; pci bus number
10606 db 0x98 ;; pci device number (bit 7-3)
10607 db 0x62 ;; link value INTA#
10608 dw 0xdef8 ;; IRQ bitmap INTA#
10609 db 0x63 ;; link value INTB#
10610 dw 0xdef8 ;; IRQ bitmap INTB#
10611 db 0x60 ;; link value INTC#
10612 dw 0xdef8 ;; IRQ bitmap INTC#
10613 db 0x61 ;; link value INTD#
10614 dw 0xdef8 ;; IRQ bitmap INTD#
10615 db 18 ;; physical slot (0 = embedded)
10616 db 0 ;; reserved
10617 ;; 20th slot entry: 19th PCI slot
10618 db 0 ;; pci bus number
10619 db 0xa0 ;; pci device number (bit 7-3)
10620 db 0x63 ;; link value INTA#
10621 dw 0xdef8 ;; IRQ bitmap INTA#
10622 db 0x60 ;; link value INTB#
10623 dw 0xdef8 ;; IRQ bitmap INTB#
10624 db 0x61 ;; link value INTC#
10625 dw 0xdef8 ;; IRQ bitmap INTC#
10626 db 0x62 ;; link value INTD#
10627 dw 0xdef8 ;; IRQ bitmap INTD#
10628 db 19 ;; physical slot (0 = embedded)
10629 db 0 ;; reserved
10630 ;; 21st slot entry: 20th PCI slot
10631 db 0 ;; pci bus number
10632 db 0xa8 ;; pci device number (bit 7-3)
10633 db 0x60 ;; link value INTA#
10634 dw 0xdef8 ;; IRQ bitmap INTA#
10635 db 0x61 ;; link value INTB#
10636 dw 0xdef8 ;; IRQ bitmap INTB#
10637 db 0x62 ;; link value INTC#
10638 dw 0xdef8 ;; IRQ bitmap INTC#
10639 db 0x63 ;; link value INTD#
10640 dw 0xdef8 ;; IRQ bitmap INTD#
10641 db 20 ;; physical slot (0 = embedded)
10642 db 0 ;; reserved
10643 ;; 22nd slot entry: 21st PCI slot
10644 db 0 ;; pci bus number
10645 db 0xb0 ;; pci device number (bit 7-3)
10646 db 0x61 ;; link value INTA#
10647 dw 0xdef8 ;; IRQ bitmap INTA#
10648 db 0x62 ;; link value INTB#
10649 dw 0xdef8 ;; IRQ bitmap INTB#
10650 db 0x63 ;; link value INTC#
10651 dw 0xdef8 ;; IRQ bitmap INTC#
10652 db 0x60 ;; link value INTD#
10653 dw 0xdef8 ;; IRQ bitmap INTD#
10654 db 21 ;; physical slot (0 = embedded)
10655 db 0 ;; reserved
10656 ;; 23rd slot entry: 22nd PCI slot
10657 db 0 ;; pci bus number
10658 db 0xb8 ;; pci device number (bit 7-3)
10659 db 0x62 ;; link value INTA#
10660 dw 0xdef8 ;; IRQ bitmap INTA#
10661 db 0x63 ;; link value INTB#
10662 dw 0xdef8 ;; IRQ bitmap INTB#
10663 db 0x60 ;; link value INTC#
10664 dw 0xdef8 ;; IRQ bitmap INTC#
10665 db 0x61 ;; link value INTD#
10666 dw 0xdef8 ;; IRQ bitmap INTD#
10667 db 22 ;; physical slot (0 = embedded)
10668 db 0 ;; reserved
10669 ;; 24th slot entry: 23rd PCI slot
10670 db 0 ;; pci bus number
10671 db 0xc0 ;; pci device number (bit 7-3)
10672 db 0x63 ;; link value INTA#
10673 dw 0xdef8 ;; IRQ bitmap INTA#
10674 db 0x60 ;; link value INTB#
10675 dw 0xdef8 ;; IRQ bitmap INTB#
10676 db 0x61 ;; link value INTC#
10677 dw 0xdef8 ;; IRQ bitmap INTC#
10678 db 0x62 ;; link value INTD#
10679 dw 0xdef8 ;; IRQ bitmap INTD#
10680 db 23 ;; physical slot (0 = embedded)
10681 db 0 ;; reserved
10682 ;; 25th slot entry: 24th PCI slot
10683 db 0 ;; pci bus number
10684 db 0xc8 ;; pci device number (bit 7-3)
10685 db 0x60 ;; link value INTA#
10686 dw 0xdef8 ;; IRQ bitmap INTA#
10687 db 0x61 ;; link value INTB#
10688 dw 0xdef8 ;; IRQ bitmap INTB#
10689 db 0x62 ;; link value INTC#
10690 dw 0xdef8 ;; IRQ bitmap INTC#
10691 db 0x63 ;; link value INTD#
10692 dw 0xdef8 ;; IRQ bitmap INTD#
10693 db 24 ;; physical slot (0 = embedded)
10694 db 0 ;; reserved
10695 ;; 26th slot entry: 25th PCI slot
10696 db 0 ;; pci bus number
10697 db 0xd0 ;; pci device number (bit 7-3)
10698 db 0x61 ;; link value INTA#
10699 dw 0xdef8 ;; IRQ bitmap INTA#
10700 db 0x62 ;; link value INTB#
10701 dw 0xdef8 ;; IRQ bitmap INTB#
10702 db 0x63 ;; link value INTC#
10703 dw 0xdef8 ;; IRQ bitmap INTC#
10704 db 0x60 ;; link value INTD#
10705 dw 0xdef8 ;; IRQ bitmap INTD#
10706 db 25 ;; physical slot (0 = embedded)
10707 db 0 ;; reserved
10708 ;; 27th slot entry: 26th PCI slot
10709 db 0 ;; pci bus number
10710 db 0xd8 ;; pci device number (bit 7-3)
10711 db 0x62 ;; link value INTA#
10712 dw 0xdef8 ;; IRQ bitmap INTA#
10713 db 0x63 ;; link value INTB#
10714 dw 0xdef8 ;; IRQ bitmap INTB#
10715 db 0x60 ;; link value INTC#
10716 dw 0xdef8 ;; IRQ bitmap INTC#
10717 db 0x61 ;; link value INTD#
10718 dw 0xdef8 ;; IRQ bitmap INTD#
10719 db 26 ;; physical slot (0 = embedded)
10720 db 0 ;; reserved
10721 ;; 28th slot entry: 27th PCI slot
10722 db 0 ;; pci bus number
10723 db 0xe0 ;; pci device number (bit 7-3)
10724 db 0x63 ;; link value INTA#
10725 dw 0xdef8 ;; IRQ bitmap INTA#
10726 db 0x60 ;; link value INTB#
10727 dw 0xdef8 ;; IRQ bitmap INTB#
10728 db 0x61 ;; link value INTC#
10729 dw 0xdef8 ;; IRQ bitmap INTC#
10730 db 0x62 ;; link value INTD#
10731 dw 0xdef8 ;; IRQ bitmap INTD#
10732 db 27 ;; physical slot (0 = embedded)
10733 db 0 ;; reserved
10734 ;; 29th slot entry: 28th PCI slot
10735 db 0 ;; pci bus number
10736 db 0xe8 ;; pci device number (bit 7-3)
10737 db 0x60 ;; link value INTA#
10738 dw 0xdef8 ;; IRQ bitmap INTA#
10739 db 0x61 ;; link value INTB#
10740 dw 0xdef8 ;; IRQ bitmap INTB#
10741 db 0x62 ;; link value INTC#
10742 dw 0xdef8 ;; IRQ bitmap INTC#
10743 db 0x63 ;; link value INTD#
10744 dw 0xdef8 ;; IRQ bitmap INTD#
10745 db 28 ;; physical slot (0 = embedded)
10746 db 0 ;; reserved
10747 ;; 30th slot entry: 29th PCI slot
10748 db 0 ;; pci bus number
10749 db 0xf0 ;; pci device number (bit 7-3)
10750 db 0x61 ;; link value INTA#
10751 dw 0xdef8 ;; IRQ bitmap INTA#
10752 db 0x62 ;; link value INTB#
10753 dw 0xdef8 ;; IRQ bitmap INTB#
10754 db 0x63 ;; link value INTC#
10755 dw 0xdef8 ;; IRQ bitmap INTC#
10756 db 0x60 ;; link value INTD#
10757 dw 0xdef8 ;; IRQ bitmap INTD#
10758 db 29 ;; physical slot (0 = embedded)
10759 db 0 ;; reserved
10760#endif /* VBOX */
10761pci_routing_table_structure_end:
10762
10763#if !BX_ROMBIOS32
10764pci_irq_list:
10765 db 11, 10, 9, 5;
10766
10767pcibios_init_sel_reg:
10768 push eax
10769 mov eax, #0x800000
10770 mov ax, bx
10771 shl eax, #8
10772 and dl, #0xfc
10773 or al, dl
10774 mov dx, #0x0cf8
10775 out dx, eax
10776 pop eax
10777 ret
10778
10779pcibios_init_iomem_bases:
10780 push bp
10781 mov bp, sp
10782 mov eax, #0xe0000000 ;; base for memory init
10783 push eax
10784 mov ax, #0xc000 ;; base for i/o init
10785 push ax
10786 mov ax, #0x0010 ;; start at base address #0
10787 push ax
10788 mov bx, #0x0008
10789pci_init_io_loop1:
10790 mov dl, #0x00
10791 call pcibios_init_sel_reg
10792 mov dx, #0x0cfc
10793 in ax, dx
10794 cmp ax, #0xffff
10795 jz next_pci_dev
10796#ifndef VBOX /* This currently breaks restoring a previously saved state. */
10797 mov dl, #0x04 ;; disable i/o and memory space access
10798 call pcibios_init_sel_reg
10799 mov dx, #0x0cfc
10800 in al, dx
10801 and al, #0xfc
10802 out dx, al
10803pci_init_io_loop2:
10804 mov dl, [bp-8]
10805 call pcibios_init_sel_reg
10806 mov dx, #0x0cfc
10807 in eax, dx
10808 test al, #0x01
10809 jnz init_io_base
10810 mov ecx, eax
10811 mov eax, #0xffffffff
10812 out dx, eax
10813 in eax, dx
10814 cmp eax, ecx
10815 je next_pci_base
10816 xor eax, #0xffffffff
10817 mov ecx, eax
10818 mov eax, [bp-4]
10819 out dx, eax
10820 add eax, ecx ;; calculate next free mem base
10821 add eax, #0x01000000
10822 and eax, #0xff000000
10823 mov [bp-4], eax
10824 jmp next_pci_base
10825init_io_base:
10826 mov cx, ax
10827 mov ax, #0xffff
10828 out dx, ax
10829 in ax, dx
10830 cmp ax, cx
10831 je next_pci_base
10832 xor ax, #0xfffe
10833 mov cx, ax
10834 mov ax, [bp-6]
10835 out dx, ax
10836 add ax, cx ;; calculate next free i/o base
10837 add ax, #0x0100
10838 and ax, #0xff00
10839 mov [bp-6], ax
10840next_pci_base:
10841 mov al, [bp-8]
10842 add al, #0x04
10843 cmp al, #0x28
10844 je enable_iomem_space
10845 mov byte ptr[bp-8], al
10846 jmp pci_init_io_loop2
10847#endif /* !VBOX */
10848enable_iomem_space:
10849 mov dl, #0x04 ;; enable i/o and memory space access if available
10850 call pcibios_init_sel_reg
10851 mov dx, #0x0cfc
10852 in al, dx
10853 or al, #0x07
10854 out dx, al
10855#ifdef VBOX
10856 mov dl, #0x00 ;; check if PCI device is AMD PCNet
10857 call pcibios_init_sel_reg
10858 mov dx, #0x0cfc
10859 in eax, dx
10860 cmp eax, #0x20001022
10861 jne next_pci_dev
10862 mov dl, #0x10 ;; get I/O address
10863 call pcibios_init_sel_reg
10864 mov dx, #0x0cfc
10865 in ax, dx
10866 and ax, #0xfffc
10867 mov cx, ax
10868 mov dx, cx
10869 add dx, #0x14 ;; reset register if PCNet is in word I/O mode
10870 in ax, dx ;; reset is performed by reading the reset register
10871 mov dx, cx
10872 add dx, #0x18 ;; reset register if PCNet is in word I/O mode
10873 in eax, dx ;; reset is performed by reading the reset register
10874#endif /* VBOX */
10875next_pci_dev:
10876 mov byte ptr[bp-8], #0x10
10877 inc bx
10878 cmp bx, #0x0100
10879 jne pci_init_io_loop1
10880 mov sp, bp
10881 pop bp
10882 ret
10883
10884pcibios_init_set_elcr:
10885 push ax
10886 push cx
10887 mov dx, #0x04d0
10888 test al, #0x08
10889 jz is_master_pic
10890 inc dx
10891 and al, #0x07
10892is_master_pic:
10893 mov cl, al
10894 mov bl, #0x01
10895 shl bl, cl
10896 in al, dx
10897 or al, bl
10898 out dx, al
10899 pop cx
10900 pop ax
10901 ret
10902
10903pcibios_init_irqs:
10904 push ds
10905 push bp
10906 mov ax, #0xf000
10907 mov ds, ax
10908 mov dx, #0x04d0 ;; reset ELCR1 + ELCR2
10909 mov al, #0x00
10910 out dx, al
10911 inc dx
10912 out dx, al
10913 mov si, #pci_routing_table_structure
10914 mov bh, [si+8]
10915 mov bl, [si+9]
10916 mov dl, #0x00
10917 call pcibios_init_sel_reg
10918 mov dx, #0x0cfc
10919 in eax, dx
10920 cmp eax, [si+12] ;; check irq router
10921 jne pci_init_end
10922 mov dl, [si+34]
10923 call pcibios_init_sel_reg
10924 push bx ;; save irq router bus + devfunc
10925 mov dx, #0x0cfc
10926 mov ax, #0x8080
10927 out dx, ax ;; reset PIRQ route control
10928 add dx, #2
10929 out dx, ax
10930 mov ax, [si+6]
10931 sub ax, #0x20
10932 shr ax, #4
10933 mov cx, ax
10934 add si, #0x20 ;; set pointer to 1st entry
10935 mov bp, sp
10936 mov ax, #pci_irq_list
10937 push ax
10938 xor ax, ax
10939 push ax
10940pci_init_irq_loop1:
10941 mov bh, [si]
10942 mov bl, [si+1]
10943pci_init_irq_loop2:
10944 mov dl, #0x00
10945 call pcibios_init_sel_reg
10946 mov dx, #0x0cfc
10947 in ax, dx
10948 cmp ax, #0xffff
10949 jnz pci_test_int_pin
10950 test bl, #0x07
10951 jz next_pir_entry
10952 jmp next_pci_func
10953pci_test_int_pin:
10954 mov dl, #0x3c
10955 call pcibios_init_sel_reg
10956 mov dx, #0x0cfd
10957 in al, dx
10958 and al, #0x07
10959 jz next_pci_func
10960 dec al ;; determine pirq reg
10961 mov dl, #0x03
10962 mul al, dl
10963 add al, #0x02
10964 xor ah, ah
10965 mov bx, ax
10966 mov al, [si+bx]
10967 mov dl, al
10968 mov bx, [bp]
10969 call pcibios_init_sel_reg
10970 mov dx, #0x0cfc
10971 and al, #0x03
10972 add dl, al
10973 in al, dx
10974 cmp al, #0x80
10975 jb pirq_found
10976 mov bx, [bp-2] ;; pci irq list pointer
10977 mov al, [bx]
10978 out dx, al
10979 inc bx
10980 mov [bp-2], bx
10981 call pcibios_init_set_elcr
10982pirq_found:
10983 mov bh, [si]
10984 mov bl, [si+1]
10985 add bl, [bp-3] ;; pci function number
10986 mov dl, #0x3c
10987 call pcibios_init_sel_reg
10988 mov dx, #0x0cfc
10989 out dx, al
10990next_pci_func:
10991 inc byte ptr[bp-3]
10992 inc bl
10993 test bl, #0x07
10994 jnz pci_init_irq_loop2
10995next_pir_entry:
10996 add si, #0x10
10997 mov byte ptr[bp-3], #0x00
10998 loop pci_init_irq_loop1
10999 mov sp, bp
11000 pop bx
11001pci_init_end:
11002 pop bp
11003 pop ds
11004 ret
11005#endif // !BX_ROMBIOS32
11006#endif // BX_PCIBIOS
11007
11008#if BX_ROMBIOS32
11009rombios32_init:
11010 ;; save a20 and enable it
11011 in al, 0x92
11012 push ax
11013 or al, #0x02
11014 out 0x92, al
11015
11016 ;; save SS:SP to the BDA
11017 xor ax, ax
11018 mov ds, ax
11019 mov 0x0469, ss
11020 mov 0x0467, sp
11021
11022 SEG CS
11023 lidt [pmode_IDT_info]
11024 SEG CS
11025 lgdt [rombios32_gdt_48]
11026 ;; set PE bit in CR0
11027 mov eax, cr0
11028 or al, #0x01
11029 mov cr0, eax
11030 ;; start protected mode code: ljmpl 0x10:rombios32_init1
11031 db 0x66, 0xea
11032 dw rombios32_05
11033 dw 0x000f ;; high 16 bit address
11034 dw 0x0010
11035
11036use32 386
11037rombios32_05:
11038 ;; init data segments
11039 mov eax, #0x18
11040 mov ds, ax
11041 mov es, ax
11042 mov ss, ax
11043 xor eax, eax
11044 mov fs, ax
11045 mov gs, ax
11046 cld
11047
11048 ;; copy rombios32 code to ram (ram offset = 1MB)
11049 mov esi, #0xfffe0000
11050 mov edi, #0x00040000
11051 mov ecx, #0x10000 / 4
11052 rep
11053 movsd
11054
11055 ;; init the stack pointer
11056 mov esp, #0x00080000
11057
11058 ;; call rombios32 code
11059 mov eax, #0x00040000
11060 call eax
11061
11062 ;; return to 16 bit protected mode first
11063 db 0xea
11064 dd rombios32_10
11065 dw 0x20
11066
11067use16 386
11068rombios32_10:
11069 ;; restore data segment limits to 0xffff
11070 mov ax, #0x28
11071 mov ds, ax
11072 mov es, ax
11073 mov ss, ax
11074 mov fs, ax
11075 mov gs, ax
11076
11077 ;; reset PE bit in CR0
11078 mov eax, cr0
11079 and al, #0xFE
11080 mov cr0, eax
11081
11082 ;; far jump to flush CPU queue after transition to real mode
11083 JMP_AP(0xf000, rombios32_real_mode)
11084
11085rombios32_real_mode:
11086 ;; restore IDT to normal real-mode defaults
11087 SEG CS
11088 lidt [rmode_IDT_info]
11089
11090 xor ax, ax
11091 mov ds, ax
11092 mov es, ax
11093 mov fs, ax
11094 mov gs, ax
11095
11096 ;; restore SS:SP from the BDA
11097 mov ss, 0x0469
11098 xor esp, esp
11099 mov sp, 0x0467
11100 ;; restore a20
11101 pop ax
11102 out 0x92, al
11103 ret
11104
11105rombios32_gdt_48:
11106 dw 0x30
11107 dw rombios32_gdt
11108 dw 0x000f
11109
11110rombios32_gdt:
11111 dw 0, 0, 0, 0
11112 dw 0, 0, 0, 0
11113 dw 0xffff, 0, 0x9b00, 0x00cf ; 32 bit flat code segment (0x10)
11114 dw 0xffff, 0, 0x9300, 0x00cf ; 32 bit flat data segment (0x18)
11115 dw 0xffff, 0, 0x9b0f, 0x0000 ; 16 bit code segment base=0xf0000 limit=0xffff
11116 dw 0xffff, 0, 0x9300, 0x0000 ; 16 bit data segment base=0x0 limit=0xffff
11117#endif // BX_ROMBIOS32
11118
11119
11120; parallel port detection: base address in DX, index in BX, timeout in CL
11121detect_parport:
11122 push dx
11123 add dx, #2
11124 in al, dx
11125 and al, #0xdf ; clear input mode
11126 out dx, al
11127 pop dx
11128 mov al, #0xaa
11129 out dx, al
11130 in al, dx
11131 cmp al, #0xaa
11132 jne no_parport
11133 push bx
11134 shl bx, #1
11135 mov [bx+0x408], dx ; Parallel I/O address
11136 pop bx
11137 mov [bx+0x478], cl ; Parallel printer timeout
11138 inc bx
11139no_parport:
11140 ret
11141
11142; serial port detection: base address in DX, index in BX, timeout in CL
11143detect_serial:
11144 push dx
11145 inc dx
11146 mov al, #0x02
11147 out dx, al
11148 in al, dx
11149 cmp al, #0x02
11150 jne no_serial
11151 inc dx
11152 in al, dx
11153 cmp al, #0x02
11154 jne no_serial
11155 dec dx
11156 xor al, al
11157 out dx, al
11158 pop dx
11159 push bx
11160 shl bx, #1
11161 mov [bx+0x400], dx ; Serial I/O address
11162 pop bx
11163 mov [bx+0x47c], cl ; Serial timeout
11164 inc bx
11165 ret
11166no_serial:
11167 pop dx
11168 ret
11169
11170rom_checksum:
11171 push ax
11172 push bx
11173 push cx
11174 xor ax, ax
11175 xor bx, bx
11176 xor cx, cx
11177 mov ch, [2]
11178 shl cx, #1
11179checksum_loop:
11180 add al, [bx]
11181 inc bx
11182 loop checksum_loop
11183 and al, #0xff
11184 pop cx
11185 pop bx
11186 pop ax
11187 ret
11188
11189rom_scan:
11190 ;; Scan for existence of valid expansion ROMS.
11191 ;; Video ROM: from 0xC0000..0xC7FFF in 2k increments
11192 ;; General ROM: from 0xC8000..0xDFFFF in 2k increments
11193 ;; System ROM: only 0xE0000
11194 ;;
11195 ;; Header:
11196 ;; Offset Value
11197 ;; 0 0x55
11198 ;; 1 0xAA
11199 ;; 2 ROM length in 512-byte blocks
11200 ;; 3 ROM initialization entry point (FAR CALL)
11201
11202 mov cx, #0xc000
11203rom_scan_loop:
11204 mov ds, cx
11205 mov ax, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
11206 cmp [0], #0xAA55 ;; look for signature
11207 jne rom_scan_increment
11208 call rom_checksum
11209 jnz rom_scan_increment
11210 mov al, [2] ;; change increment to ROM length in 512-byte blocks
11211
11212 ;; We want our increment in 512-byte quantities, rounded to
11213 ;; the nearest 2k quantity, since we only scan at 2k intervals.
11214 test al, #0x03
11215 jz block_count_rounded
11216 and al, #0xfc ;; needs rounding up
11217 add al, #0x04
11218block_count_rounded:
11219
11220 xor bx, bx ;; Restore DS back to 0000:
11221 mov ds, bx
11222 push ax ;; Save AX
11223 ;; Push addr of ROM entry point
11224 push cx ;; Push seg
11225 push #0x0003 ;; Push offset
11226 mov bp, sp ;; Call ROM init routine using seg:off on stack
11227 db 0xff ;; call_far ss:[bp+0]
11228 db 0x5e
11229 db 0
11230 cli ;; In case expansion ROM BIOS turns IF on
11231 add sp, #2 ;; Pop offset value
11232 pop cx ;; Pop seg value (restore CX)
11233 pop ax ;; Restore AX
11234rom_scan_increment:
11235 shl ax, #5 ;; convert 512-bytes blocks to 16-byte increments
11236 ;; because the segment selector is shifted left 4 bits.
11237 add cx, ax
11238 cmp cx, #0xe800 ;; Must encompass VBOX_LANBOOT_SEG!
11239 jbe rom_scan_loop
11240
11241 xor ax, ax ;; Restore DS back to 0000:
11242 mov ds, ax
11243 ret
11244
11245#define LVT0 0xFEE00350
11246#define LVT1 0xFEE00360
11247
11248;; Program LVT0/LVT1 entries in the local APIC. Some Linux kernels (e.g., RHEL4
11249;; SMP 32-bit) expect the entries to be unmasked in virtual wire mode.
11250
11251setup_lapic:
11252 pushf
11253 cli ;; Interrupts would kill us!
11254 call pmode_enter
11255 mov esi, #LVT0 ;; Program LVT0 to ExtINT and unmask
11256 mov eax, [esi]
11257 and eax, #0xfffe00ff
11258 or ah, #0x07
11259 mov [esi], eax
11260 mov esi, #LVT1 ;; Program LVT1 to NMI and unmask
11261 mov eax, [esi]
11262 and eax, #0xfffe00ff
11263 or ah, #0x04
11264 mov [esi], eax
11265 call pmode_exit
11266 popf
11267 ret
11268
11269;; Enter and exit minimal protected-mode environment. May only be called from
11270;; the F000 segment (16-bit). Does not switch stacks. Must be run with disabled
11271;; interrupts(!). On return from pmode_enter, DS contains a selector which can
11272;; address the entire 4GB address space.
11273
11274pmode_enter:
11275 push cs
11276 pop ds
11277 lgdt [pmbios_gdt_desc]
11278 mov eax, cr0
11279 or al, #0x1
11280 mov cr0, eax
11281 JMP_AP(0x20, really_enter_pm)
11282really_enter_pm:
11283 mov ax, #0x18
11284 mov ds, ax
11285 ret
11286
11287pmode_exit:
11288 mov eax, cr0
11289 and al, #0xfe
11290 mov cr0, eax
11291 JMP_AP(0xF000, really_exit_pm)
11292really_exit_pm:
11293 ret
11294
11295pmbios_gdt_desc:
11296 dw 0x30
11297 dw pmbios_gdt
11298 dw 0x000f
11299
11300pmbios_gdt:
11301 dw 0, 0, 0, 0
11302 dw 0, 0, 0, 0
11303 dw 0xffff, 0, 0x9b00, 0x00cf ; 32 bit flat code segment (0x10)
11304 dw 0xffff, 0, 0x9300, 0x00cf ; 32 bit flat data segment (0x18)
11305 dw 0xffff, 0, 0x9b0f, 0x0000 ; 16 bit code segment base=0xf0000 limit=0xffff
11306 dw 0xffff, 0, 0x9300, 0x0000 ; 16 bit data segment base=0x0 limit=0xffff
11307
11308;; for 'C' strings and other data, insert them here with
11309;; a the following hack:
11310;; DATA_SEG_DEFS_HERE
11311
11312
11313;; the following area can be used to write dynamically generated tables
11314 .align 16
11315bios_table_area_start:
11316 dd 0xaafb4442
11317 dd bios_table_area_end - bios_table_area_start - 8;
11318
11319;--------
11320;- POST -
11321;--------
11322.org 0xe05b ; POST Entry Point
11323bios_table_area_end:
11324post:
11325
11326 xor ax, ax
11327
11328 ;; first reset the DMA controllers
11329 out 0x0d,al
11330 out 0xda,al
11331
11332 ;; then initialize the DMA controllers
11333 mov al, #0xC0
11334 out 0xD6, al ; cascade mode of channel 4 enabled
11335 mov al, #0x00
11336 out 0xD4, al ; unmask channel 4
11337
11338 ;; Examine CMOS shutdown status.
11339 mov AL, #0x0f
11340 out 0x70, AL
11341 in AL, 0x71
11342
11343 ;; backup status
11344 mov bl, al
11345
11346 ;; Reset CMOS shutdown status.
11347 mov AL, #0x0f
11348 out 0x70, AL ; select CMOS register Fh
11349 mov AL, #0x00
11350 out 0x71, AL ; set shutdown action to normal
11351
11352 ;; Examine CMOS shutdown status.
11353 mov al, bl
11354
11355 ;; 0x00, 0x09, 0x0D+ = normal startup
11356 cmp AL, #0x00
11357 jz normal_post
11358 cmp AL, #0x0d
11359 jae normal_post
11360 cmp AL, #0x09
11361 je normal_post
11362
11363 ;; 0x05 = eoi + jmp via [0x40:0x67] jump
11364 cmp al, #0x05
11365 je eoi_jmp_post
11366
11367#ifdef VBOX
11368 ;; just ignore all other CMOS shutdown status values (OpenSolaris sets it to 0xA for some reason in certain cases)
11369 ;; (shutdown_status_panic just crashes the VM as it calls int 0x10 before the IDT table has been initialized)
11370 jmp normal_post
11371#else
11372 ;; Examine CMOS shutdown status.
11373 ;; 0x01,0x02,0x03,0x04,0x06,0x07,0x08, 0x0a, 0x0b, 0x0c = Unimplemented shutdown status.
11374 push bx
11375 call _shutdown_status_panic
11376#endif
11377
11378#if 0
11379 HALT(__LINE__)
11380 ;
11381 ;#if 0
11382 ; 0xb0, 0x20, /* mov al, #0x20 */
11383 ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */
11384 ;#endif
11385 ;
11386 pop es
11387 pop ds
11388 popa
11389 iret
11390#endif
11391
11392normal_post:
11393 ; case 0: normal startup
11394
11395 cli
11396 mov ax, #0xfffe
11397 mov sp, ax
11398 xor ax, ax
11399 mov ds, ax
11400 mov ss, ax
11401
11402#ifndef VBOX
11403 ;; zero out BIOS data area (40:00..40:ff)
11404 mov es, ax
11405 mov cx, #0x0080 ;; 128 words
11406 mov di, #0x0400
11407 cld
11408 rep
11409 stosw
11410#else /* VBOX */
11411 ;; zero out segment 0 (includes BIOS data area) except word at 40:72
11412 mov es, ax
11413 xor di, di
11414 cld
11415 mov cx, #0x0239 ;; 569 words
11416 rep
11417 stosw
11418 inc di
11419 inc di
11420 mov cx, #0x7dc6 ;; 32198 words
11421 rep
11422 stosw
11423 ;; zero out remaining base memory except the last 16 bytes of the EBDA
11424 ;; because we store the MP table there
11425 xor eax, eax
11426 xor bx, bx
11427memory_zero_loop:
11428 add bx, #0x1000
11429 cmp bx, #0x9000
11430 jae memory_cleared
11431 mov es, bx
11432 xor di, di
11433 mov cx, #0x4000
11434 rep
11435 stosd
11436 jmp memory_zero_loop
11437memory_cleared:
11438 mov es, bx
11439 xor di, di
11440 mov cx, #0x3f00
11441 rep
11442 stosd
11443 xor bx, bx
11444#endif
11445
11446 call _log_bios_start
11447
11448 ;; set all interrupts to default handler
11449 xor bx, bx ;; offset index
11450 mov cx, #0x0100 ;; counter (256 interrupts)
11451 mov ax, #dummy_iret_handler
11452 mov dx, #0xF000
11453
11454post_default_ints:
11455 mov [bx], ax
11456 add bx, #2
11457 mov [bx], dx
11458 add bx, #2
11459 loop post_default_ints
11460
11461 ;; set vector 0x79 to zero
11462 ;; this is used by 'guardian angel' protection system
11463 SET_INT_VECTOR(0x79, #0, #0)
11464
11465 ;; base memory in K 40:13 (word)
11466 mov ax, #BASE_MEM_IN_K
11467 mov 0x0413, ax
11468
11469
11470 ;; Manufacturing Test 40:12
11471 ;; zerod out above
11472
11473#ifndef VBOX
11474 ;; Warm Boot Flag 0040:0072
11475 ;; value of 1234h = skip memory checks
11476 ;; zerod out above
11477#endif /* !VBOX */
11478
11479
11480 ;; Printer Services vector
11481 SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
11482
11483 ;; Bootstrap failure vector
11484 SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
11485
11486 ;; Bootstrap Loader vector
11487 SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
11488
11489 ;; User Timer Tick vector
11490 SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
11491
11492 ;; Memory Size Check vector
11493 SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
11494
11495 ;; Equipment Configuration Check vector
11496 SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
11497
11498 ;; System Services
11499 SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
11500
11501 ;; EBDA setup
11502 call ebda_post
11503
11504 ;; PIT setup
11505 SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
11506 ;; int 1C already points at dummy_iret_handler (above)
11507 mov al, #0x34 ; timer0: binary count, 16bit count, mode 2
11508 out 0x43, al
11509 mov al, #0x00 ; maximum count of 0000H = 18.2Hz
11510 out 0x40, al
11511 out 0x40, al
11512
11513 ;; Keyboard
11514 SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
11515 SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
11516
11517 xor ax, ax
11518 mov ds, ax
11519 mov 0x0417, al /* keyboard shift flags, set 1 */
11520 mov 0x0418, al /* keyboard shift flags, set 2 */
11521 mov 0x0419, al /* keyboard alt-numpad work area */
11522 mov 0x0471, al /* keyboard ctrl-break flag */
11523 mov 0x0497, al /* keyboard status flags 4 */
11524 mov al, #0x10
11525 mov 0x0496, al /* keyboard status flags 3 */
11526
11527
11528 /* keyboard head of buffer pointer */
11529 mov bx, #0x001E
11530 mov 0x041A, bx
11531
11532 /* keyboard end of buffer pointer */
11533 mov 0x041C, bx
11534
11535 /* keyboard pointer to start of buffer */
11536 mov bx, #0x001E
11537 mov 0x0480, bx
11538
11539 /* keyboard pointer to end of buffer */
11540 mov bx, #0x003E
11541 mov 0x0482, bx
11542
11543 /* init the keyboard */
11544 call _keyboard_init
11545
11546 ;; mov CMOS Equipment Byte to BDA Equipment Word
11547 mov ax, 0x0410
11548 mov al, #0x14
11549 out 0x70, al
11550 in al, 0x71
11551 mov 0x0410, ax
11552
11553
11554 ;; Parallel setup
11555 SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
11556 xor ax, ax
11557 mov ds, ax
11558 xor bx, bx
11559 mov cl, #0x14 ; timeout value
11560 mov dx, #0x378 ; Parallel I/O address, port 1
11561 call detect_parport
11562 mov dx, #0x278 ; Parallel I/O address, port 2
11563 call detect_parport
11564 shl bx, #0x0e
11565 mov ax, 0x410 ; Equipment word bits 14..15 determine # parallel ports
11566 and ax, #0x3fff
11567 or ax, bx ; set number of parallel ports
11568 mov 0x410, ax
11569
11570 ;; Serial setup
11571 SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
11572 SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
11573 xor bx, bx
11574 mov cl, #0x0a ; timeout value
11575 mov dx, #0x03f8 ; Serial I/O address, port 1
11576 call detect_serial
11577 mov dx, #0x02f8 ; Serial I/O address, port 2
11578 call detect_serial
11579 mov dx, #0x03e8 ; Serial I/O address, port 3
11580 call detect_serial
11581 mov dx, #0x02e8 ; Serial I/O address, port 4
11582 call detect_serial
11583 shl bx, #0x09
11584 mov ax, 0x410 ; Equipment word bits 9..11 determine # serial ports
11585 and ax, #0xf1ff
11586 or ax, bx ; set number of serial port
11587 mov 0x410, ax
11588
11589 ;; CMOS RTC
11590 SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
11591 SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
11592 SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
11593 ;; BIOS DATA AREA 0x4CE ???
11594 call timer_tick_post
11595
11596 ;; PS/2 mouse setup
11597 SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
11598
11599 ;; IRQ13 (FPU exception) setup
11600 SET_INT_VECTOR(0x75, #0xF000, #int75_handler)
11601
11602 ;; Video setup
11603 SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
11604
11605#ifdef VBOX
11606 ;; moved the PIC initialization to another place as we need
11607 ;; some space for additions init calls. Otherwise this code
11608 ;; overlaps with the NMI handler at 0xe2c3 (fixed BIOS entry)
11609 call init_pic
11610#else /* !VBOX */
11611 ;; PIC
11612 mov al, #0x11 ; send initialisation commands
11613 out 0x20, al
11614 out 0xa0, al
11615 mov al, #0x08
11616 out 0x21, al
11617 mov al, #0x70
11618 out 0xa1, al
11619 mov al, #0x04
11620 out 0x21, al
11621 mov al, #0x02
11622 out 0xa1, al
11623 mov al, #0x01
11624 out 0x21, al
11625 out 0xa1, al
11626 mov al, #0xb8
11627 out 0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6
11628#if BX_USE_PS2_MOUSE
11629 mov al, #0x8f
11630#else
11631 mov al, #0x9f
11632#endif
11633 out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14
11634#endif /* !VBOX */
11635
11636#if BX_ROMBIOS32
11637 call rombios32_init
11638#else
11639 call pcibios_init_iomem_bases
11640 call pcibios_init_irqs
11641#endif
11642 call setup_lapic
11643 call rom_scan
11644
11645#if BX_USE_ATADRV
11646 ;;
11647 ;; ATA/ATAPI driver setup
11648 ;;
11649 call _ata_init
11650 call _ata_detect
11651 ;;
11652#endif
11653
11654#ifdef VBOX_WITH_SCSI
11655 ;;
11656 ;; SCSI driver setup
11657 ;;
11658 call _scsi_init
11659 ;;
11660#endif
11661
11662 call _print_bios_banner
11663
11664 ;;
11665 ;; Floppy setup
11666 ;;
11667 call floppy_drive_post
11668
11669 ;;
11670 ;; Hard Drive setup
11671 ;;
11672 call hard_drive_post
11673
11674#if BX_ELTORITO_BOOT
11675 ;;
11676 ;; eltorito floppy/harddisk emulation from cd
11677 ;;
11678 call _cdemu_init
11679 ;;
11680#endif // BX_ELTORITO_BOOT
11681
11682 sti ;; enable interrupts
11683 int #0x19
11684
11685.org 0xe2c3 ; NMI Handler Entry Point
11686nmi:
11687 ;; FIXME the NMI handler should not panic
11688 ;; but iret when called from int75 (fpu exception)
11689 call _nmi_handler_msg
11690 iret
11691
11692int75_handler:
11693 out 0xf0, al // clear irq13
11694 call eoi_both_pics // clear interrupt
11695 int 2 // legacy nmi call
11696 iret
11697
11698;-------------------------------------------
11699;- INT 13h Fixed Disk Services Entry Point -
11700;-------------------------------------------
11701.org 0xe3fe ; INT 13h Fixed Disk Services Entry Point
11702int13_handler:
11703 //JMPL(int13_relocated)
11704 jmp int13_relocated
11705
11706.org 0xe401 ; Fixed Disk Parameter Table
11707
11708;----------
11709;- INT19h -
11710;----------
11711.org 0xe6f2 ; INT 19h Boot Load Service Entry Point
11712int19_handler:
11713
11714 jmp int19_relocated
11715;-------------------------------------------
11716;- System BIOS Configuration Data Table
11717;-------------------------------------------
11718.org BIOS_CONFIG_TABLE
11719db 0x08 ; Table size (bytes) -Lo
11720db 0x00 ; Table size (bytes) -Hi
11721db SYS_MODEL_ID
11722db SYS_SUBMODEL_ID
11723db BIOS_REVISION
11724; Feature byte 1
11725; b7: 1=DMA channel 3 used by hard disk
11726; b6: 1=2 interrupt controllers present
11727; b5: 1=RTC present
11728; b4: 1=BIOS calls int 15h/4Fh every key
11729; b3: 1=wait for extern event supported (Int 15h/41h)
11730; b2: 1=extended BIOS data area used
11731; b1: 0=AT or ESDI bus, 1=MicroChannel
11732; b0: 1=Dual bus (MicroChannel + ISA)
11733db (0 << 7) | \
11734 (1 << 6) | \
11735 (1 << 5) | \
11736 (BX_CALL_INT15_4F << 4) | \
11737 (0 << 3) | \
11738 (BX_USE_EBDA << 2) | \
11739 (0 << 1) | \
11740 (0 << 0)
11741; Feature byte 2
11742; b7: 1=32-bit DMA supported
11743; b6: 1=int16h, function 9 supported
11744; b5: 1=int15h/C6h (get POS data) supported
11745; b4: 1=int15h/C7h (get mem map info) supported
11746; b3: 1=int15h/C8h (en/dis CPU) supported
11747; b2: 1=non-8042 kb controller
11748; b1: 1=data streaming supported
11749; b0: reserved
11750db (0 << 7) | \
11751 (1 << 6) | \
11752 (0 << 5) | \
11753 (0 << 4) | \
11754 (0 << 3) | \
11755 (0 << 2) | \
11756 (0 << 1) | \
11757 (0 << 0)
11758; Feature byte 3
11759; b7: not used
11760; b6: reserved
11761; b5: reserved
11762; b4: POST supports ROM-to-RAM enable/disable
11763; b3: SCSI on system board
11764; b2: info panel installed
11765; b1: Initial Machine Load (IML) system - BIOS on disk
11766; b0: SCSI supported in IML
11767db 0x00
11768; Feature byte 4
11769; b7: IBM private
11770; b6: EEPROM present
11771; b5-3: ABIOS presence (011 = not supported)
11772; b2: private
11773; b1: memory split above 16Mb supported
11774; b0: POSTEXT directly supported by POST
11775db 0x00
11776; Feature byte 5 (IBM)
11777; b1: enhanced mouse
11778; b0: flash EPROM
11779db 0x00
11780
11781
11782
11783.org 0xe729 ; Baud Rate Generator Table
11784
11785;----------
11786;- INT14h -
11787;----------
11788.org 0xe739 ; INT 14h Serial Communications Service Entry Point
11789int14_handler:
11790 push ds
11791 pusha
11792 xor ax, ax
11793 mov ds, ax
11794 call _int14_function
11795 popa
11796 pop ds
11797 iret
11798
11799
11800;----------------------------------------
11801;- INT 16h Keyboard Service Entry Point -
11802;----------------------------------------
11803.org 0xe82e
11804int16_handler:
11805
11806 sti
11807 push ds
11808 pushf
11809 pusha
11810
11811 cmp ah, #0x00
11812 je int16_F00
11813 cmp ah, #0x10
11814 je int16_F00
11815
11816 mov bx, #0xf000
11817 mov ds, bx
11818 call _int16_function
11819 popa
11820 popf
11821 pop ds
11822 jz int16_zero_set
11823
11824int16_zero_clear:
11825 push bp
11826 mov bp, sp
11827 //SEG SS
11828 and BYTE [bp + 0x06], #0xbf
11829 pop bp
11830 iret
11831
11832int16_zero_set:
11833 push bp
11834 mov bp, sp
11835 //SEG SS
11836 or BYTE [bp + 0x06], #0x40
11837 pop bp
11838 iret
11839
11840int16_F00:
11841 mov bx, #0x0040
11842 mov ds, bx
11843
11844int16_wait_for_key:
11845 cli
11846 mov bx, 0x001a
11847 cmp bx, 0x001c
11848 jne int16_key_found
11849 sti
11850 nop
11851#if 0
11852 /* no key yet, call int 15h, function AX=9002 */
11853 0x50, /* push AX */
11854 0xb8, 0x02, 0x90, /* mov AX, #0x9002 */
11855 0xcd, 0x15, /* int 15h */
11856 0x58, /* pop AX */
11857 0xeb, 0xea, /* jmp WAIT_FOR_KEY */
11858#endif
11859 jmp int16_wait_for_key
11860
11861int16_key_found:
11862 mov bx, #0xf000
11863 mov ds, bx
11864 call _int16_function
11865 popa
11866 popf
11867 pop ds
11868#if 0
11869 /* notify int16 complete w/ int 15h, function AX=9102 */
11870 0x50, /* push AX */
11871 0xb8, 0x02, 0x91, /* mov AX, #0x9102 */
11872 0xcd, 0x15, /* int 15h */
11873 0x58, /* pop AX */
11874#endif
11875 iret
11876
11877
11878
11879;-------------------------------------------------
11880;- INT09h : Keyboard Hardware Service Entry Point -
11881;-------------------------------------------------
11882.org 0xe987
11883int09_handler:
11884 cli
11885 push ax
11886
11887 mov al, #0xAD ;;disable keyboard
11888 out #0x64, al
11889
11890 mov al, #0x0B
11891 out #0x20, al
11892 in al, #0x20
11893 and al, #0x02
11894 jz int09_finish
11895
11896 in al, #0x60 ;;read key from keyboard controller
11897 sti
11898 push ds
11899 pusha
11900#ifdef BX_CALL_INT15_4F
11901 mov ah, #0x4f ;; allow for keyboard intercept
11902 stc
11903 int #0x15
11904 jnc int09_done
11905#endif
11906
11907 ;; check for extended key
11908 cmp al, #0xe0
11909 jne int09_check_pause
11910 xor ax, ax
11911 mov ds, ax
11912 mov al, BYTE [0x496] ;; mf2_state |= 0x02
11913 or al, #0x02
11914 mov BYTE [0x496], al
11915 jmp int09_done
11916
11917int09_check_pause: ;; check for pause key
11918 cmp al, #0xe1
11919 jne int09_process_key
11920 xor ax, ax
11921 mov ds, ax
11922 mov al, BYTE [0x496] ;; mf2_state |= 0x01
11923 or al, #0x01
11924 mov BYTE [0x496], al
11925 jmp int09_done
11926
11927int09_process_key:
11928 mov bx, #0xf000
11929 mov ds, bx
11930 call _int09_function
11931
11932int09_done:
11933 popa
11934 pop ds
11935 cli
11936 call eoi_master_pic
11937
11938int09_finish:
11939 mov al, #0xAE ;;enable keyboard
11940 out #0x64, al
11941 pop ax
11942 iret
11943
11944
11945;----------------------------------------
11946;- INT 13h Diskette Service Entry Point -
11947;----------------------------------------
11948.org 0xec59
11949int13_diskette:
11950 jmp int13_noeltorito
11951
11952;---------------------------------------------
11953;- INT 0Eh Diskette Hardware ISR Entry Point -
11954;---------------------------------------------
11955.org 0xef57 ; INT 0Eh Diskette Hardware ISR Entry Point
11956int0e_handler:
11957 push ax
11958 push dx
11959 mov dx, #0x03f4
11960 in al, dx
11961 and al, #0xc0
11962 cmp al, #0xc0
11963 je int0e_normal
11964 mov dx, #0x03f5
11965 mov al, #0x08 ; sense interrupt status
11966 out dx, al
11967int0e_loop1:
11968 mov dx, #0x03f4
11969 in al, dx
11970 and al, #0xc0
11971 cmp al, #0xc0
11972 jne int0e_loop1
11973int0e_loop2:
11974 mov dx, #0x03f5
11975 in al, dx
11976 mov dx, #0x03f4
11977 in al, dx
11978 and al, #0xc0
11979 cmp al, #0xc0
11980 je int0e_loop2
11981int0e_normal:
11982 push ds
11983 xor ax, ax ;; segment 0000
11984 mov ds, ax
11985 call eoi_master_pic
11986 mov al, 0x043e
11987 or al, #0x80 ;; diskette interrupt has occurred
11988 mov 0x043e, al
11989 pop ds
11990 pop dx
11991 pop ax
11992 iret
11993
11994
11995.org 0xefc7 ; Diskette Controller Parameter Table
11996diskette_param_table:
11997;; Since no provisions are made for multiple drive types, most
11998;; values in this table are ignored. I set parameters for 1.44M
11999;; floppy here
12000db 0xAF
12001db 0x02 ;; head load time 0000001, DMA used
12002db 0x25
12003db 0x02
12004db 18
12005db 0x1B
12006db 0xFF
12007db 0x6C
12008db 0xF6
12009db 0x0F
12010db 0x08
12011
12012
12013;----------------------------------------
12014;- INT17h : Printer Service Entry Point -
12015;----------------------------------------
12016.org 0xefd2
12017int17_handler:
12018 push ds
12019 pusha
12020 xor ax, ax
12021 mov ds, ax
12022 call _int17_function
12023 popa
12024 pop ds
12025 iret
12026
12027diskette_param_table2:
12028;; New diskette parameter table adding 3 parameters from IBM
12029;; Since no provisions are made for multiple drive types, most
12030;; values in this table are ignored. I set parameters for 1.44M
12031;; floppy here
12032db 0xAF
12033db 0x02 ;; head load time 0000001, DMA used
12034db 0x25
12035db 0x02
12036db 18
12037db 0x1B
12038db 0xFF
12039db 0x6C
12040db 0xF6
12041db 0x0F
12042db 0x08
12043db 79 ;; maximum track
12044db 0 ;; data transfer rate
12045db 4 ;; drive type in cmos
12046
12047.org 0xf045 ; INT 10 Functions 0-Fh Entry Point
12048 HALT(__LINE__)
12049 iret
12050
12051;----------
12052;- INT10h -
12053;----------
12054.org 0xf065 ; INT 10h Video Support Service Entry Point
12055int10_handler:
12056 ;; dont do anything, since the VGA BIOS handles int10h requests
12057 iret
12058
12059.org 0xf0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
12060
12061;----------
12062;- INT12h -
12063;----------
12064.org 0xf841 ; INT 12h Memory Size Service Entry Point
12065; ??? different for Pentium (machine check)?
12066int12_handler:
12067 push ds
12068 mov ax, #0x0040
12069 mov ds, ax
12070 mov ax, 0x0013
12071 pop ds
12072 iret
12073
12074;----------
12075;- INT11h -
12076;----------
12077.org 0xf84d ; INT 11h Equipment List Service Entry Point
12078int11_handler:
12079 push ds
12080 mov ax, #0x0040
12081 mov ds, ax
12082 mov ax, 0x0010
12083 pop ds
12084 iret
12085
12086;----------
12087;- INT15h -
12088;----------
12089.org 0xf859 ; INT 15h System Services Entry Point
12090int15_handler:
12091 pushf
12092#if BX_APM
12093 cmp ah, #0x53
12094 je apm_call
12095#endif
12096 push ds
12097 push es
12098 cmp ah, #0x86
12099 je int15_handler32
12100 cmp ah, #0xE8
12101 je int15_handler32
12102 pusha
12103#if BX_USE_PS2_MOUSE
12104 cmp ah, #0xC2
12105 je int15_handler_mouse
12106#endif
12107 call _int15_function
12108int15_handler_mouse_ret:
12109 popa
12110int15_handler32_ret:
12111 pop es
12112 pop ds
12113 popf
12114 jmp iret_modify_cf
12115#if BX_APM
12116apm_call:
12117 jmp _apmreal_entry
12118#endif
12119
12120#if BX_USE_PS2_MOUSE
12121int15_handler_mouse:
12122 call _int15_function_mouse
12123 jmp int15_handler_mouse_ret
12124#endif
12125
12126int15_handler32:
12127 pushad
12128 call _int15_function32
12129 popad
12130 jmp int15_handler32_ret
12131
12132;; Protected mode IDT descriptor
12133;;
12134;; I just make the limit 0, so the machine will shutdown
12135;; if an exception occurs during protected mode memory
12136;; transfers.
12137;;
12138;; Set base to f0000 to correspond to beginning of BIOS,
12139;; in case I actually define an IDT later
12140;; Set limit to 0
12141
12142pmode_IDT_info:
12143dw 0x0000 ;; limit 15:00
12144dw 0x0000 ;; base 15:00
12145db 0x0f ;; base 23:16
12146
12147;; Real mode IDT descriptor
12148;;
12149;; Set to typical real-mode values.
12150;; base = 000000
12151;; limit = 03ff
12152
12153rmode_IDT_info:
12154dw 0x03ff ;; limit 15:00
12155dw 0x0000 ;; base 15:00
12156db 0x00 ;; base 23:16
12157
12158;;
12159;; Handler for unexpected hardware interrupts
12160;;
12161dummy_isr:
12162 push ds
12163 pushad
12164 xor ax, ax
12165 mov ds, ax
12166 call _dummy_isr_function
12167 popad
12168 pop ds
12169 iret
12170
12171;----------
12172;- INT1Ah -
12173;----------
12174.org 0xfe6e ; INT 1Ah Time-of-day Service Entry Point
12175int1a_handler:
12176#if BX_PCIBIOS
12177 cmp ah, #0xb1
12178 jne int1a_normal
12179 call pcibios_real
12180 jc pcibios_error
12181 retf 2
12182pcibios_error:
12183 mov bl, ah
12184 mov ah, #0xb1
12185 push ds
12186 pusha
12187 mov ax, ss ; set readable descriptor to ds, for calling pcibios
12188 mov ds, ax ; on 16bit protected mode.
12189 jmp int1a_callfunction
12190int1a_normal:
12191#endif
12192 push ds
12193 pusha
12194 xor ax, ax
12195 mov ds, ax
12196int1a_callfunction:
12197 call _int1a_function
12198 popa
12199 pop ds
12200 iret
12201
12202;;
12203;; int70h: IRQ8 - CMOS RTC
12204;;
12205int70_handler:
12206 push ds
12207 pushad
12208 xor ax, ax
12209 mov ds, ax
12210 call _int70_function
12211 popad
12212 pop ds
12213 iret
12214
12215;---------
12216;- INT08 -
12217;---------
12218.org 0xfea5 ; INT 08h System Timer ISR Entry Point
12219int08_handler:
12220 sti
12221 push eax
12222 push ds
12223 xor ax, ax
12224 mov ds, ax
12225
12226 ;; time to turn off drive(s)?
12227 mov al,0x0440
12228 or al,al
12229 jz int08_floppy_off
12230 dec al
12231 mov 0x0440,al
12232 jnz int08_floppy_off
12233 ;; turn motor(s) off
12234 push dx
12235 mov dx,#0x03f2
12236 in al,dx
12237 and al,#0xcf
12238 out dx,al
12239 pop dx
12240int08_floppy_off:
12241
12242 mov eax, 0x046c ;; get ticks dword
12243 inc eax
12244
12245 ;; compare eax to one days worth of timer ticks at 18.2 hz
12246 cmp eax, #0x001800B0
12247 jb int08_store_ticks
12248 ;; there has been a midnight rollover at this point
12249 xor eax, eax ;; zero out counter
12250 inc BYTE 0x0470 ;; increment rollover flag
12251
12252int08_store_ticks:
12253 mov 0x046c, eax ;; store new ticks dword
12254 ;; chain to user timer tick INT #0x1c
12255 //pushf
12256 //;; call_ep [ds:loc]
12257 //CALL_EP( 0x1c << 2 )
12258 int #0x1c
12259 cli
12260 call eoi_master_pic
12261 pop ds
12262 pop eax
12263 iret
12264
12265.org 0xfef3 ; Initial Interrupt Vector Offsets Loaded by POST
12266
12267
12268.org 0xff00
12269.ascii BIOS_COPYRIGHT_STRING
12270
12271#ifdef VBOX
12272// The SMBIOS header
12273.org 0xff30
12274.align 16
12275 db 0x5f, 0x53, 0x4d, 0x5f ; "_SM_" signature
12276 db 0x00 ; checksum (set by biossums)
12277 db 0x1f ; EPS length, defined by standard
12278 db VBOX_SMBIOS_MAJOR_VER ; SMBIOS major version
12279 db VBOX_SMBIOS_MINOR_VER ; SMBIOS minor version
12280 dw VBOX_SMBIOS_MAXSS ; Maximum structure size
12281 db 0x00 ; Entry point revision
12282 db 0x00, 0x00, 0x00, 0x00, 0x00
12283
12284// The DMI header
12285 db 0x5f, 0x44, 0x4d, 0x49, 0x5f ; "_DMI_" signature
12286 db 0x00 ; checksum (set by biossums)
12287 dw VBOX_DMI_TABLE_SIZE ; DMI tables length
12288 dd VBOX_DMI_TABLE_BASE ; DMI tables base
12289 dw VBOX_DMI_TABLE_ENTR ; DMI tables entries
12290 db VBOX_DMI_TABLE_VER ; DMI version
12291 db 0x00 ; Just for alignment
12292#endif
12293
12294;------------------------------------------------
12295;- IRET Instruction for Dummy Interrupt Handler -
12296;------------------------------------------------
12297.org 0xff53 ; IRET Instruction for Dummy Interrupt Handler
12298dummy_iret_handler:
12299 iret
12300
12301.org 0xff54 ; INT 05h Print Screen Service Entry Point
12302 HALT(__LINE__)
12303 iret
12304
12305.org 0xfff0 ; Power-up Entry Point
12306 jmp 0xf000:post
12307
12308.org 0xfff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
12309.ascii BIOS_BUILD_DATE
12310
12311.org 0xfffe ; System Model ID
12312db SYS_MODEL_ID
12313db 0x00 ; filler
12314
12315.org 0xfa6e ;; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
12316ASM_END
12317/*
12318 * This font comes from the fntcol16.zip package (c) by Joseph Gil
12319 * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
12320 * This font is public domain
12321 */
12322static Bit8u vgafont8[128*8]=
12323{
12324 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
12325 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
12326 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
12327 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
12328 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
12329 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
12330 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
12331 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
12332 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
12333 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
12334 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
12335 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
12336 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
12337 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
12338 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
12339 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
12340 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
12341 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
12342 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
12343 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
12344 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
12345 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
12346 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
12347 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
12348 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
12349 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
12350 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
12351 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
12352 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
12353 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
12354 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
12355 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
12356 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
12357 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
12358 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
12359 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
12360 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
12361 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
12362 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
12363 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
12364 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
12365 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
12366 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
12367 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
12368 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
12369 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
12370 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
12371 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
12372 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
12373 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
12374 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
12375 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
12376 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
12377 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
12378 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
12379 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
12380 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
12381 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
12382 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
12383 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
12384 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
12385 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
12386 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
12387 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
12388 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
12389 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
12390 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
12391 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
12392 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
12393 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
12394 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
12395 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
12396 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
12397 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
12398 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
12399 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
12400 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
12401 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
12402 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
12403 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
12404 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
12405 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
12406 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
12407 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
12408 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
12409 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
12410 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
12411 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
12412 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
12413 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
12414 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
12415 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
12416 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
12417 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
12418 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
12419 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
12420 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
12421 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
12422 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
12423 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
12424 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
12425 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
12426 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
12427 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
12428 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
12429 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
12430 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
12431 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
12432 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
12433 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
12434 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
12435 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
12436 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
12437 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
12438 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
12439 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
12440 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
12441 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
12442 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
12443 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
12444 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
12445 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
12446 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
12447 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
12448 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
12449 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
12450 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
12451 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
12452};
12453
12454ASM_START
12455.org 0xcc00
12456// bcc-generated data will be placed here
12457ASM_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