VirtualBox

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

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

Corrected the initial media state for 1.2M and 360K drives.

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

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