VirtualBox

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

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

BIOS: Updates for the AHCI driver

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