VirtualBox

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

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

BIOS: Set text mode if not displaying logo.

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

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