VirtualBox

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

Last change on this file since 38261 was 38261, checked in by vboxsync, 13 years ago

Added (not currently used) ifdef, corrected IDT definitions.

  • Property svn:eol-style set to native
File size: 338.4 KB
Line 
1/////////////////////////////////////////////////////////////////////////
2// $Id: rombios.c,v 1.176 2006/12/30 17:13:17 vruppert Exp $
3/////////////////////////////////////////////////////////////////////////
4//
5// Copyright (C) 2002 MandrakeSoft S.A.
6//
7// MandrakeSoft S.A.
8// 43, rue d'Aboukir
9// 75002 Paris - France
10// http://www.linux-mandrake.com/
11// http://www.mandrakesoft.com/
12//
13// This library is free software; you can redistribute it and/or
14// modify it under the terms of the GNU Lesser General Public
15// License as published by the Free Software Foundation; either
16// version 2 of the License, or (at your option) any later version.
17//
18// This library is distributed in the hope that it will be useful,
19// but WITHOUT ANY WARRANTY; without even the implied warranty of
20// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21// Lesser General Public License for more details.
22//
23// You should have received a copy of the GNU Lesser General Public
24// License along with this library; if not, write to the Free Software
25// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
26
27
28/*
29 * Oracle LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
30 * other than GPL or LGPL is available it will apply instead, Oracle elects to use only
31 * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
32 * a choice of LGPL license versions is made available with the language indicating
33 * that LGPLv2 or any later version may be used, or where a choice of which version
34 * of the LGPL is applied is otherwise unspecified.
35 */
36
37// ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
38
39
40// ROM BIOS compatibility entry points:
41// ===================================
42// $e05b ; POST Entry Point
43// $e2c3 ; NMI Handler Entry Point
44// $e3fe ; INT 13h Fixed Disk Services Entry Point
45// $e401 ; Fixed Disk Parameter Table
46// $e6f2 ; INT 19h Boot Load Service Entry Point
47// $e6f5 ; Configuration Data Table
48// $e729 ; Baud Rate Generator Table
49// $e739 ; INT 14h Serial Communications Service Entry Point
50// $e82e ; INT 16h Keyboard Service Entry Point
51// $e987 ; INT 09h Keyboard Service Entry Point
52// $ec59 ; INT 13h Diskette Service Entry Point
53// $ef57 ; INT 0Eh Diskette Hardware ISR Entry Point
54// $efc7 ; Diskette Controller Parameter Table
55// $efd2 ; INT 17h Printer Service Entry Point
56// $f045 ; INT 10 Functions 0-Fh Entry Point
57// $f065 ; INT 10h Video Support Service Entry Point
58// $f0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
59// $f841 ; INT 12h Memory Size Service Entry Point
60// $f84d ; INT 11h Equipment List Service Entry Point
61// $f859 ; INT 15h System Services Entry Point
62// $fa6e ; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
63// $fe6e ; INT 1Ah Time-of-day Service Entry Point
64// $fea5 ; INT 08h System Timer ISR Entry Point
65// $fef3 ; Initial Interrupt Vector Offsets Loaded by POST
66// $ff53 ; IRET Instruction for Dummy Interrupt Handler
67// $ff54 ; INT 05h Print Screen Service Entry Point
68// $fff0 ; Power-up Entry Point
69// $fff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
70// $fffe ; System Model ID
71
72// NOTES for ATA/ATAPI driver ([email protected])
73// Features
74// - supports up to 4 ATA interfaces
75// - device/geometry detection
76// - 16bits/32bits device access
77// - pchs/lba access
78// - datain/dataout/packet command support
79//
80// NOTES for El-Torito Boot ([email protected])
81// - CD-ROM booting is only available if ATA/ATAPI Driver is available
82// - Current code is only able to boot mono-session cds
83// - Current code can not boot and emulate a hard-disk
84// the bios will panic otherwise
85// - Current code also use memory in EBDA segment.
86// - I used cmos byte 0x3D to store extended information on boot-device
87// - Code has to be modified modified to handle multiple cdrom drives
88// - Here are the cdrom boot failure codes:
89// 1 : no atapi device found
90// 2 : no atapi cdrom found
91// 3 : can not read cd - BRVD
92// 4 : cd is not eltorito (BRVD)
93// 5 : cd is not eltorito (ISO TAG)
94// 6 : cd is not eltorito (ELTORITO TAG)
95// 7 : can not read cd - boot catalog
96// 8 : boot catalog : bad header
97// 9 : boot catalog : bad platform
98// 10 : boot catalog : bad signature
99// 11 : boot catalog : bootable flag not set
100// 12 : can not read cd - boot image
101//
102// ATA driver
103// - EBDA segment.
104// I used memory starting at 0x121 in the segment
105#ifndef VBOX
106// - the translation policy is defined in cmos regs 0x39 & 0x3a
107#endif /* !VBOX */
108//
109// TODO :
110//
111// int74
112// - needs to be reworked. Uses direct [bp] offsets. (?)
113//
114// int13:
115// - f04 (verify sectors) isn't complete (?)
116// - f02/03/04 should set current cyl,etc in BDA (?)
117// - rewrite int13_relocated & clean up int13 entry code
118//
119// NOTES:
120// - NMI access (bit7 of addr written to 70h)
121//
122// ATA driver
123// - should handle the "don't detect" bit (cmos regs 0x3b & 0x3c)
124// - could send the multiple-sector read/write commands
125//
126// El-Torito
127// - Emulate a Hard-disk (currently only diskette can be emulated) see "FIXME ElTorito Harddisk"
128// - Implement remaining int13_cdemu functions (as defined by El-Torito specs)
129// - cdrom drive is hardcoded to ide 0 device 1 in several places. see "FIXME ElTorito Hardcoded"
130// - int13 Fix DL when emulating a cd. In that case DL is decremented before calling real int13.
131// This is ok. But DL should be reincremented afterwards.
132// - Fix all "FIXME ElTorito Various"
133// - should be able to boot any cdrom instead of the first one
134//
135// BCC Bug: find a generic way to handle the bug of #asm after an "if" (fixed in 0.16.7)
136
137#ifdef VBOX
138#include "DevPcBios.h"
139#include <VBox/version.h>
140#endif
141
142#define BX_ROMBIOS32 0
143#define DEBUG_ROMBIOS 0
144
145#define DEBUG_ATA 0
146#define DEBUG_INT13_HD 0
147#define DEBUG_INT13_CD 0
148#define DEBUG_INT13_ET 0
149#define DEBUG_INT13_FL 0
150#define DEBUG_INT15 0
151#define DEBUG_INT16 0
152#define DEBUG_INT1A 0
153#define DEBUG_INT74 0
154#define DEBUG_APM 0
155
156#define BX_CPU 3
157#define BX_USE_PS2_MOUSE 1
158#define BX_CALL_INT15_4F 1
159#define BX_USE_EBDA 1
160#define BX_SUPPORT_FLOPPY 1
161#define BX_FLOPPY_ON_CNT 37 /* 2 seconds */
162#define BX_PCIBIOS 1
163#define BX_APM 1
164
165#define BX_USE_ATADRV 1
166#define BX_ELTORITO_BOOT 1
167
168#define BX_MAX_ATA_INTERFACES 4
169#define BX_MAX_ATA_DEVICES (BX_MAX_ATA_INTERFACES*2)
170
171#define BX_VIRTUAL_PORTS 1 /* normal output to Bochs ports */
172#define BX_DEBUG_SERIAL 0 /* output to COM1 */
173
174 /* model byte 0xFC = AT */
175#define SYS_MODEL_ID 0xFC
176#define SYS_SUBMODEL_ID 0x00
177#define BIOS_REVISION 1
178#define BIOS_CONFIG_TABLE 0xe6f5
179
180#ifndef BIOS_BUILD_DATE
181# define BIOS_BUILD_DATE "06/23/99"
182#endif
183
184 // 1K of base memory used for Extended Bios Data Area (EBDA)
185 // EBDA is used for PS/2 mouse support, and IDE BIOS, etc.
186#define EBDA_SEG 0x9FC0
187#define EBDA_SIZE 1 // In KiB
188#define BASE_MEM_IN_K (640 - EBDA_SIZE)
189
190#define ACPI_DATA_SIZE 0x00010000L
191
192 // Define the application NAME
193#if defined(BX_QEMU)
194# define BX_APPNAME "QEMU"
195#elif defined(PLEX86)
196# define BX_APPNAME "Plex86"
197#else
198# define BX_APPNAME "Bochs"
199#endif
200
201 // Sanity Checks
202#if BX_USE_ATADRV && BX_CPU<3
203# error The ATA/ATAPI Driver can only to be used with a 386+ cpu
204#endif
205#if BX_USE_ATADRV && !BX_USE_EBDA
206# error ATA/ATAPI Driver can only be used if EBDA is available
207#endif
208#if BX_ELTORITO_BOOT && !BX_USE_ATADRV
209# error El-Torito Boot can only be use if ATA/ATAPI Driver is available
210#endif
211#if BX_PCIBIOS && BX_CPU<3
212# error PCI BIOS can only be used with 386+ cpu
213#endif
214#if BX_APM && BX_CPU<3
215# error APM BIOS can only be used with 386+ cpu
216#endif
217
218#if defined(VBOX) && !BX_USE_ATADRV
219# error VBOX requires enabling the ATA/ATAPI driver
220#endif
221
222#ifdef VBOX_WITH_SCSI
223/* Enough for now */
224# define BX_MAX_SCSI_DEVICES 4
225# define BX_MAX_STORAGE_DEVICES (BX_MAX_ATA_DEVICES + BX_MAX_SCSI_DEVICES)
226
227/* A SCSI device starts always at BX_MAX_ATA_DEVICES. */
228# define VBOX_IS_SCSI_DEVICE(device_id) (device_id >= BX_MAX_ATA_DEVICES)
229# define VBOX_GET_SCSI_DEVICE(device_id) (device_id - BX_MAX_ATA_DEVICES)
230#else
231# define BX_MAX_STORAGE_DEVICES BX_MAX_ATA_DEVICES
232#endif
233
234#ifndef VBOX
235#define PANIC_PORT 0x400
236#define PANIC_PORT2 0x401
237#define INFO_PORT 0x402
238#define DEBUG_PORT 0x403
239#else /* VBOX */
240/* Redirect INFO output to backdoor logging port. */
241#define PANIC_PORT 0x400
242#define PANIC_PORT2 0x401
243#define INFO_PORT 0x504
244#define DEBUG_PORT 0x403
245#endif /* VBOX */
246
247// define this if you want to make PCIBIOS working on a specific bridge only
248// undef enables PCIBIOS when at least one PCI device is found
249// i440FX is emulated by Bochs and QEMU
250#define PCI_FIXED_HOST_BRIDGE_1 0x12378086 ;; i440FX PCI bridge
251#define PCI_FIXED_HOST_BRIDGE_2 0x244e8086 ;; ICH9 PCI bridge
252
253// #20 is dec 20
254// #$20 is hex 20 = 32
255// #0x20 is hex 20 = 32
256// LDA #$20
257// JSR $E820
258// LDD .i,S
259// JSR $C682
260// mov al, #$20
261
262// all hex literals should be prefixed with '0x'
263// grep "#[0-9a-fA-F][0-9a-fA-F]" rombios.c
264// no mov SEG-REG, #value, must mov register into seg-reg
265// grep -i "mov[ ]*.s" rombios.c
266
267// This is for compiling with gcc2 and gcc3
268#define ASM_START #asm
269#define ASM_END #endasm
270
271ASM_START
272.rom
273
274.org 0x0000
275
276#if BX_CPU >= 3
277use16 386
278#else
279use16 286
280#endif
281
282MACRO HALT
283 ;; the HALT macro is called with the line number of the HALT call.
284 ;; The line number is then sent to the PANIC_PORT, causing Bochs/Plex
285 ;; to print a BX_PANIC message. This will normally halt the simulation
286 ;; with a message such as "BIOS panic at rombios.c, line 4091".
287 ;; However, users can choose to make panics non-fatal and continue.
288#if BX_VIRTUAL_PORTS
289 mov dx,#PANIC_PORT
290 mov ax,#?1
291 out dx,ax
292#else
293 mov dx,#0x80
294 mov ax,#?1
295 out dx,al
296#endif
297MEND
298
299MACRO JMP_AP
300 db 0xea
301 dw ?2
302 dw ?1
303MEND
304
305MACRO SET_INT_VECTOR
306 mov ax, ?3
307 mov ?1*4, ax
308 mov ax, ?2
309 mov ?1*4+2, ax
310MEND
311
312ASM_END
313
314typedef unsigned char Bit8u;
315typedef unsigned short Bit16u;
316typedef unsigned short bx_bool;
317typedef unsigned long Bit32u;
318
319#if BX_USE_ATADRV
320
321 void memsetb(seg,offset,value,count);
322 void memcpyb(dseg,doffset,sseg,soffset,count);
323 void memcpyd(dseg,doffset,sseg,soffset,count);
324
325 // memset of count bytes
326 void
327 memsetb(seg,offset,value,count)
328 Bit16u seg;
329 Bit16u offset;
330 Bit16u value;
331 Bit16u count;
332 {
333 ASM_START
334 push bp
335 mov bp, sp
336
337 push ax
338 push cx
339 push es
340 push di
341
342 mov cx, 10[bp] ; count
343 test cx, cx
344 je memsetb_end
345 mov ax, 4[bp] ; segment
346 mov es, ax
347 mov ax, 6[bp] ; offset
348 mov di, ax
349 mov al, 8[bp] ; value
350 cld
351 rep
352 stosb
353
354 memsetb_end:
355 pop di
356 pop es
357 pop cx
358 pop ax
359
360 pop bp
361 ASM_END
362 }
363
364#if 0
365 // memcpy of count bytes
366 void
367 memcpyb(dseg,doffset,sseg,soffset,count)
368 Bit16u dseg;
369 Bit16u doffset;
370 Bit16u sseg;
371 Bit16u soffset;
372 Bit16u count;
373 {
374 ASM_START
375 push bp
376 mov bp, sp
377
378 push ax
379 push cx
380 push es
381 push di
382 push ds
383 push si
384
385 mov cx, 12[bp] ; count
386 cmp cx, #0x0000
387 je memcpyb_end
388 mov ax, 4[bp] ; dsegment
389 mov es, ax
390 mov ax, 6[bp] ; doffset
391 mov di, ax
392 mov ax, 8[bp] ; ssegment
393 mov ds, ax
394 mov ax, 10[bp] ; soffset
395 mov si, ax
396 cld
397 rep
398 movsb
399
400 memcpyb_end:
401 pop si
402 pop ds
403 pop di
404 pop es
405 pop cx
406 pop ax
407
408 pop bp
409 ASM_END
410 }
411
412 // memcpy of count dword
413 void
414 memcpyd(dseg,doffset,sseg,soffset,count)
415 Bit16u dseg;
416 Bit16u doffset;
417 Bit16u sseg;
418 Bit16u soffset;
419 Bit16u count;
420 {
421 ASM_START
422 push bp
423 mov bp, sp
424
425 push ax
426 push cx
427 push es
428 push di
429 push ds
430 push si
431
432 mov cx, 12[bp] ; count
433 test cx, cx
434 je memcpyd_end
435 mov ax, 4[bp] ; dsegment
436 mov es, ax
437 mov ax, 6[bp] ; doffset
438 mov di, ax
439 mov ax, 8[bp] ; ssegment
440 mov ds, ax
441 mov ax, 10[bp] ; soffset
442 mov si, ax
443 cld
444 rep
445 movsd
446
447 memcpyd_end:
448 pop si
449 pop ds
450 pop di
451 pop es
452 pop cx
453 pop ax
454
455 pop bp
456 ASM_END
457 }
458#endif
459#endif //BX_USE_ATADRV
460
461 // read_dword and write_dword functions
462 static Bit32u read_dword();
463 static void write_dword();
464
465 Bit32u
466 read_dword(seg, offset)
467 Bit16u seg;
468 Bit16u offset;
469 {
470 ASM_START
471 push bp
472 mov bp, sp
473
474 push bx
475 push ds
476 mov ax, 4[bp] ; segment
477 mov ds, ax
478 mov bx, 6[bp] ; offset
479 mov ax, [bx]
480 add bx, #2
481 mov dx, [bx]
482 ;; ax = return value (word)
483 ;; dx = return value (word)
484 pop ds
485 pop bx
486
487 pop bp
488 ASM_END
489 }
490
491 void
492 write_dword(seg, offset, data)
493 Bit16u seg;
494 Bit16u offset;
495 Bit32u data;
496 {
497 ASM_START
498 push bp
499 mov bp, sp
500
501 push ax
502 push bx
503 push ds
504 mov ax, 4[bp] ; segment
505 mov ds, ax
506 mov bx, 6[bp] ; offset
507 mov ax, 8[bp] ; data word
508 mov [bx], ax ; write data word
509 add bx, #2
510 mov ax, 10[bp] ; data word
511 mov [bx], ax ; write data word
512 pop ds
513 pop bx
514 pop ax
515
516 pop bp
517 ASM_END
518 }
519
520 // Bit32u (unsigned long) and long helper functions
521 ASM_START
522
523 ;; and function
524 landl:
525 landul:
526 SEG SS
527 and ax,[di]
528 SEG SS
529 and bx,2[di]
530 ret
531
532 ;; add function
533 laddl:
534 laddul:
535 SEG SS
536 add ax,[di]
537 SEG SS
538 adc bx,2[di]
539 ret
540
541 ;; cmp function
542 lcmpl:
543 lcmpul:
544 and eax, #0x0000FFFF
545 shl ebx, #16
546 or eax, ebx
547 shr ebx, #16
548 SEG SS
549 cmp eax, dword ptr [di]
550 ret
551
552 ;; sub function
553 lsubl:
554 lsubul:
555 SEG SS
556 sub ax,[di]
557 SEG SS
558 sbb bx,2[di]
559 ret
560
561 ;; mul function
562 lmull:
563 lmulul:
564 and eax, #0x0000FFFF
565 shl ebx, #16
566 or eax, ebx
567 SEG SS
568 mul eax, dword ptr [di]
569 mov ebx, eax
570 shr ebx, #16
571 ret
572
573 ;; dec function
574 ldecl:
575 ldecul:
576 SEG SS
577 dec dword ptr [bx]
578 ret
579
580 ;; or function
581 lorl:
582 lorul:
583 SEG SS
584 or ax,[di]
585 SEG SS
586 or bx,2[di]
587 ret
588
589 ;; inc function
590 lincl:
591 lincul:
592 SEG SS
593 inc dword ptr [bx]
594 ret
595
596 ;; tst function
597 ltstl:
598 ltstul:
599 and eax, #0x0000FFFF
600 shl ebx, #16
601 or eax, ebx
602 shr ebx, #16
603 test eax, eax
604 ret
605
606 ;; sr function
607 lsrul:
608 mov cx,di
609 jcxz lsr_exit
610 and eax, #0x0000FFFF
611 shl ebx, #16
612 or eax, ebx
613 lsr_loop:
614 shr eax, #1
615 loop lsr_loop
616 mov ebx, eax
617 shr ebx, #16
618 lsr_exit:
619 ret
620
621 ;; sl function
622 lsll:
623 lslul:
624 mov cx,di
625 jcxz lsl_exit
626 and eax, #0x0000FFFF
627 shl ebx, #16
628 or eax, ebx
629 lsl_loop:
630 shl eax, #1
631 loop lsl_loop
632 mov ebx, eax
633 shr ebx, #16
634 lsl_exit:
635 ret
636
637 idiv_:
638 cwd
639 idiv bx
640 ret
641
642 idiv_u:
643 xor dx,dx
644 div bx
645 ret
646
647 ldivul:
648 and eax, #0x0000FFFF
649 shl ebx, #16
650 or eax, ebx
651 xor edx, edx
652 SEG SS
653 mov bx, 2[di]
654 shl ebx, #16
655 SEG SS
656 mov bx, [di]
657 div ebx
658 mov ebx, eax
659 shr ebx, #16
660 ret
661
662 ASM_END
663
664// for access to RAM area which is used by interrupt vectors
665// and BIOS Data Area
666
667typedef struct {
668 unsigned char filler1[0x400];
669 unsigned char filler2[0x6c];
670 Bit16u ticks_low;
671 Bit16u ticks_high;
672 Bit8u midnight_flag;
673 } bios_data_t;
674
675#define BiosData ((bios_data_t *) 0)
676
677#if BX_USE_ATADRV
678 typedef struct {
679 Bit16u heads; // # heads
680 Bit16u cylinders; // # cylinders
681 Bit16u spt; // # sectors / track
682 } chs_t;
683
684 // DPTE definition
685 typedef struct {
686 Bit16u iobase1;
687 Bit16u iobase2;
688 Bit8u prefix;
689 Bit8u unused;
690 Bit8u irq;
691 Bit8u blkcount;
692 Bit8u dma;
693 Bit8u pio;
694 Bit16u options;
695 Bit16u reserved;
696 Bit8u revision;
697 Bit8u checksum;
698 } dpte_t;
699
700 typedef struct {
701 Bit8u iface; // ISA or PCI
702 Bit16u iobase1; // IO Base 1
703 Bit16u iobase2; // IO Base 2
704 Bit8u irq; // IRQ
705 } ata_channel_t;
706
707 typedef struct {
708 Bit8u type; // Detected type of ata (ata/atapi/none/unknown/scsi)
709 Bit8u device; // Detected type of attached devices (hd/cd/none)
710 Bit8u removable; // Removable device flag
711 Bit8u lock; // Locks for removable devices
712 Bit8u mode; // transfer mode : PIO 16/32 bits - IRQ - ISADMA - PCIDMA
713 Bit16u blksize; // block size
714
715 Bit8u translation; // type of translation
716 chs_t lchs; // Logical CHS
717 chs_t pchs; // Physical CHS
718
719 Bit32u sectors; // Total sectors count
720 } ata_device_t;
721
722 typedef struct {
723 // ATA channels info
724 ata_channel_t channels[BX_MAX_ATA_INTERFACES];
725
726 // ATA devices info
727 ata_device_t devices[BX_MAX_ATA_DEVICES];
728 //
729 // map between (bios hd id - 0x80) and ata channels and scsi disks.
730 Bit8u hdcount, hdidmap[BX_MAX_STORAGE_DEVICES];
731
732 // map between (bios cd id - 0xE0) and ata channels
733 Bit8u cdcount, cdidmap[BX_MAX_STORAGE_DEVICES];
734
735 // Buffer for DPTE table
736 dpte_t dpte;
737
738 // Count of transferred sectors and bytes
739 Bit16u trsfsectors;
740 Bit32u trsfbytes;
741
742 } ata_t;
743
744#if BX_ELTORITO_BOOT
745 // ElTorito Device Emulation data
746 typedef struct {
747 Bit8u active;
748 Bit8u media;
749 Bit8u emulated_drive;
750 Bit8u controller_index;
751 Bit16u device_spec;
752 Bit32u ilba;
753 Bit16u buffer_segment;
754 Bit16u load_segment;
755 Bit16u sector_count;
756
757 // Virtual device
758 chs_t vdevice;
759 } cdemu_t;
760#endif // BX_ELTORITO_BOOT
761
762#ifdef VBOX_WITH_SCSI
763 typedef struct {
764 // I/O port this device is attached to.
765 Bit16u io_base;
766 // Target Id.
767 Bit8u target_id;
768 // SCSI devices info
769 ata_device_t device_info;
770 } scsi_device_t;
771
772 typedef struct {
773 // SCSi device info
774 scsi_device_t devices[BX_MAX_SCSI_DEVICES];
775 // Number of scsi disks.
776 Bit8u hdcount;
777 } scsi_t;
778#endif
779
780 // for access to EBDA area
781 // The EBDA structure should conform to
782 // http://www.frontiernet.net/~fys/rombios.htm document
783 // I made the ata and cdemu structs begin at 0x121 in the EBDA seg
784 typedef struct {
785 unsigned char filler1[0x3D];
786
787 // FDPT - Can be split into data members if needed
788 unsigned char fdpt0[0x10];
789 unsigned char fdpt1[0x10];
790
791 unsigned char filler2[0xC4];
792
793 // ATA Driver data
794 ata_t ata;
795
796#if BX_ELTORITO_BOOT
797 // El Torito Emulation data
798 cdemu_t cdemu;
799#endif // BX_ELTORITO_BOOT
800
801#ifdef VBOX
802
803#ifdef VBOX_WITH_SCSI
804 // SCSI Driver data
805 scsi_t scsi;
806# endif
807
808#ifdef VBOX_WITH_BIOS_AHCI
809 // AHCI driver data segment;
810 Bit16u SegAhci;
811#endif
812
813 unsigned char uForceBootDrive;
814 unsigned char uForceBootDevice;
815#endif /* VBOX */
816
817 } ebda_data_t;
818
819#ifdef VBOX
820 // the last 16 bytes of the EBDA segment are used for the MPS floating
821 // pointer structure (only if an IOAPIC is present)
822#endif
823
824 #define EbdaData ((ebda_data_t *) 0)
825
826 // for access to the int13ext structure
827 typedef struct {
828 Bit8u size;
829 Bit8u reserved;
830 Bit16u count;
831 Bit16u offset;
832 Bit16u segment;
833 Bit32u lba1;
834 Bit32u lba2;
835 } int13ext_t;
836
837 #define Int13Ext ((int13ext_t *) 0)
838
839 // Disk Physical Table definition
840 typedef struct {
841 Bit16u size;
842 Bit16u infos;
843 Bit32u cylinders;
844 Bit32u heads;
845 Bit32u spt;
846 Bit32u sector_count1;
847 Bit32u sector_count2;
848 Bit16u blksize;
849 Bit16u dpte_offset;
850 Bit16u dpte_segment;
851 Bit16u key;
852 Bit8u dpi_length;
853 Bit8u reserved1;
854 Bit16u reserved2;
855 Bit8u host_bus[4];
856 Bit8u iface_type[8];
857 Bit8u iface_path[8];
858 Bit8u device_path[8];
859 Bit8u reserved3;
860 Bit8u checksum;
861 } dpt_t;
862
863 #define Int13DPT ((dpt_t *) 0)
864
865#endif // BX_USE_ATADRV
866
867typedef struct {
868 union {
869 struct {
870 Bit16u di, si, bp, sp;
871 Bit16u bx, dx, cx, ax;
872 } r16;
873 struct {
874 Bit16u filler[4];
875 Bit8u bl, bh, dl, dh, cl, ch, al, ah;
876 } r8;
877 } u;
878 } pusha_regs_t;
879
880typedef struct {
881 union {
882 struct {
883 Bit32u edi, esi, ebp, esp;
884 Bit32u ebx, edx, ecx, eax;
885 } r32;
886 struct {
887 Bit16u di, filler1, si, filler2, bp, filler3, sp, filler4;
888 Bit16u bx, filler5, dx, filler6, cx, filler7, ax, filler8;
889 } r16;
890 struct {
891 Bit32u filler[4];
892 Bit8u bl, bh;
893 Bit16u filler1;
894 Bit8u dl, dh;
895 Bit16u filler2;
896 Bit8u cl, ch;
897 Bit16u filler3;
898 Bit8u al, ah;
899 Bit16u filler4;
900 } r8;
901 } u;
902} pushad_regs_t;
903
904typedef struct {
905 union {
906 struct {
907 Bit16u flags;
908 } r16;
909 struct {
910 Bit8u flagsl;
911 Bit8u flagsh;
912 } r8;
913 } u;
914 } flags_t;
915
916#define SetCF(x) x.u.r8.flagsl |= 0x01
917#define SetZF(x) x.u.r8.flagsl |= 0x40
918#define ClearCF(x) x.u.r8.flagsl &= 0xfe
919#define ClearZF(x) x.u.r8.flagsl &= 0xbf
920#define GetCF(x) (x.u.r8.flagsl & 0x01)
921
922typedef struct {
923 Bit16u ip;
924 Bit16u cs;
925 flags_t flags;
926 } iret_addr_t;
927
928
929
930static Bit8u inb();
931static Bit8u inb_cmos();
932static void outb();
933static void outb_cmos();
934static Bit16u inw();
935#ifdef VBOX_WITH_BIOS_AHCI
936static Bit32u inl();
937#endif
938static void outw();
939#ifdef VBOX_WITH_BIOS_AHCI
940static void outl();
941#endif
942static void init_rtc();
943static bx_bool rtc_updating();
944
945static Bit8u read_byte();
946static Bit16u read_word();
947static void write_byte();
948static void write_word();
949static void bios_printf();
950
951static Bit8u send_to_mouse_ctrl();
952static Bit8u get_mouse_data();
953static void set_kbd_command_byte();
954
955static void int09_function();
956static void int13_harddisk();
957static void int13_cdrom();
958static void int13_cdemu();
959static void int13_eltorito();
960static void int13_diskette_function();
961static void int14_function();
962static void int15_function();
963static void int16_function();
964static void int17_function();
965static Bit32u int19_function();
966static void int1a_function();
967static void int70_function();
968static void int74_function();
969static void dummy_isr_function();
970static Bit16u get_CS();
971static Bit16u get_SS();
972static unsigned int enqueue_key();
973static unsigned int dequeue_key();
974static void get_hd_geometry();
975static void set_diskette_ret_status();
976static void set_diskette_current_cyl();
977static void determine_floppy_media();
978static bx_bool floppy_drive_exists();
979static bx_bool floppy_drive_recal();
980static bx_bool floppy_media_known();
981static bx_bool floppy_media_sense();
982static bx_bool set_enable_a20();
983static void debugger_on();
984static void debugger_off();
985static void keyboard_init();
986static void keyboard_panic();
987static void shutdown_status_panic();
988static void nmi_handler_msg();
989
990static void print_bios_banner();
991static void print_boot_device();
992static void print_boot_failure();
993static void print_cdromboot_failure();
994
995# if BX_USE_ATADRV
996
997// ATA / ATAPI driver
998void ata_init();
999void ata_detect();
1000void ata_reset();
1001
1002Bit16u ata_cmd_non_data();
1003Bit16u ata_cmd_data_in();
1004Bit16u ata_cmd_data_out();
1005Bit16u ata_cmd_packet();
1006
1007Bit16u atapi_get_sense();
1008Bit16u atapi_is_ready();
1009Bit16u atapi_is_cdrom();
1010
1011#endif // BX_USE_ATADRV
1012
1013#if BX_ELTORITO_BOOT
1014
1015void cdemu_init();
1016Bit8u cdemu_isactive();
1017Bit8u cdemu_emulated_drive();
1018
1019Bit16u cdrom_boot();
1020
1021#endif // BX_ELTORITO_BOOT
1022
1023#ifdef VBOX
1024static char bios_prefix_string[] = "BIOS: ";
1025/* Do not use build timestamps in this string. Otherwise even rebuilding the
1026 * very same code will lead to compare errors when restoring saved state. */
1027static char bios_cvs_version_string[] = "VirtualBox " VBOX_VERSION_STRING;
1028#define BIOS_COPYRIGHT_STRING "Oracle VM VirtualBox BIOS"
1029#else /* !VBOX */
1030static char bios_cvs_version_string[] = "$Revision: 1.176 $ $Date: 2006/12/30 17:13:17 $";
1031
1032#define BIOS_COPYRIGHT_STRING "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team."
1033#endif /* !VBOX */
1034
1035#define BIOS_PRINTF_HALT 1
1036#define BIOS_PRINTF_SCREEN 2
1037#define BIOS_PRINTF_INFO 4
1038#define BIOS_PRINTF_DEBUG 8
1039#define BIOS_PRINTF_ALL (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO)
1040#define BIOS_PRINTF_DEBHALT (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO | BIOS_PRINTF_HALT)
1041
1042#define printf(format, p...) bios_printf(BIOS_PRINTF_SCREEN, format, ##p)
1043
1044// Defines the output macros.
1045// BX_DEBUG goes to INFO port until we can easily choose debug info on a
1046// per-device basis. Debug info are sent only in debug mode
1047#if DEBUG_ROMBIOS
1048# define BX_DEBUG(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
1049#else
1050# define BX_DEBUG(format, p...)
1051#endif
1052#ifdef VBOX
1053#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)
1054#else /* !VBOX */
1055#define BX_INFO(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
1056#endif /* !VBOX */
1057#define BX_PANIC(format, p...) bios_printf(BIOS_PRINTF_DEBHALT, format, ##p)
1058
1059#if DEBUG_ATA
1060# define BX_DEBUG_ATA(a...) BX_DEBUG(a)
1061#else
1062# define BX_DEBUG_ATA(a...)
1063#endif
1064#if DEBUG_INT13_HD
1065# define BX_DEBUG_INT13_HD(a...) BX_DEBUG(a)
1066#else
1067# define BX_DEBUG_INT13_HD(a...)
1068#endif
1069#if DEBUG_INT13_CD
1070# define BX_DEBUG_INT13_CD(a...) BX_DEBUG(a)
1071#else
1072# define BX_DEBUG_INT13_CD(a...)
1073#endif
1074#if DEBUG_INT13_ET
1075# define BX_DEBUG_INT13_ET(a...) BX_DEBUG(a)
1076#else
1077# define BX_DEBUG_INT13_ET(a...)
1078#endif
1079#if DEBUG_INT13_FL
1080# define BX_DEBUG_INT13_FL(a...) BX_DEBUG(a)
1081#else
1082# define BX_DEBUG_INT13_FL(a...)
1083#endif
1084#if DEBUG_INT15
1085# define BX_DEBUG_INT15(a...) BX_DEBUG(a)
1086#else
1087# define BX_DEBUG_INT15(a...)
1088#endif
1089#if DEBUG_INT16
1090# define BX_DEBUG_INT16(a...) BX_DEBUG(a)
1091#else
1092# define BX_DEBUG_INT16(a...)
1093#endif
1094#if DEBUG_INT1A
1095# define BX_DEBUG_INT1A(a...) BX_DEBUG(a)
1096#else
1097# define BX_DEBUG_INT1A(a...)
1098#endif
1099#if DEBUG_INT74
1100# define BX_DEBUG_INT74(a...) BX_DEBUG(a)
1101#else
1102# define BX_DEBUG_INT74(a...)
1103#endif
1104
1105#define SET_AL(val8) AX = ((AX & 0xff00) | (val8))
1106#define SET_BL(val8) BX = ((BX & 0xff00) | (val8))
1107#define SET_CL(val8) CX = ((CX & 0xff00) | (val8))
1108#define SET_DL(val8) DX = ((DX & 0xff00) | (val8))
1109#define SET_AH(val8) AX = ((AX & 0x00ff) | ((val8) << 8))
1110#define SET_BH(val8) BX = ((BX & 0x00ff) | ((val8) << 8))
1111#define SET_CH(val8) CX = ((CX & 0x00ff) | ((val8) << 8))
1112#define SET_DH(val8) DX = ((DX & 0x00ff) | ((val8) << 8))
1113
1114#define GET_AL() ( AX & 0x00ff )
1115#define GET_BL() ( BX & 0x00ff )
1116#define GET_CL() ( CX & 0x00ff )
1117#define GET_DL() ( DX & 0x00ff )
1118#define GET_AH() ( AX >> 8 )
1119#define GET_BH() ( BX >> 8 )
1120#define GET_CH() ( CX >> 8 )
1121#define GET_DH() ( DX >> 8 )
1122
1123#define GET_ELDL() ( ELDX & 0x00ff )
1124#define GET_ELDH() ( ELDX >> 8 )
1125
1126#define SET_CF() FLAGS |= 0x0001
1127#define CLEAR_CF() FLAGS &= 0xfffe
1128#define GET_CF() (FLAGS & 0x0001)
1129
1130#define SET_ZF() FLAGS |= 0x0040
1131#define CLEAR_ZF() FLAGS &= 0xffbf
1132#define GET_ZF() (FLAGS & 0x0040)
1133
1134#define UNSUPPORTED_FUNCTION 0x86
1135
1136#define none 0
1137#define MAX_SCAN_CODE 0x58
1138
1139static struct {
1140 Bit16u normal;
1141 Bit16u shift;
1142 Bit16u control;
1143 Bit16u alt;
1144 Bit8u lock_flags;
1145 } scan_to_scanascii[MAX_SCAN_CODE + 1] = {
1146 { none, none, none, none, none },
1147 { 0x011b, 0x011b, 0x011b, 0x0100, none }, /* escape */
1148 { 0x0231, 0x0221, none, 0x7800, none }, /* 1! */
1149 { 0x0332, 0x0340, 0x0300, 0x7900, none }, /* 2@ */
1150 { 0x0433, 0x0423, none, 0x7a00, none }, /* 3# */
1151 { 0x0534, 0x0524, none, 0x7b00, none }, /* 4$ */
1152 { 0x0635, 0x0625, none, 0x7c00, none }, /* 5% */
1153 { 0x0736, 0x075e, 0x071e, 0x7d00, none }, /* 6^ */
1154 { 0x0837, 0x0826, none, 0x7e00, none }, /* 7& */
1155 { 0x0938, 0x092a, none, 0x7f00, none }, /* 8* */
1156 { 0x0a39, 0x0a28, none, 0x8000, none }, /* 9( */
1157 { 0x0b30, 0x0b29, none, 0x8100, none }, /* 0) */
1158 { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200, none }, /* -_ */
1159 { 0x0d3d, 0x0d2b, none, 0x8300, none }, /* =+ */
1160 { 0x0e08, 0x0e08, 0x0e7f, none, none }, /* backspace */
1161 { 0x0f09, 0x0f00, none, none, none }, /* tab */
1162 { 0x1071, 0x1051, 0x1011, 0x1000, 0x40 }, /* Q */
1163 { 0x1177, 0x1157, 0x1117, 0x1100, 0x40 }, /* W */
1164 { 0x1265, 0x1245, 0x1205, 0x1200, 0x40 }, /* E */
1165 { 0x1372, 0x1352, 0x1312, 0x1300, 0x40 }, /* R */
1166 { 0x1474, 0x1454, 0x1414, 0x1400, 0x40 }, /* T */
1167 { 0x1579, 0x1559, 0x1519, 0x1500, 0x40 }, /* Y */
1168 { 0x1675, 0x1655, 0x1615, 0x1600, 0x40 }, /* U */
1169 { 0x1769, 0x1749, 0x1709, 0x1700, 0x40 }, /* I */
1170 { 0x186f, 0x184f, 0x180f, 0x1800, 0x40 }, /* O */
1171 { 0x1970, 0x1950, 0x1910, 0x1900, 0x40 }, /* P */
1172 { 0x1a5b, 0x1a7b, 0x1a1b, none, none }, /* [{ */
1173 { 0x1b5d, 0x1b7d, 0x1b1d, none, none }, /* ]} */
1174 { 0x1c0d, 0x1c0d, 0x1c0a, none, none }, /* Enter */
1175 { none, none, none, none, none }, /* L Ctrl */
1176 { 0x1e61, 0x1e41, 0x1e01, 0x1e00, 0x40 }, /* A */
1177 { 0x1f73, 0x1f53, 0x1f13, 0x1f00, 0x40 }, /* S */
1178 { 0x2064, 0x2044, 0x2004, 0x2000, 0x40 }, /* D */
1179 { 0x2166, 0x2146, 0x2106, 0x2100, 0x40 }, /* F */
1180 { 0x2267, 0x2247, 0x2207, 0x2200, 0x40 }, /* G */
1181 { 0x2368, 0x2348, 0x2308, 0x2300, 0x40 }, /* H */
1182 { 0x246a, 0x244a, 0x240a, 0x2400, 0x40 }, /* J */
1183 { 0x256b, 0x254b, 0x250b, 0x2500, 0x40 }, /* K */
1184 { 0x266c, 0x264c, 0x260c, 0x2600, 0x40 }, /* L */
1185 { 0x273b, 0x273a, none, none, none }, /* ;: */
1186 { 0x2827, 0x2822, none, none, none }, /* '" */
1187 { 0x2960, 0x297e, none, none, none }, /* `~ */
1188 { none, none, none, none, none }, /* L shift */
1189 { 0x2b5c, 0x2b7c, 0x2b1c, none, none }, /* |\ */
1190 { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, 0x40 }, /* Z */
1191 { 0x2d78, 0x2d58, 0x2d18, 0x2d00, 0x40 }, /* X */
1192 { 0x2e63, 0x2e43, 0x2e03, 0x2e00, 0x40 }, /* C */
1193 { 0x2f76, 0x2f56, 0x2f16, 0x2f00, 0x40 }, /* V */
1194 { 0x3062, 0x3042, 0x3002, 0x3000, 0x40 }, /* B */
1195 { 0x316e, 0x314e, 0x310e, 0x3100, 0x40 }, /* N */
1196 { 0x326d, 0x324d, 0x320d, 0x3200, 0x40 }, /* M */
1197 { 0x332c, 0x333c, none, none, none }, /* ,< */
1198 { 0x342e, 0x343e, none, none, none }, /* .> */
1199 { 0x352f, 0x353f, none, none, none }, /* /? */
1200 { none, none, none, none, none }, /* R Shift */
1201 { 0x372a, 0x372a, none, none, none }, /* * */
1202 { none, none, none, none, none }, /* L Alt */
1203 { 0x3920, 0x3920, 0x3920, 0x3920, none }, /* space */
1204 { none, none, none, none, none }, /* caps lock */
1205 { 0x3b00, 0x5400, 0x5e00, 0x6800, none }, /* F1 */
1206 { 0x3c00, 0x5500, 0x5f00, 0x6900, none }, /* F2 */
1207 { 0x3d00, 0x5600, 0x6000, 0x6a00, none }, /* F3 */
1208 { 0x3e00, 0x5700, 0x6100, 0x6b00, none }, /* F4 */
1209 { 0x3f00, 0x5800, 0x6200, 0x6c00, none }, /* F5 */
1210 { 0x4000, 0x5900, 0x6300, 0x6d00, none }, /* F6 */
1211 { 0x4100, 0x5a00, 0x6400, 0x6e00, none }, /* F7 */
1212 { 0x4200, 0x5b00, 0x6500, 0x6f00, none }, /* F8 */
1213 { 0x4300, 0x5c00, 0x6600, 0x7000, none }, /* F9 */
1214 { 0x4400, 0x5d00, 0x6700, 0x7100, none }, /* F10 */
1215 { none, none, none, none, none }, /* Num Lock */
1216 { none, none, none, none, none }, /* Scroll Lock */
1217 { 0x4700, 0x4737, 0x7700, none, 0x20 }, /* 7 Home */
1218 { 0x4800, 0x4838, none, none, 0x20 }, /* 8 UP */
1219 { 0x4900, 0x4939, 0x8400, none, 0x20 }, /* 9 PgUp */
1220 { 0x4a2d, 0x4a2d, none, none, none }, /* - */
1221 { 0x4b00, 0x4b34, 0x7300, none, 0x20 }, /* 4 Left */
1222 { 0x4c00, 0x4c35, none, none, 0x20 }, /* 5 */
1223 { 0x4d00, 0x4d36, 0x7400, none, 0x20 }, /* 6 Right */
1224 { 0x4e2b, 0x4e2b, none, none, none }, /* + */
1225 { 0x4f00, 0x4f31, 0x7500, none, 0x20 }, /* 1 End */
1226 { 0x5000, 0x5032, none, none, 0x20 }, /* 2 Down */
1227 { 0x5100, 0x5133, 0x7600, none, 0x20 }, /* 3 PgDn */
1228 { 0x5200, 0x5230, none, none, 0x20 }, /* 0 Ins */
1229 { 0x5300, 0x532e, none, none, 0x20 }, /* Del */
1230 { none, none, none, none, none },
1231 { none, none, none, none, none },
1232 { 0x565c, 0x567c, none, none, none }, /* \| */
1233#ifndef VBOX
1234 { 0x5700, 0x5700, none, none, none }, /* F11 */
1235 { 0x5800, 0x5800, none, none, none } /* F12 */
1236#else
1237 { 0x8500, 0x8700, 0x8900, 0x8b00, none }, /* F11 */
1238 { 0x8600, 0x8800, 0x8a00, 0x8c00, none } /* F12 */
1239#endif
1240 };
1241
1242 Bit8u
1243inb(port)
1244 Bit16u port;
1245{
1246ASM_START
1247 push bp
1248 mov bp, sp
1249
1250 push dx
1251 mov dx, 4[bp]
1252 in al, dx
1253 pop dx
1254
1255 pop bp
1256ASM_END
1257}
1258
1259#if BX_USE_ATADRV
1260 Bit16u
1261inw(port)
1262 Bit16u port;
1263{
1264ASM_START
1265 push bp
1266 mov bp, sp
1267
1268 push dx
1269 mov dx, 4[bp]
1270 in ax, dx
1271 pop dx
1272
1273 pop bp
1274ASM_END
1275}
1276#endif
1277
1278#ifdef VBOX_WITH_BIOS_AHCI
1279 Bit32u
1280inl(port)
1281 Bit16u port;
1282{
1283ASM_START
1284 push bp
1285 mov bp, sp
1286
1287 push bx
1288 mov dx, 4[bp]
1289 in eax, dx
1290 mov bx, ax ; Save lower 16 bits
1291 shr eax, #16
1292 mov dx, ax
1293 mov ax, bx
1294 pop bx
1295
1296 pop bp
1297ASM_END
1298}
1299#endif
1300
1301 void
1302outb(port, val)
1303 Bit16u port;
1304 Bit8u val;
1305{
1306ASM_START
1307 push bp
1308 mov bp, sp
1309
1310 push ax
1311 push dx
1312 mov dx, 4[bp]
1313 mov al, 6[bp]
1314 out dx, al
1315 pop dx
1316 pop ax
1317
1318 pop bp
1319ASM_END
1320}
1321
1322#if BX_USE_ATADRV
1323 void
1324outw(port, val)
1325 Bit16u port;
1326 Bit16u val;
1327{
1328ASM_START
1329 push bp
1330 mov bp, sp
1331
1332 push ax
1333 push dx
1334 mov dx, 4[bp]
1335 mov ax, 6[bp]
1336 out dx, ax
1337 pop dx
1338 pop ax
1339
1340 pop bp
1341ASM_END
1342}
1343#endif
1344
1345#ifdef VBOX_WITH_BIOS_AHCI
1346 void
1347outl(port, val)
1348 Bit16u port;
1349 Bit32u val;
1350{
1351ASM_START
1352 push bp
1353 mov bp, sp
1354
1355 push eax
1356 push dx
1357 mov dx, _outl.port + 2[bp]
1358 mov eax, _outl.val + 2[bp]
1359 out dx, eax
1360 pop dx
1361 pop eax
1362
1363 pop bp
1364ASM_END
1365}
1366#endif
1367
1368 void
1369outb_cmos(cmos_reg, val)
1370 Bit8u cmos_reg;
1371 Bit8u val;
1372{
1373ASM_START
1374 push bp
1375 mov bp, sp
1376
1377 mov al, 4[bp] ;; cmos_reg
1378 out 0x70, al
1379 mov al, 6[bp] ;; val
1380 out 0x71, al
1381
1382 pop bp
1383ASM_END
1384}
1385
1386 Bit8u
1387inb_cmos(cmos_reg)
1388 Bit8u cmos_reg;
1389{
1390ASM_START
1391 push bp
1392 mov bp, sp
1393
1394 mov al, 4[bp] ;; cmos_reg
1395 out 0x70, al
1396 in al, 0x71
1397
1398 pop bp
1399ASM_END
1400}
1401
1402 void
1403init_rtc()
1404{
1405 outb_cmos(0x0a, 0x26);
1406 outb_cmos(0x0b, 0x02);
1407 inb_cmos(0x0c);
1408 inb_cmos(0x0d);
1409}
1410
1411 bx_bool
1412rtc_updating()
1413{
1414 // This function checks to see if the update-in-progress bit
1415 // is set in CMOS Status Register A. If not, it returns 0.
1416 // If it is set, it tries to wait until there is a transition
1417 // to 0, and will return 0 if such a transition occurs. A 1
1418 // is returned only after timing out. The maximum period
1419 // that this bit should be set is constrained to 244useconds.
1420 // The count I use below guarantees coverage or more than
1421 // this time, with any reasonable IPS setting.
1422
1423 Bit16u count;
1424
1425 count = 25000;
1426 while (--count != 0) {
1427 if ( (inb_cmos(0x0a) & 0x80) == 0 )
1428 return(0);
1429 }
1430 return(1); // update-in-progress never transitioned to 0
1431}
1432
1433
1434 Bit8u
1435read_byte(seg, offset)
1436 Bit16u seg;
1437 Bit16u offset;
1438{
1439ASM_START
1440 push bp
1441 mov bp, sp
1442
1443 push bx
1444 push ds
1445 mov ax, 4[bp] ; segment
1446 mov ds, ax
1447 mov bx, 6[bp] ; offset
1448 mov al, [bx]
1449 ;; al = return value (byte)
1450 pop ds
1451 pop bx
1452
1453 pop bp
1454ASM_END
1455}
1456
1457 Bit16u
1458read_word(seg, offset)
1459 Bit16u seg;
1460 Bit16u offset;
1461{
1462ASM_START
1463 push bp
1464 mov bp, sp
1465
1466 push bx
1467 push ds
1468 mov ax, 4[bp] ; segment
1469 mov ds, ax
1470 mov bx, 6[bp] ; offset
1471 mov ax, [bx]
1472 ;; ax = return value (word)
1473 pop ds
1474 pop bx
1475
1476 pop bp
1477ASM_END
1478}
1479
1480 void
1481write_byte(seg, offset, data)
1482 Bit16u seg;
1483 Bit16u offset;
1484 Bit8u data;
1485{
1486ASM_START
1487 push bp
1488 mov bp, sp
1489
1490 push ax
1491 push bx
1492 push ds
1493 mov ax, 4[bp] ; segment
1494 mov ds, ax
1495 mov bx, 6[bp] ; offset
1496 mov al, 8[bp] ; data byte
1497 mov [bx], al ; write data byte
1498 pop ds
1499 pop bx
1500 pop ax
1501
1502 pop bp
1503ASM_END
1504}
1505
1506 void
1507write_word(seg, offset, data)
1508 Bit16u seg;
1509 Bit16u offset;
1510 Bit16u data;
1511{
1512ASM_START
1513 push bp
1514 mov bp, sp
1515
1516 push ax
1517 push bx
1518 push ds
1519 mov ax, 4[bp] ; segment
1520 mov ds, ax
1521 mov bx, 6[bp] ; offset
1522 mov ax, 8[bp] ; data word
1523 mov [bx], ax ; write data word
1524 pop ds
1525 pop bx
1526 pop ax
1527
1528 pop bp
1529ASM_END
1530}
1531
1532 Bit16u
1533get_CS()
1534{
1535ASM_START
1536 mov ax, cs
1537ASM_END
1538}
1539
1540 Bit16u
1541get_SS()
1542{
1543ASM_START
1544 mov ax, ss
1545ASM_END
1546}
1547
1548#if BX_DEBUG_SERIAL
1549/* serial debug port*/
1550#define BX_DEBUG_PORT 0x03f8
1551
1552/* data */
1553#define UART_RBR 0x00
1554#define UART_THR 0x00
1555
1556/* control */
1557#define UART_IER 0x01
1558#define UART_IIR 0x02
1559#define UART_FCR 0x02
1560#define UART_LCR 0x03
1561#define UART_MCR 0x04
1562#define UART_DLL 0x00
1563#define UART_DLM 0x01
1564
1565/* status */
1566#define UART_LSR 0x05
1567#define UART_MSR 0x06
1568#define UART_SCR 0x07
1569
1570int uart_can_tx_byte(base_port)
1571 Bit16u base_port;
1572{
1573 return inb(base_port + UART_LSR) & 0x20;
1574}
1575
1576void uart_wait_to_tx_byte(base_port)
1577 Bit16u base_port;
1578{
1579 while (!uart_can_tx_byte(base_port));
1580}
1581
1582void uart_wait_until_sent(base_port)
1583 Bit16u base_port;
1584{
1585 while (!(inb(base_port + UART_LSR) & 0x40));
1586}
1587
1588void uart_tx_byte(base_port, data)
1589 Bit16u base_port;
1590 Bit8u data;
1591{
1592 uart_wait_to_tx_byte(base_port);
1593 outb(base_port + UART_THR, data);
1594 uart_wait_until_sent(base_port);
1595}
1596#endif
1597
1598 void
1599wrch(c)
1600 Bit8u c;
1601{
1602 ASM_START
1603 push bp
1604 mov bp, sp
1605
1606 push bx
1607 mov ah, #0x0e
1608 mov al, 4[bp]
1609 xor bx,bx
1610 int #0x10
1611 pop bx
1612
1613 pop bp
1614 ASM_END
1615}
1616
1617 void
1618send(action, c)
1619 Bit16u action;
1620 Bit8u c;
1621{
1622#if BX_DEBUG_SERIAL
1623 if (c == '\n') uart_tx_byte(BX_DEBUG_PORT, '\r');
1624 uart_tx_byte(BX_DEBUG_PORT, c);
1625#endif
1626#if BX_VIRTUAL_PORTS
1627 if (action & BIOS_PRINTF_DEBUG) outb(DEBUG_PORT, c);
1628 if (action & BIOS_PRINTF_INFO) outb(INFO_PORT, c);
1629#endif
1630 if (action & BIOS_PRINTF_SCREEN) {
1631 if (c == '\n') wrch('\r');
1632 wrch(c);
1633 }
1634}
1635
1636 void
1637put_int(action, val, width, neg)
1638 Bit16u action;
1639 short val, width;
1640 bx_bool neg;
1641{
1642 short nval = val / 10;
1643 if (nval)
1644 put_int(action, nval, width - 1, neg);
1645 else {
1646 while (--width > 0) send(action, ' ');
1647 if (neg) send(action, '-');
1648 }
1649 send(action, val - (nval * 10) + '0');
1650}
1651
1652 void
1653put_uint(action, val, width, neg)
1654 Bit16u action;
1655 unsigned short val;
1656 short width;
1657 bx_bool neg;
1658{
1659 unsigned short nval = val / 10;
1660 if (nval)
1661 put_uint(action, nval, width - 1, neg);
1662 else {
1663 while (--width > 0) send(action, ' ');
1664 if (neg) send(action, '-');
1665 }
1666 send(action, val - (nval * 10) + '0');
1667}
1668
1669 void
1670put_luint(action, val, width, neg)
1671 Bit16u action;
1672 unsigned long val;
1673 short width;
1674 bx_bool neg;
1675{
1676 unsigned long nval = val / 10;
1677 if (nval)
1678 put_luint(action, nval, width - 1, neg);
1679 else {
1680 while (--width > 0) send(action, ' ');
1681 if (neg) send(action, '-');
1682 }
1683 send(action, val - (nval * 10) + '0');
1684}
1685
1686void put_str(action, segment, offset)
1687 Bit16u action;
1688 Bit16u segment;
1689 Bit16u offset;
1690{
1691 Bit8u c;
1692
1693 while (c = read_byte(segment, offset)) {
1694 send(action, c);
1695 offset++;
1696 }
1697}
1698
1699
1700//--------------------------------------------------------------------------
1701// bios_printf()
1702// A compact variable argument printf function.
1703//
1704// Supports %[format_width][length]format
1705// where format can be x,X,u,d,s,S,c
1706// and the optional length modifier is l (ell)
1707//--------------------------------------------------------------------------
1708 void
1709bios_printf(action, s)
1710 Bit16u action;
1711 Bit8u *s;
1712{
1713 Bit8u c, format_char;
1714 bx_bool in_format;
1715 short i;
1716 Bit16u *arg_ptr;
1717 Bit16u arg_seg, arg, nibble, hibyte, shift_count, format_width, hexadd;
1718
1719 arg_ptr = &s;
1720 arg_seg = get_SS();
1721
1722 in_format = 0;
1723 format_width = 0;
1724
1725 if ((action & BIOS_PRINTF_DEBHALT) == BIOS_PRINTF_DEBHALT) {
1726#if BX_VIRTUAL_PORTS
1727 outb(PANIC_PORT2, 0x00);
1728#endif
1729 bios_printf (BIOS_PRINTF_SCREEN, "FATAL: ");
1730 }
1731
1732 while (c = read_byte(get_CS(), s)) {
1733 if ( c == '%' ) {
1734 in_format = 1;
1735 format_width = 0;
1736 }
1737 else if (in_format) {
1738 if ( (c>='0') && (c<='9') ) {
1739 format_width = (format_width * 10) + (c - '0');
1740 }
1741 else {
1742 arg_ptr++; // increment to next arg
1743 arg = read_word(arg_seg, arg_ptr);
1744 if (c == 'x' || c == 'X') {
1745 if (format_width == 0)
1746 format_width = 4;
1747 if (c == 'x')
1748 hexadd = 'a';
1749 else
1750 hexadd = 'A';
1751 for (i=format_width-1; i>=0; i--) {
1752 nibble = (arg >> (4 * i)) & 0x000f;
1753 send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd));
1754 }
1755 }
1756 else if (c == 'u') {
1757 put_uint(action, arg, format_width, 0);
1758 }
1759 else if (c == 'l') {
1760 s++;
1761 c = read_byte(get_CS(), s); /* is it ld,lx,lu? */
1762 arg_ptr++; /* increment to next arg */
1763 hibyte = read_word(arg_seg, arg_ptr);
1764 if (c == 'd') {
1765 if (hibyte & 0x8000)
1766 put_luint(action, 0L-(((Bit32u) hibyte << 16) | arg), format_width-1, 1);
1767 else
1768 put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
1769 }
1770 else if (c == 'u') {
1771 put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
1772 }
1773 else if (c == 'x' || c == 'X')
1774 {
1775 if (format_width == 0)
1776 format_width = 8;
1777 if (c == 'x')
1778 hexadd = 'a';
1779 else
1780 hexadd = 'A';
1781 for (i=format_width-1; i>=0; i--) {
1782 nibble = ((((Bit32u) hibyte <<16) | arg) >> (4 * i)) & 0x000f;
1783 send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd));
1784 }
1785 }
1786 }
1787 else if (c == 'd') {
1788 if (arg & 0x8000)
1789 put_int(action, -arg, format_width - 1, 1);
1790 else
1791 put_int(action, arg, format_width, 0);
1792 }
1793 else if (c == 's') {
1794 put_str(action, get_CS(), arg);
1795 }
1796 else if (c == 'S') {
1797 hibyte = arg;
1798 arg_ptr++;
1799 arg = read_word(arg_seg, arg_ptr);
1800 put_str(action, hibyte, arg);
1801 }
1802 else if (c == 'c') {
1803 send(action, arg);
1804 }
1805 else
1806 BX_PANIC("bios_printf: unknown format\n");
1807 in_format = 0;
1808 }
1809 }
1810 else {
1811 send(action, c);
1812 }
1813 s ++;
1814 }
1815
1816 if (action & BIOS_PRINTF_HALT) {
1817 // freeze in a busy loop.
1818ASM_START
1819 cli
1820 halt2_loop:
1821 hlt
1822 jmp halt2_loop
1823ASM_END
1824 }
1825}
1826
1827//--------------------------------------------------------------------------
1828// keyboard_init
1829//--------------------------------------------------------------------------
1830// this file is based on LinuxBIOS implementation of keyboard.c
1831// could convert to #asm to gain space
1832 void
1833keyboard_init()
1834{
1835 Bit16u max;
1836
1837 /* ------------------- Flush buffers ------------------------*/
1838 /* Wait until buffer is empty */
1839 max=0xffff;
1840 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
1841
1842 /* flush incoming keys */
1843 max=4;
1844 while (--max > 0) {
1845 outb(0x80, 0x00);
1846 if (inb(0x64) & 0x01) {
1847 inb(0x60);
1848 max = 4;
1849 }
1850 }
1851
1852 // Due to timer issues, and if the IPS setting is > 15000000,
1853 // the incoming keys might not be flushed here. That will
1854 // cause a panic a few lines below. See sourceforge bug report :
1855 // [ 642031 ] FATAL: Keyboard RESET error:993
1856
1857 /* ------------------- controller side ----------------------*/
1858 /* send cmd = 0xAA, self test 8042 */
1859 outb(0x64, 0xaa);
1860
1861 /* Wait until buffer is empty */
1862 max=0xffff;
1863 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
1864 if (max==0x0) keyboard_panic(00);
1865
1866 /* Wait for data */
1867 max=0xffff;
1868 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x01);
1869 if (max==0x0) keyboard_panic(01);
1870
1871 /* read self-test result, 0x55 should be returned from 0x60 */
1872 if ((inb(0x60) != 0x55)){
1873 keyboard_panic(991);
1874 }
1875
1876 /* send cmd = 0xAB, keyboard interface test */
1877 outb(0x64,0xab);
1878
1879 /* Wait until buffer is empty */
1880 max=0xffff;
1881 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x10);
1882 if (max==0x0) keyboard_panic(10);
1883
1884 /* Wait for data */
1885 max=0xffff;
1886 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x11);
1887 if (max==0x0) keyboard_panic(11);
1888
1889 /* read keyboard interface test result, */
1890 /* 0x00 should be returned form 0x60 */
1891 if ((inb(0x60) != 0x00)) {
1892 keyboard_panic(992);
1893 }
1894
1895 /* Enable Keyboard clock */
1896 outb(0x64,0xae);
1897 outb(0x64,0xa8);
1898
1899 /* ------------------- keyboard side ------------------------*/
1900 /* reset keyboard and self test (keyboard side) */
1901 outb(0x60, 0xff);
1902
1903 /* Wait until buffer is empty */
1904 max=0xffff;
1905 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x20);
1906 if (max==0x0) keyboard_panic(20);
1907
1908 /* Wait for data */
1909 max=0xffff;
1910 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x21);
1911 if (max==0x0) keyboard_panic(21);
1912
1913 /* keyboard should return ACK */
1914 if ((inb(0x60) != 0xfa)) {
1915 keyboard_panic(993);
1916 }
1917
1918 /* Wait for data */
1919 max=0xffff;
1920 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x31);
1921 if (max==0x0) keyboard_panic(31);
1922
1923 if ((inb(0x60) != 0xaa)) {
1924 keyboard_panic(994);
1925 }
1926
1927 /* Disable keyboard */
1928 outb(0x60, 0xf5);
1929
1930 /* Wait until buffer is empty */
1931 max=0xffff;
1932 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x40);
1933 if (max==0x0) keyboard_panic(40);
1934
1935 /* Wait for data */
1936 max=0xffff;
1937 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x41);
1938 if (max==0x0) keyboard_panic(41);
1939
1940 /* keyboard should return ACK */
1941 if ((inb(0x60) != 0xfa)) {
1942 keyboard_panic(995);
1943 }
1944
1945 /* Write Keyboard Mode */
1946 outb(0x64, 0x60);
1947
1948 /* Wait until buffer is empty */
1949 max=0xffff;
1950 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x50);
1951 if (max==0x0) keyboard_panic(50);
1952
1953 /* send cmd: scan code convert, disable mouse, enable IRQ 1 */
1954 outb(0x60, 0x65);
1955
1956 /* Wait until buffer is empty */
1957 max=0xffff;
1958 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x60);
1959 if (max==0x0) keyboard_panic(60);
1960
1961 /* Enable keyboard */
1962 outb(0x60, 0xf4);
1963
1964 /* Wait until buffer is empty */
1965 max=0xffff;
1966 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x70);
1967 if (max==0x0) keyboard_panic(70);
1968
1969 /* Wait for data */
1970 max=0xffff;
1971 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x71);
1972 if (max==0x0) keyboard_panic(70);
1973
1974 /* keyboard should return ACK */
1975 if ((inb(0x60) != 0xfa)) {
1976 keyboard_panic(996);
1977 }
1978
1979 outb(0x80, 0x77);
1980}
1981
1982//--------------------------------------------------------------------------
1983// keyboard_panic
1984//--------------------------------------------------------------------------
1985 void
1986keyboard_panic(status)
1987 Bit16u status;
1988{
1989 // If you're getting a 993 keyboard panic here,
1990 // please see the comment in keyboard_init
1991
1992 BX_PANIC("Keyboard error:%u\n",status);
1993}
1994
1995//--------------------------------------------------------------------------
1996// shutdown_status_panic
1997// called when the shutdown status is not implemented, displays the status
1998//--------------------------------------------------------------------------
1999 void
2000shutdown_status_panic(status)
2001 Bit16u status;
2002{
2003 BX_PANIC("Unimplemented shutdown status: %02x\n",(Bit8u)status);
2004}
2005
2006#ifdef VBOX
2007#include "logo.c"
2008#endif /* VBOX */
2009
2010//--------------------------------------------------------------------------
2011// print_bios_banner
2012// displays a the bios version
2013//--------------------------------------------------------------------------
2014void
2015print_bios_banner()
2016{
2017#ifdef VBOX
2018 // Skip the logo if a warm boot is requested.
2019 Bit16u warm_boot = read_word(0x0040,0x0072);
2020 write_word(0x0040,0x0072, 0);
2021 if (warm_boot == 0x1234)
2022 return;
2023 /* show graphical logo */
2024 show_logo();
2025#else /* !VBOX */
2026 printf(BX_APPNAME" BIOS - build: %s\n%s\nOptions: ",
2027 BIOS_BUILD_DATE, bios_cvs_version_string);
2028 printf(
2029#if BX_APM
2030 "apmbios "
2031#endif
2032#if BX_PCIBIOS
2033 "pcibios "
2034#endif
2035#if BX_ELTORITO_BOOT
2036 "eltorito "
2037#endif
2038#if BX_ROMBIOS32
2039 "rombios32 "
2040#endif
2041 "\n\n");
2042#endif /* VBOX */
2043}
2044
2045//--------------------------------------------------------------------------
2046// print_boot_device
2047// displays the boot device
2048//--------------------------------------------------------------------------
2049
2050#ifdef VBOX
2051static char drivetypes[][10]={"Floppy","Hard Disk","CD-ROM","LAN"};
2052#else /* !VBOX */
2053static char drivetypes[][10]={"Floppy","Hard Disk","CD-Rom"};
2054#endif /* !VBOX */
2055
2056#ifdef VBOX
2057void
2058print_boot_device(cdboot, lanboot, drive)
2059 Bit8u cdboot; Bit8u lanboot; Bit16u drive;
2060#else /* !VBOX */
2061void
2062print_boot_device(cdboot, drive)
2063 Bit8u cdboot; Bit16u drive;
2064#endif /* !VBOX */
2065{
2066 Bit8u i;
2067
2068#ifdef VBOX
2069 // cdboot contains 0 if lan/floppy/harddisk, 1 otherwise
2070 // lanboot contains 0 if floppy/harddisk, 1 otherwise
2071#else /* !VBOX */
2072 // cdboot contains 0 if floppy/harddisk, 1 otherwise
2073#endif /* !VBOX */
2074 // drive contains real/emulated boot drive
2075
2076 if(cdboot)i=2; // CD-Rom
2077#ifdef VBOX
2078 else if(lanboot)i=3; // LAN
2079#endif /* VBOX */
2080 else if((drive&0x0080)==0x00)i=0; // Floppy
2081 else if((drive&0x0080)==0x80)i=1; // Hard drive
2082 else return;
2083
2084#ifdef VBOX
2085 BX_INFO("Booting from %s...\n",drivetypes[i]);
2086#else /* !VBOX */
2087 printf("Booting from %s...\n",drivetypes[i]);
2088#endif /* !VBOX */
2089}
2090
2091//--------------------------------------------------------------------------
2092// print_boot_failure
2093// displays the reason why boot failed
2094//--------------------------------------------------------------------------
2095#ifdef VBOX
2096 void
2097print_boot_failure(cdboot, lanboot, drive, reason, lastdrive)
2098 Bit8u cdboot; Bit8u lanboot; Bit8u drive; Bit8u reason; Bit8u lastdrive;
2099#else /* !VBOX */
2100 void
2101print_boot_failure(cdboot, drive, reason, lastdrive)
2102 Bit8u cdboot; Bit8u drive; Bit8u lastdrive;
2103#endif /* !VBOX */
2104{
2105 Bit16u drivenum = drive&0x7f;
2106
2107 // cdboot: 1 if boot from cd, 0 otherwise
2108#ifdef VBOX
2109 // lanboot: 1 if boot from lan, 0 otherwise
2110#endif /* VBOX */
2111 // drive : drive number
2112 // reason: 0 signature check failed, 1 read error
2113 // lastdrive: 1 boot drive is the last one in boot sequence
2114
2115 if (cdboot)
2116#ifndef VBOX
2117 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s failed\n",drivetypes[2]);
2118#else /* VBOX */
2119 BX_INFO("Boot from %s failed\n",drivetypes[2]);
2120 else if (lanboot)
2121 BX_INFO("Boot from %s failed\n",drivetypes[3]);
2122#endif /* VBOX */
2123 else if (drive & 0x80)
2124#ifndef VBOX
2125 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[1],drivenum);
2126#else /* VBOX */
2127 BX_INFO("Boot from %s %d failed\n", drivetypes[1],drivenum);
2128#endif /* VBOX */
2129 else
2130#ifndef VBOX
2131 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[0],drivenum);
2132#else /* VBOX */
2133 BX_INFO("Boot from %s %d failed\n", drivetypes[0],drivenum);
2134#endif /* VBOX */
2135
2136 if (lastdrive==1) {
2137 if (reason==0)
2138#ifndef VBOX
2139 BX_PANIC("Not a bootable disk\n");
2140#else /* VBOX */
2141 BX_PANIC("No bootable medium found! System halted.\n");
2142#endif /* VBOX */
2143 else
2144#ifndef VBOX
2145 BX_PANIC("Could not read the boot disk\n");
2146#else /* VBOX */
2147 BX_PANIC("Could not read from the boot medium! System halted.\n");
2148#endif /* VBOX */
2149 }
2150}
2151
2152//--------------------------------------------------------------------------
2153// print_cdromboot_failure
2154// displays the reason why boot failed
2155//--------------------------------------------------------------------------
2156 void
2157print_cdromboot_failure( code )
2158 Bit16u code;
2159{
2160#ifndef VBOX
2161 bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "CDROM boot failure code : %04x\n",code);
2162#else /* VBOX */
2163 BX_INFO("CDROM boot failure code : %04x\n",code);
2164#endif /* VBOX */
2165
2166 return;
2167}
2168
2169void
2170nmi_handler_msg()
2171{
2172 BX_PANIC("NMI Handler called\n");
2173}
2174
2175void
2176int18_panic_msg()
2177{
2178 BX_PANIC("INT18: BOOT FAILURE\n");
2179}
2180
2181void
2182log_bios_start()
2183{
2184#if BX_DEBUG_SERIAL
2185 outb(BX_DEBUG_PORT+UART_LCR, 0x03); /* setup for serial logging: 8N1 */
2186#endif
2187 BX_INFO("%s\n", bios_cvs_version_string);
2188}
2189
2190 bx_bool
2191set_enable_a20(val)
2192 bx_bool val;
2193{
2194 Bit8u oldval;
2195
2196 // Use PS2 System Control port A to set A20 enable
2197
2198 // get current setting first
2199 oldval = inb(0x92);
2200
2201 // change A20 status
2202 if (val)
2203 outb(0x92, oldval | 0x02);
2204 else
2205 outb(0x92, oldval & 0xfd);
2206
2207 return((oldval & 0x02) != 0);
2208}
2209
2210 void
2211debugger_on()
2212{
2213 outb(0xfedc, 0x01);
2214}
2215
2216 void
2217debugger_off()
2218{
2219 outb(0xfedc, 0x00);
2220}
2221
2222#if BX_USE_ATADRV
2223
2224// ---------------------------------------------------------------------------
2225// Start of ATA/ATAPI Driver
2226// ---------------------------------------------------------------------------
2227
2228// Global defines -- ATA register and register bits.
2229// command block & control block regs
2230#define ATA_CB_DATA 0 // data reg in/out pio_base_addr1+0
2231#define ATA_CB_ERR 1 // error in pio_base_addr1+1
2232#define ATA_CB_FR 1 // feature reg out pio_base_addr1+1
2233#define ATA_CB_SC 2 // sector count in/out pio_base_addr1+2
2234#define ATA_CB_SN 3 // sector number in/out pio_base_addr1+3
2235#define ATA_CB_CL 4 // cylinder low in/out pio_base_addr1+4
2236#define ATA_CB_CH 5 // cylinder high in/out pio_base_addr1+5
2237#define ATA_CB_DH 6 // device head in/out pio_base_addr1+6
2238#define ATA_CB_STAT 7 // primary status in pio_base_addr1+7
2239#define ATA_CB_CMD 7 // command out pio_base_addr1+7
2240#define ATA_CB_ASTAT 6 // alternate status in pio_base_addr2+6
2241#define ATA_CB_DC 6 // device control out pio_base_addr2+6
2242#define ATA_CB_DA 7 // device address in pio_base_addr2+7
2243
2244#define ATA_CB_ER_ICRC 0x80 // ATA Ultra DMA bad CRC
2245#define ATA_CB_ER_BBK 0x80 // ATA bad block
2246#define ATA_CB_ER_UNC 0x40 // ATA uncorrected error
2247#define ATA_CB_ER_MC 0x20 // ATA media change
2248#define ATA_CB_ER_IDNF 0x10 // ATA id not found
2249#define ATA_CB_ER_MCR 0x08 // ATA media change request
2250#define ATA_CB_ER_ABRT 0x04 // ATA command aborted
2251#define ATA_CB_ER_NTK0 0x02 // ATA track 0 not found
2252#define ATA_CB_ER_NDAM 0x01 // ATA address mark not found
2253
2254#define ATA_CB_ER_P_SNSKEY 0xf0 // ATAPI sense key (mask)
2255#define ATA_CB_ER_P_MCR 0x08 // ATAPI Media Change Request
2256#define ATA_CB_ER_P_ABRT 0x04 // ATAPI command abort
2257#define ATA_CB_ER_P_EOM 0x02 // ATAPI End of Media
2258#define ATA_CB_ER_P_ILI 0x01 // ATAPI Illegal Length Indication
2259
2260// ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC)
2261#define ATA_CB_SC_P_TAG 0xf8 // ATAPI tag (mask)
2262#define ATA_CB_SC_P_REL 0x04 // ATAPI release
2263#define ATA_CB_SC_P_IO 0x02 // ATAPI I/O
2264#define ATA_CB_SC_P_CD 0x01 // ATAPI C/D
2265
2266// bits 7-4 of the device/head (CB_DH) reg
2267#define ATA_CB_DH_DEV0 0xa0 // select device 0
2268#define ATA_CB_DH_DEV1 0xb0 // select device 1
2269
2270// status reg (CB_STAT and CB_ASTAT) bits
2271#define ATA_CB_STAT_BSY 0x80 // busy
2272#define ATA_CB_STAT_RDY 0x40 // ready
2273#define ATA_CB_STAT_DF 0x20 // device fault
2274#define ATA_CB_STAT_WFT 0x20 // write fault (old name)
2275#define ATA_CB_STAT_SKC 0x10 // seek complete
2276#define ATA_CB_STAT_SERV 0x10 // service
2277#define ATA_CB_STAT_DRQ 0x08 // data request
2278#define ATA_CB_STAT_CORR 0x04 // corrected
2279#define ATA_CB_STAT_IDX 0x02 // index
2280#define ATA_CB_STAT_ERR 0x01 // error (ATA)
2281#define ATA_CB_STAT_CHK 0x01 // check (ATAPI)
2282
2283// device control reg (CB_DC) bits
2284#define ATA_CB_DC_HD15 0x08 // bit should always be set to one
2285#define ATA_CB_DC_SRST 0x04 // soft reset
2286#define ATA_CB_DC_NIEN 0x02 // disable interrupts
2287
2288// Most mandatory and optional ATA commands (from ATA-3),
2289#define ATA_CMD_CFA_ERASE_SECTORS 0xC0
2290#define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03
2291#define ATA_CMD_CFA_TRANSLATE_SECTOR 0x87
2292#define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD
2293#define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38
2294#define ATA_CMD_CHECK_POWER_MODE1 0xE5
2295#define ATA_CMD_CHECK_POWER_MODE2 0x98
2296#define ATA_CMD_DEVICE_RESET 0x08
2297#define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90
2298#define ATA_CMD_FLUSH_CACHE 0xE7
2299#define ATA_CMD_FORMAT_TRACK 0x50
2300#define ATA_CMD_IDENTIFY_DEVICE 0xEC
2301#define ATA_CMD_IDENTIFY_DEVICE_PACKET 0xA1
2302#define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xA1
2303#define ATA_CMD_IDLE1 0xE3
2304#define ATA_CMD_IDLE2 0x97
2305#define ATA_CMD_IDLE_IMMEDIATE1 0xE1
2306#define ATA_CMD_IDLE_IMMEDIATE2 0x95
2307#define ATA_CMD_INITIALIZE_DRIVE_PARAMETERS 0x91
2308#define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
2309#define ATA_CMD_NOP 0x00
2310#define ATA_CMD_PACKET 0xA0
2311#define ATA_CMD_READ_BUFFER 0xE4
2312#define ATA_CMD_READ_DMA 0xC8
2313#define ATA_CMD_READ_DMA_QUEUED 0xC7
2314#define ATA_CMD_READ_MULTIPLE 0xC4
2315#define ATA_CMD_READ_SECTORS 0x20
2316#ifdef VBOX
2317#define ATA_CMD_READ_SECTORS_EXT 0x24
2318#define ATA_CMD_READ_MULTIPLE_EXT 0x29
2319#define ATA_CMD_WRITE_MULTIPLE_EXT 0x39
2320#endif /* VBOX */
2321#define ATA_CMD_READ_VERIFY_SECTORS 0x40
2322#define ATA_CMD_RECALIBRATE 0x10
2323#define ATA_CMD_SEEK 0x70
2324#define ATA_CMD_SET_FEATURES 0xEF
2325#define ATA_CMD_SET_MULTIPLE_MODE 0xC6
2326#define ATA_CMD_SLEEP1 0xE6
2327#define ATA_CMD_SLEEP2 0x99
2328#define ATA_CMD_STANDBY1 0xE2
2329#define ATA_CMD_STANDBY2 0x96
2330#define ATA_CMD_STANDBY_IMMEDIATE1 0xE0
2331#define ATA_CMD_STANDBY_IMMEDIATE2 0x94
2332#define ATA_CMD_WRITE_BUFFER 0xE8
2333#define ATA_CMD_WRITE_DMA 0xCA
2334#define ATA_CMD_WRITE_DMA_QUEUED 0xCC
2335#define ATA_CMD_WRITE_MULTIPLE 0xC5
2336#define ATA_CMD_WRITE_SECTORS 0x30
2337#ifdef VBOX
2338#define ATA_CMD_WRITE_SECTORS_EXT 0x34
2339#endif /* VBOX */
2340#define ATA_CMD_WRITE_VERIFY 0x3C
2341
2342#define ATA_IFACE_NONE 0x00
2343#define ATA_IFACE_ISA 0x00
2344#define ATA_IFACE_PCI 0x01
2345
2346#define ATA_TYPE_NONE 0x00
2347#define ATA_TYPE_UNKNOWN 0x01
2348#define ATA_TYPE_ATA 0x02
2349#define ATA_TYPE_ATAPI 0x03
2350#ifdef VBOX
2351#define ATA_TYPE_SCSI 0x04 // SCSI disk
2352#endif
2353
2354#define ATA_DEVICE_NONE 0x00
2355#define ATA_DEVICE_HD 0xFF
2356#define ATA_DEVICE_CDROM 0x05
2357
2358#define ATA_MODE_NONE 0x00
2359#define ATA_MODE_PIO16 0x00
2360#define ATA_MODE_PIO32 0x01
2361#define ATA_MODE_ISADMA 0x02
2362#define ATA_MODE_PCIDMA 0x03
2363#define ATA_MODE_USEIRQ 0x10
2364
2365#define ATA_TRANSLATION_NONE 0
2366#define ATA_TRANSLATION_LBA 1
2367#define ATA_TRANSLATION_LARGE 2
2368#define ATA_TRANSLATION_RECHS 3
2369
2370#define ATA_DATA_NO 0x00
2371#define ATA_DATA_IN 0x01
2372#define ATA_DATA_OUT 0x02
2373
2374// ---------------------------------------------------------------------------
2375// ATA/ATAPI driver : initialization
2376// ---------------------------------------------------------------------------
2377void ata_init( )
2378{
2379 Bit16u ebda_seg=read_word(0x0040,0x000E);
2380 Bit8u channel, device;
2381
2382 // Channels info init.
2383 for (channel=0; channel<BX_MAX_ATA_INTERFACES; channel++) {
2384 write_byte(ebda_seg,&EbdaData->ata.channels[channel].iface,ATA_IFACE_NONE);
2385 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1,0x0);
2386 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2,0x0);
2387 write_byte(ebda_seg,&EbdaData->ata.channels[channel].irq,0);
2388 }
2389
2390 // Devices info init.
2391 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2392 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
2393 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_NONE);
2394 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable,0);
2395 write_byte(ebda_seg,&EbdaData->ata.devices[device].lock,0);
2396 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode,ATA_MODE_NONE);
2397 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,0x200);
2398 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation,ATA_TRANSLATION_NONE);
2399 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads,0);
2400 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders,0);
2401 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt,0);
2402 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads,0);
2403 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders,0);
2404 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt,0);
2405
2406 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors,0L);
2407 }
2408
2409 // hdidmap and cdidmap init.
2410 for (device=0; device<BX_MAX_STORAGE_DEVICES; device++) {
2411 write_byte(ebda_seg,&EbdaData->ata.hdidmap[device],BX_MAX_STORAGE_DEVICES);
2412 write_byte(ebda_seg,&EbdaData->ata.cdidmap[device],BX_MAX_STORAGE_DEVICES);
2413 }
2414
2415 write_byte(ebda_seg,&EbdaData->ata.hdcount,0);
2416 write_byte(ebda_seg,&EbdaData->ata.cdcount,0);
2417}
2418
2419// ---------------------------------------------------------------------------
2420// ATA/ATAPI driver : device detection
2421// ---------------------------------------------------------------------------
2422
2423void ata_detect( )
2424{
2425 Bit16u ebda_seg=read_word(0x0040,0x000E);
2426 Bit8u hdcount, cdcount, device, type;
2427 Bit8u buffer[0x0200];
2428
2429#if BX_MAX_ATA_INTERFACES > 0
2430 write_byte(ebda_seg,&EbdaData->ata.channels[0].iface,ATA_IFACE_ISA);
2431 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase1,0x1f0);
2432 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase2,0x3f0);
2433 write_byte(ebda_seg,&EbdaData->ata.channels[0].irq,14);
2434#endif
2435#if BX_MAX_ATA_INTERFACES > 1
2436 write_byte(ebda_seg,&EbdaData->ata.channels[1].iface,ATA_IFACE_ISA);
2437 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase1,0x170);
2438 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase2,0x370);
2439 write_byte(ebda_seg,&EbdaData->ata.channels[1].irq,15);
2440#endif
2441#if BX_MAX_ATA_INTERFACES > 2
2442 write_byte(ebda_seg,&EbdaData->ata.channels[2].iface,ATA_IFACE_ISA);
2443 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase1,0x1e8);
2444 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase2,0x3e0);
2445 write_byte(ebda_seg,&EbdaData->ata.channels[2].irq,12);
2446#endif
2447#if BX_MAX_ATA_INTERFACES > 3
2448 write_byte(ebda_seg,&EbdaData->ata.channels[3].iface,ATA_IFACE_ISA);
2449 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase1,0x168);
2450 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase2,0x360);
2451 write_byte(ebda_seg,&EbdaData->ata.channels[3].irq,11);
2452#endif
2453#if BX_MAX_ATA_INTERFACES > 4
2454#error Please fill the ATA interface informations
2455#endif
2456
2457 // Device detection
2458 hdcount=cdcount=0;
2459
2460 for(device=0; device<BX_MAX_ATA_DEVICES; device++) {
2461 Bit16u iobase1, iobase2;
2462 Bit8u channel, slave, shift;
2463 Bit8u sc, sn, cl, ch, st;
2464
2465 channel = device / 2;
2466 slave = device % 2;
2467
2468 iobase1 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1);
2469 iobase2 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2);
2470
2471 // Disable interrupts
2472 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2473
2474 // Look for device
2475 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2476 outb(iobase1+ATA_CB_SC, 0x55);
2477 outb(iobase1+ATA_CB_SN, 0xaa);
2478 outb(iobase1+ATA_CB_SC, 0xaa);
2479 outb(iobase1+ATA_CB_SN, 0x55);
2480 outb(iobase1+ATA_CB_SC, 0x55);
2481 outb(iobase1+ATA_CB_SN, 0xaa);
2482
2483 // If we found something
2484 sc = inb(iobase1+ATA_CB_SC);
2485 sn = inb(iobase1+ATA_CB_SN);
2486
2487 if ( (sc == 0x55) && (sn == 0xaa) ) {
2488 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_UNKNOWN);
2489
2490 // reset the channel
2491 ata_reset(device);
2492
2493 // check for ATA or ATAPI
2494 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2495 sc = inb(iobase1+ATA_CB_SC);
2496 sn = inb(iobase1+ATA_CB_SN);
2497 if ((sc==0x01) && (sn==0x01)) {
2498 cl = inb(iobase1+ATA_CB_CL);
2499 ch = inb(iobase1+ATA_CB_CH);
2500 st = inb(iobase1+ATA_CB_STAT);
2501
2502 if ((cl==0x14) && (ch==0xeb)) {
2503 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATAPI);
2504 } else if ((cl==0x00) && (ch==0x00) && (st!=0x00)) {
2505 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATA);
2506 } else if ((cl==0xff) && (ch==0xff)) {
2507 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
2508 }
2509 }
2510 }
2511
2512#ifdef VBOX
2513 // Enable interrupts
2514 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2515#endif /* VBOX */
2516
2517 type=read_byte(ebda_seg,&EbdaData->ata.devices[device].type);
2518
2519 // Now we send a IDENTIFY command to ATA device
2520 if(type == ATA_TYPE_ATA) {
2521 Bit32u sectors;
2522 Bit16u cylinders, heads, spt, blksize;
2523#ifdef VBOX
2524 Bit16u lcylinders, lheads, lspt;
2525 Bit8u chsgeo_base;
2526#endif /* VBOX */
2527 Bit8u translation, removable, mode;
2528
2529 //Temporary values to do the transfer
2530 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2531 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2532
2533 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE, 1, 0, 0, 0, 0L, get_SS(),buffer) !=0 )
2534 BX_PANIC("ata-detect: Failed to detect ATA device\n");
2535
2536 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2537 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2538#ifdef VBOX
2539 blksize = 512; /* There is no sector size field any more. */
2540#else /* !VBOX */
2541 blksize = read_word(get_SS(),buffer+10);
2542#endif /* !VBOX */
2543
2544 cylinders = read_word(get_SS(),buffer+(1*2)); // word 1
2545 heads = read_word(get_SS(),buffer+(3*2)); // word 3
2546 spt = read_word(get_SS(),buffer+(6*2)); // word 6
2547
2548 sectors = read_dword(get_SS(),buffer+(60*2)); // word 60 and word 61
2549#ifdef VBOX
2550 /** @todo update sectors to be a 64 bit number (also lba...). */
2551 if (sectors == 268435455)
2552 sectors = read_dword(get_SS(),buffer+(100*2)); // words 100 to 103 (someday)
2553 switch (device)
2554 {
2555 case 0:
2556 chsgeo_base = 0x1e;
2557 break;
2558 case 1:
2559 chsgeo_base = 0x26;
2560 break;
2561 case 2:
2562 chsgeo_base = 0x67;
2563 break;
2564 case 3:
2565 chsgeo_base = 0x70;
2566 break;
2567#ifndef VBOX_WITH_BIOS_AHCI
2568 case 4:
2569 chsgeo_base = 0x40;
2570 break;
2571 case 5:
2572 chsgeo_base = 0x48;
2573 break;
2574 case 6:
2575 chsgeo_base = 0x50;
2576 break;
2577 case 7:
2578 chsgeo_base = 0x58;
2579 break;
2580#endif
2581 default:
2582 chsgeo_base = 0;
2583 }
2584 if (chsgeo_base != 0)
2585 {
2586 lcylinders = inb_cmos(chsgeo_base) + (inb_cmos(chsgeo_base+1) << 8);
2587 lheads = inb_cmos(chsgeo_base+2);
2588 lspt = inb_cmos(chsgeo_base+7);
2589 }
2590 else
2591 {
2592 lcylinders = 0;
2593 lheads = 0;
2594 lspt = 0;
2595 }
2596 BX_INFO("ata%d-%d: PCHS=%u/%d/%d LCHS=%u/%u/%u\n", channel, slave, cylinders, heads, spt, lcylinders, lheads, lspt);
2597#endif /* VBOX */
2598
2599 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2600 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2601 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2602 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2603 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads, heads);
2604 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders, cylinders);
2605 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt, spt);
2606 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors, sectors);
2607#ifdef VBOX
2608 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, lheads);
2609 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, lcylinders);
2610 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, lspt);
2611 if (device < 2)
2612 {
2613 Bit8u sum, i;
2614 unsigned char *fdpt;
2615 if (device == 0)
2616 fdpt = &EbdaData->fdpt0;
2617 else
2618 fdpt = &EbdaData->fdpt1;
2619
2620 /* Update the DPT for drive 0/1 pointed to by Int41/46. This used
2621 * to be done at POST time with lots of ugly assembler code, which
2622 * isn't worth the effort of converting from AMI to Award CMOS
2623 * format. Just do it here. */
2624 write_word(ebda_seg, fdpt + 0x00, lcylinders);
2625 write_byte(ebda_seg, fdpt + 0x02, lheads);
2626 write_byte(ebda_seg, fdpt + 0x0e, lspt);
2627 write_word(ebda_seg, fdpt + 0x09, cylinders);
2628 write_byte(ebda_seg, fdpt + 0x0b, heads);
2629 write_byte(ebda_seg, fdpt + 0x04, spt);
2630 write_byte(ebda_seg, fdpt + 0x03, 0xa0);
2631 sum = 0;
2632 for (i = 0; i < 0xf; i++)
2633 sum += read_byte(ebda_seg, fdpt + i);
2634 sum = -sum;
2635 write_byte(ebda_seg, fdpt + 0x0f, sum);
2636 }
2637#else /* !VBOX */
2638 BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel, slave,cylinders, heads, spt);
2639
2640 translation = inb_cmos(0x39 + channel/2);
2641 for (shift=device%4; shift>0; shift--) translation >>= 2;
2642 translation &= 0x03;
2643
2644 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation, translation);
2645
2646 switch (translation) {
2647 case ATA_TRANSLATION_NONE:
2648 BX_INFO("none");
2649 break;
2650 case ATA_TRANSLATION_LBA:
2651 BX_INFO("lba");
2652 break;
2653 case ATA_TRANSLATION_LARGE:
2654 BX_INFO("large");
2655 break;
2656 case ATA_TRANSLATION_RECHS:
2657 BX_INFO("r-echs");
2658 break;
2659 }
2660 switch (translation) {
2661 case ATA_TRANSLATION_NONE:
2662 break;
2663 case ATA_TRANSLATION_LBA:
2664 spt = 63;
2665 sectors /= 63;
2666 heads = sectors / 1024;
2667 if (heads>128) heads = 255;
2668 else if (heads>64) heads = 128;
2669 else if (heads>32) heads = 64;
2670 else if (heads>16) heads = 32;
2671 else heads=16;
2672 cylinders = sectors / heads;
2673 break;
2674 case ATA_TRANSLATION_RECHS:
2675 // Take care not to overflow
2676 if (heads==16) {
2677 if(cylinders>61439) cylinders=61439;
2678 heads=15;
2679 cylinders = (Bit16u)((Bit32u)(cylinders)*16/15);
2680 }
2681 // then go through the large bitshift process
2682 case ATA_TRANSLATION_LARGE:
2683 while(cylinders > 1024) {
2684 cylinders >>= 1;
2685 heads <<= 1;
2686
2687 // If we max out the head count
2688 if (heads > 127) break;
2689 }
2690 break;
2691 }
2692 // clip to 1024 cylinders in lchs
2693 if (cylinders > 1024) cylinders=1024;
2694 BX_INFO(" LCHS=%d/%d/%d\n", cylinders, heads, spt);
2695
2696 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, heads);
2697 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, cylinders);
2698 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, spt);
2699#endif /* VBOX */
2700
2701 // fill hdidmap
2702 write_byte(ebda_seg,&EbdaData->ata.hdidmap[hdcount], device);
2703 hdcount++;
2704 }
2705
2706 // Now we send a IDENTIFY command to ATAPI device
2707 if(type == ATA_TYPE_ATAPI) {
2708
2709 Bit8u type, removable, mode;
2710 Bit16u blksize;
2711
2712 //Temporary values to do the transfer
2713 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_CDROM);
2714 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2715
2716 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE_PACKET, 1, 0, 0, 0, 0L, get_SS(),buffer) != 0)
2717 BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
2718
2719 type = read_byte(get_SS(),buffer+1) & 0x1f;
2720 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2721 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2722 blksize = 2048;
2723
2724 write_byte(ebda_seg,&EbdaData->ata.devices[device].device, type);
2725 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2726 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2727 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2728
2729 // fill cdidmap
2730 write_byte(ebda_seg,&EbdaData->ata.cdidmap[cdcount], device);
2731 cdcount++;
2732 }
2733
2734#ifdef VBOX
2735 // we don't want any noisy output for now
2736#else /* !VBOX */
2737 {
2738 Bit32u sizeinmb;
2739 Bit16u ataversion;
2740 Bit8u c, i, version, model[41];
2741
2742 switch (type) {
2743 case ATA_TYPE_ATA:
2744 sizeinmb = read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors);
2745 sizeinmb >>= 11;
2746 case ATA_TYPE_ATAPI:
2747 // Read ATA/ATAPI version
2748 ataversion=((Bit16u)(read_byte(get_SS(),buffer+161))<<8)|read_byte(get_SS(),buffer+160);
2749 for(version=15;version>0;version--) {
2750 if((ataversion&(1<<version))!=0)
2751 break;
2752 }
2753
2754 // Read model name
2755 for(i=0;i<20;i++){
2756 write_byte(get_SS(),model+(i*2),read_byte(get_SS(),buffer+(i*2)+54+1));
2757 write_byte(get_SS(),model+(i*2)+1,read_byte(get_SS(),buffer+(i*2)+54));
2758 }
2759
2760 // Reformat
2761 write_byte(get_SS(),model+40,0x00);
2762 for(i=39;i>0;i--){
2763 if(read_byte(get_SS(),model+i)==0x20)
2764 write_byte(get_SS(),model+i,0x00);
2765 else break;
2766 }
2767 break;
2768 }
2769
2770 switch (type) {
2771 case ATA_TYPE_ATA:
2772 printf("ata%d %s: ",channel,slave?" slave":"master");
2773 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2774 printf(" ATA-%d Hard-Disk (%lu MBytes)\n", version, sizeinmb);
2775 break;
2776 case ATA_TYPE_ATAPI:
2777 printf("ata%d %s: ",channel,slave?" slave":"master");
2778 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2779 if(read_byte(ebda_seg,&EbdaData->ata.devices[device].device)==ATA_DEVICE_CDROM)
2780 printf(" ATAPI-%d CD-Rom/DVD-Rom\n",version);
2781 else
2782 printf(" ATAPI-%d Device\n",version);
2783 break;
2784 case ATA_TYPE_UNKNOWN:
2785 printf("ata%d %s: Unknown device\n",channel,slave?" slave":"master");
2786 break;
2787 }
2788 }
2789#endif /* !VBOX */
2790 }
2791
2792 // Store the devices counts
2793 write_byte(ebda_seg,&EbdaData->ata.hdcount, hdcount);
2794 write_byte(ebda_seg,&EbdaData->ata.cdcount, cdcount);
2795 write_byte(0x40,0x75, hdcount);
2796
2797#ifdef VBOX
2798 // we don't want any noisy output for now
2799#else /* !VBOX */
2800 printf("\n");
2801#endif /* !VBOX */
2802
2803 // FIXME : should use bios=cmos|auto|disable bits
2804 // FIXME : should know about translation bits
2805 // FIXME : move hard_drive_post here
2806
2807}
2808
2809// ---------------------------------------------------------------------------
2810// ATA/ATAPI driver : software reset
2811// ---------------------------------------------------------------------------
2812// ATA-3
2813// 8.2.1 Software reset - Device 0
2814
2815void ata_reset(device)
2816Bit16u device;
2817{
2818 Bit16u ebda_seg=read_word(0x0040,0x000E);
2819 Bit16u iobase1, iobase2;
2820 Bit8u channel, slave, sn, sc;
2821 Bit16u max;
2822#ifdef VBOX
2823 Bit16u pdelay;
2824#endif /* VBOX */
2825
2826 channel = device / 2;
2827 slave = device % 2;
2828
2829 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2830 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2831
2832 // Reset
2833
2834// 8.2.1 (a) -- set SRST in DC
2835 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN | ATA_CB_DC_SRST);
2836
2837// 8.2.1 (b) -- wait for BSY
2838 max=0xff;
2839 while(--max>0) {
2840 Bit8u status = inb(iobase1+ATA_CB_STAT);
2841 if ((status & ATA_CB_STAT_BSY) != 0) break;
2842 }
2843
2844// 8.2.1 (f) -- clear SRST
2845 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2846
2847 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_NONE) {
2848
2849// 8.2.1 (g) -- check for sc==sn==0x01
2850 // select device
2851 outb(iobase1+ATA_CB_DH, slave?ATA_CB_DH_DEV1:ATA_CB_DH_DEV0);
2852 sc = inb(iobase1+ATA_CB_SC);
2853 sn = inb(iobase1+ATA_CB_SN);
2854
2855 if ( (sc==0x01) && (sn==0x01) ) {
2856
2857// 8.2.1 (h) -- wait for not BSY
2858#ifdef VBOX
2859 max=0xffff; /* The ATA specification says that the drive may be busy for up to 30 seconds. */
2860#else /* !VBOX */
2861 max=0xff;
2862#endif /* !VBOX */
2863 while(--max>0) {
2864 Bit8u status = inb(iobase1+ATA_CB_STAT);
2865 if ((status & ATA_CB_STAT_BSY) == 0) break;
2866#ifdef VBOX
2867 pdelay=0xffff;
2868 while (--pdelay>0) {
2869 /* nothing */
2870 }
2871#endif /* VBOX */
2872 }
2873 }
2874 }
2875
2876// 8.2.1 (i) -- wait for DRDY
2877#ifdef VBOX
2878 max=0x10; /* Speed up for virtual drives. Disks are immediately ready, CDs never */
2879#else /* !VBOX */
2880 max=0xfff;
2881#endif /* !VBOX */
2882 while(--max>0) {
2883 Bit8u status = inb(iobase1+ATA_CB_STAT);
2884 if ((status & ATA_CB_STAT_RDY) != 0) break;
2885 }
2886
2887 // Enable interrupts
2888 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2889}
2890
2891// ---------------------------------------------------------------------------
2892// ATA/ATAPI driver : execute a non data command
2893// ---------------------------------------------------------------------------
2894
2895Bit16u ata_cmd_non_data()
2896{return 0;}
2897
2898// ---------------------------------------------------------------------------
2899// ATA/ATAPI driver : execute a data-in command
2900// ---------------------------------------------------------------------------
2901 // returns
2902 // 0 : no error
2903 // 1 : BUSY bit set
2904 // 2 : read error
2905 // 3 : expected DRQ=1
2906 // 4 : no sectors left to read/verify
2907 // 5 : more sectors to read/verify
2908 // 6 : no sectors left to write
2909 // 7 : more sectors to write
2910Bit16u ata_cmd_data_in(device, command, count, cylinder, head, sector, lba, segment, offset)
2911Bit16u device, command, count, cylinder, head, sector, segment, offset;
2912Bit32u lba;
2913{
2914 Bit16u ebda_seg=read_word(0x0040,0x000E);
2915 Bit16u iobase1, iobase2, blksize, mult_blk_cnt;
2916 Bit8u channel, slave;
2917 Bit8u status, current, mode;
2918
2919 channel = device / 2;
2920 slave = device % 2;
2921
2922 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2923 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2924 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2925 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2926 if (blksize == 0) { /* If transfer size is exactly 64K */
2927 if (mode == ATA_MODE_PIO32) blksize=0x4000;
2928 else blksize=0x8000;
2929 } else {
2930 if (mode == ATA_MODE_PIO32) blksize>>=2;
2931 else blksize>>=1;
2932 }
2933
2934#ifdef VBOX
2935 status = inb(iobase1 + ATA_CB_STAT);
2936 if (status & ATA_CB_STAT_BSY)
2937 {
2938 BX_DEBUG_ATA("ata_cmd_data_in : disk busy\n");
2939 // Enable interrupts
2940 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2941 return 1;
2942 }
2943#endif /* VBOX */
2944
2945 // sector will be 0 only on lba access. Convert to lba-chs
2946 if (sector == 0) {
2947#ifdef VBOX
2948 if (lba + count >= 268435456)
2949 {
2950 sector = (lba & 0xff000000L) >> 24;
2951 cylinder = 0; /* The parameter lba is just a 32 bit value. */
2952 outb(iobase1 + ATA_CB_SC, (count & 0xff00) >> 8);
2953 outb(iobase1 + ATA_CB_SN, sector);
2954 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2955 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2956 /* Leave the bottom 24 bits as is, they are treated correctly by the
2957 * LBA28 code path. */
2958 lba &= 0xffffff;
2959 }
2960#endif /* VBOX */
2961 sector = (Bit16u) (lba & 0x000000ffL);
2962 lba >>= 8;
2963 cylinder = (Bit16u) (lba & 0x0000ffffL);
2964 lba >>= 16;
2965 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
2966 }
2967
2968 // Reset count of transferred data
2969 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2970 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2971 current = 0;
2972
2973#ifndef VBOX
2974 status = inb(iobase1 + ATA_CB_STAT);
2975 if (status & ATA_CB_STAT_BSY) return 1;
2976#endif /* !VBOX */
2977
2978 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2979 outb(iobase1 + ATA_CB_FR, 0x00);
2980 outb(iobase1 + ATA_CB_SC, count);
2981 outb(iobase1 + ATA_CB_SN, sector);
2982 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2983 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2984 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
2985 outb(iobase1 + ATA_CB_CMD, command);
2986
2987 if (command == ATA_CMD_READ_MULTIPLE || command == ATA_CMD_READ_MULTIPLE_EXT) {
2988 mult_blk_cnt = count;
2989 count = 1;
2990 } else {
2991 mult_blk_cnt = 1;
2992 }
2993
2994 while (1) {
2995 status = inb(iobase1 + ATA_CB_STAT);
2996 if ( !(status & ATA_CB_STAT_BSY) ) break;
2997 }
2998
2999 if (status & ATA_CB_STAT_ERR) {
3000 BX_DEBUG_ATA("ata_cmd_data_in : read error\n");
3001#ifdef VBOX
3002 // Enable interrupts
3003 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3004#endif /* VBOX */
3005 return 2;
3006 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
3007 BX_DEBUG_ATA("ata_cmd_data_in : DRQ not set (status %02x)\n", (unsigned) status);
3008#ifdef VBOX
3009 // Enable interrupts
3010 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3011#endif /* VBOX */
3012 return 3;
3013 }
3014
3015 // FIXME : move seg/off translation here
3016
3017ASM_START
3018 sti ;; enable higher priority interrupts
3019ASM_END
3020
3021 while (1) {
3022
3023ASM_START
3024 push bp
3025 mov bp, sp
3026 mov di, _ata_cmd_data_in.offset + 2[bp]
3027 mov ax, _ata_cmd_data_in.segment + 2[bp]
3028 mov cx, _ata_cmd_data_in.blksize + 2[bp]
3029
3030 ;; adjust if there will be an overrun. 2K max sector size
3031 cmp di, #0xf800 ;;
3032 jbe ata_in_no_adjust
3033
3034ata_in_adjust:
3035 sub di, #0x0800 ;; sub 2 kbytes from offset
3036 add ax, #0x0080 ;; add 2 Kbytes to segment
3037
3038ata_in_no_adjust:
3039 mov es, ax ;; segment in es
3040
3041 mov dx, _ata_cmd_data_in.iobase1 + 2[bp] ;; ATA data read port
3042
3043 mov ah, _ata_cmd_data_in.mode + 2[bp]
3044 cmp ah, #ATA_MODE_PIO32
3045 je ata_in_32
3046
3047ata_in_16:
3048 rep
3049 insw ;; CX words transferred from port(DX) to ES:[DI]
3050 jmp ata_in_done
3051
3052ata_in_32:
3053 rep
3054 insd ;; CX dwords transferred from port(DX) to ES:[DI]
3055
3056ata_in_done:
3057 mov _ata_cmd_data_in.offset + 2[bp], di
3058 mov _ata_cmd_data_in.segment + 2[bp], es
3059 pop bp
3060ASM_END
3061
3062 current += mult_blk_cnt;
3063 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
3064 count--;
3065#ifdef VBOX
3066 while (1) {
3067 status = inb(iobase1 + ATA_CB_STAT);
3068 if ( !(status & ATA_CB_STAT_BSY) ) break;
3069 }
3070#else /* !VBOX */
3071 status = inb(iobase1 + ATA_CB_STAT);
3072#endif /* !VBOX */
3073 if (count == 0) {
3074 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3075 != ATA_CB_STAT_RDY ) {
3076 BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n", (unsigned) status);
3077#ifdef VBOX
3078 // Enable interrupts
3079 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3080#endif /* VBOX */
3081 return 4;
3082 }
3083 break;
3084 }
3085 else {
3086 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3087 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3088 BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n", (unsigned) status);
3089#ifdef VBOX
3090 // Enable interrupts
3091 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3092#endif /* VBOX */
3093 return 5;
3094 }
3095 continue;
3096 }
3097 }
3098 // Enable interrupts
3099 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3100 return 0;
3101}
3102
3103// ---------------------------------------------------------------------------
3104// ATA/ATAPI driver : execute a data-out command
3105// ---------------------------------------------------------------------------
3106 // returns
3107 // 0 : no error
3108 // 1 : BUSY bit set
3109 // 2 : read error
3110 // 3 : expected DRQ=1
3111 // 4 : no sectors left to read/verify
3112 // 5 : more sectors to read/verify
3113 // 6 : no sectors left to write
3114 // 7 : more sectors to write
3115Bit16u ata_cmd_data_out(device, command, count, cylinder, head, sector, lba, segment, offset)
3116Bit16u device, command, count, cylinder, head, sector, segment, offset;
3117Bit32u lba;
3118{
3119 Bit16u ebda_seg=read_word(0x0040,0x000E);
3120 Bit16u iobase1, iobase2, blksize;
3121 Bit8u channel, slave;
3122 Bit8u status, current, mode;
3123
3124 channel = device / 2;
3125 slave = device % 2;
3126
3127 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
3128 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
3129 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
3130 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
3131 if (mode == ATA_MODE_PIO32) blksize>>=2;
3132 else blksize>>=1;
3133
3134#ifdef VBOX
3135 status = inb(iobase1 + ATA_CB_STAT);
3136 if (status & ATA_CB_STAT_BSY)
3137 {
3138 // Enable interrupts
3139 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3140 return 1;
3141 }
3142#endif /* VBOX */
3143
3144 // sector will be 0 only on lba access. Convert to lba-chs
3145 if (sector == 0) {
3146#ifdef VBOX
3147 if (lba + count >= 268435456)
3148 {
3149 sector = (lba & 0xff000000L) >> 24;
3150 cylinder = 0; /* The parameter lba is just a 32 bit value. */
3151 outb(iobase1 + ATA_CB_SC, (count & 0xff00) >> 8);
3152 outb(iobase1 + ATA_CB_SN, sector);
3153 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
3154 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
3155 /* Leave the bottom 24 bits as is, they are treated correctly by the
3156 * LBA28 code path. */
3157 lba &= 0xffffff;
3158 }
3159#endif /* VBOX */
3160 sector = (Bit16u) (lba & 0x000000ffL);
3161 lba >>= 8;
3162 cylinder = (Bit16u) (lba & 0x0000ffffL);
3163 lba >>= 16;
3164 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
3165 }
3166
3167 // Reset count of transferred data
3168 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
3169 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
3170 current = 0;
3171
3172#ifndef VBOX
3173 status = inb(iobase1 + ATA_CB_STAT);
3174 if (status & ATA_CB_STAT_BSY) return 1;
3175#endif /* !VBOX */
3176
3177 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
3178 outb(iobase1 + ATA_CB_FR, 0x00);
3179 outb(iobase1 + ATA_CB_SC, count);
3180 outb(iobase1 + ATA_CB_SN, sector);
3181 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
3182 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
3183 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
3184 outb(iobase1 + ATA_CB_CMD, command);
3185
3186 while (1) {
3187 status = inb(iobase1 + ATA_CB_STAT);
3188 if ( !(status & ATA_CB_STAT_BSY) ) break;
3189 }
3190
3191 if (status & ATA_CB_STAT_ERR) {
3192 BX_DEBUG_ATA("ata_cmd_data_out : read error\n");
3193#ifdef VBOX
3194 // Enable interrupts
3195 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3196#endif /* VBOX */
3197 return 2;
3198 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
3199 BX_DEBUG_ATA("ata_cmd_data_out : DRQ not set (status %02x)\n", (unsigned) status);
3200#ifdef VBOX
3201 // Enable interrupts
3202 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3203#endif /* VBOX */
3204 return 3;
3205 }
3206
3207 // FIXME : move seg/off translation here
3208
3209ASM_START
3210 sti ;; enable higher priority interrupts
3211ASM_END
3212
3213 while (1) {
3214
3215ASM_START
3216 push bp
3217 mov bp, sp
3218 mov si, _ata_cmd_data_out.offset + 2[bp]
3219 mov ax, _ata_cmd_data_out.segment + 2[bp]
3220 mov cx, _ata_cmd_data_out.blksize + 2[bp]
3221
3222 ;; adjust if there will be an overrun. 2K max sector size
3223 cmp si, #0xf800 ;;
3224 jbe ata_out_no_adjust
3225
3226ata_out_adjust:
3227 sub si, #0x0800 ;; sub 2 kbytes from offset
3228 add ax, #0x0080 ;; add 2 Kbytes to segment
3229
3230ata_out_no_adjust:
3231 mov es, ax ;; segment in es
3232
3233 mov dx, _ata_cmd_data_out.iobase1 + 2[bp] ;; ATA data write port
3234
3235 mov ah, _ata_cmd_data_out.mode + 2[bp]
3236 cmp ah, #ATA_MODE_PIO32
3237 je ata_out_32
3238
3239ata_out_16:
3240 seg ES
3241 rep
3242 outsw ;; CX words transferred from port(DX) to ES:[SI]
3243 jmp ata_out_done
3244
3245ata_out_32:
3246 seg ES
3247 rep
3248 outsd ;; CX dwords transferred from port(DX) to ES:[SI]
3249
3250ata_out_done:
3251 mov _ata_cmd_data_out.offset + 2[bp], si
3252 mov _ata_cmd_data_out.segment + 2[bp], es
3253 pop bp
3254ASM_END
3255
3256 current++;
3257 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
3258 count--;
3259#ifdef VBOX
3260 while (1) {
3261 status = inb(iobase1 + ATA_CB_STAT);
3262 if ( !(status & ATA_CB_STAT_BSY) ) break;
3263 }
3264#else /* !VBOX */
3265 status = inb(iobase1 + ATA_CB_STAT);
3266#endif /* VBOX */
3267 if (count == 0) {
3268 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3269 != ATA_CB_STAT_RDY ) {
3270 BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n", (unsigned) status);
3271#ifdef VBOX
3272 // Enable interrupts
3273 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3274#endif /* VBOX */
3275 return 6;
3276 }
3277 break;
3278 }
3279 else {
3280 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3281 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3282 BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n", (unsigned) status);
3283#ifdef VBOX
3284 // Enable interrupts
3285 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3286#endif /* VBOX */
3287 return 7;
3288 }
3289 continue;
3290 }
3291 }
3292 // Enable interrupts
3293 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3294 return 0;
3295}
3296
3297// ---------------------------------------------------------------------------
3298// ATA/ATAPI driver : execute a packet command
3299// ---------------------------------------------------------------------------
3300 // returns
3301 // 0 : no error
3302 // 1 : error in parameters
3303 // 2 : BUSY bit set
3304 // 3 : error
3305 // 4 : not ready
3306Bit16u ata_cmd_packet(device, cmdlen, cmdseg, cmdoff, header, length, inout, bufseg, bufoff)
3307Bit8u cmdlen,inout;
3308Bit16u device,cmdseg, cmdoff, bufseg, bufoff;
3309Bit16u header;
3310Bit32u length;
3311{
3312 Bit16u ebda_seg=read_word(0x0040,0x000E);
3313 Bit16u iobase1, iobase2;
3314 Bit16u lcount, lbefore, lafter, count;
3315 Bit8u channel, slave;
3316 Bit8u status, mode, lmode;
3317 Bit32u total, transfer;
3318
3319 channel = device / 2;
3320 slave = device % 2;
3321
3322 // Data out is not supported yet
3323 if (inout == ATA_DATA_OUT) {
3324 BX_INFO("ata_cmd_packet: DATA_OUT not supported yet\n");
3325 return 1;
3326 }
3327
3328 // The header length must be even
3329 if (header & 1) {
3330 BX_DEBUG_ATA("ata_cmd_packet : header must be even (%04x)\n",header);
3331 return 1;
3332 }
3333
3334 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
3335 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
3336 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
3337 transfer= 0L;
3338
3339 if (cmdlen < 12) cmdlen=12;
3340 if (cmdlen > 12) cmdlen=16;
3341 cmdlen>>=1;
3342
3343 // Reset count of transferred data
3344 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
3345 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
3346
3347 status = inb(iobase1 + ATA_CB_STAT);
3348 if (status & ATA_CB_STAT_BSY) return 2;
3349
3350 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
3351 // outb(iobase1 + ATA_CB_FR, 0x00);
3352 // outb(iobase1 + ATA_CB_SC, 0x00);
3353 // outb(iobase1 + ATA_CB_SN, 0x00);
3354 outb(iobase1 + ATA_CB_CL, 0xfff0 & 0x00ff);
3355 outb(iobase1 + ATA_CB_CH, 0xfff0 >> 8);
3356 outb(iobase1 + ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
3357 outb(iobase1 + ATA_CB_CMD, ATA_CMD_PACKET);
3358
3359 // Device should ok to receive command
3360 while (1) {
3361 status = inb(iobase1 + ATA_CB_STAT);
3362 if ( !(status & ATA_CB_STAT_BSY) ) break;
3363 }
3364
3365 if (status & ATA_CB_STAT_ERR) {
3366 BX_DEBUG_ATA("ata_cmd_packet : error, status is %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 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
3373 BX_DEBUG_ATA("ata_cmd_packet : DRQ not set (status %02x)\n", (unsigned) status);
3374#ifdef VBOX
3375 // Enable interrupts
3376 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3377#endif /* VBOX */
3378 return 4;
3379 }
3380
3381 // Normalize address
3382 cmdseg += (cmdoff / 16);
3383 cmdoff %= 16;
3384
3385 // Send command to device
3386ASM_START
3387 sti ;; enable higher priority interrupts
3388
3389 push bp
3390 mov bp, sp
3391
3392 mov si, _ata_cmd_packet.cmdoff + 2[bp]
3393 mov ax, _ata_cmd_packet.cmdseg + 2[bp]
3394 mov cx, _ata_cmd_packet.cmdlen + 2[bp]
3395 mov es, ax ;; segment in es
3396
3397 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data write port
3398
3399 seg ES
3400 rep
3401 outsw ;; CX words transferred from port(DX) to ES:[SI]
3402
3403 pop bp
3404ASM_END
3405
3406 if (inout == ATA_DATA_NO) {
3407 status = inb(iobase1 + ATA_CB_STAT);
3408 }
3409 else {
3410 while (1) {
3411
3412#ifdef VBOX
3413 while (1) {
3414 status = inb(iobase1 + ATA_CB_STAT);
3415 if ( !(status & ATA_CB_STAT_BSY) ) break;
3416 }
3417#else /* VBOX */
3418 status = inb(iobase1 + ATA_CB_STAT);
3419#endif /* VBOX */
3420
3421 // Check if command completed
3422 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_DRQ) ) ==0 ) break;
3423
3424 if (status & ATA_CB_STAT_ERR) {
3425 BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status);
3426#ifdef VBOX
3427 // Enable interrupts
3428 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3429#endif /* VBOX */
3430 return 3;
3431 }
3432
3433 // Device must be ready to send data
3434 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3435 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3436 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", status);
3437#ifdef VBOX
3438 // Enable interrupts
3439 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3440#endif /* VBOX */
3441 return 4;
3442 }
3443
3444 // Normalize address
3445 bufseg += (bufoff / 16);
3446 bufoff %= 16;
3447
3448 // Get the byte count
3449 lcount = ((Bit16u)(inb(iobase1 + ATA_CB_CH))<<8)+inb(iobase1 + ATA_CB_CL);
3450
3451 // adjust to read what we want
3452 if(header>lcount) {
3453 lbefore=lcount;
3454 header-=lcount;
3455 lcount=0;
3456 }
3457 else {
3458 lbefore=header;
3459 header=0;
3460 lcount-=lbefore;
3461 }
3462
3463 if(lcount>length) {
3464 lafter=lcount-length;
3465 lcount=length;
3466 length=0;
3467 }
3468 else {
3469 lafter=0;
3470 length-=lcount;
3471 }
3472
3473 // Save byte count
3474 count = lcount;
3475
3476 BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore+lcount+lafter,lbefore,lcount,lafter);
3477 BX_DEBUG_ATA("to 0x%04x:0x%04x\n",bufseg,bufoff);
3478
3479 // If counts not dividable by 4, use 16bits mode
3480 lmode = mode;
3481 if (lbefore & 0x03) lmode=ATA_MODE_PIO16;
3482 if (lcount & 0x03) lmode=ATA_MODE_PIO16;
3483 if (lafter & 0x03) lmode=ATA_MODE_PIO16;
3484
3485 // adds an extra byte if count are odd. before is always even
3486 if (lcount & 0x01) {
3487 lcount+=1;
3488 if ((lafter > 0) && (lafter & 0x01)) {
3489 lafter-=1;
3490 }
3491 }
3492
3493 if (lmode == ATA_MODE_PIO32) {
3494 lcount>>=2; lbefore>>=2; lafter>>=2;
3495 }
3496 else {
3497 lcount>>=1; lbefore>>=1; lafter>>=1;
3498 }
3499
3500 ; // FIXME bcc bug
3501
3502ASM_START
3503 push bp
3504 mov bp, sp
3505
3506 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data read port
3507
3508 mov cx, _ata_cmd_packet.lbefore + 2[bp]
3509 jcxz ata_packet_no_before
3510
3511 mov ah, _ata_cmd_packet.lmode + 2[bp]
3512 cmp ah, #ATA_MODE_PIO32
3513 je ata_packet_in_before_32
3514
3515ata_packet_in_before_16:
3516 in ax, dx
3517 loop ata_packet_in_before_16
3518 jmp ata_packet_no_before
3519
3520ata_packet_in_before_32:
3521 push eax
3522ata_packet_in_before_32_loop:
3523 in eax, dx
3524 loop ata_packet_in_before_32_loop
3525 pop eax
3526
3527ata_packet_no_before:
3528 mov cx, _ata_cmd_packet.lcount + 2[bp]
3529 jcxz ata_packet_after
3530
3531 mov di, _ata_cmd_packet.bufoff + 2[bp]
3532 mov ax, _ata_cmd_packet.bufseg + 2[bp]
3533 mov es, ax
3534
3535 mov ah, _ata_cmd_packet.lmode + 2[bp]
3536 cmp ah, #ATA_MODE_PIO32
3537 je ata_packet_in_32
3538
3539ata_packet_in_16:
3540 rep
3541 insw ;; CX words transferred tp port(DX) to ES:[DI]
3542 jmp ata_packet_after
3543
3544ata_packet_in_32:
3545 rep
3546 insd ;; CX dwords transferred to port(DX) to ES:[DI]
3547
3548ata_packet_after:
3549 mov cx, _ata_cmd_packet.lafter + 2[bp]
3550 jcxz ata_packet_done
3551
3552 mov ah, _ata_cmd_packet.lmode + 2[bp]
3553 cmp ah, #ATA_MODE_PIO32
3554 je ata_packet_in_after_32
3555
3556ata_packet_in_after_16:
3557 in ax, dx
3558 loop ata_packet_in_after_16
3559 jmp ata_packet_done
3560
3561ata_packet_in_after_32:
3562 push eax
3563ata_packet_in_after_32_loop:
3564 in eax, dx
3565 loop ata_packet_in_after_32_loop
3566 pop eax
3567
3568ata_packet_done:
3569 pop bp
3570ASM_END
3571
3572 // Compute new buffer address
3573 bufoff += count;
3574
3575 // Save transferred bytes count
3576 transfer += count;
3577 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,transfer);
3578 }
3579 }
3580
3581 // Final check, device must be ready
3582 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3583 != ATA_CB_STAT_RDY ) {
3584 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", (unsigned) status);
3585#ifdef VBOX
3586 // Enable interrupts
3587 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3588#endif /* VBOX */
3589 return 4;
3590 }
3591
3592 // Enable interrupts
3593 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3594 return 0;
3595}
3596
3597// ---------------------------------------------------------------------------
3598// End of ATA/ATAPI Driver
3599// ---------------------------------------------------------------------------
3600
3601// ---------------------------------------------------------------------------
3602// Start of ATA/ATAPI generic functions
3603// ---------------------------------------------------------------------------
3604
3605#if 0 // currently unused
3606 Bit16u
3607atapi_get_sense(device)
3608 Bit16u device;
3609{
3610 Bit8u atacmd[12];
3611 Bit8u buffer[16];
3612 Bit8u i;
3613
3614 memsetb(get_SS(),atacmd,0,12);
3615
3616 // Request SENSE
3617 atacmd[0]=0x03;
3618 atacmd[4]=0x20;
3619 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 16L, ATA_DATA_IN, get_SS(), buffer) != 0)
3620 return 0x0002;
3621
3622 if ((buffer[0] & 0x7e) == 0x70) {
3623 return (((Bit16u)buffer[2]&0x0f)*0x100)+buffer[12];
3624 }
3625
3626 return 0;
3627}
3628
3629 Bit16u
3630atapi_is_ready(device)
3631 Bit16u device;
3632{
3633 Bit8u atacmd[12];
3634 Bit8u buffer[];
3635
3636 memsetb(get_SS(),atacmd,0,12);
3637
3638 // Test Unit Ready
3639 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3640 return 0x000f;
3641
3642 if (atapi_get_sense(device) !=0 ) {
3643 memsetb(get_SS(),atacmd,0,12);
3644
3645 // try to send Test Unit Ready again
3646 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3647 return 0x000f;
3648
3649 return atapi_get_sense(device);
3650 }
3651 return 0;
3652}
3653#endif
3654
3655 Bit16u
3656atapi_is_cdrom(device)
3657 Bit8u device;
3658{
3659 Bit16u ebda_seg=read_word(0x0040,0x000E);
3660
3661 if (device >= BX_MAX_ATA_DEVICES)
3662 return 0;
3663
3664 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_ATAPI)
3665 return 0;
3666
3667 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].device) != ATA_DEVICE_CDROM)
3668 return 0;
3669
3670 return 1;
3671}
3672
3673// ---------------------------------------------------------------------------
3674// End of ATA/ATAPI generic functions
3675// ---------------------------------------------------------------------------
3676
3677#endif // BX_USE_ATADRV
3678
3679#if BX_ELTORITO_BOOT
3680
3681// ---------------------------------------------------------------------------
3682// Start of El-Torito boot functions
3683// ---------------------------------------------------------------------------
3684
3685 void
3686cdemu_init()
3687{
3688 Bit16u ebda_seg=read_word(0x0040,0x000E);
3689
3690 // the only important data is this one for now
3691 write_byte(ebda_seg,&EbdaData->cdemu.active,0x00);
3692}
3693
3694 Bit8u
3695cdemu_isactive()
3696{
3697 Bit16u ebda_seg=read_word(0x0040,0x000E);
3698
3699 return(read_byte(ebda_seg,&EbdaData->cdemu.active));
3700}
3701
3702 Bit8u
3703cdemu_emulated_drive()
3704{
3705 Bit16u ebda_seg=read_word(0x0040,0x000E);
3706
3707 return(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
3708}
3709
3710static char isotag[6]="CD001";
3711static char eltorito[24]="EL TORITO SPECIFICATION";
3712//
3713// Returns ah: emulated drive, al: error code
3714//
3715 Bit16u
3716cdrom_boot()
3717{
3718 Bit16u ebda_seg=read_word(0x0040,0x000E);
3719 Bit8u atacmd[12], buffer[2048];
3720 Bit32u lba;
3721 Bit16u boot_segment, nbsectors, i, error;
3722 Bit8u device;
3723#ifdef VBOX
3724 Bit8u read_try;
3725#endif /* VBOX */
3726
3727 // Find out the first cdrom
3728 for (device=0; device<BX_MAX_ATA_DEVICES;device++) {
3729 if (atapi_is_cdrom(device)) break;
3730 }
3731
3732 // if not found
3733 if(device >= BX_MAX_ATA_DEVICES) return 2;
3734
3735 // Read the Boot Record Volume Descriptor
3736 memsetb(get_SS(),atacmd,0,12);
3737 atacmd[0]=0x28; // READ command
3738 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3739 atacmd[8]=(0x01 & 0x00ff); // Sectors
3740 atacmd[2]=(0x11 & 0xff000000) >> 24; // LBA
3741 atacmd[3]=(0x11 & 0x00ff0000) >> 16;
3742 atacmd[4]=(0x11 & 0x0000ff00) >> 8;
3743 atacmd[5]=(0x11 & 0x000000ff);
3744#ifdef VBOX
3745 for (read_try = 0; read_try <= 4; read_try++)
3746 {
3747 error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer);
3748 if (!error)
3749 break;
3750 }
3751 if (error)
3752 return 3;
3753#else /* !VBOX */
3754 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3755 return 3;
3756#endif /* !VBOX */
3757
3758 // Validity checks
3759 if(buffer[0]!=0)return 4;
3760 for(i=0;i<5;i++){
3761 if(buffer[1+i]!=read_byte(0xf000,&isotag[i]))return 5;
3762 }
3763 for(i=0;i<23;i++)
3764 if(buffer[7+i]!=read_byte(0xf000,&eltorito[i]))return 6;
3765
3766 // ok, now we calculate the Boot catalog address
3767 lba=buffer[0x4A]*0x1000000+buffer[0x49]*0x10000+buffer[0x48]*0x100+buffer[0x47];
3768
3769 // And we read the Boot Catalog
3770 memsetb(get_SS(),atacmd,0,12);
3771 atacmd[0]=0x28; // READ command
3772 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3773 atacmd[8]=(0x01 & 0x00ff); // Sectors
3774 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3775 atacmd[3]=(lba & 0x00ff0000) >> 16;
3776 atacmd[4]=(lba & 0x0000ff00) >> 8;
3777 atacmd[5]=(lba & 0x000000ff);
3778 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3779 return 7;
3780
3781 // Validation entry
3782 if(buffer[0x00]!=0x01)return 8; // Header
3783 if(buffer[0x01]!=0x00)return 9; // Platform
3784 if(buffer[0x1E]!=0x55)return 10; // key 1
3785 if(buffer[0x1F]!=0xAA)return 10; // key 2
3786
3787 // Initial/Default Entry
3788 if(buffer[0x20]!=0x88)return 11; // Bootable
3789
3790 write_byte(ebda_seg,&EbdaData->cdemu.media,buffer[0x21]);
3791 if(buffer[0x21]==0){
3792 // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
3793 // Win2000 cd boot needs to know it booted from cd
3794 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0xE0);
3795 }
3796 else if(buffer[0x21]<4)
3797 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x00);
3798 else
3799 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x80);
3800
3801 write_byte(ebda_seg,&EbdaData->cdemu.controller_index,device/2);
3802 write_byte(ebda_seg,&EbdaData->cdemu.device_spec,device%2);
3803
3804 boot_segment=buffer[0x23]*0x100+buffer[0x22];
3805 if(boot_segment==0x0000)boot_segment=0x07C0;
3806
3807 write_word(ebda_seg,&EbdaData->cdemu.load_segment,boot_segment);
3808 write_word(ebda_seg,&EbdaData->cdemu.buffer_segment,0x0000);
3809
3810 nbsectors=buffer[0x27]*0x100+buffer[0x26];
3811 write_word(ebda_seg,&EbdaData->cdemu.sector_count,nbsectors);
3812
3813 lba=buffer[0x2B]*0x1000000+buffer[0x2A]*0x10000+buffer[0x29]*0x100+buffer[0x28];
3814 write_dword(ebda_seg,&EbdaData->cdemu.ilba,lba);
3815
3816 // And we read the image in memory
3817 memsetb(get_SS(),atacmd,0,12);
3818 atacmd[0]=0x28; // READ command
3819 atacmd[7]=((1+(nbsectors-1)/4) & 0xff00) >> 8; // Sectors
3820 atacmd[8]=((1+(nbsectors-1)/4) & 0x00ff); // Sectors
3821 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3822 atacmd[3]=(lba & 0x00ff0000) >> 16;
3823 atacmd[4]=(lba & 0x0000ff00) >> 8;
3824 atacmd[5]=(lba & 0x000000ff);
3825 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, nbsectors*512L, ATA_DATA_IN, boot_segment,0)) != 0)
3826 return 12;
3827
3828 // Remember the media type
3829 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
3830 case 0x01: // 1.2M floppy
3831 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,15);
3832 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3833 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3834 break;
3835 case 0x02: // 1.44M floppy
3836 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,18);
3837 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3838 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3839 break;
3840 case 0x03: // 2.88M floppy
3841 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,36);
3842 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3843 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3844 break;
3845 case 0x04: // Harddrive
3846 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,read_byte(boot_segment,446+6)&0x3f);
3847 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,
3848 (read_byte(boot_segment,446+6)<<2) + read_byte(boot_segment,446+7) + 1);
3849 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,read_byte(boot_segment,446+5) + 1);
3850 break;
3851 }
3852
3853 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0) {
3854 // Increase bios installed hardware number of devices
3855 if(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)==0x00)
3856 write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
3857 else
3858 write_byte(ebda_seg, &EbdaData->ata.hdcount, read_byte(ebda_seg, &EbdaData->ata.hdcount) + 1);
3859 }
3860
3861
3862 // everything is ok, so from now on, the emulation is active
3863 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0)
3864 write_byte(ebda_seg,&EbdaData->cdemu.active,0x01);
3865
3866 // return the boot drive + no error
3867 return (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)*0x100)+0;
3868}
3869
3870// ---------------------------------------------------------------------------
3871// End of El-Torito boot functions
3872// ---------------------------------------------------------------------------
3873#endif // BX_ELTORITO_BOOT
3874
3875#ifdef VBOX_WITH_SCSI
3876# include "scsi.c"
3877#endif
3878
3879#ifdef VBOX_WITH_BIOS_AHCI
3880# include "ahci.c"
3881#endif
3882
3883 void
3884int14_function(regs, ds, iret_addr)
3885 pusha_regs_t regs; // regs pushed from PUSHA instruction
3886 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
3887 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
3888{
3889 Bit16u addr,timer,val16;
3890 Bit8u timeout;
3891
3892 ASM_START
3893 sti
3894 ASM_END
3895
3896 addr = read_word(0x0040, (regs.u.r16.dx << 1));
3897 timeout = read_byte(0x0040, 0x007C + regs.u.r16.dx);
3898 if ((regs.u.r16.dx < 4) && (addr > 0)) {
3899 switch (regs.u.r8.ah) {
3900 case 0:
3901 outb(addr+3, inb(addr+3) | 0x80);
3902 if (regs.u.r8.al & 0xE0 == 0) {
3903 outb(addr, 0x17);
3904 outb(addr+1, 0x04);
3905 } else {
3906 val16 = 0x600 >> ((regs.u.r8.al & 0xE0) >> 5);
3907 outb(addr, val16 & 0xFF);
3908 outb(addr+1, val16 >> 8);
3909 }
3910 outb(addr+3, regs.u.r8.al & 0x1F);
3911 regs.u.r8.ah = inb(addr+5);
3912 regs.u.r8.al = inb(addr+6);
3913 ClearCF(iret_addr.flags);
3914 break;
3915 case 1:
3916 timer = read_word(0x0040, 0x006C);
3917 while (((inb(addr+5) & 0x60) != 0x60) && (timeout)) {
3918 val16 = read_word(0x0040, 0x006C);
3919 if (val16 != timer) {
3920 timer = val16;
3921 timeout--;
3922 }
3923 }
3924 if (timeout) outb(addr, regs.u.r8.al);
3925 regs.u.r8.ah = inb(addr+5);
3926 if (!timeout) regs.u.r8.ah |= 0x80;
3927 ClearCF(iret_addr.flags);
3928 break;
3929 case 2:
3930 timer = read_word(0x0040, 0x006C);
3931 while (((inb(addr+5) & 0x01) == 0) && (timeout)) {
3932 val16 = read_word(0x0040, 0x006C);
3933 if (val16 != timer) {
3934 timer = val16;
3935 timeout--;
3936 }
3937 }
3938 if (timeout) {
3939 regs.u.r8.ah = 0;
3940 regs.u.r8.al = inb(addr);
3941 } else {
3942 regs.u.r8.ah = inb(addr+5);
3943 }
3944 ClearCF(iret_addr.flags);
3945 break;
3946 case 3:
3947 regs.u.r8.ah = inb(addr+5);
3948 regs.u.r8.al = inb(addr+6);
3949 ClearCF(iret_addr.flags);
3950 break;
3951 default:
3952 SetCF(iret_addr.flags); // Unsupported
3953 }
3954 } else {
3955 SetCF(iret_addr.flags); // Unsupported
3956 }
3957}
3958
3959 void
3960int15_function(regs, ES, DS, FLAGS)
3961 pusha_regs_t regs; // REGS pushed via pusha
3962 Bit16u ES, DS, FLAGS;
3963{
3964 Bit16u ebda_seg=read_word(0x0040,0x000E);
3965 bx_bool prev_a20_enable;
3966 Bit16u base15_00;
3967 Bit8u base23_16;
3968 Bit16u ss;
3969 Bit16u BX,CX,DX;
3970
3971 Bit16u bRegister;
3972 Bit8u irqDisable;
3973
3974BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
3975
3976 switch (regs.u.r8.ah) {
3977#ifdef VBOX
3978 case 0x00: /* assorted functions */
3979 if (regs.u.r8.al != 0xc0)
3980 goto undecoded;
3981 /* GRUB calls int15 with ax=0x00c0 to get the ROM configuration table,
3982 * which we don't support, but logging that event is annoying. In fact
3983 * it is likely that they just misread some specs, because there is a
3984 * int15 BIOS function AH=0xc0 which sounds quite similar to what GRUB
3985 * wants to achieve. */
3986 SET_CF();
3987 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3988 break;
3989#endif
3990 case 0x24: /* A20 Control */
3991 switch (regs.u.r8.al) {
3992 case 0x00:
3993 set_enable_a20(0);
3994 CLEAR_CF();
3995 regs.u.r8.ah = 0;
3996 break;
3997 case 0x01:
3998 set_enable_a20(1);
3999 CLEAR_CF();
4000 regs.u.r8.ah = 0;
4001 break;
4002 case 0x02:
4003 regs.u.r8.al = (inb(0x92) >> 1) & 0x01;
4004 CLEAR_CF();
4005 regs.u.r8.ah = 0;
4006 break;
4007 case 0x03:
4008 CLEAR_CF();
4009 regs.u.r8.ah = 0;
4010 regs.u.r16.bx = 3;
4011 break;
4012 default:
4013 BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs.u.r8.al);
4014 SET_CF();
4015 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4016 }
4017 break;
4018
4019 case 0x41:
4020 SET_CF();
4021 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4022 break;
4023
4024 case 0x4f:
4025 /* keyboard intercept */
4026#if BX_CPU < 2
4027 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4028#else
4029 // nop
4030#endif
4031 SET_CF();
4032 break;
4033
4034 case 0x52: // removable media eject
4035 CLEAR_CF();
4036 regs.u.r8.ah = 0; // "ok ejection may proceed"
4037 break;
4038
4039 case 0x83: {
4040 if( regs.u.r8.al == 0 ) {
4041 // Set Interval requested.
4042 if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
4043 // Interval not already set.
4044 write_byte( 0x40, 0xA0, 1 ); // Set status byte.
4045 write_word( 0x40, 0x98, ES ); // Byte location, segment
4046 write_word( 0x40, 0x9A, regs.u.r16.bx ); // Byte location, offset
4047 write_word( 0x40, 0x9C, regs.u.r16.dx ); // Low word, delay
4048 write_word( 0x40, 0x9E, regs.u.r16.cx ); // High word, delay.
4049 CLEAR_CF( );
4050 irqDisable = inb( 0xA1 );
4051 outb( 0xA1, irqDisable & 0xFE );
4052 bRegister = inb_cmos( 0xB ); // Unmask IRQ8 so INT70 will get through.
4053 outb_cmos( 0xB, bRegister | 0x40 ); // Turn on the Periodic Interrupt timer
4054 } else {
4055 // Interval already set.
4056 BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
4057 SET_CF();
4058 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4059 }
4060 } else if( regs.u.r8.al == 1 ) {
4061 // Clear Interval requested
4062 write_byte( 0x40, 0xA0, 0 ); // Clear status byte
4063 CLEAR_CF( );
4064 bRegister = inb_cmos( 0xB );
4065 outb_cmos( 0xB, bRegister & ~0x40 ); // Turn off the Periodic Interrupt timer
4066 } else {
4067 BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
4068 SET_CF();
4069 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4070 regs.u.r8.al--;
4071 }
4072
4073 break;
4074 }
4075
4076 case 0x87:
4077#if BX_CPU < 3
4078# error "Int15 function 87h not supported on < 80386"
4079#endif
4080 // +++ should probably have descriptor checks
4081 // +++ should have exception handlers
4082
4083 // turn off interrupts
4084ASM_START
4085 cli
4086ASM_END
4087
4088 prev_a20_enable = set_enable_a20(1); // enable A20 line
4089
4090 // 128K max of transfer on 386+ ???
4091 // source == destination ???
4092
4093 // ES:SI points to descriptor table
4094 // offset use initially comments
4095 // ==============================================
4096 // 00..07 Unused zeros Null descriptor
4097 // 08..0f GDT zeros filled in by BIOS
4098 // 10..17 source ssssssss source of data
4099 // 18..1f dest dddddddd destination of data
4100 // 20..27 CS zeros filled in by BIOS
4101 // 28..2f SS zeros filled in by BIOS
4102
4103 //es:si
4104 //eeee0
4105 //0ssss
4106 //-----
4107
4108// check for access rights of source & dest here
4109
4110 // Initialize GDT descriptor
4111 base15_00 = (ES << 4) + regs.u.r16.si;
4112 base23_16 = ES >> 12;
4113 if (base15_00 < (ES<<4))
4114 base23_16++;
4115 write_word(ES, regs.u.r16.si+0x08+0, 47); // limit 15:00 = 6 * 8bytes/descriptor
4116 write_word(ES, regs.u.r16.si+0x08+2, base15_00);// base 15:00
4117 write_byte(ES, regs.u.r16.si+0x08+4, base23_16);// base 23:16
4118 write_byte(ES, regs.u.r16.si+0x08+5, 0x93); // access
4119 write_word(ES, regs.u.r16.si+0x08+6, 0x0000); // base 31:24/reserved/limit 19:16
4120
4121 // Initialize CS descriptor
4122 write_word(ES, regs.u.r16.si+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
4123 write_word(ES, regs.u.r16.si+0x20+2, 0x0000);// base 15:00
4124 write_byte(ES, regs.u.r16.si+0x20+4, 0x000f);// base 23:16
4125 write_byte(ES, regs.u.r16.si+0x20+5, 0x9b); // access
4126 write_word(ES, regs.u.r16.si+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
4127
4128 // Initialize SS descriptor
4129 ss = get_SS();
4130 base15_00 = ss << 4;
4131 base23_16 = ss >> 12;
4132 write_word(ES, regs.u.r16.si+0x28+0, 0xffff); // limit 15:00 = normal 64K limit
4133 write_word(ES, regs.u.r16.si+0x28+2, base15_00);// base 15:00
4134 write_byte(ES, regs.u.r16.si+0x28+4, base23_16);// base 23:16
4135 write_byte(ES, regs.u.r16.si+0x28+5, 0x93); // access
4136 write_word(ES, regs.u.r16.si+0x28+6, 0x0000); // base 31:24/reserved/limit 19:16
4137
4138 CX = regs.u.r16.cx;
4139ASM_START
4140 // Compile generates locals offset info relative to SP.
4141 // Get CX (word count) from stack.
4142 mov bx, sp
4143 SEG SS
4144 mov cx, _int15_function.CX [bx]
4145
4146 // since we need to set SS:SP, save them to the BDA
4147 // for future restore
4148 push eax
4149 xor eax, eax
4150 mov ds, ax
4151 mov 0x0469, ss
4152 mov 0x0467, sp
4153
4154 SEG ES
4155 lgdt [si + 0x08]
4156 SEG CS
4157 lidt [pmode_IDT_info]
4158 ;; perhaps do something with IDT here
4159
4160 ;; set PE bit in CR0
4161 mov eax, cr0
4162 or al, #0x01
4163 mov cr0, eax
4164 ;; far jump to flush CPU queue after transition to protected mode
4165 JMP_AP(0x0020, protected_mode)
4166
4167protected_mode:
4168 ;; GDT points to valid descriptor table, now load SS, DS, ES
4169 mov ax, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
4170 mov ss, ax
4171 mov ax, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
4172 mov ds, ax
4173 mov ax, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
4174 mov es, ax
4175 xor si, si
4176 xor di, di
4177 cld
4178 rep
4179 movsw ;; move CX words from DS:SI to ES:DI
4180
4181 ;; make sure DS and ES limits are 64KB
4182 mov ax, #0x28
4183 mov ds, ax
4184 mov es, ax
4185
4186 ;; reset PG bit in CR0 ???
4187 mov eax, cr0
4188 and al, #0xFE
4189 mov cr0, eax
4190
4191 ;; far jump to flush CPU queue after transition to real mode
4192 JMP_AP(0xf000, real_mode)
4193
4194real_mode:
4195 ;; restore IDT to normal real-mode defaults
4196 SEG CS
4197 lidt [rmode_IDT_info]
4198
4199 // restore SS:SP from the BDA
4200 xor ax, ax
4201 mov ds, ax
4202 mov ss, 0x0469
4203 mov sp, 0x0467
4204 pop eax
4205ASM_END
4206
4207 set_enable_a20(prev_a20_enable);
4208
4209 // turn back on interrupts
4210ASM_START
4211 sti
4212ASM_END
4213
4214 regs.u.r8.ah = 0;
4215 CLEAR_CF();
4216 break;
4217
4218
4219 case 0x88:
4220 // Get the amount of extended memory (above 1M)
4221#if BX_CPU < 2
4222 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4223 SET_CF();
4224#else
4225 regs.u.r8.al = inb_cmos(0x30);
4226 regs.u.r8.ah = inb_cmos(0x31);
4227
4228 // According to Ralf Brown's interrupt the limit should be 15M,
4229 // but real machines mostly return max. 63M.
4230 if(regs.u.r16.ax > 0xffc0)
4231 regs.u.r16.ax = 0xffc0;
4232
4233 CLEAR_CF();
4234#endif
4235 break;
4236
4237#ifdef VBOX
4238 case 0x89:
4239 // Switch to Protected Mode.
4240 // ES:DI points to user-supplied GDT
4241 // BH/BL contains starting interrupt numbers for PIC0/PIC1
4242 // This subfunction does not return!
4243
4244// turn off interrupts
4245ASM_START
4246 cli
4247ASM_END
4248
4249 set_enable_a20(1); // enable A20 line; we're supposed to fail if that fails
4250
4251 // Initialize CS descriptor for BIOS
4252 write_word(ES, regs.u.r16.si+0x38+0, 0xffff);// limit 15:00 = normal 64K limit
4253 write_word(ES, regs.u.r16.si+0x38+2, 0x0000);// base 15:00
4254 write_byte(ES, regs.u.r16.si+0x38+4, 0x000f);// base 23:16 (hardcoded to f000:0000)
4255 write_byte(ES, regs.u.r16.si+0x38+5, 0x9b); // access
4256 write_word(ES, regs.u.r16.si+0x38+6, 0x0000);// base 31:24/reserved/limit 19:16
4257
4258 BX = regs.u.r16.bx;
4259ASM_START
4260 // Compiler generates locals offset info relative to SP.
4261 // Get BX (PIC offsets) from stack.
4262 mov bx, sp
4263 SEG SS
4264 mov bx, _int15_function.BX [bx]
4265
4266 // Program PICs
4267 mov al, #0x11 ; send initialisation commands
4268 out 0x20, al
4269 out 0xa0, al
4270 mov al, bh
4271 out 0x21, al
4272 mov al, bl
4273 out 0xa1, al
4274 mov al, #0x04
4275 out 0x21, al
4276 mov al, #0x02
4277 out 0xa1, al
4278 mov al, #0x01
4279 out 0x21, al
4280 out 0xa1, al
4281 mov al, #0xff ; mask all IRQs, user must re-enable
4282 out 0x21, al
4283 out 0xa1, al
4284
4285 // Load GDT and IDT from supplied data
4286 SEG ES
4287 lgdt [si + 0x08]
4288 SEG ES
4289 lidt [si + 0x10]
4290
4291 // set PE bit in CR0
4292 mov eax, cr0
4293 or al, #0x01
4294 mov cr0, eax
4295 // far jump to flush CPU queue after transition to protected mode
4296 JMP_AP(0x0038, protmode_switch)
4297
4298protmode_switch:
4299 ;; GDT points to valid descriptor table, now load SS, DS, ES
4300 mov ax, #0x28
4301 mov ss, ax
4302 mov ax, #0x18
4303 mov ds, ax
4304 mov ax, #0x20
4305 mov es, ax
4306
4307 // unwind the stack - this will break if calling sequence changes!
4308 mov sp,bp
4309 add sp,#4 ; skip return address
4310 popa ; restore regs
4311 pop ax ; skip saved es
4312 pop ax ; skip saved ds
4313 pop ax ; skip saved flags
4314
4315 // return to caller - note that we do not use IRET because
4316 // we cannot enable interrupts
4317 pop cx ; get return offset
4318 pop ax ; skip return segment
4319 pop ax ; skip flags
4320 mov ax, #0x30 ; ah must be 0 on successful exit
4321 push ax
4322 push cx ; re-create modified ret address on stack
4323 retf
4324
4325ASM_END
4326
4327 break;
4328#endif /* VBOX */
4329
4330 case 0x90:
4331 /* Device busy interrupt. Called by Int 16h when no key available */
4332 break;
4333
4334 case 0x91:
4335 /* Interrupt complete. Called by Int 16h when key becomes available */
4336 break;
4337
4338 case 0xbf:
4339 BX_INFO("*** int 15h function AH=bf not yet supported!\n");
4340 SET_CF();
4341 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4342 break;
4343
4344 case 0xC0:
4345#if 0
4346 SET_CF();
4347 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4348 break;
4349#endif
4350 CLEAR_CF();
4351 regs.u.r8.ah = 0;
4352 regs.u.r16.bx = BIOS_CONFIG_TABLE;
4353 ES = 0xF000;
4354 break;
4355
4356 case 0xc1:
4357 ES = ebda_seg;
4358 CLEAR_CF();
4359 break;
4360
4361 case 0xd8:
4362 bios_printf(BIOS_PRINTF_DEBUG, "EISA BIOS not present\n");
4363 SET_CF();
4364 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4365 break;
4366
4367#ifdef VBOX
4368 /* Make the BIOS warning for pretty much every Linux kernel start
4369 * disappear - it calls with ax=0xe980 to figure out SMI info. */
4370 case 0xe9: /* SMI functions (SpeedStep and similar things) */
4371 SET_CF();
4372 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4373 break;
4374 case 0xec: /* AMD64 target operating mode callback */
4375 if (regs.u.r8.al != 0)
4376 goto undecoded;
4377 regs.u.r8.ah = 0;
4378 if (regs.u.r8.bl >= 1 && regs.u.r8.bl <= 3)
4379 CLEAR_CF(); /* Accepted value. */
4380 else
4381 SET_CF(); /* Reserved, error. */
4382 break;
4383undecoded:
4384#endif /* VBOX */
4385 default:
4386 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4387 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4388 SET_CF();
4389 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4390 break;
4391 }
4392}
4393
4394#if BX_USE_PS2_MOUSE
4395 void
4396int15_function_mouse(regs, ES, DS, FLAGS)
4397 pusha_regs_t regs; // REGS pushed via pusha
4398 Bit16u ES, DS, FLAGS;
4399{
4400 Bit16u ebda_seg=read_word(0x0040,0x000E);
4401 Bit8u mouse_flags_1, mouse_flags_2;
4402 Bit16u mouse_driver_seg;
4403 Bit16u mouse_driver_offset;
4404 Bit8u mouse_cmd;
4405 Bit8u ret, mouse_data1, mouse_data2, mouse_data3;
4406
4407BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4408
4409 switch (regs.u.r8.ah) {
4410 case 0xC2:
4411 // Return Codes status in AH
4412 // =========================
4413 // 00: success
4414 // 01: invalid subfunction (AL > 7)
4415 // 02: invalid input value (out of allowable range)
4416 // 03: interface error
4417 // 04: resend command received from mouse controller,
4418 // device driver should attempt command again
4419 // 05: cannot enable mouse, since no far call has been installed
4420 // 80/86: mouse service not implemented
4421
4422 if (regs.u.r8.al > 7) {
4423BX_DEBUG_INT15("unsupported subfn\n");
4424 // invalid function
4425 SET_CF();
4426 regs.u.r8.ah = 1;
4427 break;
4428 }
4429
4430 // Valid subfn; disable AUX input and IRQ12, assume no error
4431 set_kbd_command_byte(0x65);
4432 CLEAR_CF();
4433 regs.u.r8.ah = 0;
4434
4435 switch (regs.u.r8.al) {
4436 case 0: // Disable/Enable Mouse
4437BX_DEBUG_INT15("case 0: ");
4438 if (regs.u.r8.bh > 1) {
4439 BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs.u.r8.bh);
4440 // invalid subfunction
4441 SET_CF();
4442 regs.u.r8.ah = 1;
4443 break;
4444 }
4445 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4446 if ( (mouse_flags_2 & 0x80) == 0 ) {
4447 BX_DEBUG_INT15("INT 15h C2 Enable/Disable Mouse, no far call handler\n");
4448 SET_CF();
4449 regs.u.r8.ah = 5; // no far call installed
4450 break;
4451 }
4452 if (regs.u.r8.bh == 0) {
4453BX_DEBUG_INT15("Disable Mouse\n");
4454 mouse_cmd = 0xF5; // disable mouse command
4455 } else {
4456BX_DEBUG_INT15("Enable Mouse\n");
4457 mouse_cmd = 0xF4; // enable mouse command
4458 }
4459
4460 ret = send_to_mouse_ctrl(mouse_cmd); // disable mouse command
4461 if (ret == 0) {
4462 ret = get_mouse_data(&mouse_data1);
4463 if ( (ret == 0) || (mouse_data1 == 0xFA) ) {
4464 // success
4465 break;
4466 }
4467 }
4468
4469 // interface error
4470 SET_CF();
4471 regs.u.r8.ah = 3;
4472 break;
4473
4474 case 5: // Initialize Mouse
4475 // Valid package sizes are 1 to 8
4476 if ( (regs.u.r8.bh < 1) || (regs.u.r8.bh > 8) ) {
4477 SET_CF();
4478 regs.u.r8.ah = 2; // invalid input
4479 break;
4480 }
4481 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4482 mouse_flags_2 = (mouse_flags_2 & 0xf8) | (regs.u.r8.bh - 1);
4483 write_byte(ebda_seg, 0x0027, mouse_flags_2);
4484 // fall through!
4485
4486 case 1: // Reset Mouse
4487BX_DEBUG_INT15("case 1 or 5:\n");
4488 // clear current package byte index
4489 mouse_flags_1 = read_byte(ebda_seg, 0x0026);
4490 mouse_flags_1 = mouse_flags_1 & 0xf8;
4491 write_byte(ebda_seg, 0x0026, mouse_flags_1);
4492 ret = send_to_mouse_ctrl(0xFF); // reset mouse command
4493 if (ret == 0) {
4494 ret = get_mouse_data(&mouse_data3);
4495 // if no mouse attached, it will return RESEND
4496 if (mouse_data3 == 0xfe) {
4497 SET_CF();
4498 regs.u.r8.ah = 4; // resend
4499 break;
4500 }
4501 if (mouse_data3 != 0xfa)
4502 BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3);
4503 if ( ret == 0 ) {
4504 ret = get_mouse_data(&mouse_data1);
4505 if ( ret == 0 ) {
4506 ret = get_mouse_data(&mouse_data2);
4507 if ( ret == 0 ) {
4508 // success
4509 regs.u.r8.bl = mouse_data1;
4510 regs.u.r8.bh = mouse_data2;
4511 break;
4512 }
4513 }
4514 }
4515 }
4516
4517 // interface error
4518 SET_CF();
4519 regs.u.r8.ah = 3;
4520 break;
4521
4522 case 2: // Set Sample Rate
4523BX_DEBUG_INT15("case 2:\n");
4524 switch (regs.u.r8.bh) {
4525 case 0: mouse_data1 = 10; break; // 10 reports/sec
4526 case 1: mouse_data1 = 20; break; // 20 reports/sec
4527 case 2: mouse_data1 = 40; break; // 40 reports/sec
4528 case 3: mouse_data1 = 60; break; // 60 reports/sec
4529 case 4: mouse_data1 = 80; break; // 80 reports/sec
4530 case 5: mouse_data1 = 100; break; // 100 reports/sec (default)
4531 case 6: mouse_data1 = 200; break; // 200 reports/sec
4532 default: mouse_data1 = 0;
4533 }
4534 if (mouse_data1 > 0) {
4535 ret = send_to_mouse_ctrl(0xF3); // set sample rate command
4536 if (ret == 0) {
4537 ret = get_mouse_data(&mouse_data2);
4538 ret = send_to_mouse_ctrl(mouse_data1);
4539 ret = get_mouse_data(&mouse_data2);
4540 // success
4541 } else {
4542 // interface error
4543 SET_CF();
4544 regs.u.r8.ah = 3;
4545 }
4546 } else {
4547 // invalid input
4548 SET_CF();
4549 regs.u.r8.ah = 2;
4550 }
4551 break;
4552
4553 case 3: // Set Resolution
4554BX_DEBUG_INT15("case 3:\n");
4555 // BX:
4556 // 0 = 25 dpi, 1 count per millimeter
4557 // 1 = 50 dpi, 2 counts per millimeter
4558 // 2 = 100 dpi, 4 counts per millimeter
4559 // 3 = 200 dpi, 8 counts per millimeter
4560 if (regs.u.r8.bh < 4) {
4561 ret = send_to_mouse_ctrl(0xE8); // set resolution command
4562 if (ret == 0) {
4563 ret = get_mouse_data(&mouse_data1);
4564 if (mouse_data1 != 0xfa)
4565 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4566 ret = send_to_mouse_ctrl(regs.u.r8.bh);
4567 ret = get_mouse_data(&mouse_data1);
4568 if (mouse_data1 != 0xfa)
4569 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4570 // success
4571 } else {
4572 // interface error
4573 SET_CF();
4574 regs.u.r8.ah = 3;
4575 }
4576 } else {
4577 // invalid input
4578 SET_CF();
4579 regs.u.r8.ah = 2;
4580 }
4581 break;
4582
4583 case 4: // Get Device ID
4584BX_DEBUG_INT15("case 4:\n");
4585 ret = send_to_mouse_ctrl(0xF2); // get mouse ID command
4586 if (ret == 0) {
4587 ret = get_mouse_data(&mouse_data1);
4588 ret = get_mouse_data(&mouse_data2);
4589 regs.u.r8.bh = mouse_data2;
4590 // success
4591 } else {
4592 // interface error
4593 SET_CF();
4594 regs.u.r8.ah = 3;
4595 }
4596 break;
4597
4598 case 6: // Return Status & Set Scaling Factor...
4599BX_DEBUG_INT15("case 6:\n");
4600 switch (regs.u.r8.bh) {
4601 case 0: // Return Status
4602 ret = send_to_mouse_ctrl(0xE9); // get mouse info command
4603 if (ret == 0) {
4604 ret = get_mouse_data(&mouse_data1);
4605 if (mouse_data1 != 0xfa)
4606 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4607 if (ret == 0) {
4608 ret = get_mouse_data(&mouse_data1);
4609 if ( ret == 0 ) {
4610 ret = get_mouse_data(&mouse_data2);
4611 if ( ret == 0 ) {
4612 ret = get_mouse_data(&mouse_data3);
4613 if ( ret == 0 ) {
4614 regs.u.r8.bl = mouse_data1;
4615 regs.u.r8.cl = mouse_data2;
4616 regs.u.r8.dl = mouse_data3;
4617 // success
4618 break;
4619 }
4620 }
4621 }
4622 }
4623 }
4624
4625 // interface error
4626 SET_CF();
4627 regs.u.r8.ah = 3;
4628 break;
4629
4630 case 1: // Set Scaling Factor to 1:1
4631 case 2: // Set Scaling Factor to 2:1
4632 if (regs.u.r8.bh == 1) {
4633 ret = send_to_mouse_ctrl(0xE6);
4634 } else {
4635 ret = send_to_mouse_ctrl(0xE7);
4636 }
4637 if (ret == 0) {
4638 get_mouse_data(&mouse_data1);
4639 ret = (mouse_data1 != 0xFA);
4640 }
4641 if (ret != 0) {
4642 // interface error
4643 SET_CF();
4644 regs.u.r8.ah = 3;
4645 }
4646 break;
4647
4648 default:
4649 BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs.u.r8.bh);
4650 // invalid subfunction
4651 SET_CF();
4652 regs.u.r8.ah = 1;
4653 }
4654 break;
4655
4656 case 7: // Set Mouse Handler Address
4657BX_DEBUG_INT15("case 7:\n");
4658 mouse_driver_seg = ES;
4659 mouse_driver_offset = regs.u.r16.bx;
4660 write_word(ebda_seg, 0x0022, mouse_driver_offset);
4661 write_word(ebda_seg, 0x0024, mouse_driver_seg);
4662 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4663 if (mouse_driver_offset == 0 && mouse_driver_seg == 0) {
4664 /* remove handler */
4665 if ( (mouse_flags_2 & 0x80) != 0 ) {
4666 mouse_flags_2 &= ~0x80;
4667 }
4668 }
4669 else {
4670 /* install handler */
4671 mouse_flags_2 |= 0x80;
4672 }
4673 write_byte(ebda_seg, 0x0027, mouse_flags_2);
4674 break;
4675
4676 default:
4677 BX_PANIC("INT 15h C2 default case entered\n");
4678 // invalid subfunction
4679 SET_CF();
4680 regs.u.r8.ah = 1;
4681 }
4682BX_DEBUG_INT15("returning cf = %u, ah = %02x\n", (unsigned)GET_CF(), (unsigned)regs.u.r8.ah);
4683 // Re-enable AUX input and IRQ12
4684 set_kbd_command_byte(0x47);
4685 break;
4686
4687 default:
4688 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4689 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4690 SET_CF();
4691 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4692 break;
4693 }
4694}
4695#endif // BX_USE_PS2_MOUSE
4696
4697
4698void set_e820_range(ES, DI, start, end, extra_start, extra_end, type)
4699 Bit16u ES;
4700 Bit16u DI;
4701 Bit32u start;
4702 Bit32u end;
4703 Bit8u extra_start;
4704 Bit8u extra_end;
4705 Bit16u type;
4706{
4707 write_word(ES, DI, start);
4708 write_word(ES, DI+2, start >> 16);
4709 write_word(ES, DI+4, extra_start);
4710 write_word(ES, DI+6, 0x00);
4711
4712 end -= start;
4713 extra_end -= extra_start;
4714 write_word(ES, DI+8, end);
4715 write_word(ES, DI+10, end >> 16);
4716 write_word(ES, DI+12, extra_end);
4717 write_word(ES, DI+14, 0x0000);
4718
4719 write_word(ES, DI+16, type);
4720 write_word(ES, DI+18, 0x0);
4721}
4722
4723 void
4724int15_function32(regs, ES, DS, FLAGS)
4725 pushad_regs_t regs; // REGS pushed via pushad
4726 Bit16u ES, DS, FLAGS;
4727{
4728 Bit32u extended_memory_size=0; // 64bits long
4729 Bit32u extra_lowbits_memory_size=0;
4730 Bit16u CX,DX;
4731 Bit8u extra_highbits_memory_size=0;
4732 Bit32u mcfgStart, mcfgSize;
4733
4734BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4735
4736 switch (regs.u.r8.ah) {
4737 case 0x86:
4738 // Wait for CX:DX microseconds. currently using the
4739 // refresh request port 0x61 bit4, toggling every 15usec
4740
4741 CX = regs.u.r16.cx;
4742 DX = regs.u.r16.dx;
4743
4744ASM_START
4745 sti
4746
4747 ;; Get the count in eax
4748 ;; VBOX: corrected _int15_function -> _int15_function32 here.
4749 mov bx, sp
4750 SEG SS
4751 mov ax, _int15_function32.CX [bx]
4752 shl eax, #16
4753 SEG SS
4754 mov ax, _int15_function32.DX [bx]
4755
4756 ;; convert to numbers of 15usec ticks
4757 mov ebx, #15
4758 xor edx, edx
4759 div eax, ebx
4760 mov ecx, eax
4761
4762 ;; wait for ecx number of refresh requests
4763 in al, #0x61
4764 and al,#0x10
4765 mov ah, al
4766
4767 or ecx, ecx
4768 je int1586_tick_end
4769int1586_tick:
4770 in al, #0x61
4771 and al,#0x10
4772 cmp al, ah
4773 je int1586_tick
4774 mov ah, al
4775 dec ecx
4776 jnz int1586_tick
4777int1586_tick_end:
4778ASM_END
4779
4780 break;
4781
4782 case 0xe8:
4783 switch(regs.u.r8.al)
4784 {
4785 case 0x20: // coded by osmaker aka K.J.
4786 if(regs.u.r32.edx == 0x534D4150)
4787 {
4788 extended_memory_size = inb_cmos(0x35);
4789 extended_memory_size <<= 8;
4790 extended_memory_size |= inb_cmos(0x34);
4791 extended_memory_size *= 64;
4792#ifndef VBOX /* The following excludes 0xf0000000 thru 0xffffffff. Trust DevPcBios.cpp to get this right. */
4793 // greater than EFF00000???
4794 if(extended_memory_size > 0x3bc000) {
4795 extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4796 }
4797#endif /* !VBOX */
4798 extended_memory_size *= 1024;
4799 extended_memory_size += (16L * 1024 * 1024);
4800
4801 if(extended_memory_size <= (16L * 1024 * 1024)) {
4802 extended_memory_size = inb_cmos(0x31);
4803 extended_memory_size <<= 8;
4804 extended_memory_size |= inb_cmos(0x30);
4805 extended_memory_size *= 1024;
4806 extended_memory_size += (1L * 1024 * 1024);
4807 }
4808
4809#ifdef VBOX /* We've already used the CMOS entries for SATA.
4810 BTW. This is the amount of memory above 4GB measured in 64KB units. */
4811 extra_lowbits_memory_size = inb_cmos(0x62);
4812 extra_lowbits_memory_size <<= 8;
4813 extra_lowbits_memory_size |= inb_cmos(0x61);
4814 extra_lowbits_memory_size <<= 16;
4815 extra_highbits_memory_size = inb_cmos(0x63);
4816 /* 0x64 and 0x65 can be used if we need to dig 1 TB or more at a later point. */
4817#else
4818 extra_lowbits_memory_size = inb_cmos(0x5c);
4819 extra_lowbits_memory_size <<= 8;
4820 extra_lowbits_memory_size |= inb_cmos(0x5b);
4821 extra_lowbits_memory_size *= 64;
4822 extra_lowbits_memory_size *= 1024;
4823 extra_highbits_memory_size = inb_cmos(0x5d);
4824#endif /* !VBOX */
4825
4826 mcfgStart = 0;
4827 mcfgSize = 0;
4828
4829 switch(regs.u.r16.bx)
4830 {
4831 case 0:
4832 set_e820_range(ES, regs.u.r16.di,
4833#ifndef VBOX /** @todo Upstream suggests the following, needs checking. (see next as well) */
4834 0x0000000L, 0x0009f000L, 0, 0, 1);
4835#else
4836 0x0000000L, 0x0009fc00L, 0, 0, 1);
4837#endif
4838 regs.u.r32.ebx = 1;
4839 break;
4840 case 1:
4841 set_e820_range(ES, regs.u.r16.di,
4842#ifndef VBOX /** @todo Upstream suggests the following, needs checking. (see next as well) */
4843 0x0009f000L, 0x000a0000L, 0, 0, 2);
4844#else
4845 0x0009fc00L, 0x000a0000L, 0, 0, 2);
4846#endif
4847 regs.u.r32.ebx = 2;
4848 break;
4849 case 2:
4850#ifdef VBOX
4851 /* Mark the BIOS as reserved. VBox doesn't currently
4852 * use the 0xe0000-0xeffff area. It does use the
4853 * 0xd0000-0xdffff area for the BIOS logo, but it's
4854 * not worth marking it as reserved. (this is not
4855 * true anymore because the VGA adapter handles the logo stuff)
4856 * The whole 0xe0000-0xfffff can be used for the BIOS.
4857 * Note that various
4858 * Windows versions don't accept (read: in debug builds
4859 * they trigger the "Too many similar traps" assertion)
4860 * a single reserved range from 0xd0000 to 0xffffff.
4861 * A 128K area starting from 0xd0000 works. */
4862 set_e820_range(ES, regs.u.r16.di,
4863 0x000f0000L, 0x00100000L, 0, 0, 2);
4864#else /* !VBOX */
4865 set_e820_range(ES, regs.u.r16.di,
4866 0x000e8000L, 0x00100000L, 0, 0, 2);
4867#endif /* !VBOX */
4868 regs.u.r32.ebx = 3;
4869 break;
4870 case 3:
4871#if BX_ROMBIOS32 || defined(VBOX)
4872 set_e820_range(ES, regs.u.r16.di,
4873 0x00100000L,
4874 extended_memory_size - ACPI_DATA_SIZE, 0, 0, 1);
4875 regs.u.r32.ebx = 4;
4876#else
4877 set_e820_range(ES, regs.u.r16.di,
4878 0x00100000L,
4879 extended_memory_size, 1);
4880 regs.u.r32.ebx = 5;
4881#endif
4882 break;
4883 case 4:
4884 set_e820_range(ES, regs.u.r16.di,
4885 extended_memory_size - ACPI_DATA_SIZE,
4886 extended_memory_size, 0, 0, 3); // ACPI RAM
4887 regs.u.r32.ebx = 5;
4888 break;
4889 case 5:
4890 /* 256KB BIOS area at the end of 4 GB */
4891#ifdef VBOX
4892 /* We don't set the end to 1GB here and rely on the 32-bit
4893 unsigned wrap around effect (0-0xfffc0000L). */
4894#endif
4895 set_e820_range(ES, regs.u.r16.di,
4896 0xfffc0000L, 0x00000000L, 0, 0, 2);
4897 if (mcfgStart != 0)
4898 regs.u.r32.ebx = 6;
4899 else
4900 {
4901 if (extra_highbits_memory_size || extra_lowbits_memory_size)
4902 regs.u.r32.ebx = 7;
4903 else
4904 regs.u.r32.ebx = 0;
4905 }
4906 break;
4907 case 6:
4908 /* PCI MMIO config space (MCFG) */
4909 set_e820_range(ES, regs.u.r16.di,
4910 mcfgStart, mcfgStart + mcfgSize, 0, 0, 2);
4911
4912 if (extra_highbits_memory_size || extra_lowbits_memory_size)
4913 regs.u.r32.ebx = 7;
4914 else
4915 regs.u.r32.ebx = 0;
4916 break;
4917 case 7:
4918#ifdef VBOX /* Don't succeeded if no memory above 4 GB. */
4919 /* Mapping of memory above 4 GB if present.
4920 Note: set_e820_range needs do no borrowing in the
4921 subtraction because of the nice numbers. */
4922 if (extra_highbits_memory_size || extra_lowbits_memory_size)
4923 {
4924 set_e820_range(ES, regs.u.r16.di,
4925 0x00000000L, extra_lowbits_memory_size,
4926 1 /*GB*/, extra_highbits_memory_size + 1 /*GB*/, 1);
4927 regs.u.r32.ebx = 0;
4928 }
4929 break;
4930 /* fall thru */
4931#else /* !VBOX */
4932 /* Mapping of memory above 4 GB */
4933 set_e820_range(ES, regs.u.r16.di, 0x00000000L,
4934 extra_lowbits_memory_size, 1, extra_highbits_memory_size
4935 + 1, 1);
4936 regs.u.r32.ebx = 0;
4937 break;
4938#endif /* !VBOX */
4939 default: /* AX=E820, DX=534D4150, BX unrecognized */
4940 goto int15_unimplemented;
4941 break;
4942 }
4943 regs.u.r32.eax = 0x534D4150;
4944 regs.u.r32.ecx = 0x14;
4945 CLEAR_CF();
4946 } else {
4947 // if DX != 0x534D4150)
4948 goto int15_unimplemented;
4949 }
4950 break;
4951
4952 case 0x01:
4953 // do we have any reason to fail here ?
4954 CLEAR_CF();
4955
4956 // my real system sets ax and bx to 0
4957 // this is confirmed by Ralph Brown list
4958 // but syslinux v1.48 is known to behave
4959 // strangely if ax is set to 0
4960 // regs.u.r16.ax = 0;
4961 // regs.u.r16.bx = 0;
4962
4963 // Get the amount of extended memory (above 1M)
4964 regs.u.r8.cl = inb_cmos(0x30);
4965 regs.u.r8.ch = inb_cmos(0x31);
4966
4967 // limit to 15M
4968 if(regs.u.r16.cx > 0x3c00)
4969 {
4970 regs.u.r16.cx = 0x3c00;
4971 }
4972
4973 // Get the amount of extended memory above 16M in 64k blocs
4974 regs.u.r8.dl = inb_cmos(0x34);
4975 regs.u.r8.dh = inb_cmos(0x35);
4976
4977 // Set configured memory equal to extended memory
4978 regs.u.r16.ax = regs.u.r16.cx;
4979 regs.u.r16.bx = regs.u.r16.dx;
4980 break;
4981 default: /* AH=0xE8?? but not implemented */
4982 goto int15_unimplemented;
4983 }
4984 break;
4985 int15_unimplemented:
4986 // fall into the default
4987 default:
4988 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4989 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4990 SET_CF();
4991 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4992 break;
4993 }
4994}
4995
4996 void
4997int16_function(DI, SI, BP, SP, BX, DX, CX, AX, FLAGS)
4998 Bit16u DI, SI, BP, SP, BX, DX, CX, AX, FLAGS;
4999{
5000 Bit8u scan_code, ascii_code, shift_flags, led_flags, count;
5001 Bit16u kbd_code, max;
5002
5003 BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX, BX, CX, DX);
5004
5005 shift_flags = read_byte(0x0040, 0x17);
5006 led_flags = read_byte(0x0040, 0x97);
5007 if ((((shift_flags >> 4) & 0x07) ^ (led_flags & 0x07)) != 0) {
5008ASM_START
5009 cli
5010ASM_END
5011 outb(0x60, 0xed);
5012 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
5013 if ((inb(0x60) == 0xfa)) {
5014 led_flags &= 0xf8;
5015 led_flags |= ((shift_flags >> 4) & 0x07);
5016 outb(0x60, led_flags & 0x07);
5017 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
5018 inb(0x60);
5019 write_byte(0x0040, 0x97, led_flags);
5020 }
5021ASM_START
5022 sti
5023ASM_END
5024 }
5025
5026 switch (GET_AH()) {
5027 case 0x00: /* read keyboard input */
5028
5029 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
5030 BX_PANIC("KBD: int16h: out of keyboard input\n");
5031 }
5032 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
5033 else if (ascii_code == 0xE0) ascii_code = 0;
5034 AX = (scan_code << 8) | ascii_code;
5035 break;
5036
5037 case 0x01: /* check keyboard status */
5038 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
5039 SET_ZF();
5040 return;
5041 }
5042 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
5043 else if (ascii_code == 0xE0) ascii_code = 0;
5044 AX = (scan_code << 8) | ascii_code;
5045 CLEAR_ZF();
5046 break;
5047
5048 case 0x02: /* get shift flag status */
5049 shift_flags = read_byte(0x0040, 0x17);
5050 SET_AL(shift_flags);
5051 break;
5052
5053 case 0x05: /* store key-stroke into buffer */
5054 if ( !enqueue_key(GET_CH(), GET_CL()) ) {
5055 SET_AL(1);
5056 }
5057 else {
5058 SET_AL(0);
5059 }
5060 break;
5061
5062 case 0x09: /* GET KEYBOARD FUNCTIONALITY */
5063 // bit Bochs Description
5064 // 7 0 reserved
5065 // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
5066 // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
5067 // 4 1 INT 16/AH=0Ah supported
5068 // 3 0 INT 16/AX=0306h supported
5069 // 2 0 INT 16/AX=0305h supported
5070 // 1 0 INT 16/AX=0304h supported
5071 // 0 0 INT 16/AX=0300h supported
5072 //
5073 SET_AL(0x30);
5074 break;
5075
5076 case 0x0A: /* GET KEYBOARD ID */
5077 count = 2;
5078 kbd_code = 0x0;
5079 outb(0x60, 0xf2);
5080 /* Wait for data */
5081 max=0xffff;
5082 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
5083 if (max>0x0) {
5084 if ((inb(0x60) == 0xfa)) {
5085 do {
5086 max=0xffff;
5087 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
5088 if (max>0x0) {
5089 kbd_code >>= 8;
5090 kbd_code |= (inb(0x60) << 8);
5091 }
5092 } while (--count>0);
5093 }
5094 }
5095 BX=kbd_code;
5096 break;
5097
5098 case 0x10: /* read MF-II keyboard input */
5099
5100 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
5101 BX_PANIC("KBD: int16h: out of keyboard input\n");
5102 }
5103 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
5104 AX = (scan_code << 8) | ascii_code;
5105 break;
5106
5107 case 0x11: /* check MF-II keyboard status */
5108 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
5109 SET_ZF();
5110 return;
5111 }
5112 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
5113 AX = (scan_code << 8) | ascii_code;
5114 CLEAR_ZF();
5115 break;
5116
5117 case 0x12: /* get extended keyboard status */
5118 shift_flags = read_byte(0x0040, 0x17);
5119 SET_AL(shift_flags);
5120 shift_flags = read_byte(0x0040, 0x18) & 0x73;
5121 shift_flags |= read_byte(0x0040, 0x96) & 0x0c;
5122 SET_AH(shift_flags);
5123 BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX);
5124 break;
5125
5126 case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
5127 SET_AH(0x80); // function int16 ah=0x10-0x12 supported
5128 break;
5129
5130 case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
5131 // don't change AH : function int16 ah=0x20-0x22 NOT supported
5132 break;
5133
5134 case 0x6F:
5135 if (GET_AL() == 0x08)
5136 SET_AH(0x02); // unsupported, aka normal keyboard
5137
5138 default:
5139 BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
5140 }
5141}
5142
5143 unsigned int
5144dequeue_key(scan_code, ascii_code, incr)
5145 Bit8u *scan_code;
5146 Bit8u *ascii_code;
5147 unsigned int incr;
5148{
5149 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail;
5150 Bit16u ss;
5151 Bit8u acode, scode;
5152
5153#if BX_CPU < 2
5154 buffer_start = 0x001E;
5155 buffer_end = 0x003E;
5156#else
5157 buffer_start = read_word(0x0040, 0x0080);
5158 buffer_end = read_word(0x0040, 0x0082);
5159#endif
5160
5161 buffer_head = read_word(0x0040, 0x001a);
5162 buffer_tail = read_word(0x0040, 0x001c);
5163
5164 if (buffer_head != buffer_tail) {
5165 ss = get_SS();
5166 acode = read_byte(0x0040, buffer_head);
5167 scode = read_byte(0x0040, buffer_head+1);
5168 write_byte(ss, ascii_code, acode);
5169 write_byte(ss, scan_code, scode);
5170
5171 if (incr) {
5172 buffer_head += 2;
5173 if (buffer_head >= buffer_end)
5174 buffer_head = buffer_start;
5175 write_word(0x0040, 0x001a, buffer_head);
5176 }
5177 return(1);
5178 }
5179 else {
5180 return(0);
5181 }
5182}
5183
5184static char panic_msg_keyb_buffer_full[] = "%s: keyboard input buffer full\n";
5185
5186 Bit8u
5187send_to_mouse_ctrl(sendbyte)
5188 Bit8u sendbyte;
5189{
5190 Bit8u response;
5191
5192 // wait for chance to write to ctrl
5193 if ( inb(0x64) & 0x02 )
5194 BX_PANIC(panic_msg_keyb_buffer_full,"sendmouse");
5195 outb(0x64, 0xD4);
5196 outb(0x60, sendbyte);
5197 return(0);
5198}
5199
5200
5201 Bit8u
5202get_mouse_data(data)
5203 Bit8u *data;
5204{
5205 Bit8u response;
5206 Bit16u ss;
5207
5208 while ( (inb(0x64) & 0x21) != 0x21 ) {
5209 }
5210
5211 response = inb(0x60);
5212
5213 ss = get_SS();
5214 write_byte(ss, data, response);
5215 return(0);
5216}
5217
5218 void
5219set_kbd_command_byte(command_byte)
5220 Bit8u command_byte;
5221{
5222 if ( inb(0x64) & 0x02 )
5223 BX_PANIC(panic_msg_keyb_buffer_full,"setkbdcomm");
5224
5225 outb(0x64, 0x60); // write command byte
5226 outb(0x60, command_byte);
5227}
5228
5229 void
5230int09_function(DI, SI, BP, SP, BX, DX, CX, AX)
5231 Bit16u DI, SI, BP, SP, BX, DX, CX, AX;
5232{
5233 Bit8u scancode, asciicode, shift_flags;
5234 Bit8u mf2_flags, mf2_state;
5235
5236 //
5237 // DS has been set to F000 before call
5238 //
5239
5240
5241 scancode = GET_AL();
5242
5243 if (scancode == 0) {
5244 BX_INFO("KBD: int09 handler: AL=0\n");
5245 return;
5246 }
5247
5248
5249 shift_flags = read_byte(0x0040, 0x17);
5250 mf2_flags = read_byte(0x0040, 0x18);
5251 mf2_state = read_byte(0x0040, 0x96);
5252 asciicode = 0;
5253
5254 switch (scancode) {
5255 case 0x3a: /* Caps Lock press */
5256 shift_flags ^= 0x40;
5257 write_byte(0x0040, 0x17, shift_flags);
5258 mf2_flags |= 0x40;
5259 write_byte(0x0040, 0x18, mf2_flags);
5260 break;
5261 case 0xba: /* Caps Lock release */
5262 mf2_flags &= ~0x40;
5263 write_byte(0x0040, 0x18, mf2_flags);
5264 break;
5265
5266 case 0x2a: /* L Shift press */
5267 shift_flags |= 0x02;
5268 write_byte(0x0040, 0x17, shift_flags);
5269 break;
5270 case 0xaa: /* L Shift release */
5271 shift_flags &= ~0x02;
5272 write_byte(0x0040, 0x17, shift_flags);
5273 break;
5274
5275 case 0x36: /* R Shift press */
5276 shift_flags |= 0x01;
5277 write_byte(0x0040, 0x17, shift_flags);
5278 break;
5279 case 0xb6: /* R Shift release */
5280 shift_flags &= ~0x01;
5281 write_byte(0x0040, 0x17, shift_flags);
5282 break;
5283
5284 case 0x1d: /* Ctrl press */
5285 if ((mf2_state & 0x01) == 0) {
5286 shift_flags |= 0x04;
5287 write_byte(0x0040, 0x17, shift_flags);
5288 if (mf2_state & 0x02) {
5289 mf2_state |= 0x04;
5290 write_byte(0x0040, 0x96, mf2_state);
5291 } else {
5292 mf2_flags |= 0x01;
5293 write_byte(0x0040, 0x18, mf2_flags);
5294 }
5295 }
5296 break;
5297 case 0x9d: /* Ctrl release */
5298 if ((mf2_state & 0x01) == 0) {
5299 shift_flags &= ~0x04;
5300 write_byte(0x0040, 0x17, shift_flags);
5301 if (mf2_state & 0x02) {
5302 mf2_state &= ~0x04;
5303 write_byte(0x0040, 0x96, mf2_state);
5304 } else {
5305 mf2_flags &= ~0x01;
5306 write_byte(0x0040, 0x18, mf2_flags);
5307 }
5308 }
5309 break;
5310
5311 case 0x38: /* Alt press */
5312 shift_flags |= 0x08;
5313 write_byte(0x0040, 0x17, shift_flags);
5314 if (mf2_state & 0x02) {
5315 mf2_state |= 0x08;
5316 write_byte(0x0040, 0x96, mf2_state);
5317 } else {
5318 mf2_flags |= 0x02;
5319 write_byte(0x0040, 0x18, mf2_flags);
5320 }
5321 break;
5322 case 0xb8: /* Alt release */
5323 shift_flags &= ~0x08;
5324 write_byte(0x0040, 0x17, shift_flags);
5325 if (mf2_state & 0x02) {
5326 mf2_state &= ~0x08;
5327 write_byte(0x0040, 0x96, mf2_state);
5328 } else {
5329 mf2_flags &= ~0x02;
5330 write_byte(0x0040, 0x18, mf2_flags);
5331 }
5332 break;
5333
5334 case 0x45: /* Num Lock press */
5335 if ((mf2_state & 0x03) == 0) {
5336 mf2_flags |= 0x20;
5337 write_byte(0x0040, 0x18, mf2_flags);
5338 shift_flags ^= 0x20;
5339 write_byte(0x0040, 0x17, shift_flags);
5340 }
5341 break;
5342 case 0xc5: /* Num Lock release */
5343 if ((mf2_state & 0x03) == 0) {
5344 mf2_flags &= ~0x20;
5345 write_byte(0x0040, 0x18, mf2_flags);
5346 }
5347 break;
5348
5349 case 0x46: /* Scroll Lock press */
5350 mf2_flags |= 0x10;
5351 write_byte(0x0040, 0x18, mf2_flags);
5352 shift_flags ^= 0x10;
5353 write_byte(0x0040, 0x17, shift_flags);
5354 break;
5355
5356 case 0xc6: /* Scroll Lock release */
5357 mf2_flags &= ~0x10;
5358 write_byte(0x0040, 0x18, mf2_flags);
5359 break;
5360
5361#ifdef VBOX
5362 case 0x53: /* Del press */
5363 if ((shift_flags & 0x0f) == 0x0c)
5364 {
5365ASM_START
5366 /* Ctrl+Alt+Del => Reboot */
5367 jmp 0xf000:post
5368ASM_END
5369 }
5370 /* fall through */
5371#endif
5372
5373 default:
5374 if (scancode & 0x80) {
5375 break; /* toss key releases ... */
5376 }
5377 if (scancode > MAX_SCAN_CODE) {
5378 BX_INFO("KBD: int09h_handler(): unknown scancode read: 0x%02x!\n", scancode);
5379 return;
5380 }
5381 if (shift_flags & 0x08) { /* ALT */
5382 asciicode = scan_to_scanascii[scancode].alt;
5383 scancode = scan_to_scanascii[scancode].alt >> 8;
5384 } else if (shift_flags & 0x04) { /* CONTROL */
5385 asciicode = scan_to_scanascii[scancode].control;
5386 scancode = scan_to_scanascii[scancode].control >> 8;
5387 } else if (((mf2_state & 0x02) > 0) && ((scancode >= 0x47) && (scancode <= 0x53))) {
5388 /* extended keys handling */
5389 asciicode = 0xe0;
5390 scancode = scan_to_scanascii[scancode].normal >> 8;
5391 } else if (shift_flags & 0x03) { /* LSHIFT + RSHIFT */
5392 /* check if lock state should be ignored
5393 * because a SHIFT key are pressed */
5394
5395 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
5396 asciicode = scan_to_scanascii[scancode].normal;
5397 scancode = scan_to_scanascii[scancode].normal >> 8;
5398 } else {
5399 asciicode = scan_to_scanascii[scancode].shift;
5400 scancode = scan_to_scanascii[scancode].shift >> 8;
5401 }
5402 } else {
5403 /* check if lock is on */
5404 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
5405 asciicode = scan_to_scanascii[scancode].shift;
5406 scancode = scan_to_scanascii[scancode].shift >> 8;
5407 } else {
5408 asciicode = scan_to_scanascii[scancode].normal;
5409 scancode = scan_to_scanascii[scancode].normal >> 8;
5410 }
5411 }
5412 if (scancode==0 && asciicode==0) {
5413 BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
5414 }
5415 enqueue_key(scancode, asciicode);
5416 break;
5417 }
5418 if ((scancode & 0x7f) != 0x1d) {
5419 mf2_state &= ~0x01;
5420 }
5421 mf2_state &= ~0x02;
5422 write_byte(0x0040, 0x96, mf2_state);
5423}
5424
5425 unsigned int
5426enqueue_key(scan_code, ascii_code)
5427 Bit8u scan_code, ascii_code;
5428{
5429 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail, temp_tail;
5430
5431#if BX_CPU < 2
5432 buffer_start = 0x001E;
5433 buffer_end = 0x003E;
5434#else
5435 buffer_start = read_word(0x0040, 0x0080);
5436 buffer_end = read_word(0x0040, 0x0082);
5437#endif
5438
5439 buffer_head = read_word(0x0040, 0x001A);
5440 buffer_tail = read_word(0x0040, 0x001C);
5441
5442 temp_tail = buffer_tail;
5443 buffer_tail += 2;
5444 if (buffer_tail >= buffer_end)
5445 buffer_tail = buffer_start;
5446
5447 if (buffer_tail == buffer_head) {
5448 return(0);
5449 }
5450
5451 write_byte(0x0040, temp_tail, ascii_code);
5452 write_byte(0x0040, temp_tail+1, scan_code);
5453 write_word(0x0040, 0x001C, buffer_tail);
5454 return(1);
5455}
5456
5457
5458 void
5459int74_function(make_farcall, Z, Y, X, status)
5460 Bit16u make_farcall, Z, Y, X, status;
5461{
5462 Bit16u ebda_seg=read_word(0x0040,0x000E);
5463 Bit8u in_byte, index, package_count;
5464 Bit8u mouse_flags_1, mouse_flags_2;
5465
5466BX_DEBUG_INT74("entering int74_function\n");
5467 make_farcall = 0;
5468
5469 in_byte = inb(0x64);
5470 if ( (in_byte & 0x21) != 0x21 ) {
5471 return;
5472 }
5473 in_byte = inb(0x60);
5474BX_DEBUG_INT74("int74: read byte %02x\n", in_byte);
5475
5476 mouse_flags_1 = read_byte(ebda_seg, 0x0026);
5477 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
5478
5479 if ( (mouse_flags_2 & 0x80) != 0x80 ) {
5480 return;
5481 }
5482
5483 package_count = mouse_flags_2 & 0x07;
5484 index = mouse_flags_1 & 0x07;
5485 write_byte(ebda_seg, 0x28 + index, in_byte);
5486
5487 if ( index >= package_count ) {
5488BX_DEBUG_INT74("int74_function: make_farcall=1\n");
5489 status = read_byte(ebda_seg, 0x0028 + 0);
5490 X = read_byte(ebda_seg, 0x0028 + 1);
5491 Y = read_byte(ebda_seg, 0x0028 + 2);
5492 Z = 0;
5493 mouse_flags_1 = 0;
5494 // check if far call handler installed
5495 if (mouse_flags_2 & 0x80)
5496 make_farcall = 1;
5497 }
5498 else {
5499 mouse_flags_1++;
5500 }
5501 write_byte(ebda_seg, 0x0026, mouse_flags_1);
5502}
5503
5504#define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
5505
5506#if BX_USE_ATADRV
5507
5508 void
5509int13_harddisk(EHBX, EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5510 Bit16u EHBX, EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5511{
5512 Bit32u lba;
5513 Bit16u ebda_seg=read_word(0x0040,0x000E);
5514 Bit16u cylinder, head, sector;
5515 Bit16u segment, offset;
5516 Bit16u npc, nph, npspt, nlc, nlh, nlspt;
5517 Bit16u size, count;
5518 Bit8u device, status;
5519
5520 BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5521
5522 write_byte(0x0040, 0x008e, 0); // clear completion flag
5523
5524 // basic check : device has to be defined
5525 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_STORAGE_DEVICES) ) {
5526 BX_DEBUG("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5527 goto int13_fail;
5528 }
5529
5530 // Get the ata channel
5531 device=read_byte(ebda_seg,&EbdaData->ata.hdidmap[GET_ELDL()-0x80]);
5532
5533 // basic check : device has to be valid
5534 if (device >= BX_MAX_STORAGE_DEVICES) {
5535 BX_DEBUG("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5536 goto int13_fail;
5537 }
5538
5539 switch (GET_AH()) {
5540
5541 case 0x00: /* disk controller reset */
5542#ifdef VBOX_WITH_SCSI
5543 /* SCSI controller does not need a reset. */
5544 if (!VBOX_IS_SCSI_DEVICE(device))
5545#endif
5546 ata_reset (device);
5547 goto int13_success;
5548 break;
5549
5550 case 0x01: /* read disk status */
5551 status = read_byte(0x0040, 0x0074);
5552 SET_AH(status);
5553 SET_DISK_RET_STATUS(0);
5554 /* set CF if error status read */
5555 if (status) goto int13_fail_nostatus;
5556 else goto int13_success_noah;
5557 break;
5558
5559 case 0x02: // read disk sectors
5560 case 0x03: // write disk sectors
5561 case 0x04: // verify disk sectors
5562
5563 count = GET_AL();
5564 cylinder = GET_CH();
5565 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
5566 sector = (GET_CL() & 0x3f);
5567 head = GET_DH();
5568
5569 segment = ES;
5570 offset = BX;
5571
5572 if ( (count > 128) || (count == 0) ) {
5573 BX_INFO("int13_harddisk: function %02x, count out of range!\n",GET_AH());
5574 goto int13_fail;
5575 }
5576
5577#ifdef VBOX_WITH_SCSI
5578 if (!VBOX_IS_SCSI_DEVICE(device))
5579#endif
5580 {
5581 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
5582 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
5583 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
5584 }
5585#ifdef VBOX_WITH_SCSI
5586 else
5587 {
5588 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5589
5590 nlc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.cylinders);
5591 nlh = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.heads);
5592 nlspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.spt);
5593 }
5594#endif
5595
5596 // sanity check on cyl heads, sec
5597 if( (cylinder >= nlc) || (head >= nlh) || (sector > nlspt )) {
5598 BX_INFO("int13_harddisk: function %02x, disk %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), GET_DL(), cylinder, head, sector);
5599 goto int13_fail;
5600 }
5601
5602 // FIXME verify
5603 if ( GET_AH() == 0x04 ) goto int13_success;
5604
5605#ifdef VBOX_WITH_SCSI
5606 if (!VBOX_IS_SCSI_DEVICE(device))
5607#endif
5608 {
5609 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5610 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5611 }
5612#ifdef VBOX_WITH_SCSI
5613 else
5614 {
5615 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5616 nph = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.heads);
5617 npspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.spt);
5618 }
5619#endif
5620
5621 // if needed, translate lchs to lba, and execute command
5622#ifdef VBOX_WITH_SCSI
5623 if (( (nph != nlh) || (npspt != nlspt)) || VBOX_IS_SCSI_DEVICE(device)) {
5624 lba = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
5625 sector = 0; // this forces the command to be lba
5626 }
5627#else
5628 if (( (nph != nlh) || (npspt != nlspt)) ) {
5629 lba = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
5630 sector = 0; // this forces the command to be lba
5631 }
5632#endif
5633
5634 if ( GET_AH() == 0x02 )
5635 {
5636#ifdef VBOX_WITH_SCSI
5637 if (VBOX_IS_SCSI_DEVICE(device))
5638 status=scsi_read_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5639 else
5640#endif
5641 {
5642 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,count * 0x200);
5643 status=ata_cmd_data_in(device, ATA_CMD_READ_MULTIPLE, count, cylinder, head, sector, lba, segment, offset);
5644 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,0x200);
5645 }
5646 }
5647 else
5648 {
5649#ifdef VBOX_WITH_SCSI
5650 if (VBOX_IS_SCSI_DEVICE(device))
5651 status=scsi_write_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5652 else
5653#endif
5654 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, cylinder, head, sector, lba, segment, offset);
5655 }
5656
5657 // Set nb of sector transferred
5658 SET_AL(read_word(ebda_seg, &EbdaData->ata.trsfsectors));
5659
5660 if (status != 0) {
5661 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5662 SET_AH(0x0c);
5663 goto int13_fail_noah;
5664 }
5665
5666 goto int13_success;
5667 break;
5668
5669 case 0x05: /* format disk track */
5670 BX_INFO("format disk track called\n");
5671 goto int13_success;
5672 return;
5673 break;
5674
5675 case 0x08: /* read disk drive parameters */
5676
5677 // Get logical geometry from table
5678#ifdef VBOX_WITH_SCSI
5679 if (!VBOX_IS_SCSI_DEVICE(device))
5680#endif
5681 {
5682 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
5683 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
5684 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
5685 }
5686#ifdef VBOX_WITH_SCSI
5687 else
5688 {
5689 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5690 nlc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.cylinders);
5691 nlh = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.heads);
5692 nlspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.spt);
5693 }
5694#endif
5695
5696 count = read_byte(ebda_seg, &EbdaData->ata.hdcount);
5697#ifndef VBOX
5698 nlc = nlc - 2; /* 0 based , last sector not used */
5699#else /* VBOX */
5700 /* Maximum cylinder number is just one less than the number of cylinders. */
5701 nlc = nlc - 1; /* 0 based , last sector not used */
5702#endif /* VBOX */
5703 SET_AL(0);
5704 SET_CH(nlc & 0xff);
5705 SET_CL(((nlc >> 2) & 0xc0) | (nlspt & 0x3f));
5706 SET_DH(nlh - 1);
5707 SET_DL(count); /* FIXME returns 0, 1, or n hard drives */
5708
5709 // FIXME should set ES & DI
5710
5711 goto int13_success;
5712 break;
5713
5714 case 0x10: /* check drive ready */
5715 // should look at 40:8E also???
5716
5717 // Read the status from controller
5718 status = inb(read_word(ebda_seg, &EbdaData->ata.channels[device/2].iobase1) + ATA_CB_STAT);
5719 if ( (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY ) {
5720 goto int13_success;
5721 }
5722 else {
5723 SET_AH(0xAA);
5724 goto int13_fail_noah;
5725 }
5726 break;
5727
5728 case 0x15: /* read disk drive size */
5729
5730 // Get physical geometry from table
5731#ifdef VBOX_WITH_SCSI
5732 if (!VBOX_IS_SCSI_DEVICE(device))
5733#endif
5734 {
5735 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5736 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5737 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5738 }
5739#ifdef VBOX_WITH_SCSI
5740 else
5741 {
5742 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5743 npc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.cylinders);
5744 nph = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.heads);
5745 npspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.spt);
5746 }
5747#endif
5748
5749 // Compute sector count seen by int13
5750#ifndef VBOX
5751 lba = (Bit32u)(npc - 1) * (Bit32u)nph * (Bit32u)npspt;
5752#else /* VBOX */
5753 /* Is it so hard to multiply a couple of counts (without introducing
5754 * arbitrary off by one errors)? */
5755 lba = (Bit32u)npc * (Bit32u)nph * (Bit32u)npspt;
5756#endif /* VBOX */
5757 CX = lba >> 16;
5758 DX = lba & 0xffff;
5759
5760 SET_AH(3); // hard disk accessible
5761 goto int13_success_noah;
5762 break;
5763
5764 case 0x41: // IBM/MS installation check
5765 BX=0xaa55; // install check
5766 SET_AH(0x30); // EDD 3.0
5767 CX=0x0007; // ext disk access and edd, removable supported
5768 goto int13_success_noah;
5769 break;
5770
5771 case 0x42: // IBM/MS extended read
5772 case 0x43: // IBM/MS extended write
5773 case 0x44: // IBM/MS verify
5774 case 0x47: // IBM/MS extended seek
5775
5776 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5777 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5778 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5779
5780 // Can't use 64 bits lba
5781 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5782 if (lba != 0L) {
5783 BX_PANIC("int13_harddisk: function %02x. Can't use 64bits lba\n",GET_AH());
5784 goto int13_fail;
5785 }
5786
5787 // Get 32 bits lba and check
5788 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5789
5790#ifdef VBOX_WITH_SCSI
5791 if (VBOX_IS_SCSI_DEVICE(device))
5792 {
5793 if (lba >= read_dword(ebda_seg, &EbdaData->scsi.devices[VBOX_GET_SCSI_DEVICE(device)].device_info.sectors) ) {
5794 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5795 goto int13_fail;
5796 }
5797 }
5798 else
5799#endif
5800 if (lba >= read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors) ) {
5801 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5802 goto int13_fail;
5803 }
5804
5805
5806 // If verify or seek
5807 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5808 goto int13_success;
5809
5810 // Execute the command
5811 if ( GET_AH() == 0x42 )
5812#ifdef VBOX
5813 {
5814#ifdef VBOX_WITH_SCSI
5815 if (VBOX_IS_SCSI_DEVICE(device))
5816 status=scsi_read_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5817 else
5818#endif
5819 {
5820 if (lba + count >= 268435456)
5821 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS_EXT, count, 0, 0, 0, lba, segment, offset);
5822 else {
5823 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,count * 0x200);
5824 status=ata_cmd_data_in(device, ATA_CMD_READ_MULTIPLE, count, 0, 0, 0, lba, segment, offset);
5825 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,0x200);
5826 }
5827 }
5828 }
5829#else /* !VBOX */
5830 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba, segment, offset);
5831#endif /* VBOX */
5832 else
5833#ifdef VBOX
5834 {
5835#ifdef VBOX_WITH_SCSI
5836 if (VBOX_IS_SCSI_DEVICE(device))
5837 status=scsi_write_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5838 else
5839#endif
5840 {
5841 if (lba + count >= 268435456)
5842 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS_EXT, count, 0, 0, 0, lba, segment, offset);
5843 else
5844 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
5845 }
5846 }
5847#else /* !VBOX */
5848 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
5849#endif /* VBOX */
5850
5851 count=read_word(ebda_seg, &EbdaData->ata.trsfsectors);
5852 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5853
5854 if (status != 0) {
5855 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5856 SET_AH(0x0c);
5857 goto int13_fail_noah;
5858 }
5859
5860 goto int13_success;
5861 break;
5862
5863 case 0x45: // IBM/MS lock/unlock drive
5864 case 0x49: // IBM/MS extended media change
5865 goto int13_success; // Always success for HD
5866 break;
5867
5868 case 0x46: // IBM/MS eject media
5869 SET_AH(0xb2); // Volume Not Removable
5870 goto int13_fail_noah; // Always fail for HD
5871 break;
5872
5873 case 0x48: // IBM/MS get drive parameters
5874 size=read_word(DS,SI+(Bit16u)&Int13DPT->size);
5875
5876 // Buffer is too small
5877 if(size < 0x1a)
5878 goto int13_fail;
5879
5880 // EDD 1.x
5881 if(size >= 0x1a) {
5882 Bit16u blksize;
5883
5884#ifdef VBOX_WITH_SCSI
5885 if (!VBOX_IS_SCSI_DEVICE(device))
5886#endif
5887 {
5888 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5889 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5890 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5891 lba = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors);
5892 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5893 }
5894#ifdef VBOX_WITH_SCSI
5895 else
5896 {
5897 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5898 npc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.cylinders);
5899 nph = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.heads);
5900 npspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.spt);
5901 lba = read_dword(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.sectors);
5902 blksize = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.blksize);
5903 }
5904#endif
5905
5906 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5907 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x02); // geometry is valid
5908 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, (Bit32u)npc);
5909 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, (Bit32u)nph);
5910 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, (Bit32u)npspt);
5911 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, lba); // FIXME should be Bit64
5912 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0L);
5913 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5914 }
5915
5916 // EDD 2.x
5917 if(size >= 0x1e) {
5918 Bit8u channel, dev, irq, mode, checksum, i, translation;
5919 Bit16u iobase1, iobase2, options;
5920
5921 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5922
5923 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5924 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5925
5926 // Fill in dpte
5927 channel = device / 2;
5928 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5929 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5930 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5931 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5932 translation = read_byte(ebda_seg, &EbdaData->ata.devices[device].translation);
5933
5934 options = (translation==ATA_TRANSLATION_NONE?0:1<<3); // chs translation
5935 options |= (1<<4); // lba translation
5936 options |= (mode==ATA_MODE_PIO32?1:0<<7);
5937 options |= (translation==ATA_TRANSLATION_LBA?1:0<<9);
5938 options |= (translation==ATA_TRANSLATION_RECHS?3:0<<9);
5939
5940 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5941 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5942 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5943 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5944 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5945 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5946 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5947 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5948 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5949 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5950 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5951
5952 checksum=0;
5953 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5954 checksum = -checksum;
5955 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5956 }
5957
5958 // EDD 3.x
5959 if(size >= 0x42) {
5960 Bit8u channel, iface, checksum, i;
5961 Bit16u iobase1;
5962
5963 channel = device / 2;
5964 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5965 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5966
5967 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5968 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5969 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5970 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5971 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5972
5973 if (iface==ATA_IFACE_ISA) {
5974 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5975 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5976 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5977 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5978 }
5979 else {
5980 // FIXME PCI
5981 }
5982 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5983 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5984 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5985 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5986
5987 if (iface==ATA_IFACE_ISA) {
5988 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5989 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5990 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5991 }
5992 else {
5993 // FIXME PCI
5994 }
5995 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5996 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5997 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5998 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5999
6000 checksum=0;
6001 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
6002 checksum = -checksum;
6003 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
6004 }
6005
6006 goto int13_success;
6007 break;
6008
6009 case 0x4e: // // IBM/MS set hardware configuration
6010 // DMA, prefetch, PIO maximum not supported
6011 switch (GET_AL()) {
6012 case 0x01:
6013 case 0x03:
6014 case 0x04:
6015 case 0x06:
6016 goto int13_success;
6017 break;
6018 default :
6019 goto int13_fail;
6020 }
6021 break;
6022
6023 case 0x09: /* initialize drive parameters */
6024 case 0x0c: /* seek to specified cylinder */
6025 case 0x0d: /* alternate disk reset */
6026 case 0x11: /* recalibrate */
6027 case 0x14: /* controller internal diagnostic */
6028 BX_INFO("int13_harddisk: function %02xh unimplemented, returns success\n", GET_AH());
6029 goto int13_success;
6030 break;
6031
6032 case 0x0a: /* read disk sectors with ECC */
6033 case 0x0b: /* write disk sectors with ECC */
6034 case 0x18: // set media type for format
6035 case 0x50: // IBM/MS send packet command
6036 default:
6037 BX_INFO("int13_harddisk: function %02xh unsupported, returns fail\n", GET_AH());
6038 goto int13_fail;
6039 break;
6040 }
6041
6042int13_fail:
6043 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6044int13_fail_noah:
6045 SET_DISK_RET_STATUS(GET_AH());
6046int13_fail_nostatus:
6047 SET_CF(); // error occurred
6048 return;
6049
6050int13_success:
6051 SET_AH(0x00); // no error
6052int13_success_noah:
6053 SET_DISK_RET_STATUS(0x00);
6054 CLEAR_CF(); // no error
6055 return;
6056}
6057
6058// ---------------------------------------------------------------------------
6059// Start of int13 for cdrom
6060// ---------------------------------------------------------------------------
6061
6062 void
6063int13_cdrom(EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
6064 Bit16u EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
6065{
6066 Bit16u ebda_seg=read_word(0x0040,0x000E);
6067 Bit8u device, status, locks;
6068 Bit8u atacmd[12];
6069 Bit32u lba;
6070 Bit16u count, segment, offset, i, size;
6071
6072 BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6073
6074 SET_DISK_RET_STATUS(0x00);
6075
6076 /* basic check : device should be 0xE0+ */
6077 if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES) ) {
6078 BX_DEBUG("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
6079 goto int13_fail;
6080 }
6081
6082 // Get the ata channel
6083 device=read_byte(ebda_seg,&EbdaData->ata.cdidmap[GET_ELDL()-0xE0]);
6084
6085 /* basic check : device has to be valid */
6086 if (device >= BX_MAX_ATA_DEVICES) {
6087 BX_DEBUG("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
6088 goto int13_fail;
6089 }
6090
6091 switch (GET_AH()) {
6092
6093 // all those functions return SUCCESS
6094 case 0x00: /* disk controller reset */
6095 case 0x09: /* initialize drive parameters */
6096 case 0x0c: /* seek to specified cylinder */
6097 case 0x0d: /* alternate disk reset */
6098 case 0x10: /* check drive ready */
6099 case 0x11: /* recalibrate */
6100 case 0x14: /* controller internal diagnostic */
6101 case 0x16: /* detect disk change */
6102 goto int13_success;
6103 break;
6104
6105 // all those functions return disk write-protected
6106 case 0x03: /* write disk sectors */
6107 case 0x05: /* format disk track */
6108 case 0x43: // IBM/MS extended write
6109 SET_AH(0x03);
6110 goto int13_fail_noah;
6111 break;
6112
6113 case 0x01: /* read disk status */
6114 status = read_byte(0x0040, 0x0074);
6115 SET_AH(status);
6116 SET_DISK_RET_STATUS(0);
6117
6118 /* set CF if error status read */
6119 if (status) goto int13_fail_nostatus;
6120 else goto int13_success_noah;
6121 break;
6122
6123 case 0x15: /* read disk drive size */
6124 SET_AH(0x02);
6125 goto int13_fail_noah;
6126 break;
6127
6128 case 0x41: // IBM/MS installation check
6129 BX=0xaa55; // install check
6130 SET_AH(0x30); // EDD 2.1
6131 CX=0x0007; // ext disk access, removable and edd
6132 goto int13_success_noah;
6133 break;
6134
6135 case 0x42: // IBM/MS extended read
6136 case 0x44: // IBM/MS verify sectors
6137 case 0x47: // IBM/MS extended seek
6138
6139 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
6140 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
6141 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
6142
6143 // Can't use 64 bits lba
6144 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
6145 if (lba != 0L) {
6146 BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
6147 goto int13_fail;
6148 }
6149
6150 // Get 32 bits lba
6151 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
6152
6153 // If verify or seek
6154 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
6155 goto int13_success;
6156
6157 memsetb(get_SS(),atacmd,0,12);
6158 atacmd[0]=0x28; // READ command
6159 atacmd[7]=(count & 0xff00) >> 8; // Sectors
6160 atacmd[8]=(count & 0x00ff); // Sectors
6161 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
6162 atacmd[3]=(lba & 0x00ff0000) >> 16;
6163 atacmd[4]=(lba & 0x0000ff00) >> 8;
6164 atacmd[5]=(lba & 0x000000ff);
6165 status = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, count*2048L, ATA_DATA_IN, segment,offset);
6166
6167 count = (Bit16u)(read_dword(ebda_seg, &EbdaData->ata.trsfbytes) >> 11);
6168 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
6169
6170 if (status != 0) {
6171 BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status);
6172 SET_AH(0x0c);
6173 goto int13_fail_noah;
6174 }
6175
6176 goto int13_success;
6177 break;
6178
6179 case 0x45: // IBM/MS lock/unlock drive
6180 if (GET_AL() > 2) goto int13_fail;
6181
6182 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
6183
6184 switch (GET_AL()) {
6185 case 0 : // lock
6186 if (locks == 0xff) {
6187 SET_AH(0xb4);
6188 SET_AL(1);
6189 goto int13_fail_noah;
6190 }
6191 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, ++locks);
6192 SET_AL(1);
6193 break;
6194 case 1 : // unlock
6195 if (locks == 0x00) {
6196 SET_AH(0xb0);
6197 SET_AL(0);
6198 goto int13_fail_noah;
6199 }
6200 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, --locks);
6201 SET_AL(locks==0?0:1);
6202 break;
6203 case 2 : // status
6204 SET_AL(locks==0?0:1);
6205 break;
6206 }
6207 goto int13_success;
6208 break;
6209
6210 case 0x46: // IBM/MS eject media
6211 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
6212
6213 if (locks != 0) {
6214 SET_AH(0xb1); // media locked
6215 goto int13_fail_noah;
6216 }
6217 // FIXME should handle 0x31 no media in device
6218 // FIXME should handle 0xb5 valid request failed
6219
6220 // Call removable media eject
6221 ASM_START
6222 push bp
6223 mov bp, sp
6224
6225 mov ah, #0x52
6226 int #0x15
6227 mov _int13_cdrom.status + 2[bp], ah
6228 jnc int13_cdrom_rme_end
6229 mov _int13_cdrom.status, #1
6230int13_cdrom_rme_end:
6231 pop bp
6232 ASM_END
6233
6234 if (status != 0) {
6235 SET_AH(0xb1); // media locked
6236 goto int13_fail_noah;
6237 }
6238
6239 goto int13_success;
6240 break;
6241
6242 case 0x48: // IBM/MS get drive parameters
6243 size = read_word(DS,SI+(Bit16u)&Int13Ext->size);
6244
6245 // Buffer is too small
6246 if(size < 0x1a)
6247 goto int13_fail;
6248
6249 // EDD 1.x
6250 if(size >= 0x1a) {
6251 Bit16u cylinders, heads, spt, blksize;
6252
6253 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
6254
6255 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
6256 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x74); // removable, media change, lockable, max values
6257 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, 0xffffffff);
6258 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, 0xffffffff);
6259 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, 0xffffffff);
6260 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, 0xffffffff); // FIXME should be Bit64
6261 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0xffffffff);
6262 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
6263 }
6264
6265 // EDD 2.x
6266 if(size >= 0x1e) {
6267 Bit8u channel, dev, irq, mode, checksum, i;
6268 Bit16u iobase1, iobase2, options;
6269
6270 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
6271
6272 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
6273 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
6274
6275 // Fill in dpte
6276 channel = device / 2;
6277 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
6278 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
6279 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
6280 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
6281
6282 // FIXME atapi device
6283 options = (1<<4); // lba translation
6284 options |= (1<<5); // removable device
6285 options |= (1<<6); // atapi device
6286 options |= (mode==ATA_MODE_PIO32?1:0<<7);
6287
6288 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
6289 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
6290 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
6291 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
6292 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
6293 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
6294 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
6295 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
6296 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
6297 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
6298 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
6299
6300 checksum=0;
6301 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
6302 checksum = -checksum;
6303 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
6304 }
6305
6306 // EDD 3.x
6307 if(size >= 0x42) {
6308 Bit8u channel, iface, checksum, i;
6309 Bit16u iobase1;
6310
6311 channel = device / 2;
6312 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
6313 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
6314
6315 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
6316 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
6317 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
6318 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
6319 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
6320
6321 if (iface==ATA_IFACE_ISA) {
6322 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
6323 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
6324 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
6325 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
6326 }
6327 else {
6328 // FIXME PCI
6329 }
6330 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
6331 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
6332 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
6333 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
6334
6335 if (iface==ATA_IFACE_ISA) {
6336 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
6337 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
6338 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
6339 }
6340 else {
6341 // FIXME PCI
6342 }
6343 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
6344 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
6345 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
6346 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
6347
6348 checksum=0;
6349 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
6350 checksum = -checksum;
6351 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
6352 }
6353
6354 goto int13_success;
6355 break;
6356
6357 case 0x49: // IBM/MS extended media change
6358 // always send changed ??
6359 SET_AH(06);
6360 goto int13_fail_nostatus;
6361 break;
6362
6363 case 0x4e: // // IBM/MS set hardware configuration
6364 // DMA, prefetch, PIO maximum not supported
6365 switch (GET_AL()) {
6366 case 0x01:
6367 case 0x03:
6368 case 0x04:
6369 case 0x06:
6370 goto int13_success;
6371 break;
6372 default :
6373 goto int13_fail;
6374 }
6375 break;
6376
6377 // all those functions return unimplemented
6378 case 0x02: /* read sectors */
6379 case 0x04: /* verify sectors */
6380 case 0x08: /* read disk drive parameters */
6381 case 0x0a: /* read disk sectors with ECC */
6382 case 0x0b: /* write disk sectors with ECC */
6383 case 0x18: /* set media type for format */
6384 case 0x50: // ? - send packet command
6385 default:
6386 BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
6387 goto int13_fail;
6388 break;
6389 }
6390
6391int13_fail:
6392 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6393int13_fail_noah:
6394 SET_DISK_RET_STATUS(GET_AH());
6395int13_fail_nostatus:
6396 SET_CF(); // error occurred
6397 return;
6398
6399int13_success:
6400 SET_AH(0x00); // no error
6401int13_success_noah:
6402 SET_DISK_RET_STATUS(0x00);
6403 CLEAR_CF(); // no error
6404 return;
6405}
6406
6407// ---------------------------------------------------------------------------
6408// End of int13 for cdrom
6409// ---------------------------------------------------------------------------
6410
6411#if BX_ELTORITO_BOOT
6412// ---------------------------------------------------------------------------
6413// Start of int13 for eltorito functions
6414// ---------------------------------------------------------------------------
6415
6416 void
6417int13_eltorito(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
6418 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
6419{
6420 Bit16u ebda_seg=read_word(0x0040,0x000E);
6421
6422 BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6423 // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
6424
6425 switch (GET_AH()) {
6426
6427 // FIXME ElTorito Various. Should be implemented
6428 case 0x4a: // ElTorito - Initiate disk emu
6429 case 0x4c: // ElTorito - Initiate disk emu and boot
6430 case 0x4d: // ElTorito - Return Boot catalog
6431 BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX);
6432 goto int13_fail;
6433 break;
6434
6435 case 0x4b: // ElTorito - Terminate disk emu
6436 // FIXME ElTorito Hardcoded
6437 write_byte(DS,SI+0x00,0x13);
6438 write_byte(DS,SI+0x01,read_byte(ebda_seg,&EbdaData->cdemu.media));
6439 write_byte(DS,SI+0x02,read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
6440 write_byte(DS,SI+0x03,read_byte(ebda_seg,&EbdaData->cdemu.controller_index));
6441 write_dword(DS,SI+0x04,read_dword(ebda_seg,&EbdaData->cdemu.ilba));
6442 write_word(DS,SI+0x08,read_word(ebda_seg,&EbdaData->cdemu.device_spec));
6443 write_word(DS,SI+0x0a,read_word(ebda_seg,&EbdaData->cdemu.buffer_segment));
6444 write_word(DS,SI+0x0c,read_word(ebda_seg,&EbdaData->cdemu.load_segment));
6445 write_word(DS,SI+0x0e,read_word(ebda_seg,&EbdaData->cdemu.sector_count));
6446 write_byte(DS,SI+0x10,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.cylinders));
6447 write_byte(DS,SI+0x11,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.spt));
6448 write_byte(DS,SI+0x12,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.heads));
6449
6450 // If we have to terminate emulation
6451 if(GET_AL() == 0x00) {
6452 // FIXME ElTorito Various. Should be handled accordingly to spec
6453 write_byte(ebda_seg,&EbdaData->cdemu.active, 0x00); // bye bye
6454 }
6455
6456 goto int13_success;
6457 break;
6458
6459 default:
6460 BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
6461 goto int13_fail;
6462 break;
6463 }
6464
6465int13_fail:
6466 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6467 SET_DISK_RET_STATUS(GET_AH());
6468 SET_CF(); // error occurred
6469 return;
6470
6471int13_success:
6472 SET_AH(0x00); // no error
6473 SET_DISK_RET_STATUS(0x00);
6474 CLEAR_CF(); // no error
6475 return;
6476}
6477
6478// ---------------------------------------------------------------------------
6479// End of int13 for eltorito functions
6480// ---------------------------------------------------------------------------
6481
6482// ---------------------------------------------------------------------------
6483// Start of int13 when emulating a device from the cd
6484// ---------------------------------------------------------------------------
6485
6486 void
6487int13_cdemu(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
6488 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
6489{
6490 Bit16u ebda_seg=read_word(0x0040,0x000E);
6491 Bit8u device, status;
6492 Bit16u vheads, vspt, vcylinders;
6493 Bit16u head, sector, cylinder, nbsectors;
6494 Bit32u vlba, ilba, slba, elba;
6495 Bit16u before, segment, offset;
6496 Bit8u atacmd[12];
6497
6498 BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6499
6500 /* at this point, we are emulating a floppy/harddisk */
6501
6502 // Recompute the device number
6503 device = read_byte(ebda_seg,&EbdaData->cdemu.controller_index) * 2;
6504 device += read_byte(ebda_seg,&EbdaData->cdemu.device_spec);
6505
6506 SET_DISK_RET_STATUS(0x00);
6507
6508 /* basic checks : emulation should be active, dl should equal the emulated drive */
6509 if( (read_byte(ebda_seg,&EbdaData->cdemu.active) ==0 )
6510 || (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive ) != GET_DL())) {
6511 BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
6512 goto int13_fail;
6513 }
6514
6515 switch (GET_AH()) {
6516
6517 // all those functions return SUCCESS
6518 case 0x00: /* disk controller reset */
6519 case 0x09: /* initialize drive parameters */
6520 case 0x0c: /* seek to specified cylinder */
6521 case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
6522 case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
6523 case 0x11: /* recalibrate */
6524 case 0x14: /* controller internal diagnostic */
6525 case 0x16: /* detect disk change */
6526 goto int13_success;
6527 break;
6528
6529 // all those functions return disk write-protected
6530 case 0x03: /* write disk sectors */
6531 case 0x05: /* format disk track */
6532 SET_AH(0x03);
6533 goto int13_fail_noah;
6534 break;
6535
6536 case 0x01: /* read disk status */
6537 status=read_byte(0x0040, 0x0074);
6538 SET_AH(status);
6539 SET_DISK_RET_STATUS(0);
6540
6541 /* set CF if error status read */
6542 if (status) goto int13_fail_nostatus;
6543 else goto int13_success_noah;
6544 break;
6545
6546 case 0x02: // read disk sectors
6547 case 0x04: // verify disk sectors
6548 vspt = read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
6549 vcylinders = read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders);
6550 vheads = read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads);
6551
6552 ilba = read_dword(ebda_seg,&EbdaData->cdemu.ilba);
6553
6554 sector = GET_CL() & 0x003f;
6555 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
6556 head = GET_DH();
6557 nbsectors = GET_AL();
6558 segment = ES;
6559 offset = BX;
6560
6561 // no sector to read ?
6562 if(nbsectors==0) goto int13_success;
6563
6564 // sanity checks sco openserver needs this!
6565 if ((sector > vspt)
6566 || (cylinder >= vcylinders)
6567 || (head >= vheads)) {
6568 goto int13_fail;
6569 }
6570
6571 // After controls, verify do nothing
6572 if (GET_AH() == 0x04) goto int13_success;
6573
6574 segment = ES+(BX / 16);
6575 offset = BX % 16;
6576
6577 // calculate the virtual lba inside the image
6578 vlba=((((Bit32u)cylinder*(Bit32u)vheads)+(Bit32u)head)*(Bit32u)vspt)+((Bit32u)(sector-1));
6579
6580 // In advance so we don't loose the count
6581 SET_AL(nbsectors);
6582
6583 // start lba on cd
6584 slba = (Bit32u)vlba/4;
6585 before= (Bit16u)vlba%4;
6586
6587 // end lba on cd
6588 elba = (Bit32u)(vlba+nbsectors-1)/4;
6589
6590 memsetb(get_SS(),atacmd,0,12);
6591 atacmd[0]=0x28; // READ command
6592 atacmd[7]=((Bit16u)(elba-slba+1) & 0xff00) >> 8; // Sectors
6593 atacmd[8]=((Bit16u)(elba-slba+1) & 0x00ff); // Sectors
6594 atacmd[2]=(ilba+slba & 0xff000000) >> 24; // LBA
6595 atacmd[3]=(ilba+slba & 0x00ff0000) >> 16;
6596 atacmd[4]=(ilba+slba & 0x0000ff00) >> 8;
6597 atacmd[5]=(ilba+slba & 0x000000ff);
6598 if((status = ata_cmd_packet(device, 12, get_SS(), atacmd, before*512, nbsectors*512L, ATA_DATA_IN, segment,offset)) != 0) {
6599 BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status);
6600 SET_AH(0x02);
6601 SET_AL(0);
6602 goto int13_fail_noah;
6603 }
6604
6605 goto int13_success;
6606 break;
6607
6608 case 0x08: /* read disk drive parameters */
6609 vspt=read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
6610 vcylinders=read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders) - 1;
6611 vheads=read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads) - 1;
6612
6613 SET_AL( 0x00 );
6614 SET_BL( 0x00 );
6615 SET_CH( vcylinders & 0xff );
6616 SET_CL((( vcylinders >> 2) & 0xc0) | ( vspt & 0x3f ));
6617 SET_DH( vheads );
6618 SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2
6619 // FIXME ElTorito Harddisk. should send the HD count
6620
6621 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
6622 case 0x01: SET_BL( 0x02 ); break;
6623 case 0x02: SET_BL( 0x04 ); break;
6624 case 0x03: SET_BL( 0x06 ); break;
6625 }
6626
6627ASM_START
6628 push bp
6629 mov bp, sp
6630 mov ax, #diskette_param_table2
6631 mov _int13_cdemu.DI+2[bp], ax
6632 mov _int13_cdemu.ES+2[bp], cs
6633 pop bp
6634ASM_END
6635 goto int13_success;
6636 break;
6637
6638 case 0x15: /* read disk drive size */
6639 // FIXME ElTorito Harddisk. What geometry to send ?
6640 SET_AH(0x03);
6641 goto int13_success_noah;
6642 break;
6643
6644 // all those functions return unimplemented
6645 case 0x0a: /* read disk sectors with ECC */
6646 case 0x0b: /* write disk sectors with ECC */
6647 case 0x18: /* set media type for format */
6648 case 0x41: // IBM/MS installation check
6649 // FIXME ElTorito Harddisk. Darwin would like to use EDD
6650 case 0x42: // IBM/MS extended read
6651 case 0x43: // IBM/MS extended write
6652 case 0x44: // IBM/MS verify sectors
6653 case 0x45: // IBM/MS lock/unlock drive
6654 case 0x46: // IBM/MS eject media
6655 case 0x47: // IBM/MS extended seek
6656 case 0x48: // IBM/MS get drive parameters
6657 case 0x49: // IBM/MS extended media change
6658 case 0x4e: // ? - set hardware configuration
6659 case 0x50: // ? - send packet command
6660 default:
6661 BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
6662 goto int13_fail;
6663 break;
6664 }
6665
6666int13_fail:
6667 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6668int13_fail_noah:
6669 SET_DISK_RET_STATUS(GET_AH());
6670int13_fail_nostatus:
6671 SET_CF(); // error occurred
6672 return;
6673
6674int13_success:
6675 SET_AH(0x00); // no error
6676int13_success_noah:
6677 SET_DISK_RET_STATUS(0x00);
6678 CLEAR_CF(); // no error
6679 return;
6680}
6681
6682// ---------------------------------------------------------------------------
6683// End of int13 when emulating a device from the cd
6684// ---------------------------------------------------------------------------
6685
6686#endif // BX_ELTORITO_BOOT
6687
6688#else //BX_USE_ATADRV
6689
6690 void
6691outLBA(cylinder,hd_heads,head,hd_sectors,sector,dl)
6692 Bit16u cylinder;
6693 Bit16u hd_heads;
6694 Bit16u head;
6695 Bit16u hd_sectors;
6696 Bit16u sector;
6697 Bit16u dl;
6698{
6699ASM_START
6700 push bp
6701 mov bp, sp
6702 push eax
6703 push ebx
6704 push edx
6705 xor eax,eax
6706 mov ax,4[bp] // cylinder
6707 xor ebx,ebx
6708 mov bl,6[bp] // hd_heads
6709 imul ebx
6710
6711 mov bl,8[bp] // head
6712 add eax,ebx
6713 mov bl,10[bp] // hd_sectors
6714 imul ebx
6715 mov bl,12[bp] // sector
6716 add eax,ebx
6717
6718 dec eax
6719 mov dx,#0x1f3
6720 out dx,al
6721 mov dx,#0x1f4
6722 mov al,ah
6723 out dx,al
6724 shr eax,#16
6725 mov dx,#0x1f5
6726 out dx,al
6727 and ah,#0xf
6728 mov bl,14[bp] // dl
6729 and bl,#1
6730 shl bl,#4
6731 or ah,bl
6732 or ah,#0xe0
6733 mov al,ah
6734 mov dx,#0x01f6
6735 out dx,al
6736 pop edx
6737 pop ebx
6738 pop eax
6739 pop bp
6740ASM_END
6741}
6742
6743 void
6744int13_harddisk(EHBX, EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
6745 Bit16u EHBX, EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
6746{
6747 Bit8u drive, num_sectors, sector, head, status, mod;
6748 Bit8u drive_map;
6749 Bit8u n_drives;
6750 Bit16u cyl_mod, ax;
6751 Bit16u max_cylinder, cylinder, total_sectors;
6752 Bit16u hd_cylinders;
6753 Bit8u hd_heads, hd_sectors;
6754 Bit16u val16;
6755 Bit8u sector_count;
6756 unsigned int i;
6757 Bit16u tempbx;
6758 Bit16u dpsize;
6759
6760 Bit16u count, segment, offset;
6761 Bit32u lba;
6762 Bit16u error;
6763
6764 BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6765
6766 write_byte(0x0040, 0x008e, 0); // clear completion flag
6767
6768 /* at this point, DL is >= 0x80 to be passed from the floppy int13h
6769 handler code */
6770 /* check how many disks first (cmos reg 0x12), return an error if
6771 drive not present */
6772 drive_map = inb_cmos(0x12);
6773 drive_map = (((drive_map & 0xf0)==0) ? 0 : 1) |
6774 (((drive_map & 0x0f)==0) ? 0 : 2);
6775 n_drives = (drive_map==0) ? 0 :
6776 ((drive_map==3) ? 2 : 1);
6777
6778 if (!(drive_map & (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
6779 SET_AH(0x01);
6780 SET_DISK_RET_STATUS(0x01);
6781 SET_CF(); /* error occurred */
6782 return;
6783 }
6784
6785 switch (GET_AH()) {
6786
6787 case 0x00: /* disk controller reset */
6788BX_DEBUG_INT13_HD("int13_f00\n");
6789
6790 SET_AH(0);
6791 SET_DISK_RET_STATUS(0);
6792 set_diskette_ret_status(0);
6793 set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
6794 set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
6795 CLEAR_CF(); /* successful */
6796 return;
6797 break;
6798
6799 case 0x01: /* read disk status */
6800BX_DEBUG_INT13_HD("int13_f01\n");
6801 status = read_byte(0x0040, 0x0074);
6802 SET_AH(status);
6803 SET_DISK_RET_STATUS(0);
6804 /* set CF if error status read */
6805 if (status) SET_CF();
6806 else CLEAR_CF();
6807 return;
6808 break;
6809
6810 case 0x04: // verify disk sectors
6811 case 0x02: // read disk sectors
6812 drive = GET_ELDL();
6813 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6814
6815 num_sectors = GET_AL();
6816 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
6817 sector = (GET_CL() & 0x3f);
6818 head = GET_DH();
6819
6820
6821 if (hd_cylinders > 1024) {
6822 if (hd_cylinders <= 2048) {
6823 cylinder <<= 1;
6824 }
6825 else if (hd_cylinders <= 4096) {
6826 cylinder <<= 2;
6827 }
6828 else if (hd_cylinders <= 8192) {
6829 cylinder <<= 3;
6830 }
6831 else { // hd_cylinders <= 16384
6832 cylinder <<= 4;
6833 }
6834
6835 ax = head / hd_heads;
6836 cyl_mod = ax & 0xff;
6837 head = ax >> 8;
6838 cylinder |= cyl_mod;
6839 }
6840
6841 if ( (cylinder >= hd_cylinders) ||
6842 (sector > hd_sectors) ||
6843 (head >= hd_heads) ) {
6844 SET_AH(1);
6845 SET_DISK_RET_STATUS(1);
6846 SET_CF(); /* error occurred */
6847 return;
6848 }
6849
6850 if ( (num_sectors > 128) || (num_sectors == 0) )
6851 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6852
6853 if (head > 15)
6854 BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
6855
6856 if ( GET_AH() == 0x04 ) {
6857 SET_AH(0);
6858 SET_DISK_RET_STATUS(0);
6859 CLEAR_CF();
6860 return;
6861 }
6862
6863 status = inb(0x1f7);
6864 if (status & 0x80) {
6865 BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
6866 }
6867 outb(0x01f2, num_sectors);
6868 /* activate LBA? (tomv) */
6869 if (hd_heads > 16) {
6870BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder, head, sector);
6871 outLBA(cylinder,hd_heads,head,hd_sectors,sector,drive);
6872 }
6873 else {
6874 outb(0x01f3, sector);
6875 outb(0x01f4, cylinder & 0x00ff);
6876 outb(0x01f5, cylinder >> 8);
6877 outb(0x01f6, 0xa0 | ((drive & 0x01)<<4) | (head & 0x0f));
6878 }
6879 outb(0x01f7, 0x20);
6880
6881 while (1) {
6882 status = inb(0x1f7);
6883 if ( !(status & 0x80) ) break;
6884 }
6885
6886 if (status & 0x01) {
6887 BX_PANIC("hard drive BIOS:(read/verify) read error\n");
6888 } else if ( !(status & 0x08) ) {
6889 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6890 BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
6891 }
6892
6893 sector_count = 0;
6894 tempbx = BX;
6895
6896ASM_START
6897 sti ;; enable higher priority interrupts
6898ASM_END
6899
6900 while (1) {
6901ASM_START
6902 ;; store temp bx in real DI register
6903 push bp
6904 mov bp, sp
6905 mov di, _int13_harddisk.tempbx + 2 [bp]
6906 pop bp
6907
6908 ;; adjust if there will be an overrun
6909 cmp di, #0xfe00
6910 jbe i13_f02_no_adjust
6911i13_f02_adjust:
6912 sub di, #0x0200 ; sub 512 bytes from offset
6913 mov ax, es
6914 add ax, #0x0020 ; add 512 to segment
6915 mov es, ax
6916
6917i13_f02_no_adjust:
6918 mov cx, #0x0100 ;; counter (256 words = 512b)
6919 mov dx, #0x01f0 ;; AT data read port
6920
6921 rep
6922 insw ;; CX words transferred from port(DX) to ES:[DI]
6923
6924i13_f02_done:
6925 ;; store real DI register back to temp bx
6926 push bp
6927 mov bp, sp
6928 mov _int13_harddisk.tempbx + 2 [bp], di
6929 pop bp
6930ASM_END
6931
6932 sector_count++;
6933 num_sectors--;
6934 if (num_sectors == 0) {
6935 status = inb(0x1f7);
6936 if ( (status & 0xc9) != 0x40 )
6937 BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status);
6938 break;
6939 }
6940 else {
6941 status = inb(0x1f7);
6942 if ( (status & 0xc9) != 0x48 )
6943 BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status);
6944 continue;
6945 }
6946 }
6947
6948 SET_AH(0);
6949 SET_DISK_RET_STATUS(0);
6950 SET_AL(sector_count);
6951 CLEAR_CF(); /* successful */
6952 return;
6953 break;
6954
6955
6956 case 0x03: /* write disk sectors */
6957BX_DEBUG_INT13_HD("int13_f03\n");
6958 drive = GET_ELDL ();
6959 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6960
6961 num_sectors = GET_AL();
6962 cylinder = GET_CH();
6963 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
6964 sector = (GET_CL() & 0x3f);
6965 head = GET_DH();
6966
6967 if (hd_cylinders > 1024) {
6968 if (hd_cylinders <= 2048) {
6969 cylinder <<= 1;
6970 }
6971 else if (hd_cylinders <= 4096) {
6972 cylinder <<= 2;
6973 }
6974 else if (hd_cylinders <= 8192) {
6975 cylinder <<= 3;
6976 }
6977 else { // hd_cylinders <= 16384
6978 cylinder <<= 4;
6979 }
6980
6981 ax = head / hd_heads;
6982 cyl_mod = ax & 0xff;
6983 head = ax >> 8;
6984 cylinder |= cyl_mod;
6985 }
6986
6987 if ( (cylinder >= hd_cylinders) ||
6988 (sector > hd_sectors) ||
6989 (head >= hd_heads) ) {
6990 SET_AH( 1);
6991 SET_DISK_RET_STATUS(1);
6992 SET_CF(); /* error occurred */
6993 return;
6994 }
6995
6996 if ( (num_sectors > 128) || (num_sectors == 0) )
6997 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6998
6999 if (head > 15)
7000 BX_PANIC("hard drive BIOS:(read) head > 15\n");
7001
7002 status = inb(0x1f7);
7003 if (status & 0x80) {
7004 BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
7005 }
7006// should check for Drive Ready Bit also in status reg
7007 outb(0x01f2, num_sectors);
7008
7009 /* activate LBA? (tomv) */
7010 if (hd_heads > 16) {
7011BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder, head, sector);
7012 outLBA(cylinder,hd_heads,head,hd_sectors,sector,GET_ELDL());
7013 }
7014 else {
7015 outb(0x01f3, sector);
7016 outb(0x01f4, cylinder & 0x00ff);
7017 outb(0x01f5, cylinder >> 8);
7018 outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head & 0x0f));
7019 }
7020 outb(0x01f7, 0x30);
7021
7022 // wait for busy bit to turn off after seeking
7023 while (1) {
7024 status = inb(0x1f7);
7025 if ( !(status & 0x80) ) break;
7026 }
7027
7028 if ( !(status & 0x08) ) {
7029 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
7030 BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
7031 }
7032
7033 sector_count = 0;
7034 tempbx = BX;
7035
7036ASM_START
7037 sti ;; enable higher priority interrupts
7038ASM_END
7039
7040 while (1) {
7041ASM_START
7042 ;; store temp bx in real SI register
7043 push bp
7044 mov bp, sp
7045 mov si, _int13_harddisk.tempbx + 2 [bp]
7046 pop bp
7047
7048 ;; adjust if there will be an overrun
7049 cmp si, #0xfe00
7050 jbe i13_f03_no_adjust
7051i13_f03_adjust:
7052 sub si, #0x0200 ; sub 512 bytes from offset
7053 mov ax, es
7054 add ax, #0x0020 ; add 512 to segment
7055 mov es, ax
7056
7057i13_f03_no_adjust:
7058 mov cx, #0x0100 ;; counter (256 words = 512b)
7059 mov dx, #0x01f0 ;; AT data read port
7060
7061 seg ES
7062 rep
7063 outsw ;; CX words transferred from ES:[SI] to port(DX)
7064
7065 ;; store real SI register back to temp bx
7066 push bp
7067 mov bp, sp
7068 mov _int13_harddisk.tempbx + 2 [bp], si
7069 pop bp
7070ASM_END
7071
7072 sector_count++;
7073 num_sectors--;
7074 if (num_sectors == 0) {
7075 status = inb(0x1f7);
7076 if ( (status & 0xe9) != 0x40 )
7077 BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status);
7078 break;
7079 }
7080 else {
7081 status = inb(0x1f7);
7082 if ( (status & 0xc9) != 0x48 )
7083 BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status);
7084 continue;
7085 }
7086 }
7087
7088 SET_AH(0);
7089 SET_DISK_RET_STATUS(0);
7090 SET_AL(sector_count);
7091 CLEAR_CF(); /* successful */
7092 return;
7093 break;
7094
7095 case 0x05: /* format disk track */
7096BX_DEBUG_INT13_HD("int13_f05\n");
7097 BX_PANIC("format disk track called\n");
7098 /* nop */
7099 SET_AH(0);
7100 SET_DISK_RET_STATUS(0);
7101 CLEAR_CF(); /* successful */
7102 return;
7103 break;
7104
7105 case 0x08: /* read disk drive parameters */
7106BX_DEBUG_INT13_HD("int13_f08\n");
7107
7108 drive = GET_ELDL ();
7109 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
7110
7111 // translate CHS
7112 //
7113 if (hd_cylinders <= 1024) {
7114 // hd_cylinders >>= 0;
7115 // hd_heads <<= 0;
7116 }
7117 else if (hd_cylinders <= 2048) {
7118 hd_cylinders >>= 1;
7119 hd_heads <<= 1;
7120 }
7121 else if (hd_cylinders <= 4096) {
7122 hd_cylinders >>= 2;
7123 hd_heads <<= 2;
7124 }
7125 else if (hd_cylinders <= 8192) {
7126 hd_cylinders >>= 3;
7127 hd_heads <<= 3;
7128 }
7129 else { // hd_cylinders <= 16384
7130 hd_cylinders >>= 4;
7131 hd_heads <<= 4;
7132 }
7133
7134 max_cylinder = hd_cylinders - 2; /* 0 based */
7135 SET_AL(0);
7136 SET_CH(max_cylinder & 0xff);
7137 SET_CL(((max_cylinder >> 2) & 0xc0) | (hd_sectors & 0x3f));
7138 SET_DH(hd_heads - 1);
7139 SET_DL(n_drives); /* returns 0, 1, or 2 hard drives */
7140 SET_AH(0);
7141 SET_DISK_RET_STATUS(0);
7142 CLEAR_CF(); /* successful */
7143
7144 return;
7145 break;
7146
7147 case 0x09: /* initialize drive parameters */
7148BX_DEBUG_INT13_HD("int13_f09\n");
7149 SET_AH(0);
7150 SET_DISK_RET_STATUS(0);
7151 CLEAR_CF(); /* successful */
7152 return;
7153 break;
7154
7155 case 0x0a: /* read disk sectors with ECC */
7156BX_DEBUG_INT13_HD("int13_f0a\n");
7157 case 0x0b: /* write disk sectors with ECC */
7158BX_DEBUG_INT13_HD("int13_f0b\n");
7159 BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
7160 return;
7161 break;
7162
7163 case 0x0c: /* seek to specified cylinder */
7164BX_DEBUG_INT13_HD("int13_f0c\n");
7165 BX_INFO("int13h function 0ch (seek) not implemented!\n");
7166 SET_AH(0);
7167 SET_DISK_RET_STATUS(0);
7168 CLEAR_CF(); /* successful */
7169 return;
7170 break;
7171
7172 case 0x0d: /* alternate disk reset */
7173BX_DEBUG_INT13_HD("int13_f0d\n");
7174 SET_AH(0);
7175 SET_DISK_RET_STATUS(0);
7176 CLEAR_CF(); /* successful */
7177 return;
7178 break;
7179
7180 case 0x10: /* check drive ready */
7181BX_DEBUG_INT13_HD("int13_f10\n");
7182 //SET_AH(0);
7183 //SET_DISK_RET_STATUS(0);
7184 //CLEAR_CF(); /* successful */
7185 //return;
7186 //break;
7187
7188 // should look at 40:8E also???
7189 status = inb(0x01f7);
7190 if ( (status & 0xc0) == 0x40 ) {
7191 SET_AH(0);
7192 SET_DISK_RET_STATUS(0);
7193 CLEAR_CF(); // drive ready
7194 return;
7195 }
7196 else {
7197 SET_AH(0xAA);
7198 SET_DISK_RET_STATUS(0xAA);
7199 SET_CF(); // not ready
7200 return;
7201 }
7202 break;
7203
7204 case 0x11: /* recalibrate */
7205BX_DEBUG_INT13_HD("int13_f11\n");
7206 SET_AH(0);
7207 SET_DISK_RET_STATUS(0);
7208 CLEAR_CF(); /* successful */
7209 return;
7210 break;
7211
7212 case 0x14: /* controller internal diagnostic */
7213BX_DEBUG_INT13_HD("int13_f14\n");
7214 SET_AH(0);
7215 SET_DISK_RET_STATUS(0);
7216 CLEAR_CF(); /* successful */
7217 SET_AL(0);
7218 return;
7219 break;
7220
7221 case 0x15: /* read disk drive size */
7222 drive = GET_ELDL();
7223 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
7224ASM_START
7225 push bp
7226 mov bp, sp
7227 mov al, _int13_harddisk.hd_heads + 2 [bp]
7228 mov ah, _int13_harddisk.hd_sectors + 2 [bp]
7229 mul al, ah ;; ax = heads * sectors
7230 mov bx, _int13_harddisk.hd_cylinders + 2 [bp]
7231 dec bx ;; use (cylinders - 1) ???
7232 mul ax, bx ;; dx:ax = (cylinders -1) * (heads * sectors)
7233 ;; now we need to move the 32bit result dx:ax to what the
7234 ;; BIOS wants which is cx:dx.
7235 ;; and then into CX:DX on the stack
7236 mov _int13_harddisk.CX + 2 [bp], dx
7237 mov _int13_harddisk.DX + 2 [bp], ax
7238 pop bp
7239ASM_END
7240 SET_AH(3); // hard disk accessible
7241 SET_DISK_RET_STATUS(0); // ??? should this be 0
7242 CLEAR_CF(); // successful
7243 return;
7244 break;
7245
7246 case 0x18: // set media type for format
7247 case 0x41: // IBM/MS
7248 case 0x42: // IBM/MS
7249 case 0x43: // IBM/MS
7250 case 0x44: // IBM/MS
7251 case 0x45: // IBM/MS lock/unlock drive
7252 case 0x46: // IBM/MS eject media
7253 case 0x47: // IBM/MS extended seek
7254 case 0x49: // IBM/MS extended media change
7255 case 0x50: // IBM/MS send packet command
7256 default:
7257 BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
7258
7259 SET_AH(1); // code=invalid function in AH or invalid parameter
7260 SET_DISK_RET_STATUS(1);
7261 SET_CF(); /* unsuccessful */
7262 return;
7263 break;
7264 }
7265}
7266
7267static char panic_msg_reg12h[] = "HD%d cmos reg 12h not type F\n";
7268static char panic_msg_reg19h[] = "HD%d cmos reg %02xh not user definable type 47\n";
7269
7270 void
7271get_hd_geometry(drive, hd_cylinders, hd_heads, hd_sectors)
7272 Bit8u drive;
7273 Bit16u *hd_cylinders;
7274 Bit8u *hd_heads;
7275 Bit8u *hd_sectors;
7276{
7277 Bit8u hd_type;
7278 Bit16u ss;
7279 Bit16u cylinders;
7280 Bit8u iobase;
7281
7282 ss = get_SS();
7283 if (drive == 0x80) {
7284 hd_type = inb_cmos(0x12) & 0xf0;
7285 if (hd_type != 0xf0)
7286 BX_INFO(panic_msg_reg12h,0);
7287 hd_type = inb_cmos(0x19); // HD0: extended type
7288 if (hd_type != 47)
7289 BX_INFO(panic_msg_reg19h,0,0x19);
7290 iobase = 0x1b;
7291 } else {
7292 hd_type = inb_cmos(0x12) & 0x0f;
7293 if (hd_type != 0x0f)
7294 BX_INFO(panic_msg_reg12h,1);
7295 hd_type = inb_cmos(0x1a); // HD1: extended type
7296 if (hd_type != 47)
7297 BX_INFO(panic_msg_reg19h,0,0x1a);
7298 iobase = 0x24;
7299 }
7300
7301 // cylinders
7302 cylinders = inb_cmos(iobase) | (inb_cmos(iobase+1) << 8);
7303 write_word(ss, hd_cylinders, cylinders);
7304
7305 // heads
7306 write_byte(ss, hd_heads, inb_cmos(iobase+2));
7307
7308 // sectors per track
7309 write_byte(ss, hd_sectors, inb_cmos(iobase+8));
7310}
7311
7312#endif //else BX_USE_ATADRV
7313
7314#if BX_SUPPORT_FLOPPY
7315
7316//////////////////////
7317// FLOPPY functions //
7318//////////////////////
7319
7320void floppy_reset_controller()
7321{
7322 Bit8u val8;
7323
7324 // Reset controller
7325 val8 = inb(0x03f2);
7326 outb(0x03f2, val8 & ~0x04);
7327 outb(0x03f2, val8 | 0x04);
7328
7329 // Wait for controller to come out of reset
7330 do {
7331 val8 = inb(0x3f4);
7332 } while ( (val8 & 0xc0) != 0x80 );
7333}
7334
7335void floppy_prepare_controller(drive)
7336 Bit16u drive;
7337{
7338 Bit8u val8, dor, prev_reset;
7339
7340 // set 40:3e bit 7 to 0
7341 val8 = read_byte(0x0040, 0x003e);
7342 val8 &= 0x7f;
7343 write_byte(0x0040, 0x003e, val8);
7344
7345 // turn on motor of selected drive, DMA & int enabled, normal operation
7346 prev_reset = inb(0x03f2) & 0x04;
7347 if (drive)
7348 dor = 0x20;
7349 else
7350 dor = 0x10;
7351 dor |= 0x0c;
7352 dor |= drive;
7353 outb(0x03f2, dor);
7354
7355 // reset the disk motor timeout value of INT 08
7356 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
7357
7358#ifdef VBOX
7359 // program data rate
7360 val8 = read_byte(0x0040, 0x008b);
7361 val8 >>= 6;
7362 outb(0x03f7, val8);
7363#endif
7364
7365 // wait for drive readiness
7366 do {
7367 val8 = inb(0x3f4);
7368 } while ( (val8 & 0xc0) != 0x80 );
7369
7370 if (prev_reset == 0) {
7371 // turn on interrupts
7372ASM_START
7373 sti
7374ASM_END
7375 // wait on 40:3e bit 7 to become 1
7376 do {
7377 val8 = read_byte(0x0040, 0x003e);
7378 } while ( (val8 & 0x80) == 0 );
7379 val8 &= 0x7f;
7380ASM_START
7381 cli
7382ASM_END
7383 write_byte(0x0040, 0x003e, val8);
7384 }
7385}
7386
7387 bx_bool
7388floppy_media_known(drive)
7389 Bit16u drive;
7390{
7391 Bit8u val8;
7392 Bit16u media_state_offset;
7393
7394 val8 = read_byte(0x0040, 0x003e); // diskette recal status
7395 if (drive)
7396 val8 >>= 1;
7397 val8 &= 0x01;
7398 if (val8 == 0)
7399 return(0);
7400
7401 media_state_offset = 0x0090;
7402 if (drive)
7403 media_state_offset += 1;
7404
7405 val8 = read_byte(0x0040, media_state_offset);
7406 val8 = (val8 >> 4) & 0x01;
7407 if (val8 == 0)
7408 return(0);
7409
7410 // check pass, return KNOWN
7411 return(1);
7412}
7413
7414 bx_bool
7415floppy_read_id(drive)
7416 Bit16u drive;
7417{
7418 Bit8u val8;
7419 Bit8u return_status[7];
7420
7421 floppy_prepare_controller(drive);
7422
7423 // send Read ID command (2 bytes) to controller
7424 outb(0x03f5, 0x4a); // 4a: Read ID (MFM)
7425 outb(0x03f5, drive); // 0=drive0, 1=drive1, head always 0
7426
7427 // turn on interrupts
7428ASM_START
7429 sti
7430ASM_END
7431
7432 // wait on 40:3e bit 7 to become 1
7433 do {
7434 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7435 } while ( val8 == 0 );
7436
7437 val8 = 0; // separate asm from while() loop
7438 // turn off interrupts
7439ASM_START
7440 cli
7441ASM_END
7442
7443 // read 7 return status bytes from controller
7444 return_status[0] = inb(0x3f5);
7445 return_status[1] = inb(0x3f5);
7446 return_status[2] = inb(0x3f5);
7447 return_status[3] = inb(0x3f5);
7448 return_status[4] = inb(0x3f5);
7449 return_status[5] = inb(0x3f5);
7450 return_status[6] = inb(0x3f5);
7451
7452 if ( (return_status[0] & 0xc0) != 0 )
7453 return(0);
7454 else
7455 return(1);
7456}
7457
7458 bx_bool
7459floppy_media_sense(drive)
7460 Bit16u drive;
7461{
7462 bx_bool retval;
7463 Bit16u media_state_offset;
7464 Bit8u drive_type, config_data, media_state;
7465
7466 if (floppy_drive_recal(drive) == 0) {
7467 return(0);
7468 }
7469
7470 // Try the diskette data rates in the following order:
7471 // 1 Mbps -> 500 Kbps -> 300 Kbps -> 250 Kbps
7472 // The 1 Mbps rate is only tried for 2.88M drives.
7473
7474 // ** config_data **
7475 // Bitfields for diskette media control:
7476 // Bit(s) Description (Table M0028)
7477 // 7-6 last data rate set by controller
7478 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
7479 // 5-4 last diskette drive step rate selected
7480 // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
7481 // 3-2 {data rate at start of operation}
7482 // 1-0 reserved
7483
7484 // ** media_state **
7485 // Bitfields for diskette drive media state:
7486 // Bit(s) Description (Table M0030)
7487 // 7-6 data rate
7488 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
7489 // 5 double stepping required (e.g. 360kB in 1.2MB)
7490 // 4 media type established
7491 // 3 drive capable of supporting 4MB media
7492 // 2-0 on exit from BIOS, contains
7493 // 000 trying 360kB in 360kB
7494 // 001 trying 360kB in 1.2MB
7495 // 010 trying 1.2MB in 1.2MB
7496 // 011 360kB in 360kB established
7497 // 100 360kB in 1.2MB established
7498 // 101 1.2MB in 1.2MB established
7499 // 110 reserved
7500 // 111 all other formats/drives
7501
7502 drive_type = inb_cmos(0x10);
7503 if (drive == 0)
7504 drive_type >>= 4;
7505 else
7506 drive_type &= 0x0f;
7507 if ( drive_type == 1 ) {
7508 // 360K 5.25" drive
7509 config_data = 0x00; // 0000 0000
7510 media_state = 0x15; // 0001 0101
7511 retval = 1;
7512 }
7513 else if ( drive_type == 2 ) {
7514 // 1.2 MB 5.25" drive
7515 config_data = 0x00; // 0000 0000
7516 media_state = 0x35; // 0011 0101 // need double stepping??? (bit 5)
7517 retval = 1;
7518 }
7519 else if ( drive_type == 3 ) {
7520 // 720K 3.5" drive
7521 config_data = 0x00; // 0000 0000 ???
7522 media_state = 0x17; // 0001 0111
7523 retval = 1;
7524 }
7525 else if ( drive_type == 4 ) {
7526 // 1.44 MB 3.5" drive
7527 config_data = 0x00; // 0000 0000
7528 media_state = 0x17; // 0001 0111
7529 retval = 1;
7530 }
7531 else if ( drive_type == 5 ) {
7532 // 2.88 MB 3.5" drive
7533 config_data = 0xCC; // 1100 1100
7534 media_state = 0xD7; // 1101 0111
7535 retval = 1;
7536 }
7537 //
7538 // Extended floppy size uses special cmos setting
7539 else if ( drive_type == 6 ) {
7540 // 160k 5.25" drive
7541 config_data = 0x00; // 0000 0000
7542 media_state = 0x27; // 0010 0111
7543 retval = 1;
7544 }
7545 else if ( drive_type == 7 ) {
7546 // 180k 5.25" drive
7547 config_data = 0x00; // 0000 0000
7548 media_state = 0x27; // 0010 0111
7549 retval = 1;
7550 }
7551 else if ( drive_type == 8 ) {
7552 // 320k 5.25" drive
7553 config_data = 0x00; // 0000 0000
7554 media_state = 0x27; // 0010 0111
7555 retval = 1;
7556 }
7557
7558 else {
7559 // not recognized
7560 config_data = 0x00; // 0000 0000
7561 media_state = 0x00; // 0000 0000
7562 retval = 0;
7563 }
7564
7565 write_byte(0x0040, 0x008B, config_data);
7566 while (!floppy_read_id(drive)) {
7567 if ((config_data & 0xC0) == 0x80) {
7568 // If even 250 Kbps failed, we can't do much
7569 break;
7570 }
7571 switch (config_data & 0xC0) {
7572 case 0xC0: // 1 Mbps
7573 config_data = config_data & 0x3F | 0x00;
7574 break;
7575 case 0x00: // 500 Kbps
7576 config_data = config_data & 0x3F | 0x40;
7577 break;
7578 case 0x40: // 300 Kbps
7579 config_data = config_data & 0x3F | 0x80;
7580 break;
7581 }
7582 write_byte(0x0040, 0x008B, config_data);
7583 }
7584
7585 if (drive == 0)
7586 media_state_offset = 0x0090;
7587 else
7588 media_state_offset = 0x0091;
7589 write_byte(0x0040, 0x008B, config_data);
7590 write_byte(0x0040, media_state_offset, media_state);
7591
7592 return(retval);
7593}
7594
7595 bx_bool
7596floppy_drive_recal(drive)
7597 Bit16u drive;
7598{
7599 Bit8u val8;
7600 Bit16u curr_cyl_offset;
7601
7602 floppy_prepare_controller(drive);
7603
7604 // send Recalibrate command (2 bytes) to controller
7605 outb(0x03f5, 0x07); // 07: Recalibrate
7606 outb(0x03f5, drive); // 0=drive0, 1=drive1
7607
7608 // turn on interrupts
7609ASM_START
7610 sti
7611ASM_END
7612
7613 // wait on 40:3e bit 7 to become 1
7614 do {
7615 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7616 } while ( val8 == 0 );
7617
7618 val8 = 0; // separate asm from while() loop
7619 // turn off interrupts
7620ASM_START
7621 cli
7622ASM_END
7623
7624 // set 40:3e bit 7 to 0, and calibrated bit
7625 val8 = read_byte(0x0040, 0x003e);
7626 val8 &= 0x7f;
7627 if (drive) {
7628 val8 |= 0x02; // Drive 1 calibrated
7629 curr_cyl_offset = 0x0095;
7630 } else {
7631 val8 |= 0x01; // Drive 0 calibrated
7632 curr_cyl_offset = 0x0094;
7633 }
7634 write_byte(0x0040, 0x003e, val8);
7635 write_byte(0x0040, curr_cyl_offset, 0); // current cylinder is 0
7636
7637 return(1);
7638}
7639
7640
7641
7642 bx_bool
7643floppy_drive_exists(drive)
7644 Bit16u drive;
7645{
7646 Bit8u drive_type;
7647
7648 // check CMOS to see if drive exists
7649 drive_type = inb_cmos(0x10);
7650 if (drive == 0)
7651 drive_type >>= 4;
7652 else
7653 drive_type &= 0x0f;
7654 if ( drive_type == 0 )
7655 return(0);
7656 else
7657 return(1);
7658}
7659
7660 void
7661int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
7662 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
7663{
7664 Bit8u drive, num_sectors, track, sector, head, status;
7665 Bit16u base_address, base_count, base_es;
7666 Bit8u page, mode_register, val8, dor;
7667 Bit8u return_status[7];
7668 Bit8u drive_type, num_floppies, ah;
7669 Bit16u es, last_addr;
7670
7671 BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
7672
7673 ah = GET_AH();
7674
7675 switch ( ah ) {
7676 case 0x00: // diskette controller reset
7677BX_DEBUG_INT13_FL("floppy f00\n");
7678 drive = GET_ELDL();
7679 if (drive > 1) {
7680 SET_AH(1); // invalid param
7681 set_diskette_ret_status(1);
7682 SET_CF();
7683 return;
7684 }
7685 drive_type = inb_cmos(0x10);
7686
7687 if (drive == 0)
7688 drive_type >>= 4;
7689 else
7690 drive_type &= 0x0f;
7691 if (drive_type == 0) {
7692 SET_AH(0x80); // drive not responding
7693 set_diskette_ret_status(0x80);
7694 SET_CF();
7695 return;
7696 }
7697
7698 // force re-calibration etc.
7699 write_byte(0x0040, 0x003e, 0);
7700
7701 SET_AH(0);
7702 set_diskette_ret_status(0);
7703 CLEAR_CF(); // successful
7704 set_diskette_current_cyl(drive, 0); // current cylinder
7705 return;
7706
7707 case 0x01: // Read Diskette Status
7708 CLEAR_CF();
7709 val8 = read_byte(0x0000, 0x0441);
7710 SET_AH(val8);
7711 if (val8) {
7712 SET_CF();
7713 }
7714 return;
7715
7716 case 0x02: // Read Diskette Sectors
7717 case 0x03: // Write Diskette Sectors
7718 case 0x04: // Verify Diskette Sectors
7719 num_sectors = GET_AL();
7720 track = GET_CH();
7721 sector = GET_CL();
7722 head = GET_DH();
7723 drive = GET_ELDL();
7724
7725 if ( (drive > 1) || (head > 1) ||
7726 (num_sectors == 0) || (num_sectors > 72) ) {
7727BX_INFO("floppy: drive>1 || head>1 ...\n");
7728 SET_AH(1);
7729 set_diskette_ret_status(1);
7730 SET_AL(0); // no sectors read
7731 SET_CF(); // error occurred
7732 return;
7733 }
7734
7735 // see if drive exists
7736 if (floppy_drive_exists(drive) == 0) {
7737 SET_AH(0x80); // not responding
7738 set_diskette_ret_status(0x80);
7739 SET_AL(0); // no sectors read
7740 SET_CF(); // error occurred
7741 return;
7742 }
7743
7744 // see if media in drive, and type is known
7745 if (floppy_media_known(drive) == 0) {
7746 if (floppy_media_sense(drive) == 0) {
7747 SET_AH(0x0C); // Media type not found
7748 set_diskette_ret_status(0x0C);
7749 SET_AL(0); // no sectors read
7750 SET_CF(); // error occurred
7751 return;
7752 }
7753 }
7754
7755 if (ah == 0x02) {
7756 // Read Diskette Sectors
7757
7758 //-----------------------------------
7759 // set up DMA controller for transfer
7760 //-----------------------------------
7761
7762 // es:bx = pointer to where to place information from diskette
7763 // port 04: DMA-1 base and current address, channel 2
7764 // port 05: DMA-1 base and current count, channel 2
7765 page = (ES >> 12); // upper 4 bits
7766 base_es = (ES << 4); // lower 16bits contributed by ES
7767 base_address = base_es + BX; // lower 16 bits of address
7768 // contributed by ES:BX
7769 if ( base_address < base_es ) {
7770 // in case of carry, adjust page by 1
7771 page++;
7772 }
7773 base_count = (num_sectors * 512) - 1;
7774
7775 // check for 64K boundary overrun
7776 last_addr = base_address + base_count;
7777 if (last_addr < base_address) {
7778 SET_AH(0x09);
7779 set_diskette_ret_status(0x09);
7780 SET_AL(0); // no sectors read
7781 SET_CF(); // error occurred
7782 return;
7783 }
7784
7785 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7786 outb(0x000a, 0x06);
7787
7788 BX_DEBUG_INT13_FL("clear flip-flop\n");
7789 outb(0x000c, 0x00); // clear flip-flop
7790 outb(0x0004, base_address);
7791 outb(0x0004, base_address>>8);
7792 BX_DEBUG_INT13_FL("clear flip-flop\n");
7793 outb(0x000c, 0x00); // clear flip-flop
7794 outb(0x0005, base_count);
7795 outb(0x0005, base_count>>8);
7796
7797 // port 0b: DMA-1 Mode Register
7798 mode_register = 0x46; // single mode, increment, autoinit disable,
7799 // transfer type=write, channel 2
7800 BX_DEBUG_INT13_FL("setting mode register\n");
7801 outb(0x000b, mode_register);
7802
7803 BX_DEBUG_INT13_FL("setting page register\n");
7804 // port 81: DMA-1 Page Register, channel 2
7805 outb(0x0081, page);
7806
7807 BX_DEBUG_INT13_FL("unmask chan 2\n");
7808 outb(0x000a, 0x02); // unmask channel 2
7809
7810 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7811 outb(0x000a, 0x02);
7812
7813 //--------------------------------------
7814 // set up floppy controller for transfer
7815 //--------------------------------------
7816 floppy_prepare_controller(drive);
7817
7818 // send read-normal-data command (9 bytes) to controller
7819 outb(0x03f5, 0xe6); // e6: read normal data
7820 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7821 outb(0x03f5, track);
7822 outb(0x03f5, head);
7823 outb(0x03f5, sector);
7824 outb(0x03f5, 2); // 512 byte sector size
7825 outb(0x03f5, sector + num_sectors - 1); // last sector to read on track
7826 outb(0x03f5, 0); // Gap length
7827 outb(0x03f5, 0xff); // Gap length
7828
7829 // turn on interrupts
7830 ASM_START
7831 sti
7832 ASM_END
7833
7834 // wait on 40:3e bit 7 to become 1
7835 do {
7836 val8 = read_byte(0x0040, 0x0040);
7837 if (val8 == 0) {
7838 floppy_reset_controller();
7839 SET_AH(0x80); // drive not ready (timeout)
7840 set_diskette_ret_status(0x80);
7841 SET_AL(0); // no sectors read
7842 SET_CF(); // error occurred
7843 return;
7844 }
7845 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7846 } while ( val8 == 0 );
7847
7848 val8 = 0; // separate asm from while() loop
7849 // turn off interrupts
7850 ASM_START
7851 cli
7852 ASM_END
7853
7854 // set 40:3e bit 7 to 0
7855 val8 = read_byte(0x0040, 0x003e);
7856 val8 &= 0x7f;
7857 write_byte(0x0040, 0x003e, val8);
7858
7859 // check port 3f4 for accessibility to status bytes
7860 val8 = inb(0x3f4);
7861 if ( (val8 & 0xc0) != 0xc0 )
7862 BX_PANIC("int13_diskette: ctrl not ready\n");
7863
7864 // read 7 return status bytes from controller
7865 // using loop index broken, have to unroll...
7866 return_status[0] = inb(0x3f5);
7867 return_status[1] = inb(0x3f5);
7868 return_status[2] = inb(0x3f5);
7869 return_status[3] = inb(0x3f5);
7870 return_status[4] = inb(0x3f5);
7871 return_status[5] = inb(0x3f5);
7872 return_status[6] = inb(0x3f5);
7873 // record in BIOS Data Area
7874 write_byte(0x0040, 0x0042, return_status[0]);
7875 write_byte(0x0040, 0x0043, return_status[1]);
7876 write_byte(0x0040, 0x0044, return_status[2]);
7877 write_byte(0x0040, 0x0045, return_status[3]);
7878 write_byte(0x0040, 0x0046, return_status[4]);
7879 write_byte(0x0040, 0x0047, return_status[5]);
7880 write_byte(0x0040, 0x0048, return_status[6]);
7881
7882 if ( (return_status[0] & 0xc0) != 0 ) {
7883 SET_AH(0x20);
7884 set_diskette_ret_status(0x20);
7885 SET_AL(0); // no sectors read
7886 SET_CF(); // error occurred
7887 return;
7888 }
7889
7890 // ??? should track be new val from return_status[3] ?
7891 set_diskette_current_cyl(drive, track);
7892 // AL = number of sectors read (same value as passed)
7893 SET_AH(0x00); // success
7894 CLEAR_CF(); // success
7895 return;
7896 } else if (ah == 0x03) {
7897 // Write Diskette Sectors
7898
7899 //-----------------------------------
7900 // set up DMA controller for transfer
7901 //-----------------------------------
7902
7903 // es:bx = pointer to where to place information from diskette
7904 // port 04: DMA-1 base and current address, channel 2
7905 // port 05: DMA-1 base and current count, channel 2
7906 page = (ES >> 12); // upper 4 bits
7907 base_es = (ES << 4); // lower 16bits contributed by ES
7908 base_address = base_es + BX; // lower 16 bits of address
7909 // contributed by ES:BX
7910 if ( base_address < base_es ) {
7911 // in case of carry, adjust page by 1
7912 page++;
7913 }
7914 base_count = (num_sectors * 512) - 1;
7915
7916 // check for 64K boundary overrun
7917 last_addr = base_address + base_count;
7918 if (last_addr < base_address) {
7919 SET_AH(0x09);
7920 set_diskette_ret_status(0x09);
7921 SET_AL(0); // no sectors read
7922 SET_CF(); // error occurred
7923 return;
7924 }
7925
7926 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7927 outb(0x000a, 0x06);
7928
7929 outb(0x000c, 0x00); // clear flip-flop
7930 outb(0x0004, base_address);
7931 outb(0x0004, base_address>>8);
7932 outb(0x000c, 0x00); // clear flip-flop
7933 outb(0x0005, base_count);
7934 outb(0x0005, base_count>>8);
7935
7936 // port 0b: DMA-1 Mode Register
7937 mode_register = 0x4a; // single mode, increment, autoinit disable,
7938 // transfer type=read, channel 2
7939 outb(0x000b, mode_register);
7940
7941 // port 81: DMA-1 Page Register, channel 2
7942 outb(0x0081, page);
7943
7944 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7945 outb(0x000a, 0x02);
7946
7947 //--------------------------------------
7948 // set up floppy controller for transfer
7949 //--------------------------------------
7950 floppy_prepare_controller(drive);
7951
7952 // send write-normal-data command (9 bytes) to controller
7953 outb(0x03f5, 0xc5); // c5: write normal data
7954 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7955 outb(0x03f5, track);
7956 outb(0x03f5, head);
7957 outb(0x03f5, sector);
7958 outb(0x03f5, 2); // 512 byte sector size
7959 outb(0x03f5, sector + num_sectors - 1); // last sector to write on track
7960 outb(0x03f5, 0); // Gap length
7961 outb(0x03f5, 0xff); // Gap length
7962
7963 // turn on interrupts
7964 ASM_START
7965 sti
7966 ASM_END
7967
7968 // wait on 40:3e bit 7 to become 1
7969 do {
7970 val8 = read_byte(0x0040, 0x0040);
7971 if (val8 == 0) {
7972 floppy_reset_controller();
7973 SET_AH(0x80); // drive not ready (timeout)
7974 set_diskette_ret_status(0x80);
7975 SET_AL(0); // no sectors written
7976 SET_CF(); // error occurred
7977 return;
7978 }
7979 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7980 } while ( val8 == 0 );
7981
7982 val8 = 0; // separate asm from while() loop
7983 // turn off interrupts
7984 ASM_START
7985 cli
7986 ASM_END
7987
7988 // set 40:3e bit 7 to 0
7989 val8 = read_byte(0x0040, 0x003e);
7990 val8 &= 0x7f;
7991 write_byte(0x0040, 0x003e, val8);
7992
7993 // check port 3f4 for accessibility to status bytes
7994 val8 = inb(0x3f4);
7995 if ( (val8 & 0xc0) != 0xc0 )
7996 BX_PANIC("int13_diskette: ctrl not ready\n");
7997
7998 // read 7 return status bytes from controller
7999 // using loop index broken, have to unroll...
8000 return_status[0] = inb(0x3f5);
8001 return_status[1] = inb(0x3f5);
8002 return_status[2] = inb(0x3f5);
8003 return_status[3] = inb(0x3f5);
8004 return_status[4] = inb(0x3f5);
8005 return_status[5] = inb(0x3f5);
8006 return_status[6] = inb(0x3f5);
8007 // record in BIOS Data Area
8008 write_byte(0x0040, 0x0042, return_status[0]);
8009 write_byte(0x0040, 0x0043, return_status[1]);
8010 write_byte(0x0040, 0x0044, return_status[2]);
8011 write_byte(0x0040, 0x0045, return_status[3]);
8012 write_byte(0x0040, 0x0046, return_status[4]);
8013 write_byte(0x0040, 0x0047, return_status[5]);
8014 write_byte(0x0040, 0x0048, return_status[6]);
8015
8016 if ( (return_status[0] & 0xc0) != 0 ) {
8017 if ( (return_status[1] & 0x02) != 0 ) {
8018 // diskette not writable.
8019 // AH=status code=0x03 (tried to write on write-protected disk)
8020 // AL=number of sectors written=0
8021 AX = 0x0300;
8022 SET_CF();
8023 return;
8024 } else {
8025 BX_PANIC("int13_diskette_function: read error\n");
8026 }
8027 }
8028
8029 // ??? should track be new val from return_status[3] ?
8030 set_diskette_current_cyl(drive, track);
8031 // AL = number of sectors read (same value as passed)
8032 SET_AH(0x00); // success
8033 CLEAR_CF(); // success
8034 return;
8035 } else { // if (ah == 0x04)
8036 // Verify Diskette Sectors
8037
8038 // ??? should track be new val from return_status[3] ?
8039 set_diskette_current_cyl(drive, track);
8040 // AL = number of sectors verified (same value as passed)
8041 CLEAR_CF(); // success
8042 SET_AH(0x00); // success
8043 return;
8044 }
8045 break;
8046
8047 case 0x05: // format diskette track
8048BX_DEBUG_INT13_FL("floppy f05\n");
8049
8050 num_sectors = GET_AL();
8051 track = GET_CH();
8052 head = GET_DH();
8053 drive = GET_ELDL();
8054
8055 if ((drive > 1) || (head > 1) || (track > 79) ||
8056 (num_sectors == 0) || (num_sectors > 18)) {
8057 SET_AH(1);
8058 set_diskette_ret_status(1);
8059 SET_CF(); // error occurred
8060 }
8061
8062 // see if drive exists
8063 if (floppy_drive_exists(drive) == 0) {
8064 SET_AH(0x80); // drive not responding
8065 set_diskette_ret_status(0x80);
8066 SET_CF(); // error occurred
8067 return;
8068 }
8069
8070 // see if media in drive, and type is known
8071 if (floppy_media_known(drive) == 0) {
8072 if (floppy_media_sense(drive) == 0) {
8073 SET_AH(0x0C); // Media type not found
8074 set_diskette_ret_status(0x0C);
8075 SET_AL(0); // no sectors read
8076 SET_CF(); // error occurred
8077 return;
8078 }
8079 }
8080
8081 // set up DMA controller for transfer
8082 page = (ES >> 12); // upper 4 bits
8083 base_es = (ES << 4); // lower 16bits contributed by ES
8084 base_address = base_es + BX; // lower 16 bits of address
8085 // contributed by ES:BX
8086 if ( base_address < base_es ) {
8087 // in case of carry, adjust page by 1
8088 page++;
8089 }
8090 base_count = (num_sectors * 4) - 1;
8091
8092 // check for 64K boundary overrun
8093 last_addr = base_address + base_count;
8094 if (last_addr < base_address) {
8095 SET_AH(0x09);
8096 set_diskette_ret_status(0x09);
8097 SET_AL(0); // no sectors read
8098 SET_CF(); // error occurred
8099 return;
8100 }
8101
8102 outb(0x000a, 0x06);
8103 outb(0x000c, 0x00); // clear flip-flop
8104 outb(0x0004, base_address);
8105 outb(0x0004, base_address>>8);
8106 outb(0x000c, 0x00); // clear flip-flop
8107 outb(0x0005, base_count);
8108 outb(0x0005, base_count>>8);
8109 mode_register = 0x4a; // single mode, increment, autoinit disable,
8110 // transfer type=read, channel 2
8111 outb(0x000b, mode_register);
8112 // port 81: DMA-1 Page Register, channel 2
8113 outb(0x0081, page);
8114 outb(0x000a, 0x02);
8115
8116 // set up floppy controller for transfer
8117 floppy_prepare_controller(drive);
8118
8119 // send format-track command (6 bytes) to controller
8120 outb(0x03f5, 0x4d); // 4d: format track
8121 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
8122 outb(0x03f5, 2); // 512 byte sector size
8123 outb(0x03f5, num_sectors); // number of sectors per track
8124 outb(0x03f5, 0); // Gap length
8125 outb(0x03f5, 0xf6); // Fill byte
8126 // turn on interrupts
8127 ASM_START
8128 sti
8129 ASM_END
8130
8131 // wait on 40:3e bit 7 to become 1
8132 do {
8133 val8 = read_byte(0x0040, 0x0040);
8134 if (val8 == 0) {
8135 floppy_reset_controller();
8136 SET_AH(0x80); // drive not ready (timeout)
8137 set_diskette_ret_status(0x80);
8138 SET_CF(); // error occurred
8139 return;
8140 }
8141 val8 = (read_byte(0x0040, 0x003e) & 0x80);
8142 } while ( val8 == 0 );
8143
8144 val8 = 0; // separate asm from while() loop
8145 // turn off interrupts
8146 ASM_START
8147 cli
8148 ASM_END
8149 // set 40:3e bit 7 to 0
8150 val8 = read_byte(0x0040, 0x003e);
8151 val8 &= 0x7f;
8152 write_byte(0x0040, 0x003e, val8);
8153 // check port 3f4 for accessibility to status bytes
8154 val8 = inb(0x3f4);
8155 if ( (val8 & 0xc0) != 0xc0 )
8156 BX_PANIC("int13_diskette: ctrl not ready\n");
8157
8158 // read 7 return status bytes from controller
8159 // using loop index broken, have to unroll...
8160 return_status[0] = inb(0x3f5);
8161 return_status[1] = inb(0x3f5);
8162 return_status[2] = inb(0x3f5);
8163 return_status[3] = inb(0x3f5);
8164 return_status[4] = inb(0x3f5);
8165 return_status[5] = inb(0x3f5);
8166 return_status[6] = inb(0x3f5);
8167 // record in BIOS Data Area
8168 write_byte(0x0040, 0x0042, return_status[0]);
8169 write_byte(0x0040, 0x0043, return_status[1]);
8170 write_byte(0x0040, 0x0044, return_status[2]);
8171 write_byte(0x0040, 0x0045, return_status[3]);
8172 write_byte(0x0040, 0x0046, return_status[4]);
8173 write_byte(0x0040, 0x0047, return_status[5]);
8174 write_byte(0x0040, 0x0048, return_status[6]);
8175
8176 if ( (return_status[0] & 0xc0) != 0 ) {
8177 if ( (return_status[1] & 0x02) != 0 ) {
8178 // diskette not writable.
8179 // AH=status code=0x03 (tried to write on write-protected disk)
8180 // AL=number of sectors written=0
8181 AX = 0x0300;
8182 SET_CF();
8183 return;
8184 } else {
8185 BX_PANIC("int13_diskette_function: write error\n");
8186 }
8187 }
8188
8189 SET_AH(0);
8190 set_diskette_ret_status(0);
8191 set_diskette_current_cyl(drive, 0);
8192 CLEAR_CF(); // successful
8193 return;
8194
8195
8196 case 0x08: // read diskette drive parameters
8197BX_DEBUG_INT13_FL("floppy f08\n");
8198 drive = GET_ELDL();
8199
8200 if (drive > 1) {
8201 AX = 0;
8202 BX = 0;
8203 CX = 0;
8204 DX = 0;
8205 ES = 0;
8206 DI = 0;
8207 SET_DL(num_floppies);
8208 SET_CF();
8209 return;
8210 }
8211
8212 drive_type = inb_cmos(0x10);
8213 num_floppies = 0;
8214 if (drive_type & 0xf0)
8215 num_floppies++;
8216 if (drive_type & 0x0f)
8217 num_floppies++;
8218
8219 if (drive == 0)
8220 drive_type >>= 4;
8221 else
8222 drive_type &= 0x0f;
8223
8224 SET_BH(0);
8225 SET_BL(drive_type);
8226 SET_AH(0);
8227 SET_AL(0);
8228 SET_DL(num_floppies);
8229
8230 switch (drive_type) {
8231 case 0: // none
8232 CX = 0;
8233 SET_DH(0); // max head #
8234 break;
8235
8236 case 1: // 360KB, 5.25"
8237 CX = 0x2709; // 40 tracks, 9 sectors
8238 SET_DH(1); // max head #
8239 break;
8240
8241 case 2: // 1.2MB, 5.25"
8242 CX = 0x4f0f; // 80 tracks, 15 sectors
8243 SET_DH(1); // max head #
8244 break;
8245
8246 case 3: // 720KB, 3.5"
8247 CX = 0x4f09; // 80 tracks, 9 sectors
8248 SET_DH(1); // max head #
8249 break;
8250
8251 case 4: // 1.44MB, 3.5"
8252 CX = 0x4f12; // 80 tracks, 18 sectors
8253 SET_DH(1); // max head #
8254 break;
8255
8256 case 5: // 2.88MB, 3.5"
8257 CX = 0x4f24; // 80 tracks, 36 sectors
8258 SET_DH(1); // max head #
8259 break;
8260
8261 case 6: // 160k, 5.25"
8262 CX = 0x2708; // 40 tracks, 8 sectors
8263 SET_DH(0); // max head #
8264 break;
8265
8266 case 7: // 180k, 5.25"
8267 CX = 0x2709; // 40 tracks, 9 sectors
8268 SET_DH(0); // max head #
8269 break;
8270
8271 case 8: // 320k, 5.25"
8272 CX = 0x2708; // 40 tracks, 8 sectors
8273 SET_DH(1); // max head #
8274 break;
8275
8276 default: // ?
8277 BX_PANIC("floppy: int13: bad floppy type\n");
8278 }
8279
8280 /* set es & di to point to 11 byte diskette param table in ROM */
8281ASM_START
8282 push bp
8283 mov bp, sp
8284 mov ax, #diskette_param_table2
8285 mov _int13_diskette_function.DI+2[bp], ax
8286 mov _int13_diskette_function.ES+2[bp], cs
8287 pop bp
8288ASM_END
8289 CLEAR_CF(); // success
8290 /* disk status not changed upon success */
8291 return;
8292
8293
8294 case 0x15: // read diskette drive type
8295BX_DEBUG_INT13_FL("floppy f15\n");
8296 drive = GET_ELDL();
8297 if (drive > 1) {
8298 SET_AH(0); // only 2 drives supported
8299 // set_diskette_ret_status here ???
8300 SET_CF();
8301 return;
8302 }
8303 drive_type = inb_cmos(0x10);
8304
8305 if (drive == 0)
8306 drive_type >>= 4;
8307 else
8308 drive_type &= 0x0f;
8309 CLEAR_CF(); // successful, not present
8310 if (drive_type==0) {
8311 SET_AH(0); // drive not present
8312 }
8313 else {
8314 SET_AH(1); // drive present, does not support change line
8315 }
8316
8317 return;
8318
8319 case 0x16: // get diskette change line status
8320BX_DEBUG_INT13_FL("floppy f16\n");
8321 drive = GET_ELDL();
8322 if (drive > 1) {
8323 SET_AH(0x01); // invalid drive
8324 set_diskette_ret_status(0x01);
8325 SET_CF();
8326 return;
8327 }
8328
8329 SET_AH(0x06); // change line not supported
8330 set_diskette_ret_status(0x06);
8331 SET_CF();
8332 return;
8333
8334 case 0x17: // set diskette type for format(old)
8335BX_DEBUG_INT13_FL("floppy f17\n");
8336 /* not used for 1.44M floppies */
8337 SET_AH(0x01); // not supported
8338 set_diskette_ret_status(1); /* not supported */
8339 SET_CF();
8340 return;
8341
8342 case 0x18: // set diskette type for format(new)
8343BX_DEBUG_INT13_FL("floppy f18\n");
8344 SET_AH(0x01); // do later
8345 set_diskette_ret_status(1);
8346 SET_CF();
8347 return;
8348
8349 default:
8350 BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
8351
8352 // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
8353 SET_AH(0x01); // ???
8354 set_diskette_ret_status(1);
8355 SET_CF();
8356 return;
8357 // }
8358 }
8359}
8360#else // #if BX_SUPPORT_FLOPPY
8361 void
8362int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
8363 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
8364{
8365 Bit8u val8;
8366
8367 switch ( GET_AH() ) {
8368
8369 case 0x01: // Read Diskette Status
8370 CLEAR_CF();
8371 val8 = read_byte(0x0000, 0x0441);
8372 SET_AH(val8);
8373 if (val8) {
8374 SET_CF();
8375 }
8376 return;
8377
8378 default:
8379 SET_CF();
8380 write_byte(0x0000, 0x0441, 0x01);
8381 SET_AH(0x01);
8382 }
8383}
8384#endif // #if BX_SUPPORT_FLOPPY
8385
8386 void
8387set_diskette_ret_status(value)
8388 Bit8u value;
8389{
8390 write_byte(0x0040, 0x0041, value);
8391}
8392
8393 void
8394set_diskette_current_cyl(drive, cyl)
8395 Bit8u drive;
8396 Bit8u cyl;
8397{
8398 if (drive > 1)
8399 BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
8400 write_byte(0x0040, 0x0094+drive, cyl);
8401}
8402
8403 void
8404determine_floppy_media(drive)
8405 Bit16u drive;
8406{
8407#if 0
8408 Bit8u val8, DOR, ctrl_info;
8409
8410 ctrl_info = read_byte(0x0040, 0x008F);
8411 if (drive==1)
8412 ctrl_info >>= 4;
8413 else
8414 ctrl_info &= 0x0f;
8415
8416#if 0
8417 if (drive == 0) {
8418 DOR = 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
8419 }
8420 else {
8421 DOR = 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
8422 }
8423#endif
8424
8425 if ( (ctrl_info & 0x04) != 0x04 ) {
8426 // Drive not determined means no drive exists, done.
8427 return;
8428 }
8429
8430#if 0
8431 // check Main Status Register for readiness
8432 val8 = inb(0x03f4) & 0x80; // Main Status Register
8433 if (val8 != 0x80)
8434 BX_PANIC("d_f_m: MRQ bit not set\n");
8435
8436 // change line
8437
8438 // existing BDA values
8439
8440 // turn on drive motor
8441 outb(0x03f2, DOR); // Digital Output Register
8442 //
8443#endif
8444 BX_PANIC("d_f_m: OK so far\n");
8445#endif
8446}
8447
8448 void
8449int17_function(regs, ds, iret_addr)
8450 pusha_regs_t regs; // regs pushed from PUSHA instruction
8451 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8452 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8453{
8454 Bit16u addr,timeout;
8455 Bit8u val8;
8456
8457 ASM_START
8458 sti
8459 ASM_END
8460
8461 addr = read_word(0x0040, (regs.u.r16.dx << 1) + 8);
8462 if ((regs.u.r8.ah < 3) && (regs.u.r16.dx < 3) && (addr > 0)) {
8463 timeout = read_byte(0x0040, 0x0078 + regs.u.r16.dx) << 8;
8464 if (regs.u.r8.ah == 0) {
8465 outb(addr, regs.u.r8.al);
8466 val8 = inb(addr+2);
8467 outb(addr+2, val8 | 0x01); // send strobe
8468 ASM_START
8469 nop
8470 ASM_END
8471 outb(addr+2, val8 & ~0x01);
8472 while (((inb(addr+1) & 0x40) == 0x40) && (timeout)) {
8473 timeout--;
8474 }
8475 }
8476 if (regs.u.r8.ah == 1) {
8477 val8 = inb(addr+2);
8478 outb(addr+2, val8 & ~0x04); // send init
8479 ASM_START
8480 nop
8481 ASM_END
8482 outb(addr+2, val8 | 0x04);
8483 }
8484 val8 = inb(addr+1);
8485 regs.u.r8.ah = (val8 ^ 0x48);
8486 if (!timeout) regs.u.r8.ah |= 0x01;
8487 ClearCF(iret_addr.flags);
8488 } else {
8489 SetCF(iret_addr.flags); // Unsupported
8490 }
8491}
8492
8493// returns bootsegment in ax, drive in bl
8494 Bit32u
8495int19_function(bseqnr)
8496Bit8u bseqnr;
8497{
8498 Bit16u ebda_seg=read_word(0x0040,0x000E);
8499 Bit16u bootseq;
8500 Bit8u bootdrv;
8501 Bit8u bootcd;
8502#ifdef VBOX
8503 Bit8u bootlan;
8504#endif /* VBOX */
8505 Bit8u bootchk;
8506 Bit16u bootseg;
8507 Bit16u status;
8508 Bit8u lastdrive=0;
8509
8510 // if BX_ELTORITO_BOOT is not defined, old behavior
8511 // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
8512 // in preparation for the initial INT 13h (0=floppy A:, 0x80=C:)
8513 // 0: system boot sequence, first drive C: then A:
8514 // 1: system boot sequence, first drive A: then C:
8515 // else BX_ELTORITO_BOOT is defined
8516 // CMOS regs 0x3D and 0x38 contain the boot sequence:
8517 // CMOS reg 0x3D & 0x0f : 1st boot device
8518 // CMOS reg 0x3D & 0xf0 : 2nd boot device
8519 // CMOS reg 0x38 & 0xf0 : 3rd boot device
8520#ifdef VBOX
8521 // CMOS reg 0x3C & 0x0f : 4th boot device
8522#endif /* VBOX */
8523 // boot device codes:
8524 // 0x00 : not defined
8525 // 0x01 : first floppy
8526 // 0x02 : first harddrive
8527 // 0x03 : first cdrom
8528#ifdef VBOX
8529 // 0x04 : local area network
8530#endif /* VBOX */
8531 // else : boot failure
8532
8533 // Get the boot sequence
8534#if BX_ELTORITO_BOOT
8535 bootseq=inb_cmos(0x3d);
8536 bootseq|=((inb_cmos(0x38) & 0xf0) << 4);
8537#ifdef VBOX
8538 bootseq|=((inb_cmos(0x3c) & 0x0f) << 12);
8539 if (read_byte(ebda_seg, &EbdaData->uForceBootDevice))
8540 bootseq = read_byte(ebda_seg, &EbdaData->uForceBootDevice);
8541 /* Boot delay hack. */
8542 if (bseqnr == 1)
8543 delay_boot((inb_cmos(0x3c) & 0xf0) >> 4); /* Implemented in logo.c */
8544#endif /* VBOX */
8545
8546 if (bseqnr==2) bootseq >>= 4;
8547 if (bseqnr==3) bootseq >>= 8;
8548#ifdef VBOX
8549 if (bseqnr==4) bootseq >>= 12;
8550#endif /* VBOX */
8551 if (bootseq<0x10) lastdrive = 1;
8552 bootdrv=0x00; bootcd=0;
8553#ifdef VBOX
8554 bootlan=0;
8555#endif /* VBOX */
8556
8557 switch(bootseq & 0x0f) {
8558 case 0x01:
8559 bootdrv=0x00;
8560 bootcd=0;
8561 break;
8562 case 0x02:
8563 {
8564 // Get the Boot drive.
8565 Bit8u boot_drive = read_byte(ebda_seg, &EbdaData->uForceBootDrive);
8566
8567 bootdrv = boot_drive + 0x80;
8568 bootcd=0;
8569 break;
8570 }
8571 case 0x03:
8572 bootdrv=0x00;
8573 bootcd=1;
8574 break;
8575#ifdef VBOX
8576 case 0x04: bootlan=1; break;
8577#endif /* VBOX */
8578 default: return 0x00000000;
8579 }
8580#else
8581 bootseq=inb_cmos(0x2d);
8582
8583 if (bseqnr==2) {
8584 bootseq ^= 0x20;
8585 lastdrive = 1;
8586 }
8587 bootdrv=0x00; bootcd=0;
8588 if((bootseq&0x20)==0) bootdrv=0x80;
8589#endif // BX_ELTORITO_BOOT
8590
8591#if BX_ELTORITO_BOOT
8592 // We have to boot from cd
8593 if (bootcd != 0) {
8594 status = cdrom_boot();
8595
8596 // If failure
8597 if ( (status & 0x00ff) !=0 ) {
8598 print_cdromboot_failure(status);
8599#ifdef VBOX
8600 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
8601#else /* !VBOX */
8602 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
8603#endif /* !VBOX */
8604 return 0x00000000;
8605 }
8606
8607 bootseg = read_word(ebda_seg,&EbdaData->cdemu.load_segment);
8608 bootdrv = (Bit8u)(status>>8);
8609 }
8610
8611#endif // BX_ELTORITO_BOOT
8612
8613#ifdef VBOX
8614 // Check for boot from LAN first
8615 if (bootlan == 1) {
8616 if (read_word(VBOX_LANBOOT_SEG,0) == 0xaa55) {
8617 Bit16u pnpoff;
8618 Bit32u manuf;
8619 // This is NOT a generic PnP implementation, but an Etherboot-specific hack.
8620 pnpoff = read_word(VBOX_LANBOOT_SEG,0x1a);
8621 if (read_dword(VBOX_LANBOOT_SEG,pnpoff) == 0x506e5024) {
8622 // Found PnP signature
8623 manuf = read_dword(VBOX_LANBOOT_SEG,read_word(VBOX_LANBOOT_SEG,pnpoff+0xe));
8624 if (manuf == 0x65687445) {
8625 // Found Etherboot ROM
8626 print_boot_device(bootcd, bootlan, bootdrv);
8627ASM_START
8628 push ds
8629 push es
8630 pusha
8631 calli 0x0006,VBOX_LANBOOT_SEG
8632 popa
8633 pop es
8634 pop ds
8635ASM_END
8636 } else if (manuf == 0x65746E49) {
8637 // Found Intel PXE ROM
8638 print_boot_device(bootcd, bootlan, bootdrv);
8639ASM_START
8640 push ds
8641 push es
8642 pusha
8643 sti ; Why are interrupts disabled now? Because we were called through an INT!
8644 push #VBOX_LANBOOT_SEG
8645 pop ds
8646 mov bx,#0x1a ; PnP header offset
8647 mov bx,[bx]
8648 add bx,#0x1a ; BEV offset in PnP header
8649 mov ax,[bx]
8650 test ax,ax
8651 jz no_rom
8652bev_jump:
8653 push cs
8654 push #no_rom
8655 push #VBOX_LANBOOT_SEG
8656 push ax
8657 retf ; call Boot Entry Vector
8658no_rom:
8659 popa
8660 pop es
8661 pop ds
8662ASM_END
8663 }
8664 }
8665 }
8666
8667 // boot from LAN will not return if successful.
8668 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
8669 return 0x00000000;
8670 }
8671#endif /* VBOX */
8672 // We have to boot from harddisk or floppy
8673#ifdef VBOX
8674 if (bootcd == 0 && bootlan == 0) {
8675#else /* !VBOX */
8676 if (bootcd == 0) {
8677#endif /* !VBOX */
8678 bootseg=0x07c0;
8679
8680ASM_START
8681 push bp
8682 mov bp, sp
8683
8684 xor ax, ax
8685 mov _int19_function.status + 2[bp], ax
8686 mov dl, _int19_function.bootdrv + 2[bp]
8687 mov ax, _int19_function.bootseg + 2[bp]
8688 mov es, ax ;; segment
8689 xor bx, bx ;; offset
8690 mov ah, #0x02 ;; function 2, read diskette sector
8691 mov al, #0x01 ;; read 1 sector
8692 mov ch, #0x00 ;; track 0
8693 mov cl, #0x01 ;; sector 1
8694 mov dh, #0x00 ;; head 0
8695 int #0x13 ;; read sector
8696 jnc int19_load_done
8697 mov ax, #0x0001
8698 mov _int19_function.status + 2[bp], ax
8699
8700int19_load_done:
8701 pop bp
8702ASM_END
8703
8704 if (status != 0) {
8705#ifdef VBOX
8706 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
8707#else /* !VBOX */
8708 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
8709#endif /* !VBOX */
8710 return 0x00000000;
8711 }
8712 }
8713
8714#ifdef VBOX
8715 // Don't check boot sectors on floppies and don't read CMOS - byte
8716 // 0x38 in CMOS always has the low bit clear.
8717 // There is *no* requirement whatsoever for a valid boot sector to
8718 // have a 55AAh signature. UNIX boot floppies typically have no such
8719 // signature. In general, it is impossible to tell a valid bootsector
8720 // from an invalid one.
8721 // NB: It is somewhat common for failed OS installs to have the
8722 // 0x55AA signature and a valid partition table but zeros in the
8723 // rest of the boot sector. We do a quick check by comparing the first
8724 // two words of boot sector; if identical, the boot sector is
8725 // extremely unlikely to be valid.
8726#endif
8727 // check signature if instructed by cmos reg 0x38, only for floppy
8728 // bootchk = 1 : signature check disabled
8729 // bootchk = 0 : signature check enabled
8730 if (bootdrv != 0) bootchk = 0;
8731#ifdef VBOX
8732 else bootchk = 1; /* disable 0x55AA signature check on drive A: */
8733#else
8734 else bootchk = inb_cmos(0x38) & 0x01;
8735#endif
8736
8737#if BX_ELTORITO_BOOT
8738 // if boot from cd, no signature check
8739 if (bootcd != 0)
8740 bootchk = 1;
8741#endif // BX_ELTORITO_BOOT
8742
8743 if (bootchk == 0) {
8744 if (read_word(bootseg,0x1fe) != 0xaa55 ||
8745 read_word(bootseg,0) == read_word(bootseg,2)) {
8746#ifdef VBOX
8747 print_boot_failure(bootcd, bootlan, bootdrv, 0, lastdrive);
8748#else /* !VBOX */
8749 print_boot_failure(bootcd, bootdrv, 0, lastdrive);
8750#endif /* VBOX */
8751 return 0x00000000;
8752 }
8753 }
8754
8755#if BX_ELTORITO_BOOT
8756 // Print out the boot string
8757#ifdef VBOX
8758 print_boot_device(bootcd, bootlan, bootdrv);
8759#else /* !VBOX */
8760 print_boot_device(bootcd, bootdrv);
8761#endif /* !VBOX */
8762#else // BX_ELTORITO_BOOT
8763#ifdef VBOX
8764 print_boot_device(0, bootlan, bootdrv);
8765#else /* !VBOX */
8766 print_boot_device(0, bootdrv);
8767#endif /* !VBOX */
8768#endif // BX_ELTORITO_BOOT
8769
8770 // return the boot segment
8771 return (((Bit32u)bootdrv) << 16) + bootseg;
8772}
8773
8774 void
8775int1a_function(regs, ds, iret_addr)
8776 pusha_regs_t regs; // regs pushed from PUSHA instruction
8777 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8778 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8779{
8780 Bit8u val8;
8781
8782 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);
8783
8784 ASM_START
8785 sti
8786 ASM_END
8787
8788 switch (regs.u.r8.ah) {
8789 case 0: // get current clock count
8790 ASM_START
8791 cli
8792 ASM_END
8793 regs.u.r16.cx = BiosData->ticks_high;
8794 regs.u.r16.dx = BiosData->ticks_low;
8795 regs.u.r8.al = BiosData->midnight_flag;
8796 BiosData->midnight_flag = 0; // reset flag
8797 ASM_START
8798 sti
8799 ASM_END
8800 // AH already 0
8801 ClearCF(iret_addr.flags); // OK
8802 break;
8803
8804 case 1: // Set Current Clock Count
8805 ASM_START
8806 cli
8807 ASM_END
8808 BiosData->ticks_high = regs.u.r16.cx;
8809 BiosData->ticks_low = regs.u.r16.dx;
8810 BiosData->midnight_flag = 0; // reset flag
8811 ASM_START
8812 sti
8813 ASM_END
8814 regs.u.r8.ah = 0;
8815 ClearCF(iret_addr.flags); // OK
8816 break;
8817
8818
8819 case 2: // Read CMOS Time
8820 if (rtc_updating()) {
8821 SetCF(iret_addr.flags);
8822 break;
8823 }
8824
8825 regs.u.r8.dh = inb_cmos(0x00); // Seconds
8826 regs.u.r8.cl = inb_cmos(0x02); // Minutes
8827 regs.u.r8.ch = inb_cmos(0x04); // Hours
8828 regs.u.r8.dl = inb_cmos(0x0b) & 0x01; // Stat Reg B
8829 regs.u.r8.ah = 0;
8830 regs.u.r8.al = regs.u.r8.ch;
8831 ClearCF(iret_addr.flags); // OK
8832 break;
8833
8834 case 3: // Set CMOS Time
8835 // Using a debugger, I notice the following masking/setting
8836 // of bits in Status Register B, by setting Reg B to
8837 // a few values and getting its value after INT 1A was called.
8838 //
8839 // try#1 try#2 try#3
8840 // before 1111 1101 0111 1101 0000 0000
8841 // after 0110 0010 0110 0010 0000 0010
8842 //
8843 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8844 // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
8845 if (rtc_updating()) {
8846 init_rtc();
8847 // fall through as if an update were not in progress
8848 }
8849 outb_cmos(0x00, regs.u.r8.dh); // Seconds
8850 outb_cmos(0x02, regs.u.r8.cl); // Minutes
8851 outb_cmos(0x04, regs.u.r8.ch); // Hours
8852 // Set Daylight Savings time enabled bit to requested value
8853 val8 = (inb_cmos(0x0b) & 0x60) | 0x02 | (regs.u.r8.dl & 0x01);
8854 // (reg B already selected)
8855 outb_cmos(0x0b, val8);
8856 regs.u.r8.ah = 0;
8857 regs.u.r8.al = val8; // val last written to Reg B
8858 ClearCF(iret_addr.flags); // OK
8859 break;
8860
8861 case 4: // Read CMOS Date
8862 regs.u.r8.ah = 0;
8863 if (rtc_updating()) {
8864 SetCF(iret_addr.flags);
8865 break;
8866 }
8867 regs.u.r8.cl = inb_cmos(0x09); // Year
8868 regs.u.r8.dh = inb_cmos(0x08); // Month
8869 regs.u.r8.dl = inb_cmos(0x07); // Day of Month
8870 regs.u.r8.ch = inb_cmos(0x32); // Century
8871 regs.u.r8.al = regs.u.r8.ch;
8872 ClearCF(iret_addr.flags); // OK
8873 break;
8874
8875 case 5: // Set CMOS Date
8876 // Using a debugger, I notice the following masking/setting
8877 // of bits in Status Register B, by setting Reg B to
8878 // a few values and getting its value after INT 1A was called.
8879 //
8880 // try#1 try#2 try#3 try#4
8881 // before 1111 1101 0111 1101 0000 0010 0000 0000
8882 // after 0110 1101 0111 1101 0000 0010 0000 0000
8883 //
8884 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8885 // My assumption: RegB = (RegB & 01111111b)
8886 if (rtc_updating()) {
8887 init_rtc();
8888 SetCF(iret_addr.flags);
8889 break;
8890 }
8891 outb_cmos(0x09, regs.u.r8.cl); // Year
8892 outb_cmos(0x08, regs.u.r8.dh); // Month
8893 outb_cmos(0x07, regs.u.r8.dl); // Day of Month
8894 outb_cmos(0x32, regs.u.r8.ch); // Century
8895 val8 = inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
8896 outb_cmos(0x0b, val8);
8897 regs.u.r8.ah = 0;
8898 regs.u.r8.al = val8; // AL = val last written to Reg B
8899 ClearCF(iret_addr.flags); // OK
8900 break;
8901
8902 case 6: // Set Alarm Time in CMOS
8903 // Using a debugger, I notice the following masking/setting
8904 // of bits in Status Register B, by setting Reg B to
8905 // a few values and getting its value after INT 1A was called.
8906 //
8907 // try#1 try#2 try#3
8908 // before 1101 1111 0101 1111 0000 0000
8909 // after 0110 1111 0111 1111 0010 0000
8910 //
8911 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8912 // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
8913 val8 = inb_cmos(0x0b); // Get Status Reg B
8914 regs.u.r16.ax = 0;
8915 if (val8 & 0x20) {
8916 // Alarm interrupt enabled already
8917 SetCF(iret_addr.flags); // Error: alarm in use
8918 break;
8919 }
8920 if (rtc_updating()) {
8921 init_rtc();
8922 // fall through as if an update were not in progress
8923 }
8924 outb_cmos(0x01, regs.u.r8.dh); // Seconds alarm
8925 outb_cmos(0x03, regs.u.r8.cl); // Minutes alarm
8926 outb_cmos(0x05, regs.u.r8.ch); // Hours alarm
8927 outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
8928 // enable Status Reg B alarm bit, clear halt clock bit
8929 outb_cmos(0x0b, (val8 & 0x7f) | 0x20);
8930 ClearCF(iret_addr.flags); // OK
8931 break;
8932
8933 case 7: // Turn off Alarm
8934 // Using a debugger, I notice the following masking/setting
8935 // of bits in Status Register B, by setting Reg B to
8936 // a few values and getting its value after INT 1A was called.
8937 //
8938 // try#1 try#2 try#3 try#4
8939 // before 1111 1101 0111 1101 0010 0000 0010 0010
8940 // after 0100 0101 0101 0101 0000 0000 0000 0010
8941 //
8942 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8943 // My assumption: RegB = (RegB & 01010111b)
8944 val8 = inb_cmos(0x0b); // Get Status Reg B
8945 // clear clock-halt bit, disable alarm bit
8946 outb_cmos(0x0b, val8 & 0x57); // disable alarm bit
8947 regs.u.r8.ah = 0;
8948 regs.u.r8.al = val8; // val last written to Reg B
8949 ClearCF(iret_addr.flags); // OK
8950 break;
8951#if BX_PCIBIOS
8952 case 0xb1:
8953 // real mode PCI BIOS functions now handled in assembler code
8954 // this C code handles the error code for information only
8955 if (regs.u.r8.bl == 0xff) {
8956 BX_INFO("PCI BIOS: PCI not present\n");
8957 } else if (regs.u.r8.bl == 0x81) {
8958 BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs.u.r8.al);
8959 } else if (regs.u.r8.bl == 0x83) {
8960 BX_INFO("bad PCI vendor ID %04x\n", regs.u.r16.dx);
8961 } else if (regs.u.r8.bl == 0x86) {
8962 if (regs.u.r8.al == 0x02) {
8963 BX_INFO("PCI device %04x:%04x not found at index %d\n", regs.u.r16.dx, regs.u.r16.cx, regs.u.r16.si);
8964 } else {
8965 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);
8966 }
8967 }
8968 regs.u.r8.ah = regs.u.r8.bl;
8969 SetCF(iret_addr.flags);
8970 break;
8971#endif
8972
8973 default:
8974 SetCF(iret_addr.flags); // Unsupported
8975 }
8976}
8977
8978 void
8979int70_function(regs, ds, iret_addr)
8980 pusha_regs_t regs; // regs pushed from PUSHA instruction
8981 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8982 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8983{
8984 // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
8985 Bit8u registerB = 0, registerC = 0;
8986
8987 // Check which modes are enabled and have occurred.
8988 registerB = inb_cmos( 0xB );
8989 registerC = inb_cmos( 0xC );
8990
8991 if( ( registerB & 0x60 ) != 0 ) {
8992 if( ( registerC & 0x20 ) != 0 ) {
8993 // Handle Alarm Interrupt.
8994ASM_START
8995 sti
8996 int #0x4a
8997 cli
8998ASM_END
8999 }
9000 if( ( registerC & 0x40 ) != 0 ) {
9001 // Handle Periodic Interrupt.
9002
9003 if( read_byte( 0x40, 0xA0 ) != 0 ) {
9004 // Wait Interval (Int 15, AH=83) active.
9005 Bit32u time, toggle;
9006
9007 time = read_dword( 0x40, 0x9C ); // Time left in microseconds.
9008 if( time < 0x3D1 ) {
9009 // Done waiting.
9010 Bit16u segment, offset;
9011
9012 segment = read_word( 0x40, 0x98 );
9013 offset = read_word( 0x40, 0x9A );
9014 write_byte( 0x40, 0xA0, 0 ); // Turn of status byte.
9015 outb_cmos( 0xB, registerB & 0x37 ); // Clear the Periodic Interrupt.
9016 write_byte(segment, offset, read_byte(segment, offset) | 0x80 ); // Write to specified flag byte.
9017 } else {
9018 // Continue waiting.
9019 time -= 0x3D1;
9020 write_dword( 0x40, 0x9C, time );
9021 }
9022 }
9023 }
9024 }
9025
9026ASM_START
9027 call eoi_both_pics
9028ASM_END
9029}
9030
9031 void
9032dummy_isr_function(regs, ds, iret_addr)
9033 pusha_regs_t regs; // regs pushed from PUSHA instruction
9034 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
9035 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
9036{
9037 // Interrupt handler for unexpected hardware interrupts. We have to clear
9038 // the PIC because if we don't, the next EOI will clear the wrong interrupt
9039 // and all hell will break loose! This routine also masks the unexpected
9040 // interrupt so it will generally be called only once for each unexpected
9041 // interrupt level.
9042 Bit8u isrA, isrB, imr, last_int = 0xFF;
9043
9044 outb( 0x20, 0x0B );
9045 isrA = inb( 0x20 );
9046 if (isrA) {
9047 outb( 0xA0, 0x0B );
9048 isrB = inb( 0xA0 );
9049 if (isrB) {
9050 imr = inb( 0xA1 );
9051 outb( 0xA1, imr | isrB ); // Mask this interrupt
9052 outb( 0xA0, 0x20 ); // Send EOI on slave PIC
9053 } else {
9054 imr = inb( 0x21 );
9055 isrA &= 0xFB; // Never mask the cascade interrupt
9056 outb( 0x21, imr | isrA); // Mask this interrupt
9057 }
9058 outb( 0x20, 0x20 ); // Send EOI on master PIC
9059 last_int = isrA;
9060 }
9061 write_byte( 0x40, 0x6B, last_int ); // Write INTR_FLAG
9062}
9063
9064ASM_START
9065;------------------------------------------
9066;- INT74h : PS/2 mouse hardware interrupt -
9067;------------------------------------------
9068int74_handler:
9069 sti
9070 pusha
9071 push ds ;; save DS
9072 push #0x00 ;; placeholder for status
9073 push #0x00 ;; placeholder for X
9074 push #0x00 ;; placeholder for Y
9075 push #0x00 ;; placeholder for Z
9076 push #0x00 ;; placeholder for make_far_call boolean
9077 call _int74_function
9078 pop cx ;; remove make_far_call from stack
9079 jcxz int74_done
9080
9081 ;; make far call to EBDA:0022
9082 push #0x00
9083 pop ds
9084 push 0x040E ;; push 0000:040E (opcodes 0xff, 0x36, 0x0E, 0x04)
9085 pop ds
9086 //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
9087 call far ptr[0x22]
9088int74_done:
9089 cli
9090 call eoi_both_pics
9091 add sp, #8 ;; pop status, x, y, z
9092
9093 pop ds ;; restore DS
9094 popa
9095 iret
9096
9097
9098;; This will perform an IRET, but will retain value of current CF
9099;; by altering flags on stack. Better than RETF #02.
9100iret_modify_cf:
9101 jc carry_set
9102 push bp
9103 mov bp, sp
9104 and BYTE [bp + 0x06], #0xfe
9105 pop bp
9106 iret
9107carry_set:
9108 push bp
9109 mov bp, sp
9110 or BYTE [bp + 0x06], #0x01
9111 pop bp
9112 iret
9113
9114
9115;----------------------
9116;- INT13h (relocated) -
9117;----------------------
9118;
9119; int13_relocated is a little bit messed up since I played with it
9120; I have to rewrite it:
9121; - call a function that detect which function to call
9122; - make all called C function get the same parameters list
9123;
9124int13_relocated:
9125 cld ;; we will be doing some string I/O
9126
9127#if BX_ELTORITO_BOOT
9128 ;; check for an eltorito function
9129 cmp ah,#0x4a
9130 jb int13_not_eltorito
9131 cmp ah,#0x4d
9132 ja int13_not_eltorito
9133
9134 pusha
9135 push es
9136 push ds
9137 push ss
9138 pop ds
9139
9140 push #int13_out
9141 jmp _int13_eltorito ;; ELDX not used
9142
9143int13_not_eltorito:
9144 push ax
9145 push bx
9146 push cx
9147 push dx
9148
9149 ;; check if emulation active
9150 call _cdemu_isactive
9151 cmp al,#0x00
9152 je int13_cdemu_inactive
9153
9154 ;; check if access to the emulated drive
9155 call _cdemu_emulated_drive
9156 pop dx
9157 push dx
9158 cmp al,dl ;; int13 on emulated drive
9159 jne int13_nocdemu
9160
9161 pop dx
9162 pop cx
9163 pop bx
9164 pop ax
9165
9166 pusha
9167 push es
9168 push ds
9169 push ss
9170 pop ds
9171
9172 push #int13_out
9173 jmp _int13_cdemu ;; ELDX not used
9174
9175int13_nocdemu:
9176 and dl,#0xE0 ;; mask to get device class, including cdroms
9177 cmp al,dl ;; al is 0x00 or 0x80
9178 jne int13_cdemu_inactive ;; inactive for device class
9179
9180 pop dx
9181 pop cx
9182 pop bx
9183 pop ax
9184
9185 push ax
9186 push cx
9187 push dx
9188 push bx
9189
9190 dec dl ;; real drive is dl - 1
9191 jmp int13_legacy
9192
9193int13_cdemu_inactive:
9194 pop dx
9195 pop cx
9196 pop bx
9197 pop ax
9198
9199#endif // BX_ELTORITO_BOOT
9200
9201int13_noeltorito:
9202
9203 push ax
9204 push cx
9205 push dx
9206 push bx
9207
9208int13_legacy:
9209
9210 push dx ;; push eltorito value of dx instead of sp
9211
9212 push bp
9213 push si
9214 push di
9215
9216 push es
9217 push ds
9218 push ss
9219 pop ds
9220
9221 ;; now the 16-bit registers can be restored with:
9222 ;; pop ds; pop es; popa; iret
9223 ;; arguments passed to functions should be
9224 ;; DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS
9225
9226 test dl, #0x80
9227 jnz int13_notfloppy
9228
9229 push #int13_out
9230 jmp _int13_diskette_function
9231
9232int13_notfloppy:
9233
9234#if BX_USE_ATADRV
9235
9236 cmp dl, #0xE0
9237 jb int13_notcdrom
9238
9239 // ebx is modified: BSD 5.2.1 boot loader problem
9240 // someone should figure out which 32 bit register that actually are used
9241
9242 shr ebx, #16
9243 push bx
9244
9245 call _int13_cdrom
9246
9247 pop bx
9248 shl ebx, #16
9249
9250 jmp int13_out
9251
9252int13_notcdrom:
9253
9254#endif
9255
9256int13_disk:
9257 ;; int13_harddisk modifies high word of EAX and EBX
9258 shr eax, #16
9259 push ax
9260 shr ebx, #16
9261 push bx
9262 call _int13_harddisk
9263 pop bx
9264 shl ebx, #16
9265 pop ax
9266 shl eax, #16
9267
9268int13_out:
9269 pop ds
9270 pop es
9271 popa
9272 iret
9273
9274;----------
9275;- INT18h -
9276;----------
9277int18_handler: ;; Boot Failure routing
9278 call _int18_panic_msg
9279 hlt
9280 iret
9281
9282;----------
9283;- INT19h -
9284;----------
9285int19_relocated: ;; Boot function, relocated
9286
9287#ifdef VBOX
9288 // If an already booted OS calls int 0x19 to reboot, it is not sufficient
9289 // just to try booting from the configured drives. All BIOS variables and
9290 // interrupt vectors need to be reset, otherwise strange things may happen.
9291 // The approach used is faking a warm reboot (which just skips showing the
9292 // logo), which is a bit more than what we need, but hey, it's fast.
9293 mov bp, sp
9294 mov ax, 2[bp]
9295 cmp ax, #0xf000
9296 jz bios_initiated_boot
9297 xor ax, ax
9298 mov ds, ax
9299 mov ax, #0x1234
9300 mov 0x472, ax
9301 jmp post
9302bios_initiated_boot:
9303#endif /* VBOX */
9304
9305 ;; int19 was beginning to be really complex, so now it
9306 ;; just calls a C function that does the work
9307 ;; it returns in BL the boot drive, and in AX the boot segment
9308 ;; the boot segment will be 0x0000 if something has failed
9309
9310 push bp
9311 mov bp, sp
9312
9313 ;; drop ds
9314 xor ax, ax
9315 mov ds, ax
9316
9317 ;; 1st boot device
9318 mov ax, #0x0001
9319 push ax
9320 call _int19_function
9321 inc sp
9322 inc sp
9323 ;; bl contains the boot drive
9324 ;; ax contains the boot segment or 0 if failure
9325
9326 test ax, ax ;; if ax is 0 try next boot device
9327 jnz boot_setup
9328
9329 ;; 2nd boot device
9330 mov ax, #0x0002
9331 push ax
9332 call _int19_function
9333 inc sp
9334 inc sp
9335 test ax, ax ;; if ax is 0 try next boot device
9336 jnz boot_setup
9337
9338 ;; 3rd boot device
9339 mov ax, #0x0003
9340 push ax
9341 call _int19_function
9342 inc sp
9343 inc sp
9344#ifdef VBOX
9345 test ax, ax ;; if ax is 0 try next boot device
9346 jnz boot_setup
9347
9348 ;; 4th boot device
9349 mov ax, #0x0004
9350 push ax
9351 call _int19_function
9352 inc sp
9353 inc sp
9354#endif /* VBOX */
9355 test ax, ax ;; if ax is 0 call int18
9356 jz int18_handler
9357
9358boot_setup:
9359 mov dl, bl ;; set drive so guest os find it
9360 shl eax, #0x04 ;; convert seg to ip
9361 mov 2[bp], ax ;; set ip
9362
9363 shr eax, #0x04 ;; get cs back
9364 and ax, #0xF000 ;; remove what went in ip
9365 mov 4[bp], ax ;; set cs
9366 xor ax, ax
9367 mov es, ax ;; set es to zero fixes [ 549815 ]
9368 mov [bp], ax ;; set bp to zero
9369 mov ax, #0xaa55 ;; set ok flag
9370
9371 pop bp
9372 iret ;; Beam me up Scotty
9373
9374;----------
9375;- INT1Ch -
9376;----------
9377int1c_handler: ;; User Timer Tick
9378 iret
9379
9380
9381;----------------------
9382;- POST: Floppy Drive -
9383;----------------------
9384floppy_drive_post:
9385 xor ax, ax
9386 mov ds, ax
9387
9388 mov al, #0x00
9389 mov 0x043e, al ;; drive 0 & 1 uncalibrated, no interrupt has occurred
9390
9391 mov 0x043f, al ;; diskette motor status: read op, drive0, motors off
9392
9393 mov 0x0440, al ;; diskette motor timeout counter: not active
9394 mov 0x0441, al ;; diskette controller status return code
9395
9396 mov 0x0442, al ;; disk & diskette controller status register 0
9397 mov 0x0443, al ;; diskette controller status register 1
9398 mov 0x0444, al ;; diskette controller status register 2
9399 mov 0x0445, al ;; diskette controller cylinder number
9400 mov 0x0446, al ;; diskette controller head number
9401 mov 0x0447, al ;; diskette controller sector number
9402 mov 0x0448, al ;; diskette controller bytes written
9403
9404 mov 0x048b, al ;; diskette configuration data
9405
9406 ;; -----------------------------------------------------------------
9407 ;; (048F) diskette controller information
9408 ;;
9409 mov al, #0x10 ;; get CMOS diskette drive type
9410 out 0x70, AL
9411 in AL, 0x71
9412 mov ah, al ;; save byte to AH
9413
9414look_drive0:
9415 shr al, #4 ;; look at top 4 bits for drive 0
9416 jz f0_missing ;; jump if no drive0
9417 mov bl, #0x07 ;; drive0 determined, multi-rate, has changed line
9418 jmp look_drive1
9419f0_missing:
9420 mov bl, #0x00 ;; no drive0
9421
9422look_drive1:
9423 mov al, ah ;; restore from AH
9424 and al, #0x0f ;; look at bottom 4 bits for drive 1
9425 jz f1_missing ;; jump if no drive1
9426 or bl, #0x70 ;; drive1 determined, multi-rate, has changed line
9427f1_missing:
9428 ;; leave high bits in BL zerod
9429 mov 0x048f, bl ;; put new val in BDA (diskette controller information)
9430 ;; -----------------------------------------------------------------
9431
9432 mov al, #0x00
9433 mov 0x0490, al ;; diskette 0 media state
9434 mov 0x0491, al ;; diskette 1 media state
9435
9436 ;; diskette 0,1 operational starting state
9437 ;; drive type has not been determined,
9438 ;; has no changed detection line
9439 mov 0x0492, al
9440 mov 0x0493, al
9441
9442 mov 0x0494, al ;; diskette 0 current cylinder
9443 mov 0x0495, al ;; diskette 1 current cylinder
9444
9445 mov al, #0x02
9446 out #0x0a, al ;; clear DMA-1 channel 2 mask bit
9447
9448 SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
9449 SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
9450 SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
9451
9452 ret
9453
9454
9455;--------------------
9456;- POST: HARD DRIVE -
9457;--------------------
9458; relocated here because the primary POST area isnt big enough.
9459hard_drive_post:
9460 // IRQ 14 = INT 76h
9461 // INT 76h calls INT 15h function ax=9100
9462
9463 mov al, #0x0a ; 0000 1010 = reserved, disable IRQ 14
9464 mov dx, #0x03f6
9465 out dx, al
9466
9467 xor ax, ax
9468 mov ds, ax
9469 mov 0x0474, al /* hard disk status of last operation */
9470 mov 0x0477, al /* hard disk port offset (XT only ???) */
9471 mov 0x048c, al /* hard disk status register */
9472 mov 0x048d, al /* hard disk error register */
9473 mov 0x048e, al /* hard disk task complete flag */
9474#ifndef VBOX /* Why is this hardcoded to 1? */
9475 mov al, #0x01
9476 mov 0x0475, al /* hard disk number attached */
9477#endif
9478 mov al, #0xc0
9479 mov 0x0476, al /* hard disk control byte */
9480 SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
9481 SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
9482 ;; INT 41h: hard disk 0 configuration pointer
9483 ;; INT 46h: hard disk 1 configuration pointer
9484 SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D)
9485 SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D)
9486
9487#ifndef VBOX /* This is done later (and the CMOS format is now different). */
9488 ;; move disk geometry data from CMOS to EBDA disk parameter table(s)
9489 mov al, #0x12
9490 out #0x70, al
9491 in al, #0x71
9492 and al, #0xf0
9493 cmp al, #0xf0
9494 je post_d0_extended
9495 jmp check_for_hd1
9496post_d0_extended:
9497 mov al, #0x19
9498 out #0x70, al
9499 in al, #0x71
9500 cmp al, #47 ;; decimal 47 - user definable
9501 je post_d0_type47
9502 HALT(__LINE__)
9503post_d0_type47:
9504 ;; CMOS purpose param table offset
9505 ;; 1b cylinders low 0
9506 ;; 1c cylinders high 1
9507 ;; 1d heads 2
9508 ;; 1e write pre-comp low 5
9509 ;; 1f write pre-comp high 6
9510 ;; 20 retries/bad map/heads>8 8
9511 ;; 21 landing zone low C
9512 ;; 22 landing zone high D
9513 ;; 23 sectors/track E
9514
9515 mov ax, #EBDA_SEG
9516 mov ds, ax
9517
9518 ;;; Filling EBDA table for hard disk 0.
9519 mov al, #0x1f
9520 out #0x70, al
9521 in al, #0x71
9522 mov ah, al
9523 mov al, #0x1e
9524 out #0x70, al
9525 in al, #0x71
9526 mov (0x003d + 0x05), ax ;; write precomp word
9527
9528 mov al, #0x20
9529 out #0x70, al
9530 in al, #0x71
9531 mov (0x003d + 0x08), al ;; drive control byte
9532
9533 mov al, #0x22
9534 out #0x70, al
9535 in al, #0x71
9536 mov ah, al
9537 mov al, #0x21
9538 out #0x70, al
9539 in al, #0x71
9540 mov (0x003d + 0x0C), ax ;; landing zone word
9541
9542 mov al, #0x1c ;; get cylinders word in AX
9543 out #0x70, al
9544 in al, #0x71 ;; high byte
9545 mov ah, al
9546 mov al, #0x1b
9547 out #0x70, al
9548 in al, #0x71 ;; low byte
9549 mov bx, ax ;; BX = cylinders
9550
9551 mov al, #0x1d
9552 out #0x70, al
9553 in al, #0x71
9554 mov cl, al ;; CL = heads
9555
9556 mov al, #0x23
9557 out #0x70, al
9558 in al, #0x71
9559 mov dl, al ;; DL = sectors
9560
9561 cmp bx, #1024
9562 jnbe hd0_post_logical_chs ;; if cylinders > 1024, use translated style CHS
9563
9564hd0_post_physical_chs:
9565 ;; no logical CHS mapping used, just physical CHS
9566 ;; use Standard Fixed Disk Parameter Table (FDPT)
9567 mov (0x003d + 0x00), bx ;; number of physical cylinders
9568 mov (0x003d + 0x02), cl ;; number of physical heads
9569 mov (0x003d + 0x0E), dl ;; number of physical sectors
9570 jmp check_for_hd1
9571
9572hd0_post_logical_chs:
9573 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
9574 mov (0x003d + 0x09), bx ;; number of physical cylinders
9575 mov (0x003d + 0x0b), cl ;; number of physical heads
9576 mov (0x003d + 0x04), dl ;; number of physical sectors
9577 mov (0x003d + 0x0e), dl ;; number of logical sectors (same)
9578 mov al, #0xa0
9579 mov (0x003d + 0x03), al ;; A0h signature, indicates translated table
9580
9581 cmp bx, #2048
9582 jnbe hd0_post_above_2048
9583 ;; 1024 < c <= 2048 cylinders
9584 shr bx, #0x01
9585 shl cl, #0x01
9586 jmp hd0_post_store_logical
9587
9588hd0_post_above_2048:
9589 cmp bx, #4096
9590 jnbe hd0_post_above_4096
9591 ;; 2048 < c <= 4096 cylinders
9592 shr bx, #0x02
9593 shl cl, #0x02
9594 jmp hd0_post_store_logical
9595
9596hd0_post_above_4096:
9597 cmp bx, #8192
9598 jnbe hd0_post_above_8192
9599 ;; 4096 < c <= 8192 cylinders
9600 shr bx, #0x03
9601 shl cl, #0x03
9602 jmp hd0_post_store_logical
9603
9604hd0_post_above_8192:
9605 ;; 8192 < c <= 16384 cylinders
9606 shr bx, #0x04
9607 shl cl, #0x04
9608
9609hd0_post_store_logical:
9610 mov (0x003d + 0x00), bx ;; number of physical cylinders
9611 mov (0x003d + 0x02), cl ;; number of physical heads
9612 ;; checksum
9613 mov cl, #0x0f ;; repeat count
9614 mov si, #0x003d ;; offset to disk0 FDPT
9615 mov al, #0x00 ;; sum
9616hd0_post_checksum_loop:
9617 add al, [si]
9618 inc si
9619 dec cl
9620 jnz hd0_post_checksum_loop
9621 not al ;; now take 2s complement
9622 inc al
9623 mov [si], al
9624;;; Done filling EBDA table for hard disk 0.
9625
9626
9627check_for_hd1:
9628 ;; is there really a second hard disk? if not, return now
9629 mov al, #0x12
9630 out #0x70, al
9631 in al, #0x71
9632 and al, #0x0f
9633 jnz post_d1_exists
9634 ret
9635post_d1_exists:
9636 ;; check that the hd type is really 0x0f.
9637 cmp al, #0x0f
9638 jz post_d1_extended
9639 HALT(__LINE__)
9640post_d1_extended:
9641 ;; check that the extended type is 47 - user definable
9642 mov al, #0x1a
9643 out #0x70, al
9644 in al, #0x71
9645 cmp al, #47 ;; decimal 47 - user definable
9646 je post_d1_type47
9647 HALT(__LINE__)
9648post_d1_type47:
9649 ;; Table for disk1.
9650 ;; CMOS purpose param table offset
9651 ;; 0x24 cylinders low 0
9652 ;; 0x25 cylinders high 1
9653 ;; 0x26 heads 2
9654 ;; 0x27 write pre-comp low 5
9655 ;; 0x28 write pre-comp high 6
9656 ;; 0x29 heads>8 8
9657 ;; 0x2a landing zone low C
9658 ;; 0x2b landing zone high D
9659 ;; 0x2c sectors/track E
9660;;; Fill EBDA table for hard disk 1.
9661 mov ax, #EBDA_SEG
9662 mov ds, ax
9663 mov al, #0x28
9664 out #0x70, al
9665 in al, #0x71
9666 mov ah, al
9667 mov al, #0x27
9668 out #0x70, al
9669 in al, #0x71
9670 mov (0x004d + 0x05), ax ;; write precomp word
9671
9672 mov al, #0x29
9673 out #0x70, al
9674 in al, #0x71
9675 mov (0x004d + 0x08), al ;; drive control byte
9676
9677 mov al, #0x2b
9678 out #0x70, al
9679 in al, #0x71
9680 mov ah, al
9681 mov al, #0x2a
9682 out #0x70, al
9683 in al, #0x71
9684 mov (0x004d + 0x0C), ax ;; landing zone word
9685
9686 mov al, #0x25 ;; get cylinders word in AX
9687 out #0x70, al
9688 in al, #0x71 ;; high byte
9689 mov ah, al
9690 mov al, #0x24
9691 out #0x70, al
9692 in al, #0x71 ;; low byte
9693 mov bx, ax ;; BX = cylinders
9694
9695 mov al, #0x26
9696 out #0x70, al
9697 in al, #0x71
9698 mov cl, al ;; CL = heads
9699
9700 mov al, #0x2c
9701 out #0x70, al
9702 in al, #0x71
9703 mov dl, al ;; DL = sectors
9704
9705 cmp bx, #1024
9706 jnbe hd1_post_logical_chs ;; if cylinders > 1024, use translated style CHS
9707
9708hd1_post_physical_chs:
9709 ;; no logical CHS mapping used, just physical CHS
9710 ;; use Standard Fixed Disk Parameter Table (FDPT)
9711 mov (0x004d + 0x00), bx ;; number of physical cylinders
9712 mov (0x004d + 0x02), cl ;; number of physical heads
9713 mov (0x004d + 0x0E), dl ;; number of physical sectors
9714 ret
9715
9716hd1_post_logical_chs:
9717 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
9718 mov (0x004d + 0x09), bx ;; number of physical cylinders
9719 mov (0x004d + 0x0b), cl ;; number of physical heads
9720 mov (0x004d + 0x04), dl ;; number of physical sectors
9721 mov (0x004d + 0x0e), dl ;; number of logical sectors (same)
9722 mov al, #0xa0
9723 mov (0x004d + 0x03), al ;; A0h signature, indicates translated table
9724
9725 cmp bx, #2048
9726 jnbe hd1_post_above_2048
9727 ;; 1024 < c <= 2048 cylinders
9728 shr bx, #0x01
9729 shl cl, #0x01
9730 jmp hd1_post_store_logical
9731
9732hd1_post_above_2048:
9733 cmp bx, #4096
9734 jnbe hd1_post_above_4096
9735 ;; 2048 < c <= 4096 cylinders
9736 shr bx, #0x02
9737 shl cl, #0x02
9738 jmp hd1_post_store_logical
9739
9740hd1_post_above_4096:
9741 cmp bx, #8192
9742 jnbe hd1_post_above_8192
9743 ;; 4096 < c <= 8192 cylinders
9744 shr bx, #0x03
9745 shl cl, #0x03
9746 jmp hd1_post_store_logical
9747
9748hd1_post_above_8192:
9749 ;; 8192 < c <= 16384 cylinders
9750 shr bx, #0x04
9751 shl cl, #0x04
9752
9753hd1_post_store_logical:
9754 mov (0x004d + 0x00), bx ;; number of physical cylinders
9755 mov (0x004d + 0x02), cl ;; number of physical heads
9756 ;; checksum
9757 mov cl, #0x0f ;; repeat count
9758 mov si, #0x004d ;; offset to disk0 FDPT
9759 mov al, #0x00 ;; sum
9760hd1_post_checksum_loop:
9761 add al, [si]
9762 inc si
9763 dec cl
9764 jnz hd1_post_checksum_loop
9765 not al ;; now take 2s complement
9766 inc al
9767 mov [si], al
9768;;; Done filling EBDA table for hard disk 1.
9769#endif /* !VBOX */
9770
9771 ret
9772
9773;--------------------
9774;- POST: EBDA segment
9775;--------------------
9776; relocated here because the primary POST area isnt big enough.
9777; the SET_INT_VECTORs have nothing to do with EBDA but do not
9778; fit into the primary POST area either
9779ebda_post:
9780 SET_INT_VECTOR(0x0D, #0xF000, #dummy_isr); IRQ 5
9781 SET_INT_VECTOR(0x0F, #0xF000, #dummy_isr); IRQ 7
9782 SET_INT_VECTOR(0x72, #0xF000, #dummy_isr); IRQ 11
9783 SET_INT_VECTOR(0x77, #0xF000, #dummy_isr); IRQ 15
9784
9785#if BX_USE_EBDA
9786 mov ax, #EBDA_SEG
9787 mov ds, ax
9788 mov byte ptr [0x0], #EBDA_SIZE
9789#endif
9790 xor ax, ax ; mov EBDA seg into 40E
9791 mov ds, ax
9792 mov word ptr [0x40E], #EBDA_SEG
9793 ret;;
9794
9795;--------------------
9796;- POST: EOI + jmp via [0x40:67)
9797;--------------------
9798; relocated here because the primary POST area isnt big enough.
9799eoi_jmp_post:
9800 call eoi_both_pics
9801
9802 xor ax, ax
9803 mov ds, ax
9804
9805 jmp far ptr [0x467]
9806
9807
9808;--------------------
9809eoi_both_pics:
9810 mov al, #0x20
9811 out #0xA0, al ;; slave PIC EOI
9812eoi_master_pic:
9813 mov al, #0x20
9814 out #0x20, al ;; master PIC EOI
9815 ret
9816
9817;--------------------
9818BcdToBin:
9819 ;; in: AL in BCD format
9820 ;; out: AL in binary format, AH will always be 0
9821 ;; trashes BX
9822 mov bl, al
9823 and bl, #0x0f ;; bl has low digit
9824 shr al, #4 ;; al has high digit
9825 mov bh, #10
9826 mul al, bh ;; multiply high digit by 10 (result in AX)
9827 add al, bl ;; then add low digit
9828 ret
9829
9830;--------------------
9831timer_tick_post:
9832 ;; Setup the Timer Ticks Count (0x46C:dword) and
9833 ;; Timer Ticks Roller Flag (0x470:byte)
9834 ;; The Timer Ticks Count needs to be set according to
9835 ;; the current CMOS time, as if ticks have been occurring
9836 ;; at 18.2hz since midnight up to this point. Calculating
9837 ;; this is a little complicated. Here are the factors I gather
9838 ;; regarding this. 14,318,180 hz was the original clock speed,
9839 ;; chosen so it could be divided by either 3 to drive the 5Mhz CPU
9840 ;; at the time, or 4 to drive the CGA video adapter. The div3
9841 ;; source was divided again by 4 to feed a 1.193Mhz signal to
9842 ;; the timer. With a maximum 16bit timer count, this is again
9843 ;; divided down by 65536 to 18.2hz.
9844 ;;
9845 ;; 14,318,180 Hz clock
9846 ;; /3 = 4,772,726 Hz fed to original 5Mhz CPU
9847 ;; /4 = 1,193,181 Hz fed to timer
9848 ;; /65536 (maximum timer count) = 18.20650736 ticks/second
9849 ;; 1 second = 18.20650736 ticks
9850 ;; 1 minute = 1092.390442 ticks
9851 ;; 1 hour = 65543.42651 ticks
9852 ;;
9853 ;; Given the values in the CMOS clock, one could calculate
9854 ;; the number of ticks by the following:
9855 ;; ticks = (BcdToBin(seconds) * 18.206507) +
9856 ;; (BcdToBin(minutes) * 1092.3904)
9857 ;; (BcdToBin(hours) * 65543.427)
9858 ;; To get a little more accuracy, since Im using integer
9859 ;; arithmetic, I use:
9860 ;; ticks = (BcdToBin(seconds) * 18206507) / 1000000 +
9861 ;; (BcdToBin(minutes) * 10923904) / 10000 +
9862 ;; (BcdToBin(hours) * 65543427) / 1000
9863
9864 ;; assuming DS=0000
9865
9866 ;; get CMOS seconds
9867 xor eax, eax ;; clear EAX
9868 mov al, #0x00
9869 out #0x70, al
9870 in al, #0x71 ;; AL has CMOS seconds in BCD
9871 call BcdToBin ;; EAX now has seconds in binary
9872 mov edx, #18206507
9873 mul eax, edx
9874 mov ebx, #1000000
9875 xor edx, edx
9876 div eax, ebx
9877 mov ecx, eax ;; ECX will accumulate total ticks
9878
9879 ;; get CMOS minutes
9880 xor eax, eax ;; clear EAX
9881 mov al, #0x02
9882 out #0x70, al
9883 in al, #0x71 ;; AL has CMOS minutes in BCD
9884 call BcdToBin ;; EAX now has minutes in binary
9885 mov edx, #10923904
9886 mul eax, edx
9887 mov ebx, #10000
9888 xor edx, edx
9889 div eax, ebx
9890 add ecx, eax ;; add to total ticks
9891
9892 ;; get CMOS hours
9893 xor eax, eax ;; clear EAX
9894 mov al, #0x04
9895 out #0x70, al
9896 in al, #0x71 ;; AL has CMOS hours in BCD
9897 call BcdToBin ;; EAX now has hours in binary
9898 mov edx, #65543427
9899 mul eax, edx
9900 mov ebx, #1000
9901 xor edx, edx
9902 div eax, ebx
9903 add ecx, eax ;; add to total ticks
9904
9905 mov 0x46C, ecx ;; Timer Ticks Count
9906 xor al, al
9907 mov 0x470, al ;; Timer Ticks Rollover Flag
9908 ret
9909
9910;--------------------
9911int76_handler:
9912 ;; record completion in BIOS task complete flag
9913 push ax
9914 push ds
9915 mov ax, #0x0040
9916 mov ds, ax
9917 mov 0x008E, #0xff
9918 call eoi_both_pics
9919 pop ds
9920 pop ax
9921 iret
9922
9923
9924;--------------------
9925#ifdef VBOX
9926init_pic:
9927 ;; init PIC
9928 mov al, #0x11 ; send initialisation commands
9929 out 0x20, al
9930 out 0xa0, al
9931 mov al, #0x08
9932 out 0x21, al
9933 mov al, #0x70
9934 out 0xa1, al
9935 mov al, #0x04
9936 out 0x21, al
9937 mov al, #0x02
9938 out 0xa1, al
9939 mov al, #0x01
9940 out 0x21, al
9941 out 0xa1, al
9942 mov al, #0xb8
9943 out 0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6
9944#if BX_USE_PS2_MOUSE
9945 mov al, #0x8f
9946#else
9947 mov al, #0x9f
9948#endif
9949 out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14
9950 ret
9951#endif /* VBOX */
9952
9953;--------------------
9954#if BX_APM
9955
9956use32 386
9957#define APM_PROT32
9958#include "apmbios.S"
9959
9960use16 386
9961#define APM_PROT16
9962#include "apmbios.S"
9963
9964#define APM_REAL
9965#include "apmbios.S"
9966
9967#endif
9968
9969;--------------------
9970#if BX_PCIBIOS
9971use32 386
9972.align 16
9973bios32_structure:
9974 db 0x5f, 0x33, 0x32, 0x5f ;; "_32_" signature
9975 dw bios32_entry_point, 0xf ;; 32 bit physical address
9976 db 0 ;; revision level
9977 ;; length in paragraphs and checksum stored in a word to prevent errors
9978 dw (~(((bios32_entry_point >> 8) + (bios32_entry_point & 0xff) + 0x32) \
9979 & 0xff) << 8) + 0x01
9980 db 0,0,0,0,0 ;; reserved
9981
9982.align 16
9983bios32_entry_point:
9984 pushfd
9985 cmp eax, #0x49435024 ;; "$PCI"
9986 jne unknown_service
9987
9988#ifdef PCI_FIXED_HOST_BRIDGE_1
9989 mov eax, #0x80000000
9990 mov dx, #0x0cf8
9991 out dx, eax
9992 mov dx, #0x0cfc
9993 in eax, dx
9994 cmp eax, #PCI_FIXED_HOST_BRIDGE_1
9995 je device_ok
9996#endif
9997
9998#ifdef PCI_FIXED_HOST_BRIDGE_2
9999 /* 0x1e << 11 */
10000 mov eax, #0x8000f000
10001 mov dx, #0x0cf8
10002 out dx, eax
10003 mov dx, #0x0cfc
10004 in eax, dx
10005 cmp eax, #PCI_FIXED_HOST_BRIDGE_2
10006 je device_ok
10007#endif
10008 jmp unknown_service
10009device_ok:
10010 mov ebx, #0x000f0000
10011 mov ecx, #0
10012 mov edx, #pcibios_protected
10013 xor al, al
10014 jmp bios32_end
10015unknown_service:
10016 mov al, #0x80
10017bios32_end:
10018#ifdef BX_QEMU
10019 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
10020#endif
10021 popfd
10022 retf
10023
10024.align 16
10025pcibios_protected:
10026 pushfd
10027 cli
10028 push esi
10029 push edi
10030 cmp al, #0x01 ;; installation check
10031 jne pci_pro_f02
10032 mov bx, #0x0210
10033 mov cx, #0
10034 mov edx, #0x20494350 ;; "PCI "
10035 mov al, #0x01
10036 jmp pci_pro_ok
10037pci_pro_f02: ;; find pci device
10038 cmp al, #0x02
10039 jne pci_pro_f03
10040 shl ecx, #16
10041 mov cx, dx
10042 xor ebx, ebx
10043 mov di, #0x00
10044pci_pro_devloop:
10045 call pci_pro_select_reg
10046 mov dx, #0x0cfc
10047 in eax, dx
10048 cmp eax, ecx
10049 jne pci_pro_nextdev
10050 cmp si, #0
10051 je pci_pro_ok
10052 dec si
10053pci_pro_nextdev:
10054 inc ebx
10055 cmp ebx, #0x10000
10056 jne pci_pro_devloop
10057 mov ah, #0x86
10058 jmp pci_pro_fail
10059pci_pro_f03: ;; find class code
10060 cmp al, #0x03
10061 jne pci_pro_f08
10062 xor ebx, ebx
10063 mov di, #0x08
10064pci_pro_devloop2:
10065 call pci_pro_select_reg
10066 mov dx, #0x0cfc
10067 in eax, dx
10068 shr eax, #8
10069 cmp eax, ecx
10070 jne pci_pro_nextdev2
10071 cmp si, #0
10072 je pci_pro_ok
10073 dec si
10074pci_pro_nextdev2:
10075 inc ebx
10076 cmp ebx, #0x10000
10077 jne pci_pro_devloop2
10078 mov ah, #0x86
10079 jmp pci_pro_fail
10080pci_pro_f08: ;; read configuration byte
10081 cmp al, #0x08
10082 jne pci_pro_f09
10083 call pci_pro_select_reg
10084 push edx
10085 mov dx, di
10086 and dx, #0x03
10087 add dx, #0x0cfc
10088 in al, dx
10089 pop edx
10090 mov cl, al
10091 jmp pci_pro_ok
10092pci_pro_f09: ;; read configuration word
10093 cmp al, #0x09
10094 jne pci_pro_f0a
10095 call pci_pro_select_reg
10096 push edx
10097 mov dx, di
10098 and dx, #0x02
10099 add dx, #0x0cfc
10100 in ax, dx
10101 pop edx
10102 mov cx, ax
10103 jmp pci_pro_ok
10104pci_pro_f0a: ;; read configuration dword
10105 cmp al, #0x0a
10106 jne pci_pro_f0b
10107 call pci_pro_select_reg
10108 push edx
10109 mov dx, #0x0cfc
10110 in eax, dx
10111 pop edx
10112 mov ecx, eax
10113 jmp pci_pro_ok
10114pci_pro_f0b: ;; write configuration byte
10115 cmp al, #0x0b
10116 jne pci_pro_f0c
10117 call pci_pro_select_reg
10118 push edx
10119 mov dx, di
10120 and dx, #0x03
10121 add dx, #0x0cfc
10122 mov al, cl
10123 out dx, al
10124 pop edx
10125 jmp pci_pro_ok
10126pci_pro_f0c: ;; write configuration word
10127 cmp al, #0x0c
10128 jne pci_pro_f0d
10129 call pci_pro_select_reg
10130 push edx
10131 mov dx, di
10132 and dx, #0x02
10133 add dx, #0x0cfc
10134 mov ax, cx
10135 out dx, ax
10136 pop edx
10137 jmp pci_pro_ok
10138pci_pro_f0d: ;; write configuration dword
10139 cmp al, #0x0d
10140 jne pci_pro_unknown
10141 call pci_pro_select_reg
10142 push edx
10143 mov dx, #0x0cfc
10144 mov eax, ecx
10145 out dx, eax
10146 pop edx
10147 jmp pci_pro_ok
10148pci_pro_unknown:
10149 mov ah, #0x81
10150pci_pro_fail:
10151 pop edi
10152 pop esi
10153#ifdef BX_QEMU
10154 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
10155#endif
10156 popfd
10157 stc
10158 retf
10159pci_pro_ok:
10160 xor ah, ah
10161 pop edi
10162 pop esi
10163#ifdef BX_QEMU
10164 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
10165#endif
10166 popfd
10167 clc
10168 retf
10169
10170pci_pro_select_reg:
10171 push edx
10172 mov eax, #0x800000
10173 mov ax, bx
10174 shl eax, #8
10175 and di, #0xff
10176 or ax, di
10177 and al, #0xfc
10178 mov dx, #0x0cf8
10179 out dx, eax
10180 pop edx
10181 ret
10182
10183use16 386
10184
10185pcibios_real:
10186 push eax
10187 push dx
10188#ifdef PCI_FIXED_HOST_BRIDGE_1
10189 mov eax, #0x80000000
10190 mov dx, #0x0cf8
10191 out dx, eax
10192 mov dx, #0x0cfc
10193 in eax, dx
10194 cmp eax, #PCI_FIXED_HOST_BRIDGE_1
10195 je pci_present
10196#endif
10197
10198#ifdef PCI_FIXED_HOST_BRIDGE_2
10199 /* 0x1e << 11 */
10200 mov eax, #0x8000f000
10201 mov dx, #0x0cf8
10202 out dx, eax
10203 mov dx, #0x0cfc
10204 in eax, dx
10205 cmp eax, #PCI_FIXED_HOST_BRIDGE_2
10206 je pci_present
10207#endif
10208 pop dx
10209 pop eax
10210 mov ah, #0xff
10211 stc
10212 ret
10213pci_present:
10214 pop dx
10215 pop eax
10216 cmp al, #0x01 ;; installation check
10217 jne pci_real_f02
10218 mov ax, #0x0001
10219 mov bx, #0x0210
10220 mov cx, #0
10221 mov edx, #0x20494350 ;; "PCI "
10222 mov edi, #0xf0000
10223 mov di, #pcibios_protected
10224 clc
10225 ret
10226pci_real_f02: ;; find pci device
10227 push esi
10228 push edi
10229 push edx
10230 cmp al, #0x02
10231 jne pci_real_f03
10232 shl ecx, #16
10233 mov cx, dx
10234 xor ebx, ebx
10235 mov di, #0x00
10236pci_real_devloop:
10237 call pci_real_select_reg
10238 mov dx, #0x0cfc
10239 in eax, dx
10240 cmp eax, ecx
10241 jne pci_real_nextdev
10242 cmp si, #0
10243 je pci_real_ok
10244 dec si
10245pci_real_nextdev:
10246 inc ebx
10247 cmp ebx, #0x10000
10248 jne pci_real_devloop
10249 mov dx, cx
10250 shr ecx, #16
10251 mov ax, #0x8602
10252 jmp pci_real_fail
10253pci_real_f03: ;; find class code
10254 cmp al, #0x03
10255 jne pci_real_f08
10256 xor ebx, ebx
10257 mov di, #0x08
10258pci_real_devloop2:
10259 call pci_real_select_reg
10260 mov dx, #0x0cfc
10261 in eax, dx
10262 shr eax, #8
10263 cmp eax, ecx
10264 jne pci_real_nextdev2
10265 cmp si, #0
10266 je pci_real_ok
10267 dec si
10268pci_real_nextdev2:
10269 inc ebx
10270 cmp ebx, #0x10000
10271 jne pci_real_devloop2
10272 mov ax, #0x8603
10273 jmp pci_real_fail
10274pci_real_f08: ;; read configuration byte
10275 cmp al, #0x08
10276 jne pci_real_f09
10277 call pci_real_select_reg
10278 push dx
10279 mov dx, di
10280 and dx, #0x03
10281 add dx, #0x0cfc
10282 in al, dx
10283 pop dx
10284 mov cl, al
10285 jmp pci_real_ok
10286pci_real_f09: ;; read configuration word
10287 cmp al, #0x09
10288 jne pci_real_f0a
10289 call pci_real_select_reg
10290 push dx
10291 mov dx, di
10292 and dx, #0x02
10293 add dx, #0x0cfc
10294 in ax, dx
10295 pop dx
10296 mov cx, ax
10297 jmp pci_real_ok
10298pci_real_f0a: ;; read configuration dword
10299 cmp al, #0x0a
10300 jne pci_real_f0b
10301 call pci_real_select_reg
10302 push dx
10303 mov dx, #0x0cfc
10304 in eax, dx
10305 pop dx
10306 mov ecx, eax
10307 jmp pci_real_ok
10308pci_real_f0b: ;; write configuration byte
10309 cmp al, #0x0b
10310 jne pci_real_f0c
10311 call pci_real_select_reg
10312 push dx
10313 mov dx, di
10314 and dx, #0x03
10315 add dx, #0x0cfc
10316 mov al, cl
10317 out dx, al
10318 pop dx
10319 jmp pci_real_ok
10320pci_real_f0c: ;; write configuration word
10321 cmp al, #0x0c
10322 jne pci_real_f0d
10323 call pci_real_select_reg
10324 push dx
10325 mov dx, di
10326 and dx, #0x02
10327 add dx, #0x0cfc
10328 mov ax, cx
10329 out dx, ax
10330 pop dx
10331 jmp pci_real_ok
10332pci_real_f0d: ;; write configuration dword
10333 cmp al, #0x0d
10334 jne pci_real_f0e
10335 call pci_real_select_reg
10336 push dx
10337 mov dx, #0x0cfc
10338 mov eax, ecx
10339 out dx, eax
10340 pop dx
10341 jmp pci_real_ok
10342pci_real_f0e: ;; get irq routing options
10343 cmp al, #0x0e
10344 jne pci_real_unknown
10345 SEG ES
10346 cmp word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
10347 jb pci_real_too_small
10348 SEG ES
10349 mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
10350 pushf
10351 push ds
10352 push es
10353 push cx
10354 push si
10355 push di
10356 cld
10357 mov si, #pci_routing_table_structure_start
10358 push cs
10359 pop ds
10360 SEG ES
10361 mov cx, [di+2]
10362 SEG ES
10363 mov es, [di+4]
10364 mov di, cx
10365 mov cx, #pci_routing_table_structure_end - pci_routing_table_structure_start
10366 rep
10367 movsb
10368 pop di
10369 pop si
10370 pop cx
10371 pop es
10372 pop ds
10373 popf
10374 mov bx, #(1 << 9) | (1 << 11) ;; irq 9 and 11 are used
10375 jmp pci_real_ok
10376pci_real_too_small:
10377 SEG ES
10378 mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
10379 mov ah, #0x89
10380 jmp pci_real_fail
10381
10382pci_real_unknown:
10383 mov ah, #0x81
10384pci_real_fail:
10385 pop edx
10386 pop edi
10387 pop esi
10388 stc
10389 ret
10390pci_real_ok:
10391 xor ah, ah
10392 pop edx
10393 pop edi
10394 pop esi
10395 clc
10396 ret
10397
10398;; prepare from reading the PCI config space; on input:
10399;; bx = bus/dev/fn
10400;; di = offset into config space header
10401;; destroys eax and may modify di
10402pci_real_select_reg:
10403 push dx
10404 mov eax, #0x800000
10405 mov ax, bx
10406 shl eax, #8
10407 and di, #0xff
10408 or ax, di
10409 and al, #0xfc
10410 mov dx, #0x0cf8
10411 out dx, eax
10412 pop dx
10413 ret
10414
10415.align 16
10416pci_routing_table_structure:
10417 db 0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature
10418 db 0, 1 ;; version
10419#ifdef VBOX
10420 dw 32 + (30 * 16) ;; table size
10421#else /* !VBOX */
10422 dw 32 + (6 * 16) ;; table size
10423#endif /* !VBOX */
10424 db 0 ;; PCI interrupt router bus
10425 db 0x08 ;; PCI interrupt router DevFunc
10426 dw 0x0000 ;; PCI exclusive IRQs
10427 dw 0x8086 ;; compatible PCI interrupt router vendor ID
10428 dw 0x7000 ;; compatible PCI interrupt router device ID
10429 dw 0,0 ;; Miniport data
10430 db 0,0,0,0,0,0,0,0,0,0,0 ;; reserved
10431#ifdef VBOX
10432 db 0x00 ;; checksum (set by biossums)
10433#else /* !VBOX */
10434 db 0x07 ;; checksum
10435#endif /* !VBOX */
10436pci_routing_table_structure_start:
10437 ;; first slot entry PCI-to-ISA (embedded)
10438 db 0 ;; pci bus number
10439 db 0x08 ;; pci device number (bit 7-3)
10440 db 0x60 ;; link value INTA#: pointer into PCI2ISA config space
10441 dw 0xdef8 ;; IRQ bitmap INTA#
10442 db 0x61 ;; link value INTB#
10443 dw 0xdef8 ;; IRQ bitmap INTB#
10444 db 0x62 ;; link value INTC#
10445 dw 0xdef8 ;; IRQ bitmap INTC#
10446 db 0x63 ;; link value INTD#
10447 dw 0xdef8 ;; IRQ bitmap INTD#
10448 db 0 ;; physical slot (0 = embedded)
10449 db 0 ;; reserved
10450 ;; second slot entry: 1st PCI slot
10451 db 0 ;; pci bus number
10452 db 0x10 ;; pci device number (bit 7-3)
10453 db 0x61 ;; link value INTA#
10454 dw 0xdef8 ;; IRQ bitmap INTA#
10455 db 0x62 ;; link value INTB#
10456 dw 0xdef8 ;; IRQ bitmap INTB#
10457 db 0x63 ;; link value INTC#
10458 dw 0xdef8 ;; IRQ bitmap INTC#
10459 db 0x60 ;; link value INTD#
10460 dw 0xdef8 ;; IRQ bitmap INTD#
10461 db 1 ;; physical slot (0 = embedded)
10462 db 0 ;; reserved
10463 ;; third slot entry: 2nd PCI slot
10464 db 0 ;; pci bus number
10465 db 0x18 ;; pci device number (bit 7-3)
10466 db 0x62 ;; link value INTA#
10467 dw 0xdef8 ;; IRQ bitmap INTA#
10468 db 0x63 ;; link value INTB#
10469 dw 0xdef8 ;; IRQ bitmap INTB#
10470 db 0x60 ;; link value INTC#
10471 dw 0xdef8 ;; IRQ bitmap INTC#
10472 db 0x61 ;; link value INTD#
10473 dw 0xdef8 ;; IRQ bitmap INTD#
10474 db 2 ;; physical slot (0 = embedded)
10475 db 0 ;; reserved
10476 ;; 4th slot entry: 3rd PCI slot
10477 db 0 ;; pci bus number
10478 db 0x20 ;; pci device number (bit 7-3)
10479 db 0x63 ;; link value INTA#
10480 dw 0xdef8 ;; IRQ bitmap INTA#
10481 db 0x60 ;; link value INTB#
10482 dw 0xdef8 ;; IRQ bitmap INTB#
10483 db 0x61 ;; link value INTC#
10484 dw 0xdef8 ;; IRQ bitmap INTC#
10485 db 0x62 ;; link value INTD#
10486 dw 0xdef8 ;; IRQ bitmap INTD#
10487 db 3 ;; physical slot (0 = embedded)
10488 db 0 ;; reserved
10489 ;; 5th slot entry: 4rd PCI slot
10490 db 0 ;; pci bus number
10491 db 0x28 ;; pci device number (bit 7-3)
10492 db 0x60 ;; link value INTA#
10493 dw 0xdef8 ;; IRQ bitmap INTA#
10494 db 0x61 ;; link value INTB#
10495 dw 0xdef8 ;; IRQ bitmap INTB#
10496 db 0x62 ;; link value INTC#
10497 dw 0xdef8 ;; IRQ bitmap INTC#
10498 db 0x63 ;; link value INTD#
10499 dw 0xdef8 ;; IRQ bitmap INTD#
10500 db 4 ;; physical slot (0 = embedded)
10501 db 0 ;; reserved
10502 ;; 6th slot entry: 5rd PCI slot
10503 db 0 ;; pci bus number
10504 db 0x30 ;; pci device number (bit 7-3)
10505 db 0x61 ;; link value INTA#
10506 dw 0xdef8 ;; IRQ bitmap INTA#
10507 db 0x62 ;; link value INTB#
10508 dw 0xdef8 ;; IRQ bitmap INTB#
10509 db 0x63 ;; link value INTC#
10510 dw 0xdef8 ;; IRQ bitmap INTC#
10511 db 0x60 ;; link value INTD#
10512 dw 0xdef8 ;; IRQ bitmap INTD#
10513 db 5 ;; physical slot (0 = embedded)
10514 db 0 ;; reserved
10515#ifdef VBOX
10516 ;; 7th slot entry: 6th PCI slot
10517 db 0 ;; pci bus number
10518 db 0x38 ;; pci device number (bit 7-3)
10519 db 0x62 ;; link value INTA#
10520 dw 0xdef8 ;; IRQ bitmap INTA#
10521 db 0x63 ;; link value INTB#
10522 dw 0xdef8 ;; IRQ bitmap INTB#
10523 db 0x60 ;; link value INTC#
10524 dw 0xdef8 ;; IRQ bitmap INTC#
10525 db 0x61 ;; link value INTD#
10526 dw 0xdef8 ;; IRQ bitmap INTD#
10527 db 6 ;; physical slot (0 = embedded)
10528 db 0 ;; reserved
10529 ;; 8th slot entry: 7th PCI slot
10530 db 0 ;; pci bus number
10531 db 0x40 ;; pci device number (bit 7-3)
10532 db 0x63 ;; link value INTA#
10533 dw 0xdef8 ;; IRQ bitmap INTA#
10534 db 0x60 ;; link value INTB#
10535 dw 0xdef8 ;; IRQ bitmap INTB#
10536 db 0x61 ;; link value INTC#
10537 dw 0xdef8 ;; IRQ bitmap INTC#
10538 db 0x62 ;; link value INTD#
10539 dw 0xdef8 ;; IRQ bitmap INTD#
10540 db 7 ;; physical slot (0 = embedded)
10541 db 0 ;; reserved
10542 ;; 9th slot entry: 8th PCI slot
10543 db 0 ;; pci bus number
10544 db 0x48 ;; pci device number (bit 7-3)
10545 db 0x60 ;; link value INTA#
10546 dw 0xdef8 ;; IRQ bitmap INTA#
10547 db 0x61 ;; link value INTB#
10548 dw 0xdef8 ;; IRQ bitmap INTB#
10549 db 0x62 ;; link value INTC#
10550 dw 0xdef8 ;; IRQ bitmap INTC#
10551 db 0x63 ;; link value INTD#
10552 dw 0xdef8 ;; IRQ bitmap INTD#
10553 db 8 ;; physical slot (0 = embedded)
10554 db 0 ;; reserved
10555 ;; 10th slot entry: 9th PCI slot
10556 db 0 ;; pci bus number
10557 db 0x50 ;; pci device number (bit 7-3)
10558 db 0x61 ;; link value INTA#
10559 dw 0xdef8 ;; IRQ bitmap INTA#
10560 db 0x62 ;; link value INTB#
10561 dw 0xdef8 ;; IRQ bitmap INTB#
10562 db 0x63 ;; link value INTC#
10563 dw 0xdef8 ;; IRQ bitmap INTC#
10564 db 0x60 ;; link value INTD#
10565 dw 0xdef8 ;; IRQ bitmap INTD#
10566 db 9 ;; physical slot (0 = embedded)
10567 db 0 ;; reserved
10568 ;; 11th slot entry: 10th PCI slot
10569 db 0 ;; pci bus number
10570 db 0x58 ;; pci device number (bit 7-3)
10571 db 0x62 ;; link value INTA#
10572 dw 0xdef8 ;; IRQ bitmap INTA#
10573 db 0x63 ;; link value INTB#
10574 dw 0xdef8 ;; IRQ bitmap INTB#
10575 db 0x60 ;; link value INTC#
10576 dw 0xdef8 ;; IRQ bitmap INTC#
10577 db 0x61 ;; link value INTD#
10578 dw 0xdef8 ;; IRQ bitmap INTD#
10579 db 10 ;; physical slot (0 = embedded)
10580 db 0 ;; reserved
10581 ;; 12th slot entry: 11th PCI slot
10582 db 0 ;; pci bus number
10583 db 0x60 ;; pci device number (bit 7-3)
10584 db 0x63 ;; link value INTA#
10585 dw 0xdef8 ;; IRQ bitmap INTA#
10586 db 0x60 ;; link value INTB#
10587 dw 0xdef8 ;; IRQ bitmap INTB#
10588 db 0x61 ;; link value INTC#
10589 dw 0xdef8 ;; IRQ bitmap INTC#
10590 db 0x62 ;; link value INTD#
10591 dw 0xdef8 ;; IRQ bitmap INTD#
10592 db 11 ;; physical slot (0 = embedded)
10593 db 0 ;; reserved
10594 ;; 13th slot entry: 12th PCI slot
10595 db 0 ;; pci bus number
10596 db 0x68 ;; pci device number (bit 7-3)
10597 db 0x60 ;; link value INTA#
10598 dw 0xdef8 ;; IRQ bitmap INTA#
10599 db 0x61 ;; link value INTB#
10600 dw 0xdef8 ;; IRQ bitmap INTB#
10601 db 0x62 ;; link value INTC#
10602 dw 0xdef8 ;; IRQ bitmap INTC#
10603 db 0x63 ;; link value INTD#
10604 dw 0xdef8 ;; IRQ bitmap INTD#
10605 db 12 ;; physical slot (0 = embedded)
10606 db 0 ;; reserved
10607 ;; 14th slot entry: 13th PCI slot
10608 db 0 ;; pci bus number
10609 db 0x70 ;; pci device number (bit 7-3)
10610 db 0x61 ;; link value INTA#
10611 dw 0xdef8 ;; IRQ bitmap INTA#
10612 db 0x62 ;; link value INTB#
10613 dw 0xdef8 ;; IRQ bitmap INTB#
10614 db 0x63 ;; link value INTC#
10615 dw 0xdef8 ;; IRQ bitmap INTC#
10616 db 0x60 ;; link value INTD#
10617 dw 0xdef8 ;; IRQ bitmap INTD#
10618 db 13 ;; physical slot (0 = embedded)
10619 db 0 ;; reserved
10620 ;; 15th slot entry: 14th PCI slot
10621 db 0 ;; pci bus number
10622 db 0x78 ;; pci device number (bit 7-3)
10623 db 0x62 ;; link value INTA#
10624 dw 0xdef8 ;; IRQ bitmap INTA#
10625 db 0x63 ;; link value INTB#
10626 dw 0xdef8 ;; IRQ bitmap INTB#
10627 db 0x60 ;; link value INTC#
10628 dw 0xdef8 ;; IRQ bitmap INTC#
10629 db 0x61 ;; link value INTD#
10630 dw 0xdef8 ;; IRQ bitmap INTD#
10631 db 14 ;; physical slot (0 = embedded)
10632 db 0 ;; reserved
10633 ;; 16th slot entry: 15th PCI slot
10634 db 0 ;; pci bus number
10635 db 0x80 ;; pci device number (bit 7-3)
10636 db 0x63 ;; link value INTA#
10637 dw 0xdef8 ;; IRQ bitmap INTA#
10638 db 0x60 ;; link value INTB#
10639 dw 0xdef8 ;; IRQ bitmap INTB#
10640 db 0x61 ;; link value INTC#
10641 dw 0xdef8 ;; IRQ bitmap INTC#
10642 db 0x62 ;; link value INTD#
10643 dw 0xdef8 ;; IRQ bitmap INTD#
10644 db 15 ;; physical slot (0 = embedded)
10645 db 0 ;; reserved
10646 ;; 17th slot entry: 16th PCI slot
10647 db 0 ;; pci bus number
10648 db 0x88 ;; pci device number (bit 7-3)
10649 db 0x60 ;; link value INTA#
10650 dw 0xdef8 ;; IRQ bitmap INTA#
10651 db 0x61 ;; link value INTB#
10652 dw 0xdef8 ;; IRQ bitmap INTB#
10653 db 0x62 ;; link value INTC#
10654 dw 0xdef8 ;; IRQ bitmap INTC#
10655 db 0x63 ;; link value INTD#
10656 dw 0xdef8 ;; IRQ bitmap INTD#
10657 db 16 ;; physical slot (0 = embedded)
10658 db 0 ;; reserved
10659 ;; 18th slot entry: 17th PCI slot
10660 db 0 ;; pci bus number
10661 db 0x90 ;; pci device number (bit 7-3)
10662 db 0x61 ;; link value INTA#
10663 dw 0xdef8 ;; IRQ bitmap INTA#
10664 db 0x62 ;; link value INTB#
10665 dw 0xdef8 ;; IRQ bitmap INTB#
10666 db 0x63 ;; link value INTC#
10667 dw 0xdef8 ;; IRQ bitmap INTC#
10668 db 0x60 ;; link value INTD#
10669 dw 0xdef8 ;; IRQ bitmap INTD#
10670 db 17 ;; physical slot (0 = embedded)
10671 db 0 ;; reserved
10672 ;; 19th slot entry: 18th PCI slot
10673 db 0 ;; pci bus number
10674 db 0x98 ;; pci device number (bit 7-3)
10675 db 0x62 ;; link value INTA#
10676 dw 0xdef8 ;; IRQ bitmap INTA#
10677 db 0x63 ;; link value INTB#
10678 dw 0xdef8 ;; IRQ bitmap INTB#
10679 db 0x60 ;; link value INTC#
10680 dw 0xdef8 ;; IRQ bitmap INTC#
10681 db 0x61 ;; link value INTD#
10682 dw 0xdef8 ;; IRQ bitmap INTD#
10683 db 18 ;; physical slot (0 = embedded)
10684 db 0 ;; reserved
10685 ;; 20th slot entry: 19th PCI slot
10686 db 0 ;; pci bus number
10687 db 0xa0 ;; pci device number (bit 7-3)
10688 db 0x63 ;; link value INTA#
10689 dw 0xdef8 ;; IRQ bitmap INTA#
10690 db 0x60 ;; link value INTB#
10691 dw 0xdef8 ;; IRQ bitmap INTB#
10692 db 0x61 ;; link value INTC#
10693 dw 0xdef8 ;; IRQ bitmap INTC#
10694 db 0x62 ;; link value INTD#
10695 dw 0xdef8 ;; IRQ bitmap INTD#
10696 db 19 ;; physical slot (0 = embedded)
10697 db 0 ;; reserved
10698 ;; 21st slot entry: 20th PCI slot
10699 db 0 ;; pci bus number
10700 db 0xa8 ;; pci device number (bit 7-3)
10701 db 0x60 ;; link value INTA#
10702 dw 0xdef8 ;; IRQ bitmap INTA#
10703 db 0x61 ;; link value INTB#
10704 dw 0xdef8 ;; IRQ bitmap INTB#
10705 db 0x62 ;; link value INTC#
10706 dw 0xdef8 ;; IRQ bitmap INTC#
10707 db 0x63 ;; link value INTD#
10708 dw 0xdef8 ;; IRQ bitmap INTD#
10709 db 20 ;; physical slot (0 = embedded)
10710 db 0 ;; reserved
10711 ;; 22nd slot entry: 21st PCI slot
10712 db 0 ;; pci bus number
10713 db 0xb0 ;; pci device number (bit 7-3)
10714 db 0x61 ;; link value INTA#
10715 dw 0xdef8 ;; IRQ bitmap INTA#
10716 db 0x62 ;; link value INTB#
10717 dw 0xdef8 ;; IRQ bitmap INTB#
10718 db 0x63 ;; link value INTC#
10719 dw 0xdef8 ;; IRQ bitmap INTC#
10720 db 0x60 ;; link value INTD#
10721 dw 0xdef8 ;; IRQ bitmap INTD#
10722 db 21 ;; physical slot (0 = embedded)
10723 db 0 ;; reserved
10724 ;; 23rd slot entry: 22nd PCI slot
10725 db 0 ;; pci bus number
10726 db 0xb8 ;; pci device number (bit 7-3)
10727 db 0x62 ;; link value INTA#
10728 dw 0xdef8 ;; IRQ bitmap INTA#
10729 db 0x63 ;; link value INTB#
10730 dw 0xdef8 ;; IRQ bitmap INTB#
10731 db 0x60 ;; link value INTC#
10732 dw 0xdef8 ;; IRQ bitmap INTC#
10733 db 0x61 ;; link value INTD#
10734 dw 0xdef8 ;; IRQ bitmap INTD#
10735 db 22 ;; physical slot (0 = embedded)
10736 db 0 ;; reserved
10737 ;; 24th slot entry: 23rd PCI slot
10738 db 0 ;; pci bus number
10739 db 0xc0 ;; pci device number (bit 7-3)
10740 db 0x63 ;; link value INTA#
10741 dw 0xdef8 ;; IRQ bitmap INTA#
10742 db 0x60 ;; link value INTB#
10743 dw 0xdef8 ;; IRQ bitmap INTB#
10744 db 0x61 ;; link value INTC#
10745 dw 0xdef8 ;; IRQ bitmap INTC#
10746 db 0x62 ;; link value INTD#
10747 dw 0xdef8 ;; IRQ bitmap INTD#
10748 db 23 ;; physical slot (0 = embedded)
10749 db 0 ;; reserved
10750 ;; 25th slot entry: 24th PCI slot
10751 db 0 ;; pci bus number
10752 db 0xc8 ;; pci device number (bit 7-3)
10753 db 0x60 ;; link value INTA#
10754 dw 0xdef8 ;; IRQ bitmap INTA#
10755 db 0x61 ;; link value INTB#
10756 dw 0xdef8 ;; IRQ bitmap INTB#
10757 db 0x62 ;; link value INTC#
10758 dw 0xdef8 ;; IRQ bitmap INTC#
10759 db 0x63 ;; link value INTD#
10760 dw 0xdef8 ;; IRQ bitmap INTD#
10761 db 24 ;; physical slot (0 = embedded)
10762 db 0 ;; reserved
10763 ;; 26th slot entry: 25th PCI slot
10764 db 0 ;; pci bus number
10765 db 0xd0 ;; pci device number (bit 7-3)
10766 db 0x61 ;; link value INTA#
10767 dw 0xdef8 ;; IRQ bitmap INTA#
10768 db 0x62 ;; link value INTB#
10769 dw 0xdef8 ;; IRQ bitmap INTB#
10770 db 0x63 ;; link value INTC#
10771 dw 0xdef8 ;; IRQ bitmap INTC#
10772 db 0x60 ;; link value INTD#
10773 dw 0xdef8 ;; IRQ bitmap INTD#
10774 db 25 ;; physical slot (0 = embedded)
10775 db 0 ;; reserved
10776 ;; 27th slot entry: 26th PCI slot
10777 db 0 ;; pci bus number
10778 db 0xd8 ;; pci device number (bit 7-3)
10779 db 0x62 ;; link value INTA#
10780 dw 0xdef8 ;; IRQ bitmap INTA#
10781 db 0x63 ;; link value INTB#
10782 dw 0xdef8 ;; IRQ bitmap INTB#
10783 db 0x60 ;; link value INTC#
10784 dw 0xdef8 ;; IRQ bitmap INTC#
10785 db 0x61 ;; link value INTD#
10786 dw 0xdef8 ;; IRQ bitmap INTD#
10787 db 26 ;; physical slot (0 = embedded)
10788 db 0 ;; reserved
10789 ;; 28th slot entry: 27th PCI slot
10790 db 0 ;; pci bus number
10791 db 0xe0 ;; pci device number (bit 7-3)
10792 db 0x63 ;; link value INTA#
10793 dw 0xdef8 ;; IRQ bitmap INTA#
10794 db 0x60 ;; link value INTB#
10795 dw 0xdef8 ;; IRQ bitmap INTB#
10796 db 0x61 ;; link value INTC#
10797 dw 0xdef8 ;; IRQ bitmap INTC#
10798 db 0x62 ;; link value INTD#
10799 dw 0xdef8 ;; IRQ bitmap INTD#
10800 db 27 ;; physical slot (0 = embedded)
10801 db 0 ;; reserved
10802 ;; 29th slot entry: 28th PCI slot
10803 db 0 ;; pci bus number
10804 db 0xe8 ;; pci device number (bit 7-3)
10805 db 0x60 ;; link value INTA#
10806 dw 0xdef8 ;; IRQ bitmap INTA#
10807 db 0x61 ;; link value INTB#
10808 dw 0xdef8 ;; IRQ bitmap INTB#
10809 db 0x62 ;; link value INTC#
10810 dw 0xdef8 ;; IRQ bitmap INTC#
10811 db 0x63 ;; link value INTD#
10812 dw 0xdef8 ;; IRQ bitmap INTD#
10813 db 28 ;; physical slot (0 = embedded)
10814 db 0 ;; reserved
10815 ;; 30th slot entry: 29th PCI slot
10816 db 0 ;; pci bus number
10817 db 0xf0 ;; pci device number (bit 7-3)
10818 db 0x61 ;; link value INTA#
10819 dw 0xdef8 ;; IRQ bitmap INTA#
10820 db 0x62 ;; link value INTB#
10821 dw 0xdef8 ;; IRQ bitmap INTB#
10822 db 0x63 ;; link value INTC#
10823 dw 0xdef8 ;; IRQ bitmap INTC#
10824 db 0x60 ;; link value INTD#
10825 dw 0xdef8 ;; IRQ bitmap INTD#
10826 db 29 ;; physical slot (0 = embedded)
10827 db 0 ;; reserved
10828#endif /* VBOX */
10829pci_routing_table_structure_end:
10830
10831#if !BX_ROMBIOS32
10832pci_irq_list:
10833 db 11, 10, 9, 5;
10834
10835pcibios_init_sel_reg:
10836 push eax
10837 mov eax, #0x800000
10838 mov ax, bx
10839 shl eax, #8
10840 and dl, #0xfc
10841 or al, dl
10842 mov dx, #0x0cf8
10843 out dx, eax
10844 pop eax
10845 ret
10846
10847pcibios_init_iomem_bases:
10848 push bp
10849 mov bp, sp
10850 mov eax, #0xe0000000 ;; base for memory init
10851 push eax
10852 mov ax, #0xc000 ;; base for i/o init
10853 push ax
10854 mov ax, #0x0010 ;; start at base address #0
10855 push ax
10856 mov bx, #0x0008
10857pci_init_io_loop1:
10858 mov dl, #0x00
10859 call pcibios_init_sel_reg
10860 mov dx, #0x0cfc
10861 in ax, dx
10862 cmp ax, #0xffff
10863 jz next_pci_dev
10864#ifndef VBOX /* This currently breaks restoring a previously saved state. */
10865 mov dl, #0x04 ;; disable i/o and memory space access
10866 call pcibios_init_sel_reg
10867 mov dx, #0x0cfc
10868 in al, dx
10869 and al, #0xfc
10870 out dx, al
10871pci_init_io_loop2:
10872 mov dl, [bp-8]
10873 call pcibios_init_sel_reg
10874 mov dx, #0x0cfc
10875 in eax, dx
10876 test al, #0x01
10877 jnz init_io_base
10878 mov ecx, eax
10879 mov eax, #0xffffffff
10880 out dx, eax
10881 in eax, dx
10882 cmp eax, ecx
10883 je next_pci_base
10884 xor eax, #0xffffffff
10885 mov ecx, eax
10886 mov eax, [bp-4]
10887 out dx, eax
10888 add eax, ecx ;; calculate next free mem base
10889 add eax, #0x01000000
10890 and eax, #0xff000000
10891 mov [bp-4], eax
10892 jmp next_pci_base
10893init_io_base:
10894 mov cx, ax
10895 mov ax, #0xffff
10896 out dx, ax
10897 in ax, dx
10898 cmp ax, cx
10899 je next_pci_base
10900 xor ax, #0xfffe
10901 mov cx, ax
10902 mov ax, [bp-6]
10903 out dx, ax
10904 add ax, cx ;; calculate next free i/o base
10905 add ax, #0x0100
10906 and ax, #0xff00
10907 mov [bp-6], ax
10908next_pci_base:
10909 mov al, [bp-8]
10910 add al, #0x04
10911 cmp al, #0x28
10912 je enable_iomem_space
10913 mov byte ptr[bp-8], al
10914 jmp pci_init_io_loop2
10915#endif /* !VBOX */
10916enable_iomem_space:
10917 mov dl, #0x04 ;; enable i/o and memory space access if available
10918 call pcibios_init_sel_reg
10919 mov dx, #0x0cfc
10920 in al, dx
10921 or al, #0x07
10922 out dx, al
10923#ifdef VBOX
10924 mov dl, #0x00 ;; check if PCI device is AMD PCNet
10925 call pcibios_init_sel_reg
10926 mov dx, #0x0cfc
10927 in eax, dx
10928 cmp eax, #0x20001022
10929 jne next_pci_dev
10930 mov dl, #0x10 ;; get I/O address
10931 call pcibios_init_sel_reg
10932 mov dx, #0x0cfc
10933 in ax, dx
10934 and ax, #0xfffc
10935 mov cx, ax
10936 mov dx, cx
10937 add dx, #0x14 ;; reset register if PCNet is in word I/O mode
10938 in ax, dx ;; reset is performed by reading the reset register
10939 mov dx, cx
10940 add dx, #0x18 ;; reset register if PCNet is in word I/O mode
10941 in eax, dx ;; reset is performed by reading the reset register
10942#endif /* VBOX */
10943next_pci_dev:
10944 mov byte ptr[bp-8], #0x10
10945 inc bx
10946 cmp bx, #0x0100
10947 jne pci_init_io_loop1
10948 mov sp, bp
10949 pop bp
10950 ret
10951
10952pcibios_init_set_elcr:
10953 push ax
10954 push cx
10955 mov dx, #0x04d0
10956 test al, #0x08
10957 jz is_master_pic
10958 inc dx
10959 and al, #0x07
10960is_master_pic:
10961 mov cl, al
10962 mov bl, #0x01
10963 shl bl, cl
10964 in al, dx
10965 or al, bl
10966 out dx, al
10967 pop cx
10968 pop ax
10969 ret
10970
10971pcibios_init_irqs:
10972 push ds
10973 push bp
10974 mov ax, #0xf000
10975 mov ds, ax
10976 mov dx, #0x04d0 ;; reset ELCR1 + ELCR2
10977 mov al, #0x00
10978 out dx, al
10979 inc dx
10980 out dx, al
10981 mov si, #pci_routing_table_structure
10982 mov bh, [si+8]
10983 mov bl, [si+9]
10984 mov dl, #0x00
10985 call pcibios_init_sel_reg
10986 mov dx, #0x0cfc
10987 in eax, dx
10988 cmp eax, [si+12] ;; check irq router
10989 jne pci_init_end
10990 mov dl, [si+34]
10991 call pcibios_init_sel_reg
10992 push bx ;; save irq router bus + devfunc
10993 mov dx, #0x0cfc
10994 mov ax, #0x8080
10995 out dx, ax ;; reset PIRQ route control
10996 add dx, #2
10997 out dx, ax
10998 mov ax, [si+6]
10999 sub ax, #0x20
11000 shr ax, #4
11001 mov cx, ax
11002 add si, #0x20 ;; set pointer to 1st entry
11003 mov bp, sp
11004 mov ax, #pci_irq_list
11005 push ax
11006 xor ax, ax
11007 push ax
11008pci_init_irq_loop1:
11009 mov bh, [si]
11010 mov bl, [si+1]
11011pci_init_irq_loop2:
11012 mov dl, #0x00
11013 call pcibios_init_sel_reg
11014 mov dx, #0x0cfc
11015 in ax, dx
11016 cmp ax, #0xffff
11017 jnz pci_test_int_pin
11018 test bl, #0x07
11019 jz next_pir_entry
11020 jmp next_pci_func
11021pci_test_int_pin:
11022 mov dl, #0x3c
11023 call pcibios_init_sel_reg
11024 mov dx, #0x0cfd
11025 in al, dx
11026 and al, #0x07
11027 jz next_pci_func
11028 dec al ;; determine pirq reg
11029 mov dl, #0x03
11030 mul al, dl
11031 add al, #0x02
11032 xor ah, ah
11033 mov bx, ax
11034 mov al, [si+bx]
11035 mov dl, al
11036 mov bx, [bp]
11037 call pcibios_init_sel_reg
11038 mov dx, #0x0cfc
11039 and al, #0x03
11040 add dl, al
11041 in al, dx
11042 cmp al, #0x80
11043 jb pirq_found
11044 mov bx, [bp-2] ;; pci irq list pointer
11045 mov al, [bx]
11046 out dx, al
11047 inc bx
11048 mov [bp-2], bx
11049 call pcibios_init_set_elcr
11050pirq_found:
11051 mov bh, [si]
11052 mov bl, [si+1]
11053 add bl, [bp-3] ;; pci function number
11054 mov dl, #0x3c
11055 call pcibios_init_sel_reg
11056 mov dx, #0x0cfc
11057 out dx, al
11058next_pci_func:
11059 inc byte ptr[bp-3]
11060 inc bl
11061 test bl, #0x07
11062 jnz pci_init_irq_loop2
11063next_pir_entry:
11064 add si, #0x10
11065 mov byte ptr[bp-3], #0x00
11066 loop pci_init_irq_loop1
11067 mov sp, bp
11068 pop bx
11069pci_init_end:
11070 pop bp
11071 pop ds
11072 ret
11073#endif // !BX_ROMBIOS32
11074#endif // BX_PCIBIOS
11075
11076#if BX_ROMBIOS32
11077rombios32_init:
11078 ;; save a20 and enable it
11079 in al, 0x92
11080 push ax
11081 or al, #0x02
11082 out 0x92, al
11083
11084 ;; save SS:SP to the BDA
11085 xor ax, ax
11086 mov ds, ax
11087 mov 0x0469, ss
11088 mov 0x0467, sp
11089
11090 SEG CS
11091 lidt [pmode_IDT_info]
11092 SEG CS
11093 lgdt [rombios32_gdt_48]
11094 ;; set PE bit in CR0
11095 mov eax, cr0
11096 or al, #0x01
11097 mov cr0, eax
11098 ;; start protected mode code: ljmpl 0x10:rombios32_init1
11099 db 0x66, 0xea
11100 dw rombios32_05
11101 dw 0x000f ;; high 16 bit address
11102 dw 0x0010
11103
11104use32 386
11105rombios32_05:
11106 ;; init data segments
11107 mov eax, #0x18
11108 mov ds, ax
11109 mov es, ax
11110 mov ss, ax
11111 xor eax, eax
11112 mov fs, ax
11113 mov gs, ax
11114 cld
11115
11116 ;; copy rombios32 code to ram (ram offset = 1MB)
11117 mov esi, #0xfffe0000
11118 mov edi, #0x00040000
11119 mov ecx, #0x10000 / 4
11120 rep
11121 movsd
11122
11123 ;; init the stack pointer
11124 mov esp, #0x00080000
11125
11126 ;; call rombios32 code
11127 mov eax, #0x00040000
11128 call eax
11129
11130 ;; return to 16 bit protected mode first
11131 db 0xea
11132 dd rombios32_10
11133 dw 0x20
11134
11135use16 386
11136rombios32_10:
11137 ;; restore data segment limits to 0xffff
11138 mov ax, #0x28
11139 mov ds, ax
11140 mov es, ax
11141 mov ss, ax
11142 mov fs, ax
11143 mov gs, ax
11144
11145 ;; reset PE bit in CR0
11146 mov eax, cr0
11147 and al, #0xFE
11148 mov cr0, eax
11149
11150 ;; far jump to flush CPU queue after transition to real mode
11151 JMP_AP(0xf000, rombios32_real_mode)
11152
11153rombios32_real_mode:
11154 ;; restore IDT to normal real-mode defaults
11155 SEG CS
11156 lidt [rmode_IDT_info]
11157
11158 xor ax, ax
11159 mov ds, ax
11160 mov es, ax
11161 mov fs, ax
11162 mov gs, ax
11163
11164 ;; restore SS:SP from the BDA
11165 mov ss, 0x0469
11166 xor esp, esp
11167 mov sp, 0x0467
11168 ;; restore a20
11169 pop ax
11170 out 0x92, al
11171 ret
11172
11173rombios32_gdt_48:
11174 dw 0x30
11175 dw rombios32_gdt
11176 dw 0x000f
11177
11178rombios32_gdt:
11179 dw 0, 0, 0, 0
11180 dw 0, 0, 0, 0
11181 dw 0xffff, 0, 0x9b00, 0x00cf ; 32 bit flat code segment (0x10)
11182 dw 0xffff, 0, 0x9300, 0x00cf ; 32 bit flat data segment (0x18)
11183 dw 0xffff, 0, 0x9b0f, 0x0000 ; 16 bit code segment base=0xf0000 limit=0xffff
11184 dw 0xffff, 0, 0x9300, 0x0000 ; 16 bit data segment base=0x0 limit=0xffff
11185#endif // BX_ROMBIOS32
11186
11187
11188; parallel port detection: base address in DX, index in BX, timeout in CL
11189detect_parport:
11190 push dx
11191 add dx, #2
11192 in al, dx
11193 and al, #0xdf ; clear input mode
11194 out dx, al
11195 pop dx
11196 mov al, #0xaa
11197 out dx, al
11198 in al, dx
11199 cmp al, #0xaa
11200 jne no_parport
11201 push bx
11202 shl bx, #1
11203 mov [bx+0x408], dx ; Parallel I/O address
11204 pop bx
11205 mov [bx+0x478], cl ; Parallel printer timeout
11206 inc bx
11207no_parport:
11208 ret
11209
11210; serial port detection: base address in DX, index in BX, timeout in CL
11211detect_serial:
11212 push dx
11213 inc dx
11214 mov al, #0x02
11215 out dx, al
11216 in al, dx
11217 cmp al, #0x02
11218 jne no_serial
11219 inc dx
11220 in al, dx
11221 cmp al, #0x02
11222 jne no_serial
11223 dec dx
11224 xor al, al
11225 out dx, al
11226 pop dx
11227 push bx
11228 shl bx, #1
11229 mov [bx+0x400], dx ; Serial I/O address
11230 pop bx
11231 mov [bx+0x47c], cl ; Serial timeout
11232 inc bx
11233 ret
11234no_serial:
11235 pop dx
11236 ret
11237
11238rom_checksum:
11239 push ax
11240#ifdef NO_ROM_CHECKSUM
11241 xor ax, ax
11242#endif
11243 push bx
11244 push cx
11245 xor ax, ax
11246 xor bx, bx
11247 xor cx, cx
11248 mov ch, [2]
11249 shl cx, #1
11250checksum_loop:
11251 add al, [bx]
11252 inc bx
11253 loop checksum_loop
11254 and al, #0xff
11255 pop cx
11256 pop bx
11257#endif
11258 pop ax
11259 ret
11260
11261rom_scan:
11262 ;; Scan for existence of valid expansion ROMS.
11263 ;; Video ROM: from 0xC0000..0xC7FFF in 2k increments
11264 ;; General ROM: from 0xC8000..0xDFFFF in 2k increments
11265 ;; System ROM: only 0xE0000
11266 ;;
11267 ;; Header:
11268 ;; Offset Value
11269 ;; 0 0x55
11270 ;; 1 0xAA
11271 ;; 2 ROM length in 512-byte blocks
11272 ;; 3 ROM initialization entry point (FAR CALL)
11273
11274 mov cx, #0xc000
11275rom_scan_loop:
11276 mov ds, cx
11277 mov ax, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
11278 cmp [0], #0xAA55 ;; look for signature
11279 jne rom_scan_increment
11280 call rom_checksum
11281 jnz rom_scan_increment
11282 mov al, [2] ;; change increment to ROM length in 512-byte blocks
11283
11284 ;; We want our increment in 512-byte quantities, rounded to
11285 ;; the nearest 2k quantity, since we only scan at 2k intervals.
11286 test al, #0x03
11287 jz block_count_rounded
11288 and al, #0xfc ;; needs rounding up
11289 add al, #0x04
11290block_count_rounded:
11291
11292 xor bx, bx ;; Restore DS back to 0000:
11293 mov ds, bx
11294 push ax ;; Save AX
11295 ;; Push addr of ROM entry point
11296 push cx ;; Push seg
11297 push #0x0003 ;; Push offset
11298 mov bp, sp ;; Call ROM init routine using seg:off on stack
11299 db 0xff ;; call_far ss:[bp+0]
11300 db 0x5e
11301 db 0
11302 cli ;; In case expansion ROM BIOS turns IF on
11303 add sp, #2 ;; Pop offset value
11304 pop cx ;; Pop seg value (restore CX)
11305 pop ax ;; Restore AX
11306rom_scan_increment:
11307 shl ax, #5 ;; convert 512-bytes blocks to 16-byte increments
11308 ;; because the segment selector is shifted left 4 bits.
11309 add cx, ax
11310 cmp cx, #0xe800 ;; Must encompass VBOX_LANBOOT_SEG!
11311 jbe rom_scan_loop
11312
11313 xor ax, ax ;; Restore DS back to 0000:
11314 mov ds, ax
11315 ret
11316
11317#define LVT0 0xFEE00350
11318#define LVT1 0xFEE00360
11319
11320;; Program LVT0/LVT1 entries in the local APIC. Some Linux kernels (e.g., RHEL4
11321;; SMP 32-bit) expect the entries to be unmasked in virtual wire mode.
11322
11323setup_lapic:
11324 pushf
11325 cli ;; Interrupts would kill us!
11326 call pmode_enter
11327 mov esi, #LVT0 ;; Program LVT0 to ExtINT and unmask
11328 mov eax, [esi]
11329 and eax, #0xfffe00ff
11330 or ah, #0x07
11331 mov [esi], eax
11332 mov esi, #LVT1 ;; Program LVT1 to NMI and unmask
11333 mov eax, [esi]
11334 and eax, #0xfffe00ff
11335 or ah, #0x04
11336 mov [esi], eax
11337 call pmode_exit
11338 popf
11339 ret
11340
11341;; Enter and exit minimal protected-mode environment. May only be called from
11342;; the F000 segment (16-bit). Does not switch stacks. Must be run with disabled
11343;; interrupts(!). On return from pmode_enter, DS contains a selector which can
11344;; address the entire 4GB address space.
11345
11346pmode_enter:
11347 push cs
11348 pop ds
11349 lgdt [pmbios_gdt_desc]
11350 mov eax, cr0
11351 or al, #0x1
11352 mov cr0, eax
11353 JMP_AP(0x20, really_enter_pm)
11354really_enter_pm:
11355 mov ax, #0x18
11356 mov ds, ax
11357 ret
11358
11359pmode_exit:
11360 mov eax, cr0
11361 and al, #0xfe
11362 mov cr0, eax
11363 JMP_AP(0xF000, really_exit_pm)
11364really_exit_pm:
11365 ret
11366
11367pmbios_gdt_desc:
11368 dw 0x30
11369 dw pmbios_gdt
11370 dw 0x000f
11371
11372pmbios_gdt:
11373 dw 0, 0, 0, 0
11374 dw 0, 0, 0, 0
11375 dw 0xffff, 0, 0x9b00, 0x00cf ; 32 bit flat code segment (0x10)
11376 dw 0xffff, 0, 0x9300, 0x00cf ; 32 bit flat data segment (0x18)
11377 dw 0xffff, 0, 0x9b0f, 0x0000 ; 16 bit code segment base=0xf0000 limit=0xffff
11378 dw 0xffff, 0, 0x9300, 0x0000 ; 16 bit data segment base=0x0 limit=0xffff
11379
11380;; for 'C' strings and other data, insert them here with
11381;; a the following hack:
11382;; DATA_SEG_DEFS_HERE
11383
11384
11385;; the following area can be used to write dynamically generated tables
11386 .align 16
11387bios_table_area_start:
11388 dd 0xaafb4442
11389 dd bios_table_area_end - bios_table_area_start - 8;
11390
11391;--------
11392;- POST -
11393;--------
11394.org 0xe05b ; POST Entry Point
11395bios_table_area_end:
11396post:
11397
11398 xor ax, ax
11399
11400 ;; first reset the DMA controllers
11401 out 0x0d,al
11402 out 0xda,al
11403
11404 ;; then initialize the DMA controllers
11405 mov al, #0xC0
11406 out 0xD6, al ; cascade mode of channel 4 enabled
11407 mov al, #0x00
11408 out 0xD4, al ; unmask channel 4
11409
11410 ;; Examine CMOS shutdown status.
11411 mov AL, #0x0f
11412 out 0x70, AL
11413 in AL, 0x71
11414
11415 ;; backup status
11416 mov bl, al
11417
11418 ;; Reset CMOS shutdown status.
11419 mov AL, #0x0f
11420 out 0x70, AL ; select CMOS register Fh
11421 mov AL, #0x00
11422 out 0x71, AL ; set shutdown action to normal
11423
11424 ;; Examine CMOS shutdown status.
11425 mov al, bl
11426
11427 ;; 0x00, 0x09, 0x0D+ = normal startup
11428 cmp AL, #0x00
11429 jz normal_post
11430 cmp AL, #0x0d
11431 jae normal_post
11432 cmp AL, #0x09
11433 je normal_post
11434
11435 ;; 0x05 = eoi + jmp via [0x40:0x67] jump
11436 cmp al, #0x05
11437 je eoi_jmp_post
11438
11439#ifdef VBOX
11440 ;; just ignore all other CMOS shutdown status values (OpenSolaris sets it to 0xA for some reason in certain cases)
11441 ;; (shutdown_status_panic just crashes the VM as it calls int 0x10 before the IDT table has been initialized)
11442 jmp normal_post
11443#else
11444 ;; Examine CMOS shutdown status.
11445 ;; 0x01,0x02,0x03,0x04,0x06,0x07,0x08, 0x0a, 0x0b, 0x0c = Unimplemented shutdown status.
11446 push bx
11447 call _shutdown_status_panic
11448#endif
11449
11450#if 0
11451 HALT(__LINE__)
11452 ;
11453 ;#if 0
11454 ; 0xb0, 0x20, /* mov al, #0x20 */
11455 ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */
11456 ;#endif
11457 ;
11458 pop es
11459 pop ds
11460 popa
11461 iret
11462#endif
11463
11464normal_post:
11465 ; case 0: normal startup
11466
11467 cli
11468 mov ax, #0xfffe
11469 mov sp, ax
11470 xor ax, ax
11471 mov ds, ax
11472 mov ss, ax
11473
11474#ifndef VBOX
11475 ;; zero out BIOS data area (40:00..40:ff)
11476 mov es, ax
11477 mov cx, #0x0080 ;; 128 words
11478 mov di, #0x0400
11479 cld
11480 rep
11481 stosw
11482#else /* VBOX */
11483 ;; zero out segment 0 (includes BIOS data area) except word at 40:72
11484 mov es, ax
11485 xor di, di
11486 cld
11487 mov cx, #0x0239 ;; 569 words
11488 rep
11489 stosw
11490 inc di
11491 inc di
11492 mov cx, #0x7dc6 ;; 32198 words
11493 rep
11494 stosw
11495 ;; zero out remaining base memory except the last 16 bytes of the EBDA
11496 ;; because we store the MP table there
11497 xor eax, eax
11498 xor bx, bx
11499memory_zero_loop:
11500 add bx, #0x1000
11501 cmp bx, #0x9000
11502 jae memory_cleared
11503 mov es, bx
11504 xor di, di
11505 mov cx, #0x4000
11506 rep
11507 stosd
11508 jmp memory_zero_loop
11509memory_cleared:
11510 mov es, bx
11511 xor di, di
11512 mov cx, #0x3f00
11513 rep
11514 stosd
11515 xor bx, bx
11516#endif
11517
11518 call _log_bios_start
11519
11520 ;; set all interrupts to default handler
11521 xor bx, bx ;; offset index
11522 mov cx, #0x0100 ;; counter (256 interrupts)
11523 mov ax, #dummy_iret_handler
11524 mov dx, #0xF000
11525
11526post_default_ints:
11527 mov [bx], ax
11528 add bx, #2
11529 mov [bx], dx
11530 add bx, #2
11531 loop post_default_ints
11532
11533 ;; set vector 0x79 to zero
11534 ;; this is used by 'guardian angel' protection system
11535 SET_INT_VECTOR(0x79, #0, #0)
11536
11537 ;; base memory in K 40:13 (word)
11538 mov ax, #BASE_MEM_IN_K
11539 mov 0x0413, ax
11540
11541
11542 ;; Manufacturing Test 40:12
11543 ;; zerod out above
11544
11545#ifndef VBOX
11546 ;; Warm Boot Flag 0040:0072
11547 ;; value of 1234h = skip memory checks
11548 ;; zerod out above
11549#endif /* !VBOX */
11550
11551
11552 ;; Printer Services vector
11553 SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
11554
11555 ;; Bootstrap failure vector
11556 SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
11557
11558 ;; Bootstrap Loader vector
11559 SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
11560
11561 ;; User Timer Tick vector
11562 SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
11563
11564 ;; Memory Size Check vector
11565 SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
11566
11567 ;; Equipment Configuration Check vector
11568 SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
11569
11570 ;; System Services
11571 SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
11572
11573 ;; EBDA setup
11574 call ebda_post
11575
11576 ;; PIT setup
11577 SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
11578 ;; int 1C already points at dummy_iret_handler (above)
11579 mov al, #0x34 ; timer0: binary count, 16bit count, mode 2
11580 out 0x43, al
11581 mov al, #0x00 ; maximum count of 0000H = 18.2Hz
11582 out 0x40, al
11583 out 0x40, al
11584
11585 ;; Keyboard
11586 SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
11587 SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
11588
11589 xor ax, ax
11590 mov ds, ax
11591 mov 0x0417, al /* keyboard shift flags, set 1 */
11592 mov 0x0418, al /* keyboard shift flags, set 2 */
11593 mov 0x0419, al /* keyboard alt-numpad work area */
11594 mov 0x0471, al /* keyboard ctrl-break flag */
11595 mov 0x0497, al /* keyboard status flags 4 */
11596 mov al, #0x10
11597 mov 0x0496, al /* keyboard status flags 3 */
11598
11599
11600 /* keyboard head of buffer pointer */
11601 mov bx, #0x001E
11602 mov 0x041A, bx
11603
11604 /* keyboard end of buffer pointer */
11605 mov 0x041C, bx
11606
11607 /* keyboard pointer to start of buffer */
11608 mov bx, #0x001E
11609 mov 0x0480, bx
11610
11611 /* keyboard pointer to end of buffer */
11612 mov bx, #0x003E
11613 mov 0x0482, bx
11614
11615 /* init the keyboard */
11616 call _keyboard_init
11617
11618 ;; mov CMOS Equipment Byte to BDA Equipment Word
11619 mov ax, 0x0410
11620 mov al, #0x14
11621 out 0x70, al
11622 in al, 0x71
11623 mov 0x0410, ax
11624
11625
11626 ;; Parallel setup
11627 SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
11628 xor ax, ax
11629 mov ds, ax
11630 xor bx, bx
11631 mov cl, #0x14 ; timeout value
11632 mov dx, #0x378 ; Parallel I/O address, port 1
11633 call detect_parport
11634 mov dx, #0x278 ; Parallel I/O address, port 2
11635 call detect_parport
11636 shl bx, #0x0e
11637 mov ax, 0x410 ; Equipment word bits 14..15 determine # parallel ports
11638 and ax, #0x3fff
11639 or ax, bx ; set number of parallel ports
11640 mov 0x410, ax
11641
11642 ;; Serial setup
11643 SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
11644 SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
11645 xor bx, bx
11646 mov cl, #0x0a ; timeout value
11647 mov dx, #0x03f8 ; Serial I/O address, port 1
11648 call detect_serial
11649 mov dx, #0x02f8 ; Serial I/O address, port 2
11650 call detect_serial
11651 mov dx, #0x03e8 ; Serial I/O address, port 3
11652 call detect_serial
11653 mov dx, #0x02e8 ; Serial I/O address, port 4
11654 call detect_serial
11655 shl bx, #0x09
11656 mov ax, 0x410 ; Equipment word bits 9..11 determine # serial ports
11657 and ax, #0xf1ff
11658 or ax, bx ; set number of serial port
11659 mov 0x410, ax
11660
11661 ;; CMOS RTC
11662 SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
11663 SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
11664 SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
11665 ;; BIOS DATA AREA 0x4CE ???
11666 call timer_tick_post
11667
11668 ;; PS/2 mouse setup
11669 SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
11670
11671 ;; IRQ13 (FPU exception) setup
11672 SET_INT_VECTOR(0x75, #0xF000, #int75_handler)
11673
11674 ;; Video setup
11675 SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
11676
11677#ifdef VBOX
11678 ;; moved the PIC initialization to another place as we need
11679 ;; some space for additions init calls. Otherwise this code
11680 ;; overlaps with the NMI handler at 0xe2c3 (fixed BIOS entry)
11681 call init_pic
11682#else /* !VBOX */
11683 ;; PIC
11684 mov al, #0x11 ; send initialisation commands
11685 out 0x20, al
11686 out 0xa0, al
11687 mov al, #0x08
11688 out 0x21, al
11689 mov al, #0x70
11690 out 0xa1, al
11691 mov al, #0x04
11692 out 0x21, al
11693 mov al, #0x02
11694 out 0xa1, al
11695 mov al, #0x01
11696 out 0x21, al
11697 out 0xa1, al
11698 mov al, #0xb8
11699 out 0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6
11700#if BX_USE_PS2_MOUSE
11701 mov al, #0x8f
11702#else
11703 mov al, #0x9f
11704#endif
11705 out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14
11706#endif /* !VBOX */
11707
11708#if BX_ROMBIOS32
11709 call rombios32_init
11710#else
11711 call pcibios_init_iomem_bases
11712 call pcibios_init_irqs
11713#endif
11714 call setup_lapic
11715 call rom_scan
11716
11717#if BX_USE_ATADRV
11718 ;;
11719 ;; ATA/ATAPI driver setup
11720 ;;
11721 call _ata_init
11722 call _ata_detect
11723 ;;
11724#endif
11725
11726#ifdef VBOX_WITH_SCSI
11727 ;;
11728 ;; SCSI driver setup
11729 ;;
11730 call _scsi_init
11731 ;;
11732#endif
11733
11734 call _print_bios_banner
11735
11736 ;;
11737 ;; Floppy setup
11738 ;;
11739 call floppy_drive_post
11740
11741 ;;
11742 ;; Hard Drive setup
11743 ;;
11744 call hard_drive_post
11745
11746#ifdef VBOX_WITH_BIOS_AHCI
11747 ;;
11748 ;; AHCI driver setup
11749 ;;
11750 call _ahci_init
11751 ;;
11752#endif
11753
11754#if BX_ELTORITO_BOOT
11755 ;;
11756 ;; eltorito floppy/harddisk emulation from cd
11757 ;;
11758 call _cdemu_init
11759 ;;
11760#endif // BX_ELTORITO_BOOT
11761
11762 sti ;; enable interrupts
11763 int #0x19
11764
11765.org 0xe2c3 ; NMI Handler Entry Point
11766nmi:
11767 ;; FIXME the NMI handler should not panic
11768 ;; but iret when called from int75 (fpu exception)
11769 call _nmi_handler_msg
11770 iret
11771
11772int75_handler:
11773 out 0xf0, al // clear irq13
11774 call eoi_both_pics // clear interrupt
11775 int 2 // legacy nmi call
11776 iret
11777
11778;-------------------------------------------
11779;- INT 13h Fixed Disk Services Entry Point -
11780;-------------------------------------------
11781.org 0xe3fe ; INT 13h Fixed Disk Services Entry Point
11782int13_handler:
11783 //JMPL(int13_relocated)
11784 jmp int13_relocated
11785
11786.org 0xe401 ; Fixed Disk Parameter Table
11787
11788;----------
11789;- INT19h -
11790;----------
11791.org 0xe6f2 ; INT 19h Boot Load Service Entry Point
11792int19_handler:
11793
11794 jmp int19_relocated
11795;-------------------------------------------
11796;- System BIOS Configuration Data Table
11797;-------------------------------------------
11798.org BIOS_CONFIG_TABLE
11799db 0x08 ; Table size (bytes) -Lo
11800db 0x00 ; Table size (bytes) -Hi
11801db SYS_MODEL_ID
11802db SYS_SUBMODEL_ID
11803db BIOS_REVISION
11804; Feature byte 1
11805; b7: 1=DMA channel 3 used by hard disk
11806; b6: 1=2 interrupt controllers present
11807; b5: 1=RTC present
11808; b4: 1=BIOS calls int 15h/4Fh every key
11809; b3: 1=wait for extern event supported (Int 15h/41h)
11810; b2: 1=extended BIOS data area used
11811; b1: 0=AT or ESDI bus, 1=MicroChannel
11812; b0: 1=Dual bus (MicroChannel + ISA)
11813db (0 << 7) | \
11814 (1 << 6) | \
11815 (1 << 5) | \
11816 (BX_CALL_INT15_4F << 4) | \
11817 (0 << 3) | \
11818 (BX_USE_EBDA << 2) | \
11819 (0 << 1) | \
11820 (0 << 0)
11821; Feature byte 2
11822; b7: 1=32-bit DMA supported
11823; b6: 1=int16h, function 9 supported
11824; b5: 1=int15h/C6h (get POS data) supported
11825; b4: 1=int15h/C7h (get mem map info) supported
11826; b3: 1=int15h/C8h (en/dis CPU) supported
11827; b2: 1=non-8042 kb controller
11828; b1: 1=data streaming supported
11829; b0: reserved
11830db (0 << 7) | \
11831 (1 << 6) | \
11832 (0 << 5) | \
11833 (0 << 4) | \
11834 (0 << 3) | \
11835 (0 << 2) | \
11836 (0 << 1) | \
11837 (0 << 0)
11838; Feature byte 3
11839; b7: not used
11840; b6: reserved
11841; b5: reserved
11842; b4: POST supports ROM-to-RAM enable/disable
11843; b3: SCSI on system board
11844; b2: info panel installed
11845; b1: Initial Machine Load (IML) system - BIOS on disk
11846; b0: SCSI supported in IML
11847db 0x00
11848; Feature byte 4
11849; b7: IBM private
11850; b6: EEPROM present
11851; b5-3: ABIOS presence (011 = not supported)
11852; b2: private
11853; b1: memory split above 16Mb supported
11854; b0: POSTEXT directly supported by POST
11855db 0x00
11856; Feature byte 5 (IBM)
11857; b1: enhanced mouse
11858; b0: flash EPROM
11859db 0x00
11860
11861
11862
11863.org 0xe729 ; Baud Rate Generator Table
11864
11865;----------
11866;- INT14h -
11867;----------
11868.org 0xe739 ; INT 14h Serial Communications Service Entry Point
11869int14_handler:
11870 push ds
11871 pusha
11872 xor ax, ax
11873 mov ds, ax
11874 call _int14_function
11875 popa
11876 pop ds
11877 iret
11878
11879
11880;----------------------------------------
11881;- INT 16h Keyboard Service Entry Point -
11882;----------------------------------------
11883.org 0xe82e
11884int16_handler:
11885
11886 sti
11887 push ds
11888 pushf
11889 pusha
11890
11891 cmp ah, #0x00
11892 je int16_F00
11893 cmp ah, #0x10
11894 je int16_F00
11895
11896 mov bx, #0xf000
11897 mov ds, bx
11898 call _int16_function
11899 popa
11900 popf
11901 pop ds
11902 jz int16_zero_set
11903
11904int16_zero_clear:
11905 push bp
11906 mov bp, sp
11907 //SEG SS
11908 and BYTE [bp + 0x06], #0xbf
11909 pop bp
11910 iret
11911
11912int16_zero_set:
11913 push bp
11914 mov bp, sp
11915 //SEG SS
11916 or BYTE [bp + 0x06], #0x40
11917 pop bp
11918 iret
11919
11920int16_F00:
11921 mov bx, #0x0040
11922 mov ds, bx
11923
11924int16_wait_for_key:
11925 cli
11926 mov bx, 0x001a
11927 cmp bx, 0x001c
11928 jne int16_key_found
11929 sti
11930 nop
11931#if 0
11932 /* no key yet, call int 15h, function AX=9002 */
11933 0x50, /* push AX */
11934 0xb8, 0x02, 0x90, /* mov AX, #0x9002 */
11935 0xcd, 0x15, /* int 15h */
11936 0x58, /* pop AX */
11937 0xeb, 0xea, /* jmp WAIT_FOR_KEY */
11938#endif
11939 jmp int16_wait_for_key
11940
11941int16_key_found:
11942 mov bx, #0xf000
11943 mov ds, bx
11944 call _int16_function
11945 popa
11946 popf
11947 pop ds
11948#if 0
11949 /* notify int16 complete w/ int 15h, function AX=9102 */
11950 0x50, /* push AX */
11951 0xb8, 0x02, 0x91, /* mov AX, #0x9102 */
11952 0xcd, 0x15, /* int 15h */
11953 0x58, /* pop AX */
11954#endif
11955 iret
11956
11957
11958
11959;-------------------------------------------------
11960;- INT09h : Keyboard Hardware Service Entry Point -
11961;-------------------------------------------------
11962.org 0xe987
11963int09_handler:
11964 cli
11965 push ax
11966
11967 mov al, #0xAD ;;disable keyboard
11968 out #0x64, al
11969
11970 mov al, #0x0B
11971 out #0x20, al
11972 in al, #0x20
11973 and al, #0x02
11974 jz int09_finish
11975
11976 in al, #0x60 ;;read key from keyboard controller
11977 sti
11978 push ds
11979 pusha
11980#ifdef BX_CALL_INT15_4F
11981 mov ah, #0x4f ;; allow for keyboard intercept
11982 stc
11983 int #0x15
11984 jnc int09_done
11985#endif
11986
11987 ;; check for extended key
11988 cmp al, #0xe0
11989 jne int09_check_pause
11990 xor ax, ax
11991 mov ds, ax
11992 mov al, BYTE [0x496] ;; mf2_state |= 0x02
11993 or al, #0x02
11994 mov BYTE [0x496], al
11995 jmp int09_done
11996
11997int09_check_pause: ;; check for pause key
11998 cmp al, #0xe1
11999 jne int09_process_key
12000 xor ax, ax
12001 mov ds, ax
12002 mov al, BYTE [0x496] ;; mf2_state |= 0x01
12003 or al, #0x01
12004 mov BYTE [0x496], al
12005 jmp int09_done
12006
12007int09_process_key:
12008 mov bx, #0xf000
12009 mov ds, bx
12010 call _int09_function
12011
12012int09_done:
12013 popa
12014 pop ds
12015 cli
12016 call eoi_master_pic
12017
12018int09_finish:
12019 mov al, #0xAE ;;enable keyboard
12020 out #0x64, al
12021 pop ax
12022 iret
12023
12024
12025;----------------------------------------
12026;- INT 13h Diskette Service Entry Point -
12027;----------------------------------------
12028.org 0xec59
12029int13_diskette:
12030 jmp int13_noeltorito
12031
12032;---------------------------------------------
12033;- INT 0Eh Diskette Hardware ISR Entry Point -
12034;---------------------------------------------
12035.org 0xef57 ; INT 0Eh Diskette Hardware ISR Entry Point
12036int0e_handler:
12037 push ax
12038 push dx
12039 mov dx, #0x03f4
12040 in al, dx
12041 and al, #0xc0
12042 cmp al, #0xc0
12043 je int0e_normal
12044 mov dx, #0x03f5
12045 mov al, #0x08 ; sense interrupt status
12046 out dx, al
12047int0e_loop1:
12048 mov dx, #0x03f4
12049 in al, dx
12050 and al, #0xc0
12051 cmp al, #0xc0
12052 jne int0e_loop1
12053int0e_loop2:
12054 mov dx, #0x03f5
12055 in al, dx
12056 mov dx, #0x03f4
12057 in al, dx
12058 and al, #0xc0
12059 cmp al, #0xc0
12060 je int0e_loop2
12061int0e_normal:
12062 push ds
12063 xor ax, ax ;; segment 0000
12064 mov ds, ax
12065 call eoi_master_pic
12066 mov al, 0x043e
12067 or al, #0x80 ;; diskette interrupt has occurred
12068 mov 0x043e, al
12069 pop ds
12070 pop dx
12071 pop ax
12072 iret
12073
12074
12075.org 0xefc7 ; Diskette Controller Parameter Table
12076diskette_param_table:
12077;; Since no provisions are made for multiple drive types, most
12078;; values in this table are ignored. I set parameters for 1.44M
12079;; floppy here
12080db 0xAF
12081db 0x02 ;; head load time 0000001, DMA used
12082db 0x25
12083db 0x02
12084db 18
12085db 0x1B
12086db 0xFF
12087db 0x6C
12088db 0xF6
12089db 0x0F
12090db 0x08
12091
12092
12093;----------------------------------------
12094;- INT17h : Printer Service Entry Point -
12095;----------------------------------------
12096.org 0xefd2
12097int17_handler:
12098 push ds
12099 pusha
12100 xor ax, ax
12101 mov ds, ax
12102 call _int17_function
12103 popa
12104 pop ds
12105 iret
12106
12107diskette_param_table2:
12108;; New diskette parameter table adding 3 parameters from IBM
12109;; Since no provisions are made for multiple drive types, most
12110;; values in this table are ignored. I set parameters for 1.44M
12111;; floppy here
12112db 0xAF
12113db 0x02 ;; head load time 0000001, DMA used
12114db 0x25
12115db 0x02
12116db 18
12117db 0x1B
12118db 0xFF
12119db 0x6C
12120db 0xF6
12121db 0x0F
12122db 0x08
12123db 79 ;; maximum track
12124db 0 ;; data transfer rate
12125db 4 ;; drive type in cmos
12126
12127.org 0xf045 ; INT 10 Functions 0-Fh Entry Point
12128 HALT(__LINE__)
12129 iret
12130
12131;----------
12132;- INT10h -
12133;----------
12134.org 0xf065 ; INT 10h Video Support Service Entry Point
12135int10_handler:
12136 ;; dont do anything, since the VGA BIOS handles int10h requests
12137 iret
12138
12139.org 0xf0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
12140
12141;----------
12142;- INT12h -
12143;----------
12144.org 0xf841 ; INT 12h Memory Size Service Entry Point
12145; ??? different for Pentium (machine check)?
12146int12_handler:
12147 push ds
12148 mov ax, #0x0040
12149 mov ds, ax
12150 mov ax, 0x0013
12151 pop ds
12152 iret
12153
12154;----------
12155;- INT11h -
12156;----------
12157.org 0xf84d ; INT 11h Equipment List Service Entry Point
12158int11_handler:
12159 push ds
12160 mov ax, #0x0040
12161 mov ds, ax
12162 mov ax, 0x0010
12163 pop ds
12164 iret
12165
12166;----------
12167;- INT15h -
12168;----------
12169.org 0xf859 ; INT 15h System Services Entry Point
12170int15_handler:
12171 pushf
12172#if BX_APM
12173 cmp ah, #0x53
12174 je apm_call
12175#endif
12176 push ds
12177 push es
12178 cmp ah, #0x86
12179 je int15_handler32
12180 cmp ah, #0xE8
12181 je int15_handler32
12182 pusha
12183#if BX_USE_PS2_MOUSE
12184 cmp ah, #0xC2
12185 je int15_handler_mouse
12186#endif
12187 call _int15_function
12188int15_handler_mouse_ret:
12189 popa
12190int15_handler32_ret:
12191 pop es
12192 pop ds
12193 popf
12194 jmp iret_modify_cf
12195#if BX_APM
12196apm_call:
12197 jmp _apmreal_entry
12198#endif
12199
12200#if BX_USE_PS2_MOUSE
12201int15_handler_mouse:
12202 call _int15_function_mouse
12203 jmp int15_handler_mouse_ret
12204#endif
12205
12206int15_handler32:
12207 pushad
12208 call _int15_function32
12209 popad
12210 jmp int15_handler32_ret
12211
12212;; Protected mode IDT descriptor
12213;;
12214;; I just make the limit 0, so the machine will shutdown
12215;; if an exception occurs during protected mode memory
12216;; transfers.
12217;;
12218;; Set base to f0000 to correspond to beginning of BIOS,
12219;; in case I actually define an IDT later
12220;; Set limit to 0
12221
12222pmode_IDT_info:
12223dw 0x0000 ;; limit 15:00
12224dw 0x0000 ;; base 15:00
12225dw 0x0f ;; base 23:16
12226
12227;; Real mode IDT descriptor
12228;;
12229;; Set to typical real-mode values.
12230;; base = 000000
12231;; limit = 03ff
12232
12233rmode_IDT_info:
12234dw 0x03ff ;; limit 15:00
12235dw 0x0000 ;; base 15:00
12236dw 0x00 ;; base 23:16
12237
12238;;
12239;; Handler for unexpected hardware interrupts
12240;;
12241dummy_isr:
12242 push ds
12243 pushad
12244 xor ax, ax
12245 mov ds, ax
12246 call _dummy_isr_function
12247 popad
12248 pop ds
12249 iret
12250
12251;----------
12252;- INT1Ah -
12253;----------
12254.org 0xfe6e ; INT 1Ah Time-of-day Service Entry Point
12255int1a_handler:
12256#if BX_PCIBIOS
12257 cmp ah, #0xb1
12258 jne int1a_normal
12259 call pcibios_real
12260 jc pcibios_error
12261 retf 2
12262pcibios_error:
12263 mov bl, ah
12264 mov ah, #0xb1
12265 push ds
12266 pusha
12267 mov ax, ss ; set readable descriptor to ds, for calling pcibios
12268 mov ds, ax ; on 16bit protected mode.
12269 jmp int1a_callfunction
12270int1a_normal:
12271#endif
12272 push ds
12273 pusha
12274 xor ax, ax
12275 mov ds, ax
12276int1a_callfunction:
12277 call _int1a_function
12278 popa
12279 pop ds
12280 iret
12281
12282;;
12283;; int70h: IRQ8 - CMOS RTC
12284;;
12285int70_handler:
12286 push ds
12287 pushad
12288 xor ax, ax
12289 mov ds, ax
12290 call _int70_function
12291 popad
12292 pop ds
12293 iret
12294
12295;---------
12296;- INT08 -
12297;---------
12298.org 0xfea5 ; INT 08h System Timer ISR Entry Point
12299int08_handler:
12300 sti
12301 push eax
12302 push ds
12303 xor ax, ax
12304 mov ds, ax
12305
12306 ;; time to turn off drive(s)?
12307 mov al,0x0440
12308 or al,al
12309 jz int08_floppy_off
12310 dec al
12311 mov 0x0440,al
12312 jnz int08_floppy_off
12313 ;; turn motor(s) off
12314 push dx
12315 mov dx,#0x03f2
12316 in al,dx
12317 and al,#0xcf
12318 out dx,al
12319 pop dx
12320int08_floppy_off:
12321
12322 mov eax, 0x046c ;; get ticks dword
12323 inc eax
12324
12325 ;; compare eax to one days worth of timer ticks at 18.2 hz
12326 cmp eax, #0x001800B0
12327 jb int08_store_ticks
12328 ;; there has been a midnight rollover at this point
12329 xor eax, eax ;; zero out counter
12330 inc BYTE 0x0470 ;; increment rollover flag
12331
12332int08_store_ticks:
12333 mov 0x046c, eax ;; store new ticks dword
12334 ;; chain to user timer tick INT #0x1c
12335 //pushf
12336 //;; call_ep [ds:loc]
12337 //CALL_EP( 0x1c << 2 )
12338 int #0x1c
12339 cli
12340 call eoi_master_pic
12341 pop ds
12342 pop eax
12343 iret
12344
12345.org 0xfef3 ; Initial Interrupt Vector Offsets Loaded by POST
12346
12347
12348.org 0xff00
12349.ascii BIOS_COPYRIGHT_STRING
12350
12351#ifdef VBOX
12352// The SMBIOS header
12353.org 0xff30
12354.align 16
12355 db 0x5f, 0x53, 0x4d, 0x5f ; "_SM_" signature
12356 db 0x00 ; checksum (set by biossums)
12357 db 0x1f ; EPS length, defined by standard
12358 db VBOX_SMBIOS_MAJOR_VER ; SMBIOS major version
12359 db VBOX_SMBIOS_MINOR_VER ; SMBIOS minor version
12360 dw VBOX_SMBIOS_MAXSS ; Maximum structure size
12361 db 0x00 ; Entry point revision
12362 db 0x00, 0x00, 0x00, 0x00, 0x00
12363
12364// The DMI header
12365 db 0x5f, 0x44, 0x4d, 0x49, 0x5f ; "_DMI_" signature
12366 db 0x00 ; checksum (set by biossums)
12367 dw VBOX_DMI_TABLE_SIZE ; DMI tables length
12368 dd VBOX_DMI_TABLE_BASE ; DMI tables base
12369 dw VBOX_DMI_TABLE_ENTR ; DMI tables entries
12370 db VBOX_DMI_TABLE_VER ; DMI version
12371 db 0x00 ; Just for alignment
12372#endif
12373
12374;------------------------------------------------
12375;- IRET Instruction for Dummy Interrupt Handler -
12376;------------------------------------------------
12377.org 0xff53 ; IRET Instruction for Dummy Interrupt Handler
12378dummy_iret_handler:
12379 iret
12380
12381.org 0xff54 ; INT 05h Print Screen Service Entry Point
12382 HALT(__LINE__)
12383 iret
12384
12385.org 0xfff0 ; Power-up Entry Point
12386 jmp 0xf000:post
12387
12388.org 0xfff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
12389.ascii BIOS_BUILD_DATE
12390
12391.org 0xfffe ; System Model ID
12392db SYS_MODEL_ID
12393db 0x00 ; filler
12394
12395.org 0xfa6e ;; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
12396ASM_END
12397/*
12398 * This font comes from the fntcol16.zip package (c) by Joseph Gil
12399 * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
12400 * This font is public domain
12401 */
12402static Bit8u vgafont8[128*8]=
12403{
12404 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
12405 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
12406 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
12407 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
12408 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
12409 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
12410 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
12411 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
12412 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
12413 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
12414 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
12415 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
12416 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
12417 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
12418 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
12419 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
12420 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
12421 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
12422 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
12423 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
12424 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
12425 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
12426 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
12427 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
12428 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
12429 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
12430 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
12431 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
12432 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
12433 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
12434 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
12435 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
12436 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
12437 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
12438 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
12439 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
12440 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
12441 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
12442 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
12443 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
12444 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
12445 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
12446 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
12447 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
12448 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
12449 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
12450 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
12451 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
12452 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
12453 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
12454 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
12455 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
12456 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
12457 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
12458 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
12459 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
12460 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
12461 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
12462 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
12463 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
12464 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
12465 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
12466 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
12467 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
12468 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
12469 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
12470 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
12471 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
12472 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
12473 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
12474 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
12475 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
12476 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
12477 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
12478 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
12479 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
12480 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
12481 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
12482 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
12483 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
12484 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
12485 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
12486 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
12487 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
12488 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
12489 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
12490 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
12491 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
12492 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
12493 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
12494 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
12495 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
12496 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
12497 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
12498 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
12499 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
12500 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
12501 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
12502 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
12503 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
12504 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
12505 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
12506 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
12507 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
12508 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
12509 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
12510 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
12511 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
12512 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
12513 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
12514 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
12515 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
12516 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
12517 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
12518 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
12519 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
12520 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
12521 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
12522 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
12523 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
12524 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
12525 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
12526 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
12527 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
12528 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
12529 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
12530 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
12531 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
12532};
12533
12534ASM_START
12535.org 0xcc00
12536// bcc-generated data will be placed here
12537ASM_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