VirtualBox

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

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

BIOS: Do not let fake shift keys modify shift flags.

  • Property svn:eol-style set to native
File size: 339.1 KB
Line 
1/////////////////////////////////////////////////////////////////////////
2// $Id: rombios.c,v 1.176 2006/12/30 17:13:17 vruppert Exp $
3/////////////////////////////////////////////////////////////////////////
4//
5// Copyright (C) 2002 MandrakeSoft S.A.
6//
7// MandrakeSoft S.A.
8// 43, rue d'Aboukir
9// 75002 Paris - France
10// http://www.linux-mandrake.com/
11// http://www.mandrakesoft.com/
12//
13// This library is free software; you can redistribute it and/or
14// modify it under the terms of the GNU Lesser General Public
15// License as published by the Free Software Foundation; either
16// version 2 of the License, or (at your option) any later version.
17//
18// This library is distributed in the hope that it will be useful,
19// but WITHOUT ANY WARRANTY; without even the implied warranty of
20// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21// Lesser General Public License for more details.
22//
23// You should have received a copy of the GNU Lesser General Public
24// License along with this library; if not, write to the Free Software
25// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
26
27
28/*
29 * Oracle LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
30 * other than GPL or LGPL is available it will apply instead, Oracle elects to use only
31 * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
32 * a choice of LGPL license versions is made available with the language indicating
33 * that LGPLv2 or any later version may be used, or where a choice of which version
34 * of the LGPL is applied is otherwise unspecified.
35 */
36
37// ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
38
39
40// ROM BIOS compatibility entry points:
41// ===================================
42// $e05b ; POST Entry Point
43// $e2c3 ; NMI Handler Entry Point
44// $e3fe ; INT 13h Fixed Disk Services Entry Point
45// $e401 ; Fixed Disk Parameter Table
46// $e6f2 ; INT 19h Boot Load Service Entry Point
47// $e6f5 ; Configuration Data Table
48// $e729 ; Baud Rate Generator Table
49// $e739 ; INT 14h Serial Communications Service Entry Point
50// $e82e ; INT 16h Keyboard Service Entry Point
51// $e987 ; INT 09h Keyboard Service Entry Point
52// $ec59 ; INT 13h Diskette Service Entry Point
53// $ef57 ; INT 0Eh Diskette Hardware ISR Entry Point
54// $efc7 ; Diskette Controller Parameter Table
55// $efd2 ; INT 17h Printer Service Entry Point
56// $f045 ; INT 10 Functions 0-Fh Entry Point
57// $f065 ; INT 10h Video Support Service Entry Point
58// $f0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
59// $f841 ; INT 12h Memory Size Service Entry Point
60// $f84d ; INT 11h Equipment List Service Entry Point
61// $f859 ; INT 15h System Services Entry Point
62// $fa6e ; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
63// $fe6e ; INT 1Ah Time-of-day Service Entry Point
64// $fea5 ; INT 08h System Timer ISR Entry Point
65// $fef3 ; Initial Interrupt Vector Offsets Loaded by POST
66// $ff53 ; IRET Instruction for Dummy Interrupt Handler
67// $ff54 ; INT 05h Print Screen Service Entry Point
68// $fff0 ; Power-up Entry Point
69// $fff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
70// $fffe ; System Model ID
71
72// NOTES for ATA/ATAPI driver ([email protected])
73// Features
74// - supports up to 4 ATA interfaces
75// - device/geometry detection
76// - 16bits/32bits device access
77// - pchs/lba access
78// - datain/dataout/packet command support
79//
80// NOTES for El-Torito Boot ([email protected])
81// - CD-ROM booting is only available if ATA/ATAPI Driver is available
82// - Current code is only able to boot mono-session cds
83// - Current code can not boot and emulate a hard-disk
84// the bios will panic otherwise
85// - Current code also use memory in EBDA segment.
86// - I used cmos byte 0x3D to store extended information on boot-device
87// - Code has to be modified modified to handle multiple cdrom drives
88// - Here are the cdrom boot failure codes:
89// 1 : no atapi device found
90// 2 : no atapi cdrom found
91// 3 : can not read cd - BRVD
92// 4 : cd is not eltorito (BRVD)
93// 5 : cd is not eltorito (ISO TAG)
94// 6 : cd is not eltorito (ELTORITO TAG)
95// 7 : can not read cd - boot catalog
96// 8 : boot catalog : bad header
97// 9 : boot catalog : bad platform
98// 10 : boot catalog : bad signature
99// 11 : boot catalog : bootable flag not set
100// 12 : can not read cd - boot image
101//
102// ATA driver
103// - EBDA segment.
104// I used memory starting at 0x121 in the segment
105#ifndef VBOX
106// - the translation policy is defined in cmos regs 0x39 & 0x3a
107#endif /* !VBOX */
108//
109// TODO :
110//
111// int74
112// - needs to be reworked. Uses direct [bp] offsets. (?)
113//
114// int13:
115// - f04 (verify sectors) isn't complete (?)
116// - f02/03/04 should set current cyl,etc in BDA (?)
117// - rewrite int13_relocated & clean up int13 entry code
118//
119// NOTES:
120// - NMI access (bit7 of addr written to 70h)
121//
122// ATA driver
123// - should handle the "don't detect" bit (cmos regs 0x3b & 0x3c)
124// - could send the multiple-sector read/write commands
125//
126// El-Torito
127// - Emulate a Hard-disk (currently only diskette can be emulated) see "FIXME ElTorito Harddisk"
128// - Implement remaining int13_cdemu functions (as defined by El-Torito specs)
129// - cdrom drive is hardcoded to ide 0 device 1 in several places. see "FIXME ElTorito Hardcoded"
130// - int13 Fix DL when emulating a cd. In that case DL is decremented before calling real int13.
131// This is ok. But DL should be reincremented afterwards.
132// - Fix all "FIXME ElTorito Various"
133// - should be able to boot any cdrom instead of the first one
134//
135// BCC Bug: find a generic way to handle the bug of #asm after an "if" (fixed in 0.16.7)
136
137#ifdef VBOX
138#include "DevPcBios.h"
139#include <VBox/version.h>
140#endif
141
142#define BX_ROMBIOS32 0
143#define DEBUG_ROMBIOS 0
144
145#define DEBUG_ATA 0
146#define DEBUG_INT13_HD 0
147#define DEBUG_INT13_CD 0
148#define DEBUG_INT13_ET 0
149#define DEBUG_INT13_FL 0
150#define DEBUG_INT15 0
151#define DEBUG_INT16 0
152#define DEBUG_INT1A 0
153#define DEBUG_INT74 0
154#define DEBUG_APM 0
155
156#define BX_CPU 3
157#define BX_USE_PS2_MOUSE 1
158#define BX_CALL_INT15_4F 1
159#define BX_USE_EBDA 1
160#define BX_SUPPORT_FLOPPY 1
161#define BX_FLOPPY_ON_CNT 37 /* 2 seconds */
162#define BX_PCIBIOS 1
163#define BX_APM 1
164
165#define BX_USE_ATADRV 1
166#define BX_ELTORITO_BOOT 1
167
168#define BX_MAX_ATA_INTERFACES 4
169#define BX_MAX_ATA_DEVICES (BX_MAX_ATA_INTERFACES*2)
170
171#define BX_VIRTUAL_PORTS 1 /* normal output to Bochs ports */
172#define BX_DEBUG_SERIAL 0 /* output to COM1 */
173
174 /* model byte 0xFC = AT */
175#define SYS_MODEL_ID 0xFC
176#define SYS_SUBMODEL_ID 0x00
177#define BIOS_REVISION 1
178#define BIOS_CONFIG_TABLE 0xe6f5
179
180#ifndef BIOS_BUILD_DATE
181# define BIOS_BUILD_DATE "06/23/99"
182#endif
183
184 // 1K of base memory used for Extended Bios Data Area (EBDA)
185 // EBDA is used for PS/2 mouse support, and IDE BIOS, etc.
186#define EBDA_SEG 0x9FC0
187#define EBDA_SIZE 1 // In KiB
188#define BASE_MEM_IN_K (640 - EBDA_SIZE)
189
190#define ACPI_DATA_SIZE 0x00010000L
191
192 // Define the application NAME
193#if defined(BX_QEMU)
194# define BX_APPNAME "QEMU"
195#elif defined(PLEX86)
196# define BX_APPNAME "Plex86"
197#else
198# define BX_APPNAME "Bochs"
199#endif
200
201 // Sanity Checks
202#if BX_USE_ATADRV && BX_CPU<3
203# error The ATA/ATAPI Driver can only to be used with a 386+ cpu
204#endif
205#if BX_USE_ATADRV && !BX_USE_EBDA
206# error ATA/ATAPI Driver can only be used if EBDA is available
207#endif
208#if BX_ELTORITO_BOOT && !BX_USE_ATADRV
209# error El-Torito Boot can only be use if ATA/ATAPI Driver is available
210#endif
211#if BX_PCIBIOS && BX_CPU<3
212# error PCI BIOS can only be used with 386+ cpu
213#endif
214#if BX_APM && BX_CPU<3
215# error APM BIOS can only be used with 386+ cpu
216#endif
217
218#if defined(VBOX) && !BX_USE_ATADRV
219# error VBOX requires enabling the ATA/ATAPI driver
220#endif
221
222#ifdef VBOX_WITH_SCSI
223/* Enough for now */
224# define BX_MAX_SCSI_DEVICES 4
225# define BX_MAX_STORAGE_DEVICES (BX_MAX_ATA_DEVICES + BX_MAX_SCSI_DEVICES)
226
227/* A SCSI device starts always at BX_MAX_ATA_DEVICES. */
228# define VBOX_IS_SCSI_DEVICE(device_id) (device_id >= BX_MAX_ATA_DEVICES)
229# define VBOX_GET_SCSI_DEVICE(device_id) (device_id - BX_MAX_ATA_DEVICES)
230#else
231# define BX_MAX_STORAGE_DEVICES BX_MAX_ATA_DEVICES
232#endif
233
234#ifndef VBOX
235#define PANIC_PORT 0x400
236#define PANIC_PORT2 0x401
237#define INFO_PORT 0x402
238#define DEBUG_PORT 0x403
239#else /* VBOX */
240/* Redirect INFO output to backdoor logging port. */
241#define PANIC_PORT 0x400
242#define PANIC_PORT2 0x401
243#define INFO_PORT 0x504
244#define DEBUG_PORT 0x403
245#endif /* VBOX */
246
247// define this if you want to make PCIBIOS working on a specific bridge only
248// undef enables PCIBIOS when at least one PCI device is found
249// i440FX is emulated by Bochs and QEMU
250#define PCI_FIXED_HOST_BRIDGE_1 0x12378086 ;; i440FX PCI bridge
251#define PCI_FIXED_HOST_BRIDGE_2 0x244e8086 ;; ICH9 PCI bridge
252
253// #20 is dec 20
254// #$20 is hex 20 = 32
255// #0x20 is hex 20 = 32
256// LDA #$20
257// JSR $E820
258// LDD .i,S
259// JSR $C682
260// mov al, #$20
261
262// all hex literals should be prefixed with '0x'
263// grep "#[0-9a-fA-F][0-9a-fA-F]" rombios.c
264// no mov SEG-REG, #value, must mov register into seg-reg
265// grep -i "mov[ ]*.s" rombios.c
266
267// This is for compiling with gcc2 and gcc3
268#define ASM_START #asm
269#define ASM_END #endasm
270
271ASM_START
272.rom
273
274.org 0x0000
275
276#if BX_CPU >= 3
277use16 386
278#else
279use16 286
280#endif
281
282MACRO HALT
283 ;; the HALT macro is called with the line number of the HALT call.
284 ;; The line number is then sent to the PANIC_PORT, causing Bochs/Plex
285 ;; to print a BX_PANIC message. This will normally halt the simulation
286 ;; with a message such as "BIOS panic at rombios.c, line 4091".
287 ;; However, users can choose to make panics non-fatal and continue.
288#if BX_VIRTUAL_PORTS
289 mov dx,#PANIC_PORT
290 mov ax,#?1
291 out dx,ax
292#else
293 mov dx,#0x80
294 mov ax,#?1
295 out dx,al
296#endif
297MEND
298
299MACRO JMP_AP
300 db 0xea
301 dw ?2
302 dw ?1
303MEND
304
305MACRO SET_INT_VECTOR
306 mov ax, ?3
307 mov ?1*4, ax
308 mov ax, ?2
309 mov ?1*4+2, ax
310MEND
311
312ASM_END
313
314typedef unsigned char Bit8u;
315typedef unsigned short Bit16u;
316typedef unsigned short bx_bool;
317typedef unsigned long Bit32u;
318
319#if BX_USE_ATADRV
320
321 void memsetb(seg,offset,value,count);
322 void memcpyb(dseg,doffset,sseg,soffset,count);
323 void memcpyd(dseg,doffset,sseg,soffset,count);
324
325 // memset of count bytes
326 void
327 memsetb(seg,offset,value,count)
328 Bit16u seg;
329 Bit16u offset;
330 Bit16u value;
331 Bit16u count;
332 {
333 ASM_START
334 push bp
335 mov bp, sp
336
337 push ax
338 push cx
339 push es
340 push di
341
342 mov cx, 10[bp] ; count
343 test cx, cx
344 je memsetb_end
345 mov ax, 4[bp] ; segment
346 mov es, ax
347 mov ax, 6[bp] ; offset
348 mov di, ax
349 mov al, 8[bp] ; value
350 cld
351 rep
352 stosb
353
354 memsetb_end:
355 pop di
356 pop es
357 pop cx
358 pop ax
359
360 pop bp
361 ASM_END
362 }
363
364#if 0
365 // memcpy of count bytes
366 void
367 memcpyb(dseg,doffset,sseg,soffset,count)
368 Bit16u dseg;
369 Bit16u doffset;
370 Bit16u sseg;
371 Bit16u soffset;
372 Bit16u count;
373 {
374 ASM_START
375 push bp
376 mov bp, sp
377
378 push ax
379 push cx
380 push es
381 push di
382 push ds
383 push si
384
385 mov cx, 12[bp] ; count
386 cmp cx, #0x0000
387 je memcpyb_end
388 mov ax, 4[bp] ; dsegment
389 mov es, ax
390 mov ax, 6[bp] ; doffset
391 mov di, ax
392 mov ax, 8[bp] ; ssegment
393 mov ds, ax
394 mov ax, 10[bp] ; soffset
395 mov si, ax
396 cld
397 rep
398 movsb
399
400 memcpyb_end:
401 pop si
402 pop ds
403 pop di
404 pop es
405 pop cx
406 pop ax
407
408 pop bp
409 ASM_END
410 }
411
412 // memcpy of count dword
413 void
414 memcpyd(dseg,doffset,sseg,soffset,count)
415 Bit16u dseg;
416 Bit16u doffset;
417 Bit16u sseg;
418 Bit16u soffset;
419 Bit16u count;
420 {
421 ASM_START
422 push bp
423 mov bp, sp
424
425 push ax
426 push cx
427 push es
428 push di
429 push ds
430 push si
431
432 mov cx, 12[bp] ; count
433 test cx, cx
434 je memcpyd_end
435 mov ax, 4[bp] ; dsegment
436 mov es, ax
437 mov ax, 6[bp] ; doffset
438 mov di, ax
439 mov ax, 8[bp] ; ssegment
440 mov ds, ax
441 mov ax, 10[bp] ; soffset
442 mov si, ax
443 cld
444 rep
445 movsd
446
447 memcpyd_end:
448 pop si
449 pop ds
450 pop di
451 pop es
452 pop cx
453 pop ax
454
455 pop bp
456 ASM_END
457 }
458#endif
459#endif //BX_USE_ATADRV
460
461 // read_dword and write_dword functions
462 static Bit32u read_dword();
463 static void write_dword();
464
465 Bit32u
466 read_dword(seg, offset)
467 Bit16u seg;
468 Bit16u offset;
469 {
470 ASM_START
471 push bp
472 mov bp, sp
473
474 push bx
475 push ds
476 mov ax, 4[bp] ; segment
477 mov ds, ax
478 mov bx, 6[bp] ; offset
479 mov ax, [bx]
480 add bx, #2
481 mov dx, [bx]
482 ;; ax = return value (word)
483 ;; dx = return value (word)
484 pop ds
485 pop bx
486
487 pop bp
488 ASM_END
489 }
490
491 void
492 write_dword(seg, offset, data)
493 Bit16u seg;
494 Bit16u offset;
495 Bit32u data;
496 {
497 ASM_START
498 push bp
499 mov bp, sp
500
501 push ax
502 push bx
503 push ds
504 mov ax, 4[bp] ; segment
505 mov ds, ax
506 mov bx, 6[bp] ; offset
507 mov ax, 8[bp] ; data word
508 mov [bx], ax ; write data word
509 add bx, #2
510 mov ax, 10[bp] ; data word
511 mov [bx], ax ; write data word
512 pop ds
513 pop bx
514 pop ax
515
516 pop bp
517 ASM_END
518 }
519
520 // Bit32u (unsigned long) and long helper functions
521 ASM_START
522
523 ;; and function
524 landl:
525 landul:
526 SEG SS
527 and ax,[di]
528 SEG SS
529 and bx,2[di]
530 ret
531
532 ;; add function
533 laddl:
534 laddul:
535 SEG SS
536 add ax,[di]
537 SEG SS
538 adc bx,2[di]
539 ret
540
541 ;; cmp function
542 lcmpl:
543 lcmpul:
544 and eax, #0x0000FFFF
545 shl ebx, #16
546 or eax, ebx
547 shr ebx, #16
548 SEG SS
549 cmp eax, dword ptr [di]
550 ret
551
552 ;; sub function
553 lsubl:
554 lsubul:
555 SEG SS
556 sub ax,[di]
557 SEG SS
558 sbb bx,2[di]
559 ret
560
561 ;; mul function
562 lmull:
563 lmulul:
564 and eax, #0x0000FFFF
565 shl ebx, #16
566 or eax, ebx
567 SEG SS
568 mul eax, dword ptr [di]
569 mov ebx, eax
570 shr ebx, #16
571 ret
572
573 ;; dec function
574 ldecl:
575 ldecul:
576 SEG SS
577 dec dword ptr [bx]
578 ret
579
580 ;; or function
581 lorl:
582 lorul:
583 SEG SS
584 or ax,[di]
585 SEG SS
586 or bx,2[di]
587 ret
588
589 ;; inc function
590 lincl:
591 lincul:
592 SEG SS
593 inc dword ptr [bx]
594 ret
595
596 ;; tst function
597 ltstl:
598 ltstul:
599 and eax, #0x0000FFFF
600 shl ebx, #16
601 or eax, ebx
602 shr ebx, #16
603 test eax, eax
604 ret
605
606 ;; sr function
607 lsrul:
608 mov cx,di
609 jcxz lsr_exit
610 and eax, #0x0000FFFF
611 shl ebx, #16
612 or eax, ebx
613 lsr_loop:
614 shr eax, #1
615 loop lsr_loop
616 mov ebx, eax
617 shr ebx, #16
618 lsr_exit:
619 ret
620
621 ;; sl function
622 lsll:
623 lslul:
624 mov cx,di
625 jcxz lsl_exit
626 and eax, #0x0000FFFF
627 shl ebx, #16
628 or eax, ebx
629 lsl_loop:
630 shl eax, #1
631 loop lsl_loop
632 mov ebx, eax
633 shr ebx, #16
634 lsl_exit:
635 ret
636
637 idiv_:
638 cwd
639 idiv bx
640 ret
641
642 idiv_u:
643 xor dx,dx
644 div bx
645 ret
646
647 ldivul:
648 and eax, #0x0000FFFF
649 shl ebx, #16
650 or eax, ebx
651 xor edx, edx
652 SEG SS
653 mov bx, 2[di]
654 shl ebx, #16
655 SEG SS
656 mov bx, [di]
657 div ebx
658 mov ebx, eax
659 shr ebx, #16
660 ret
661
662 ASM_END
663
664// for access to RAM area which is used by interrupt vectors
665// and BIOS Data Area
666
667typedef struct {
668 unsigned char filler1[0x400];
669 unsigned char filler2[0x6c];
670 Bit16u ticks_low;
671 Bit16u ticks_high;
672 Bit8u midnight_flag;
673 } bios_data_t;
674
675#define BiosData ((bios_data_t *) 0)
676
677#if BX_USE_ATADRV
678 typedef struct {
679 Bit16u heads; // # heads
680 Bit16u cylinders; // # cylinders
681 Bit16u spt; // # sectors / track
682 } chs_t;
683
684 // DPTE definition
685 typedef struct {
686 Bit16u iobase1;
687 Bit16u iobase2;
688 Bit8u prefix;
689 Bit8u unused;
690 Bit8u irq;
691 Bit8u blkcount;
692 Bit8u dma;
693 Bit8u pio;
694 Bit16u options;
695 Bit16u reserved;
696 Bit8u revision;
697 Bit8u checksum;
698 } dpte_t;
699
700 typedef struct {
701 Bit8u iface; // ISA or PCI
702 Bit16u iobase1; // IO Base 1
703 Bit16u iobase2; // IO Base 2
704 Bit8u irq; // IRQ
705 } ata_channel_t;
706
707 typedef struct {
708 Bit8u type; // Detected type of ata (ata/atapi/none/unknown/scsi)
709 Bit8u device; // Detected type of attached devices (hd/cd/none)
710 Bit8u removable; // Removable device flag
711 Bit8u lock; // Locks for removable devices
712 Bit8u mode; // transfer mode : PIO 16/32 bits - IRQ - ISADMA - PCIDMA
713 Bit16u blksize; // block size
714
715 Bit8u translation; // type of translation
716 chs_t lchs; // Logical CHS
717 chs_t pchs; // Physical CHS
718
719 Bit32u sectors; // Total sectors count
720 } ata_device_t;
721
722 typedef struct {
723 // ATA channels info
724 ata_channel_t channels[BX_MAX_ATA_INTERFACES];
725
726 // ATA devices info
727 ata_device_t devices[BX_MAX_ATA_DEVICES];
728 //
729 // map between (bios hd id - 0x80) and ata channels and scsi disks.
730 Bit8u hdcount, hdidmap[BX_MAX_STORAGE_DEVICES];
731
732 // map between (bios cd id - 0xE0) and ata channels
733 Bit8u cdcount, cdidmap[BX_MAX_STORAGE_DEVICES];
734
735 // Buffer for DPTE table
736 dpte_t dpte;
737
738 // Count of transferred sectors and bytes
739 Bit16u trsfsectors;
740 Bit32u trsfbytes;
741
742 } ata_t;
743
744#if BX_ELTORITO_BOOT
745 // ElTorito Device Emulation data
746 typedef struct {
747 Bit8u active;
748 Bit8u media;
749 Bit8u emulated_drive;
750 Bit8u controller_index;
751 Bit16u device_spec;
752 Bit32u ilba;
753 Bit16u buffer_segment;
754 Bit16u load_segment;
755 Bit16u sector_count;
756
757 // Virtual device
758 chs_t vdevice;
759 } cdemu_t;
760#endif // BX_ELTORITO_BOOT
761
762#ifdef VBOX_WITH_SCSI
763 typedef struct {
764 // I/O port this device is attached to.
765 Bit16u io_base;
766 // Target Id.
767 Bit8u target_id;
768 // SCSI devices info
769 ata_device_t device_info;
770 } scsi_device_t;
771
772 typedef struct {
773 // SCSi device info
774 scsi_device_t devices[BX_MAX_SCSI_DEVICES];
775 // Number of scsi disks.
776 Bit8u hdcount;
777 } scsi_t;
778#endif
779
780 // for access to EBDA area
781 // The EBDA structure should conform to
782 // http://www.frontiernet.net/~fys/rombios.htm document
783 // I made the ata and cdemu structs begin at 0x121 in the EBDA seg
784 typedef struct {
785 unsigned char filler1[0x3D];
786
787 // FDPT - Can be split into data members if needed
788 unsigned char fdpt0[0x10];
789 unsigned char fdpt1[0x10];
790
791 unsigned char filler2[0xC4];
792
793 // ATA Driver data
794 ata_t ata;
795
796#if BX_ELTORITO_BOOT
797 // El Torito Emulation data
798 cdemu_t cdemu;
799#endif // BX_ELTORITO_BOOT
800
801#ifdef VBOX
802
803#ifdef VBOX_WITH_SCSI
804 // SCSI Driver data
805 scsi_t scsi;
806# endif
807
808#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 return;
2023 /* show graphical logo */
2024 show_logo();
2025#else /* !VBOX */
2026 printf(BX_APPNAME" BIOS - build: %s\n%s\nOptions: ",
2027 BIOS_BUILD_DATE, bios_cvs_version_string);
2028 printf(
2029#if BX_APM
2030 "apmbios "
2031#endif
2032#if BX_PCIBIOS
2033 "pcibios "
2034#endif
2035#if BX_ELTORITO_BOOT
2036 "eltorito "
2037#endif
2038#if BX_ROMBIOS32
2039 "rombios32 "
2040#endif
2041 "\n\n");
2042#endif /* VBOX */
2043}
2044
2045//--------------------------------------------------------------------------
2046// print_boot_device
2047// displays the boot device
2048//--------------------------------------------------------------------------
2049
2050#ifdef VBOX
2051static char drivetypes[][10]={"Floppy","Hard Disk","CD-ROM","LAN"};
2052#else /* !VBOX */
2053static char drivetypes[][10]={"Floppy","Hard Disk","CD-Rom"};
2054#endif /* !VBOX */
2055
2056#ifdef VBOX
2057void
2058print_boot_device(cdboot, lanboot, drive)
2059 Bit8u cdboot; Bit8u lanboot; Bit16u drive;
2060#else /* !VBOX */
2061void
2062print_boot_device(cdboot, drive)
2063 Bit8u cdboot; Bit16u drive;
2064#endif /* !VBOX */
2065{
2066 Bit8u i;
2067
2068#ifdef VBOX
2069 // cdboot contains 0 if lan/floppy/harddisk, 1 otherwise
2070 // lanboot contains 0 if floppy/harddisk, 1 otherwise
2071#else /* !VBOX */
2072 // cdboot contains 0 if floppy/harddisk, 1 otherwise
2073#endif /* !VBOX */
2074 // drive contains real/emulated boot drive
2075
2076 if(cdboot)i=2; // CD-Rom
2077#ifdef VBOX
2078 else if(lanboot)i=3; // LAN
2079#endif /* VBOX */
2080 else if((drive&0x0080)==0x00)i=0; // Floppy
2081 else if((drive&0x0080)==0x80)i=1; // Hard drive
2082 else return;
2083
2084#ifdef VBOX
2085 BX_INFO("Booting from %s...\n",drivetypes[i]);
2086#else /* !VBOX */
2087 printf("Booting from %s...\n",drivetypes[i]);
2088#endif /* !VBOX */
2089}
2090
2091//--------------------------------------------------------------------------
2092// print_boot_failure
2093// displays the reason why boot failed
2094//--------------------------------------------------------------------------
2095#ifdef VBOX
2096 void
2097print_boot_failure(cdboot, lanboot, drive, reason, lastdrive)
2098 Bit8u cdboot; Bit8u lanboot; Bit8u drive; Bit8u reason; Bit8u lastdrive;
2099#else /* !VBOX */
2100 void
2101print_boot_failure(cdboot, drive, reason, lastdrive)
2102 Bit8u cdboot; Bit8u drive; Bit8u lastdrive;
2103#endif /* !VBOX */
2104{
2105 Bit16u drivenum = drive&0x7f;
2106
2107 // cdboot: 1 if boot from cd, 0 otherwise
2108#ifdef VBOX
2109 // lanboot: 1 if boot from lan, 0 otherwise
2110#endif /* VBOX */
2111 // drive : drive number
2112 // reason: 0 signature check failed, 1 read error
2113 // lastdrive: 1 boot drive is the last one in boot sequence
2114
2115 if (cdboot)
2116#ifndef VBOX
2117 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s failed\n",drivetypes[2]);
2118#else /* VBOX */
2119 BX_INFO("Boot from %s failed\n",drivetypes[2]);
2120 else if (lanboot)
2121 BX_INFO("Boot from %s failed\n",drivetypes[3]);
2122#endif /* VBOX */
2123 else if (drive & 0x80)
2124#ifndef VBOX
2125 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[1],drivenum);
2126#else /* VBOX */
2127 BX_INFO("Boot from %s %d failed\n", drivetypes[1],drivenum);
2128#endif /* VBOX */
2129 else
2130#ifndef VBOX
2131 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[0],drivenum);
2132#else /* VBOX */
2133 BX_INFO("Boot from %s %d failed\n", drivetypes[0],drivenum);
2134#endif /* VBOX */
2135
2136 if (lastdrive==1) {
2137 if (reason==0)
2138#ifndef VBOX
2139 BX_PANIC("Not a bootable disk\n");
2140#else /* VBOX */
2141 BX_PANIC("No bootable medium found! System halted.\n");
2142#endif /* VBOX */
2143 else
2144#ifndef VBOX
2145 BX_PANIC("Could not read the boot disk\n");
2146#else /* VBOX */
2147 BX_PANIC("Could not read from the boot medium! System halted.\n");
2148#endif /* VBOX */
2149 }
2150}
2151
2152//--------------------------------------------------------------------------
2153// print_cdromboot_failure
2154// displays the reason why boot failed
2155//--------------------------------------------------------------------------
2156 void
2157print_cdromboot_failure( code )
2158 Bit16u code;
2159{
2160#ifndef VBOX
2161 bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "CDROM boot failure code : %04x\n",code);
2162#else /* VBOX */
2163 BX_INFO("CDROM boot failure code : %04x\n",code);
2164#endif /* VBOX */
2165
2166 return;
2167}
2168
2169void
2170nmi_handler_msg()
2171{
2172 BX_PANIC("NMI Handler called\n");
2173}
2174
2175void
2176int18_panic_msg()
2177{
2178 BX_PANIC("INT18: BOOT FAILURE\n");
2179}
2180
2181void
2182log_bios_start()
2183{
2184#if BX_DEBUG_SERIAL
2185 outb(BX_DEBUG_PORT+UART_LCR, 0x03); /* setup for serial logging: 8N1 */
2186#endif
2187 BX_INFO("%s\n", bios_cvs_version_string);
2188}
2189
2190 bx_bool
2191set_enable_a20(val)
2192 bx_bool val;
2193{
2194 Bit8u oldval;
2195
2196 // Use PS2 System Control port A to set A20 enable
2197
2198 // get current setting first
2199 oldval = inb(0x92);
2200
2201 // change A20 status
2202 if (val)
2203 outb(0x92, oldval | 0x02);
2204 else
2205 outb(0x92, oldval & 0xfd);
2206
2207 return((oldval & 0x02) != 0);
2208}
2209
2210 void
2211debugger_on()
2212{
2213 outb(0xfedc, 0x01);
2214}
2215
2216 void
2217debugger_off()
2218{
2219 outb(0xfedc, 0x00);
2220}
2221
2222#if BX_USE_ATADRV
2223
2224// ---------------------------------------------------------------------------
2225// Start of ATA/ATAPI Driver
2226// ---------------------------------------------------------------------------
2227
2228// Global defines -- ATA register and register bits.
2229// command block & control block regs
2230#define ATA_CB_DATA 0 // data reg in/out pio_base_addr1+0
2231#define ATA_CB_ERR 1 // error in pio_base_addr1+1
2232#define ATA_CB_FR 1 // feature reg out pio_base_addr1+1
2233#define ATA_CB_SC 2 // sector count in/out pio_base_addr1+2
2234#define ATA_CB_SN 3 // sector number in/out pio_base_addr1+3
2235#define ATA_CB_CL 4 // cylinder low in/out pio_base_addr1+4
2236#define ATA_CB_CH 5 // cylinder high in/out pio_base_addr1+5
2237#define ATA_CB_DH 6 // device head in/out pio_base_addr1+6
2238#define ATA_CB_STAT 7 // primary status in pio_base_addr1+7
2239#define ATA_CB_CMD 7 // command out pio_base_addr1+7
2240#define ATA_CB_ASTAT 6 // alternate status in pio_base_addr2+6
2241#define ATA_CB_DC 6 // device control out pio_base_addr2+6
2242#define ATA_CB_DA 7 // device address in pio_base_addr2+7
2243
2244#define ATA_CB_ER_ICRC 0x80 // ATA Ultra DMA bad CRC
2245#define ATA_CB_ER_BBK 0x80 // ATA bad block
2246#define ATA_CB_ER_UNC 0x40 // ATA uncorrected error
2247#define ATA_CB_ER_MC 0x20 // ATA media change
2248#define ATA_CB_ER_IDNF 0x10 // ATA id not found
2249#define ATA_CB_ER_MCR 0x08 // ATA media change request
2250#define ATA_CB_ER_ABRT 0x04 // ATA command aborted
2251#define ATA_CB_ER_NTK0 0x02 // ATA track 0 not found
2252#define ATA_CB_ER_NDAM 0x01 // ATA address mark not found
2253
2254#define ATA_CB_ER_P_SNSKEY 0xf0 // ATAPI sense key (mask)
2255#define ATA_CB_ER_P_MCR 0x08 // ATAPI Media Change Request
2256#define ATA_CB_ER_P_ABRT 0x04 // ATAPI command abort
2257#define ATA_CB_ER_P_EOM 0x02 // ATAPI End of Media
2258#define ATA_CB_ER_P_ILI 0x01 // ATAPI Illegal Length Indication
2259
2260// ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC)
2261#define ATA_CB_SC_P_TAG 0xf8 // ATAPI tag (mask)
2262#define ATA_CB_SC_P_REL 0x04 // ATAPI release
2263#define ATA_CB_SC_P_IO 0x02 // ATAPI I/O
2264#define ATA_CB_SC_P_CD 0x01 // ATAPI C/D
2265
2266// bits 7-4 of the device/head (CB_DH) reg
2267#define ATA_CB_DH_DEV0 0xa0 // select device 0
2268#define ATA_CB_DH_DEV1 0xb0 // select device 1
2269
2270// status reg (CB_STAT and CB_ASTAT) bits
2271#define ATA_CB_STAT_BSY 0x80 // busy
2272#define ATA_CB_STAT_RDY 0x40 // ready
2273#define ATA_CB_STAT_DF 0x20 // device fault
2274#define ATA_CB_STAT_WFT 0x20 // write fault (old name)
2275#define ATA_CB_STAT_SKC 0x10 // seek complete
2276#define ATA_CB_STAT_SERV 0x10 // service
2277#define ATA_CB_STAT_DRQ 0x08 // data request
2278#define ATA_CB_STAT_CORR 0x04 // corrected
2279#define ATA_CB_STAT_IDX 0x02 // index
2280#define ATA_CB_STAT_ERR 0x01 // error (ATA)
2281#define ATA_CB_STAT_CHK 0x01 // check (ATAPI)
2282
2283// device control reg (CB_DC) bits
2284#define ATA_CB_DC_HD15 0x08 // bit should always be set to one
2285#define ATA_CB_DC_SRST 0x04 // soft reset
2286#define ATA_CB_DC_NIEN 0x02 // disable interrupts
2287
2288// Most mandatory and optional ATA commands (from ATA-3),
2289#define ATA_CMD_CFA_ERASE_SECTORS 0xC0
2290#define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03
2291#define ATA_CMD_CFA_TRANSLATE_SECTOR 0x87
2292#define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD
2293#define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38
2294#define ATA_CMD_CHECK_POWER_MODE1 0xE5
2295#define ATA_CMD_CHECK_POWER_MODE2 0x98
2296#define ATA_CMD_DEVICE_RESET 0x08
2297#define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90
2298#define ATA_CMD_FLUSH_CACHE 0xE7
2299#define ATA_CMD_FORMAT_TRACK 0x50
2300#define ATA_CMD_IDENTIFY_DEVICE 0xEC
2301#define ATA_CMD_IDENTIFY_DEVICE_PACKET 0xA1
2302#define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xA1
2303#define ATA_CMD_IDLE1 0xE3
2304#define ATA_CMD_IDLE2 0x97
2305#define ATA_CMD_IDLE_IMMEDIATE1 0xE1
2306#define ATA_CMD_IDLE_IMMEDIATE2 0x95
2307#define ATA_CMD_INITIALIZE_DRIVE_PARAMETERS 0x91
2308#define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
2309#define ATA_CMD_NOP 0x00
2310#define ATA_CMD_PACKET 0xA0
2311#define ATA_CMD_READ_BUFFER 0xE4
2312#define ATA_CMD_READ_DMA 0xC8
2313#define ATA_CMD_READ_DMA_QUEUED 0xC7
2314#define ATA_CMD_READ_MULTIPLE 0xC4
2315#define ATA_CMD_READ_SECTORS 0x20
2316#ifdef VBOX
2317#define ATA_CMD_READ_SECTORS_EXT 0x24
2318#define ATA_CMD_READ_MULTIPLE_EXT 0x29
2319#define ATA_CMD_WRITE_MULTIPLE_EXT 0x39
2320#endif /* VBOX */
2321#define ATA_CMD_READ_VERIFY_SECTORS 0x40
2322#define ATA_CMD_RECALIBRATE 0x10
2323#define ATA_CMD_SEEK 0x70
2324#define ATA_CMD_SET_FEATURES 0xEF
2325#define ATA_CMD_SET_MULTIPLE_MODE 0xC6
2326#define ATA_CMD_SLEEP1 0xE6
2327#define ATA_CMD_SLEEP2 0x99
2328#define ATA_CMD_STANDBY1 0xE2
2329#define ATA_CMD_STANDBY2 0x96
2330#define ATA_CMD_STANDBY_IMMEDIATE1 0xE0
2331#define ATA_CMD_STANDBY_IMMEDIATE2 0x94
2332#define ATA_CMD_WRITE_BUFFER 0xE8
2333#define ATA_CMD_WRITE_DMA 0xCA
2334#define ATA_CMD_WRITE_DMA_QUEUED 0xCC
2335#define ATA_CMD_WRITE_MULTIPLE 0xC5
2336#define ATA_CMD_WRITE_SECTORS 0x30
2337#ifdef VBOX
2338#define ATA_CMD_WRITE_SECTORS_EXT 0x34
2339#endif /* VBOX */
2340#define ATA_CMD_WRITE_VERIFY 0x3C
2341
2342#define ATA_IFACE_NONE 0x00
2343#define ATA_IFACE_ISA 0x00
2344#define ATA_IFACE_PCI 0x01
2345
2346#define ATA_TYPE_NONE 0x00
2347#define ATA_TYPE_UNKNOWN 0x01
2348#define ATA_TYPE_ATA 0x02
2349#define ATA_TYPE_ATAPI 0x03
2350#ifdef VBOX
2351#define ATA_TYPE_SCSI 0x04 // SCSI disk
2352#endif
2353
2354#define ATA_DEVICE_NONE 0x00
2355#define ATA_DEVICE_HD 0xFF
2356#define ATA_DEVICE_CDROM 0x05
2357
2358#define ATA_MODE_NONE 0x00
2359#define ATA_MODE_PIO16 0x00
2360#define ATA_MODE_PIO32 0x01
2361#define ATA_MODE_ISADMA 0x02
2362#define ATA_MODE_PCIDMA 0x03
2363#define ATA_MODE_USEIRQ 0x10
2364
2365#define ATA_TRANSLATION_NONE 0
2366#define ATA_TRANSLATION_LBA 1
2367#define ATA_TRANSLATION_LARGE 2
2368#define ATA_TRANSLATION_RECHS 3
2369
2370#define ATA_DATA_NO 0x00
2371#define ATA_DATA_IN 0x01
2372#define ATA_DATA_OUT 0x02
2373
2374// ---------------------------------------------------------------------------
2375// ATA/ATAPI driver : initialization
2376// ---------------------------------------------------------------------------
2377void ata_init( )
2378{
2379 Bit16u ebda_seg=read_word(0x0040,0x000E);
2380 Bit8u channel, device;
2381
2382 // Channels info init.
2383 for (channel=0; channel<BX_MAX_ATA_INTERFACES; channel++) {
2384 write_byte(ebda_seg,&EbdaData->ata.channels[channel].iface,ATA_IFACE_NONE);
2385 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1,0x0);
2386 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2,0x0);
2387 write_byte(ebda_seg,&EbdaData->ata.channels[channel].irq,0);
2388 }
2389
2390 // Devices info init.
2391 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2392 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
2393 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_NONE);
2394 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable,0);
2395 write_byte(ebda_seg,&EbdaData->ata.devices[device].lock,0);
2396 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode,ATA_MODE_NONE);
2397 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,0x200);
2398 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation,ATA_TRANSLATION_NONE);
2399 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads,0);
2400 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders,0);
2401 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt,0);
2402 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads,0);
2403 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders,0);
2404 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt,0);
2405
2406 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors,0L);
2407 }
2408
2409 // hdidmap and cdidmap init.
2410 for (device=0; device<BX_MAX_STORAGE_DEVICES; device++) {
2411 write_byte(ebda_seg,&EbdaData->ata.hdidmap[device],BX_MAX_STORAGE_DEVICES);
2412 write_byte(ebda_seg,&EbdaData->ata.cdidmap[device],BX_MAX_STORAGE_DEVICES);
2413 }
2414
2415 write_byte(ebda_seg,&EbdaData->ata.hdcount,0);
2416 write_byte(ebda_seg,&EbdaData->ata.cdcount,0);
2417}
2418
2419// ---------------------------------------------------------------------------
2420// ATA/ATAPI driver : device detection
2421// ---------------------------------------------------------------------------
2422
2423void ata_detect( )
2424{
2425 Bit16u ebda_seg=read_word(0x0040,0x000E);
2426 Bit8u hdcount, cdcount, device, type;
2427 Bit8u buffer[0x0200];
2428
2429#if BX_MAX_ATA_INTERFACES > 0
2430 write_byte(ebda_seg,&EbdaData->ata.channels[0].iface,ATA_IFACE_ISA);
2431 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase1,0x1f0);
2432 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase2,0x3f0);
2433 write_byte(ebda_seg,&EbdaData->ata.channels[0].irq,14);
2434#endif
2435#if BX_MAX_ATA_INTERFACES > 1
2436 write_byte(ebda_seg,&EbdaData->ata.channels[1].iface,ATA_IFACE_ISA);
2437 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase1,0x170);
2438 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase2,0x370);
2439 write_byte(ebda_seg,&EbdaData->ata.channels[1].irq,15);
2440#endif
2441#if BX_MAX_ATA_INTERFACES > 2
2442 write_byte(ebda_seg,&EbdaData->ata.channels[2].iface,ATA_IFACE_ISA);
2443 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase1,0x1e8);
2444 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase2,0x3e0);
2445 write_byte(ebda_seg,&EbdaData->ata.channels[2].irq,12);
2446#endif
2447#if BX_MAX_ATA_INTERFACES > 3
2448 write_byte(ebda_seg,&EbdaData->ata.channels[3].iface,ATA_IFACE_ISA);
2449 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase1,0x168);
2450 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase2,0x360);
2451 write_byte(ebda_seg,&EbdaData->ata.channels[3].irq,11);
2452#endif
2453#if BX_MAX_ATA_INTERFACES > 4
2454#error Please fill the ATA interface informations
2455#endif
2456
2457 // Device detection
2458 hdcount=cdcount=0;
2459
2460 for(device=0; device<BX_MAX_ATA_DEVICES; device++) {
2461 Bit16u iobase1, iobase2;
2462 Bit8u channel, slave, shift;
2463 Bit8u sc, sn, cl, ch, st;
2464
2465 channel = device / 2;
2466 slave = device % 2;
2467
2468 iobase1 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1);
2469 iobase2 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2);
2470
2471 // Disable interrupts
2472 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2473
2474 // Look for device
2475 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2476 outb(iobase1+ATA_CB_SC, 0x55);
2477 outb(iobase1+ATA_CB_SN, 0xaa);
2478 outb(iobase1+ATA_CB_SC, 0xaa);
2479 outb(iobase1+ATA_CB_SN, 0x55);
2480 outb(iobase1+ATA_CB_SC, 0x55);
2481 outb(iobase1+ATA_CB_SN, 0xaa);
2482
2483 // If we found something
2484 sc = inb(iobase1+ATA_CB_SC);
2485 sn = inb(iobase1+ATA_CB_SN);
2486
2487 if ( (sc == 0x55) && (sn == 0xaa) ) {
2488 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_UNKNOWN);
2489
2490 // reset the channel
2491 ata_reset(device);
2492
2493 // check for ATA or ATAPI
2494 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2495 sc = inb(iobase1+ATA_CB_SC);
2496 sn = inb(iobase1+ATA_CB_SN);
2497 if ((sc==0x01) && (sn==0x01)) {
2498 cl = inb(iobase1+ATA_CB_CL);
2499 ch = inb(iobase1+ATA_CB_CH);
2500 st = inb(iobase1+ATA_CB_STAT);
2501
2502 if ((cl==0x14) && (ch==0xeb)) {
2503 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATAPI);
2504 } else if ((cl==0x00) && (ch==0x00) && (st!=0x00)) {
2505 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATA);
2506 } else if ((cl==0xff) && (ch==0xff)) {
2507 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
2508 }
2509 }
2510 }
2511
2512#ifdef VBOX
2513 // Enable interrupts
2514 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2515#endif /* VBOX */
2516
2517 type=read_byte(ebda_seg,&EbdaData->ata.devices[device].type);
2518
2519 // Now we send a IDENTIFY command to ATA device
2520 if(type == ATA_TYPE_ATA) {
2521 Bit32u sectors;
2522 Bit16u cylinders, heads, spt, blksize;
2523#ifdef VBOX
2524 Bit16u lcylinders, lheads, lspt;
2525 Bit8u chsgeo_base;
2526#endif /* VBOX */
2527 Bit8u translation, removable, mode;
2528
2529 //Temporary values to do the transfer
2530 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2531 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2532
2533 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE, 1, 0, 0, 0, 0L, get_SS(),buffer) !=0 )
2534 BX_PANIC("ata-detect: Failed to detect ATA device\n");
2535
2536 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2537 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2538#ifdef VBOX
2539 blksize = 512; /* There is no sector size field any more. */
2540#else /* !VBOX */
2541 blksize = read_word(get_SS(),buffer+10);
2542#endif /* !VBOX */
2543
2544 cylinders = read_word(get_SS(),buffer+(1*2)); // word 1
2545 heads = read_word(get_SS(),buffer+(3*2)); // word 3
2546 spt = read_word(get_SS(),buffer+(6*2)); // word 6
2547
2548 sectors = read_dword(get_SS(),buffer+(60*2)); // word 60 and word 61
2549#ifdef VBOX
2550 /** @todo update sectors to be a 64 bit number (also lba...). */
2551 if (sectors == 268435455)
2552 sectors = read_dword(get_SS(),buffer+(100*2)); // words 100 to 103 (someday)
2553 switch (device)
2554 {
2555 case 0:
2556 chsgeo_base = 0x1e;
2557 break;
2558 case 1:
2559 chsgeo_base = 0x26;
2560 break;
2561 case 2:
2562 chsgeo_base = 0x67;
2563 break;
2564 case 3:
2565 chsgeo_base = 0x70;
2566 break;
2567#ifndef VBOX_WITH_BIOS_AHCI
2568 case 4:
2569 chsgeo_base = 0x40;
2570 break;
2571 case 5:
2572 chsgeo_base = 0x48;
2573 break;
2574 case 6:
2575 chsgeo_base = 0x50;
2576 break;
2577 case 7:
2578 chsgeo_base = 0x58;
2579 break;
2580#endif
2581 default:
2582 chsgeo_base = 0;
2583 }
2584 if (chsgeo_base != 0)
2585 {
2586 lcylinders = inb_cmos(chsgeo_base) + (inb_cmos(chsgeo_base+1) << 8);
2587 lheads = inb_cmos(chsgeo_base+2);
2588 lspt = inb_cmos(chsgeo_base+7);
2589 }
2590 else
2591 {
2592 lcylinders = 0;
2593 lheads = 0;
2594 lspt = 0;
2595 }
2596 BX_INFO("ata%d-%d: PCHS=%u/%d/%d LCHS=%u/%u/%u\n", channel, slave, cylinders, heads, spt, lcylinders, lheads, lspt);
2597#endif /* VBOX */
2598
2599 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2600 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2601 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2602 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2603 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads, heads);
2604 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders, cylinders);
2605 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt, spt);
2606 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors, sectors);
2607#ifdef VBOX
2608 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, lheads);
2609 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, lcylinders);
2610 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, lspt);
2611 if (device < 2)
2612 {
2613 Bit8u sum, i;
2614 unsigned char *fdpt;
2615 if (device == 0)
2616 fdpt = &EbdaData->fdpt0;
2617 else
2618 fdpt = &EbdaData->fdpt1;
2619
2620 /* Update the DPT for drive 0/1 pointed to by Int41/46. This used
2621 * to be done at POST time with lots of ugly assembler code, which
2622 * isn't worth the effort of converting from AMI to Award CMOS
2623 * format. Just do it here. */
2624 write_word(ebda_seg, fdpt + 0x00, lcylinders);
2625 write_byte(ebda_seg, fdpt + 0x02, lheads);
2626 write_byte(ebda_seg, fdpt + 0x0e, lspt);
2627 write_word(ebda_seg, fdpt + 0x09, cylinders);
2628 write_byte(ebda_seg, fdpt + 0x0b, heads);
2629 write_byte(ebda_seg, fdpt + 0x04, spt);
2630 write_byte(ebda_seg, fdpt + 0x03, 0xa0);
2631 sum = 0;
2632 for (i = 0; i < 0xf; i++)
2633 sum += read_byte(ebda_seg, fdpt + i);
2634 sum = -sum;
2635 write_byte(ebda_seg, fdpt + 0x0f, sum);
2636 }
2637#else /* !VBOX */
2638 BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel, slave,cylinders, heads, spt);
2639
2640 translation = inb_cmos(0x39 + channel/2);
2641 for (shift=device%4; shift>0; shift--) translation >>= 2;
2642 translation &= 0x03;
2643
2644 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation, translation);
2645
2646 switch (translation) {
2647 case ATA_TRANSLATION_NONE:
2648 BX_INFO("none");
2649 break;
2650 case ATA_TRANSLATION_LBA:
2651 BX_INFO("lba");
2652 break;
2653 case ATA_TRANSLATION_LARGE:
2654 BX_INFO("large");
2655 break;
2656 case ATA_TRANSLATION_RECHS:
2657 BX_INFO("r-echs");
2658 break;
2659 }
2660 switch (translation) {
2661 case ATA_TRANSLATION_NONE:
2662 break;
2663 case ATA_TRANSLATION_LBA:
2664 spt = 63;
2665 sectors /= 63;
2666 heads = sectors / 1024;
2667 if (heads>128) heads = 255;
2668 else if (heads>64) heads = 128;
2669 else if (heads>32) heads = 64;
2670 else if (heads>16) heads = 32;
2671 else heads=16;
2672 cylinders = sectors / heads;
2673 break;
2674 case ATA_TRANSLATION_RECHS:
2675 // Take care not to overflow
2676 if (heads==16) {
2677 if(cylinders>61439) cylinders=61439;
2678 heads=15;
2679 cylinders = (Bit16u)((Bit32u)(cylinders)*16/15);
2680 }
2681 // then go through the large bitshift process
2682 case ATA_TRANSLATION_LARGE:
2683 while(cylinders > 1024) {
2684 cylinders >>= 1;
2685 heads <<= 1;
2686
2687 // If we max out the head count
2688 if (heads > 127) break;
2689 }
2690 break;
2691 }
2692 // clip to 1024 cylinders in lchs
2693 if (cylinders > 1024) cylinders=1024;
2694 BX_INFO(" LCHS=%d/%d/%d\n", cylinders, heads, spt);
2695
2696 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, heads);
2697 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, cylinders);
2698 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, spt);
2699#endif /* VBOX */
2700
2701 // fill hdidmap
2702 write_byte(ebda_seg,&EbdaData->ata.hdidmap[hdcount], device);
2703 hdcount++;
2704 }
2705
2706 // Now we send a IDENTIFY command to ATAPI device
2707 if(type == ATA_TYPE_ATAPI) {
2708
2709 Bit8u type, removable, mode;
2710 Bit16u blksize;
2711
2712 //Temporary values to do the transfer
2713 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_CDROM);
2714 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2715
2716 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE_PACKET, 1, 0, 0, 0, 0L, get_SS(),buffer) != 0)
2717 BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
2718
2719 type = read_byte(get_SS(),buffer+1) & 0x1f;
2720 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2721 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2722 blksize = 2048;
2723
2724 write_byte(ebda_seg,&EbdaData->ata.devices[device].device, type);
2725 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2726 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2727 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2728
2729 // fill cdidmap
2730 write_byte(ebda_seg,&EbdaData->ata.cdidmap[cdcount], device);
2731 cdcount++;
2732 }
2733
2734#ifdef VBOX
2735 // we don't want any noisy output for now
2736#else /* !VBOX */
2737 {
2738 Bit32u sizeinmb;
2739 Bit16u ataversion;
2740 Bit8u c, i, version, model[41];
2741
2742 switch (type) {
2743 case ATA_TYPE_ATA:
2744 sizeinmb = read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors);
2745 sizeinmb >>= 11;
2746 case ATA_TYPE_ATAPI:
2747 // Read ATA/ATAPI version
2748 ataversion=((Bit16u)(read_byte(get_SS(),buffer+161))<<8)|read_byte(get_SS(),buffer+160);
2749 for(version=15;version>0;version--) {
2750 if((ataversion&(1<<version))!=0)
2751 break;
2752 }
2753
2754 // Read model name
2755 for(i=0;i<20;i++){
2756 write_byte(get_SS(),model+(i*2),read_byte(get_SS(),buffer+(i*2)+54+1));
2757 write_byte(get_SS(),model+(i*2)+1,read_byte(get_SS(),buffer+(i*2)+54));
2758 }
2759
2760 // Reformat
2761 write_byte(get_SS(),model+40,0x00);
2762 for(i=39;i>0;i--){
2763 if(read_byte(get_SS(),model+i)==0x20)
2764 write_byte(get_SS(),model+i,0x00);
2765 else break;
2766 }
2767 break;
2768 }
2769
2770 switch (type) {
2771 case ATA_TYPE_ATA:
2772 printf("ata%d %s: ",channel,slave?" slave":"master");
2773 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2774 printf(" ATA-%d Hard-Disk (%lu MBytes)\n", version, sizeinmb);
2775 break;
2776 case ATA_TYPE_ATAPI:
2777 printf("ata%d %s: ",channel,slave?" slave":"master");
2778 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2779 if(read_byte(ebda_seg,&EbdaData->ata.devices[device].device)==ATA_DEVICE_CDROM)
2780 printf(" ATAPI-%d CD-Rom/DVD-Rom\n",version);
2781 else
2782 printf(" ATAPI-%d Device\n",version);
2783 break;
2784 case ATA_TYPE_UNKNOWN:
2785 printf("ata%d %s: Unknown device\n",channel,slave?" slave":"master");
2786 break;
2787 }
2788 }
2789#endif /* !VBOX */
2790 }
2791
2792 // Store the devices counts
2793 write_byte(ebda_seg,&EbdaData->ata.hdcount, hdcount);
2794 write_byte(ebda_seg,&EbdaData->ata.cdcount, cdcount);
2795 write_byte(0x40,0x75, hdcount);
2796
2797#ifdef VBOX
2798 // we don't want any noisy output for now
2799#else /* !VBOX */
2800 printf("\n");
2801#endif /* !VBOX */
2802
2803 // FIXME : should use bios=cmos|auto|disable bits
2804 // FIXME : should know about translation bits
2805 // FIXME : move hard_drive_post here
2806
2807}
2808
2809// ---------------------------------------------------------------------------
2810// ATA/ATAPI driver : software reset
2811// ---------------------------------------------------------------------------
2812// ATA-3
2813// 8.2.1 Software reset - Device 0
2814
2815void ata_reset(device)
2816Bit16u device;
2817{
2818 Bit16u ebda_seg=read_word(0x0040,0x000E);
2819 Bit16u iobase1, iobase2;
2820 Bit8u channel, slave, sn, sc;
2821 Bit16u max;
2822#ifdef VBOX
2823 Bit16u pdelay;
2824#endif /* VBOX */
2825
2826 channel = device / 2;
2827 slave = device % 2;
2828
2829 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2830 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2831
2832 // Reset
2833
2834// 8.2.1 (a) -- set SRST in DC
2835 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN | ATA_CB_DC_SRST);
2836
2837// 8.2.1 (b) -- wait for BSY
2838 max=0xff;
2839 while(--max>0) {
2840 Bit8u status = inb(iobase1+ATA_CB_STAT);
2841 if ((status & ATA_CB_STAT_BSY) != 0) break;
2842 }
2843
2844// 8.2.1 (f) -- clear SRST
2845 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2846
2847 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_NONE) {
2848
2849// 8.2.1 (g) -- check for sc==sn==0x01
2850 // select device
2851 outb(iobase1+ATA_CB_DH, slave?ATA_CB_DH_DEV1:ATA_CB_DH_DEV0);
2852 sc = inb(iobase1+ATA_CB_SC);
2853 sn = inb(iobase1+ATA_CB_SN);
2854
2855 if ( (sc==0x01) && (sn==0x01) ) {
2856
2857// 8.2.1 (h) -- wait for not BSY
2858#ifdef VBOX
2859 max=0xffff; /* The ATA specification says that the drive may be busy for up to 30 seconds. */
2860#else /* !VBOX */
2861 max=0xff;
2862#endif /* !VBOX */
2863 while(--max>0) {
2864 Bit8u status = inb(iobase1+ATA_CB_STAT);
2865 if ((status & ATA_CB_STAT_BSY) == 0) break;
2866#ifdef VBOX
2867 pdelay=0xffff;
2868 while (--pdelay>0) {
2869 /* nothing */
2870 }
2871#endif /* VBOX */
2872 }
2873 }
2874 }
2875
2876// 8.2.1 (i) -- wait for DRDY
2877#ifdef VBOX
2878 max=0x10; /* Speed up for virtual drives. Disks are immediately ready, CDs never */
2879#else /* !VBOX */
2880 max=0xfff;
2881#endif /* !VBOX */
2882 while(--max>0) {
2883 Bit8u status = inb(iobase1+ATA_CB_STAT);
2884 if ((status & ATA_CB_STAT_RDY) != 0) break;
2885 }
2886
2887 // Enable interrupts
2888 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2889}
2890
2891// ---------------------------------------------------------------------------
2892// ATA/ATAPI driver : execute a non data command
2893// ---------------------------------------------------------------------------
2894
2895Bit16u ata_cmd_non_data()
2896{return 0;}
2897
2898// ---------------------------------------------------------------------------
2899// ATA/ATAPI driver : execute a data-in command
2900// ---------------------------------------------------------------------------
2901 // returns
2902 // 0 : no error
2903 // 1 : BUSY bit set
2904 // 2 : read error
2905 // 3 : expected DRQ=1
2906 // 4 : no sectors left to read/verify
2907 // 5 : more sectors to read/verify
2908 // 6 : no sectors left to write
2909 // 7 : more sectors to write
2910Bit16u ata_cmd_data_in(device, command, count, cylinder, head, sector, lba, segment, offset)
2911Bit16u device, command, count, cylinder, head, sector, segment, offset;
2912Bit32u lba;
2913{
2914 Bit16u ebda_seg=read_word(0x0040,0x000E);
2915 Bit16u iobase1, iobase2, blksize, mult_blk_cnt;
2916 Bit8u channel, slave;
2917 Bit8u status, current, mode;
2918
2919 channel = device / 2;
2920 slave = device % 2;
2921
2922 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2923 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2924 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2925 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2926 if (blksize == 0) { /* If transfer size is exactly 64K */
2927 if (mode == ATA_MODE_PIO32) blksize=0x4000;
2928 else blksize=0x8000;
2929 } else {
2930 if (mode == ATA_MODE_PIO32) blksize>>=2;
2931 else blksize>>=1;
2932 }
2933
2934#ifdef VBOX
2935 status = inb(iobase1 + ATA_CB_STAT);
2936 if (status & ATA_CB_STAT_BSY)
2937 {
2938 BX_DEBUG_ATA("ata_cmd_data_in : disk busy\n");
2939 // Enable interrupts
2940 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2941 return 1;
2942 }
2943#endif /* VBOX */
2944
2945 // sector will be 0 only on lba access. Convert to lba-chs
2946 if (sector == 0) {
2947#ifdef VBOX
2948 if (lba + count >= 268435456)
2949 {
2950 sector = (lba & 0xff000000L) >> 24;
2951 cylinder = 0; /* The parameter lba is just a 32 bit value. */
2952 outb(iobase1 + ATA_CB_SC, (count & 0xff00) >> 8);
2953 outb(iobase1 + ATA_CB_SN, sector);
2954 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2955 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2956 /* Leave the bottom 24 bits as is, they are treated correctly by the
2957 * LBA28 code path. */
2958 lba &= 0xffffff;
2959 }
2960#endif /* VBOX */
2961 sector = (Bit16u) (lba & 0x000000ffL);
2962 lba >>= 8;
2963 cylinder = (Bit16u) (lba & 0x0000ffffL);
2964 lba >>= 16;
2965 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
2966 }
2967
2968 // Reset count of transferred data
2969 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2970 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2971 current = 0;
2972
2973#ifndef VBOX
2974 status = inb(iobase1 + ATA_CB_STAT);
2975 if (status & ATA_CB_STAT_BSY) return 1;
2976#endif /* !VBOX */
2977
2978 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2979 outb(iobase1 + ATA_CB_FR, 0x00);
2980 outb(iobase1 + ATA_CB_SC, count);
2981 outb(iobase1 + ATA_CB_SN, sector);
2982 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2983 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2984 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
2985 outb(iobase1 + ATA_CB_CMD, command);
2986
2987 if (command == ATA_CMD_READ_MULTIPLE || command == ATA_CMD_READ_MULTIPLE_EXT) {
2988 mult_blk_cnt = count;
2989 count = 1;
2990 } else {
2991 mult_blk_cnt = 1;
2992 }
2993
2994 while (1) {
2995 status = inb(iobase1 + ATA_CB_STAT);
2996 if ( !(status & ATA_CB_STAT_BSY) ) break;
2997 }
2998
2999 if (status & ATA_CB_STAT_ERR) {
3000 BX_DEBUG_ATA("ata_cmd_data_in : read error\n");
3001#ifdef VBOX
3002 // Enable interrupts
3003 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3004#endif /* VBOX */
3005 return 2;
3006 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
3007 BX_DEBUG_ATA("ata_cmd_data_in : DRQ not set (status %02x)\n", (unsigned) status);
3008#ifdef VBOX
3009 // Enable interrupts
3010 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3011#endif /* VBOX */
3012 return 3;
3013 }
3014
3015 // FIXME : move seg/off translation here
3016
3017ASM_START
3018 sti ;; enable higher priority interrupts
3019ASM_END
3020
3021 while (1) {
3022
3023ASM_START
3024 push bp
3025 mov bp, sp
3026 mov di, _ata_cmd_data_in.offset + 2[bp]
3027 mov ax, _ata_cmd_data_in.segment + 2[bp]
3028 mov cx, _ata_cmd_data_in.blksize + 2[bp]
3029
3030 ;; adjust if there will be an overrun. 2K max sector size
3031 cmp di, #0xf800 ;;
3032 jbe ata_in_no_adjust
3033
3034ata_in_adjust:
3035 sub di, #0x0800 ;; sub 2 kbytes from offset
3036 add ax, #0x0080 ;; add 2 Kbytes to segment
3037
3038ata_in_no_adjust:
3039 mov es, ax ;; segment in es
3040
3041 mov dx, _ata_cmd_data_in.iobase1 + 2[bp] ;; ATA data read port
3042
3043 mov ah, _ata_cmd_data_in.mode + 2[bp]
3044 cmp ah, #ATA_MODE_PIO32
3045 je ata_in_32
3046
3047ata_in_16:
3048 rep
3049 insw ;; CX words transferred from port(DX) to ES:[DI]
3050 jmp ata_in_done
3051
3052ata_in_32:
3053 rep
3054 insd ;; CX dwords transferred from port(DX) to ES:[DI]
3055
3056ata_in_done:
3057 mov _ata_cmd_data_in.offset + 2[bp], di
3058 mov _ata_cmd_data_in.segment + 2[bp], es
3059 pop bp
3060ASM_END
3061
3062 current += mult_blk_cnt;
3063 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
3064 count--;
3065#ifdef VBOX
3066 while (1) {
3067 status = inb(iobase1 + ATA_CB_STAT);
3068 if ( !(status & ATA_CB_STAT_BSY) ) break;
3069 }
3070#else /* !VBOX */
3071 status = inb(iobase1 + ATA_CB_STAT);
3072#endif /* !VBOX */
3073 if (count == 0) {
3074 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3075 != ATA_CB_STAT_RDY ) {
3076 BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n", (unsigned) status);
3077#ifdef VBOX
3078 // Enable interrupts
3079 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3080#endif /* VBOX */
3081 return 4;
3082 }
3083 break;
3084 }
3085 else {
3086 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3087 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3088 BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n", (unsigned) status);
3089#ifdef VBOX
3090 // Enable interrupts
3091 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3092#endif /* VBOX */
3093 return 5;
3094 }
3095 continue;
3096 }
3097 }
3098 // Enable interrupts
3099 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3100 return 0;
3101}
3102
3103// ---------------------------------------------------------------------------
3104// ATA/ATAPI driver : execute a data-out command
3105// ---------------------------------------------------------------------------
3106 // returns
3107 // 0 : no error
3108 // 1 : BUSY bit set
3109 // 2 : read error
3110 // 3 : expected DRQ=1
3111 // 4 : no sectors left to read/verify
3112 // 5 : more sectors to read/verify
3113 // 6 : no sectors left to write
3114 // 7 : more sectors to write
3115Bit16u ata_cmd_data_out(device, command, count, cylinder, head, sector, lba, segment, offset)
3116Bit16u device, command, count, cylinder, head, sector, segment, offset;
3117Bit32u lba;
3118{
3119 Bit16u ebda_seg=read_word(0x0040,0x000E);
3120 Bit16u iobase1, iobase2, blksize;
3121 Bit8u channel, slave;
3122 Bit8u status, current, mode;
3123
3124 channel = device / 2;
3125 slave = device % 2;
3126
3127 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
3128 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
3129 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
3130 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
3131 if (mode == ATA_MODE_PIO32) blksize>>=2;
3132 else blksize>>=1;
3133
3134#ifdef VBOX
3135 status = inb(iobase1 + ATA_CB_STAT);
3136 if (status & ATA_CB_STAT_BSY)
3137 {
3138 // Enable interrupts
3139 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3140 return 1;
3141 }
3142#endif /* VBOX */
3143
3144 // sector will be 0 only on lba access. Convert to lba-chs
3145 if (sector == 0) {
3146#ifdef VBOX
3147 if (lba + count >= 268435456)
3148 {
3149 sector = (lba & 0xff000000L) >> 24;
3150 cylinder = 0; /* The parameter lba is just a 32 bit value. */
3151 outb(iobase1 + ATA_CB_SC, (count & 0xff00) >> 8);
3152 outb(iobase1 + ATA_CB_SN, sector);
3153 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
3154 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
3155 /* Leave the bottom 24 bits as is, they are treated correctly by the
3156 * LBA28 code path. */
3157 lba &= 0xffffff;
3158 }
3159#endif /* VBOX */
3160 sector = (Bit16u) (lba & 0x000000ffL);
3161 lba >>= 8;
3162 cylinder = (Bit16u) (lba & 0x0000ffffL);
3163 lba >>= 16;
3164 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
3165 }
3166
3167 // Reset count of transferred data
3168 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
3169 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
3170 current = 0;
3171
3172#ifndef VBOX
3173 status = inb(iobase1 + ATA_CB_STAT);
3174 if (status & ATA_CB_STAT_BSY) return 1;
3175#endif /* !VBOX */
3176
3177 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
3178 outb(iobase1 + ATA_CB_FR, 0x00);
3179 outb(iobase1 + ATA_CB_SC, count);
3180 outb(iobase1 + ATA_CB_SN, sector);
3181 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
3182 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
3183 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
3184 outb(iobase1 + ATA_CB_CMD, command);
3185
3186 while (1) {
3187 status = inb(iobase1 + ATA_CB_STAT);
3188 if ( !(status & ATA_CB_STAT_BSY) ) break;
3189 }
3190
3191 if (status & ATA_CB_STAT_ERR) {
3192 BX_DEBUG_ATA("ata_cmd_data_out : read error\n");
3193#ifdef VBOX
3194 // Enable interrupts
3195 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3196#endif /* VBOX */
3197 return 2;
3198 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
3199 BX_DEBUG_ATA("ata_cmd_data_out : DRQ not set (status %02x)\n", (unsigned) status);
3200#ifdef VBOX
3201 // Enable interrupts
3202 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3203#endif /* VBOX */
3204 return 3;
3205 }
3206
3207 // FIXME : move seg/off translation here
3208
3209ASM_START
3210 sti ;; enable higher priority interrupts
3211ASM_END
3212
3213 while (1) {
3214
3215ASM_START
3216 push bp
3217 mov bp, sp
3218 mov si, _ata_cmd_data_out.offset + 2[bp]
3219 mov ax, _ata_cmd_data_out.segment + 2[bp]
3220 mov cx, _ata_cmd_data_out.blksize + 2[bp]
3221
3222 ;; adjust if there will be an overrun. 2K max sector size
3223 cmp si, #0xf800 ;;
3224 jbe ata_out_no_adjust
3225
3226ata_out_adjust:
3227 sub si, #0x0800 ;; sub 2 kbytes from offset
3228 add ax, #0x0080 ;; add 2 Kbytes to segment
3229
3230ata_out_no_adjust:
3231 mov es, ax ;; segment in es
3232
3233 mov dx, _ata_cmd_data_out.iobase1 + 2[bp] ;; ATA data write port
3234
3235 mov ah, _ata_cmd_data_out.mode + 2[bp]
3236 cmp ah, #ATA_MODE_PIO32
3237 je ata_out_32
3238
3239ata_out_16:
3240 seg ES
3241 rep
3242 outsw ;; CX words transferred from port(DX) to ES:[SI]
3243 jmp ata_out_done
3244
3245ata_out_32:
3246 seg ES
3247 rep
3248 outsd ;; CX dwords transferred from port(DX) to ES:[SI]
3249
3250ata_out_done:
3251 mov _ata_cmd_data_out.offset + 2[bp], si
3252 mov _ata_cmd_data_out.segment + 2[bp], es
3253 pop bp
3254ASM_END
3255
3256 current++;
3257 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
3258 count--;
3259#ifdef VBOX
3260 while (1) {
3261 status = inb(iobase1 + ATA_CB_STAT);
3262 if ( !(status & ATA_CB_STAT_BSY) ) break;
3263 }
3264#else /* !VBOX */
3265 status = inb(iobase1 + ATA_CB_STAT);
3266#endif /* VBOX */
3267 if (count == 0) {
3268 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3269 != ATA_CB_STAT_RDY ) {
3270 BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n", (unsigned) status);
3271#ifdef VBOX
3272 // Enable interrupts
3273 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3274#endif /* VBOX */
3275 return 6;
3276 }
3277 break;
3278 }
3279 else {
3280 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3281 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3282 BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n", (unsigned) status);
3283#ifdef VBOX
3284 // Enable interrupts
3285 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3286#endif /* VBOX */
3287 return 7;
3288 }
3289 continue;
3290 }
3291 }
3292 // Enable interrupts
3293 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3294 return 0;
3295}
3296
3297// ---------------------------------------------------------------------------
3298// ATA/ATAPI driver : execute a packet command
3299// ---------------------------------------------------------------------------
3300 // returns
3301 // 0 : no error
3302 // 1 : error in parameters
3303 // 2 : BUSY bit set
3304 // 3 : error
3305 // 4 : not ready
3306Bit16u ata_cmd_packet(device, cmdlen, cmdseg, cmdoff, header, length, inout, bufseg, bufoff)
3307Bit8u cmdlen,inout;
3308Bit16u device,cmdseg, cmdoff, bufseg, bufoff;
3309Bit16u header;
3310Bit32u length;
3311{
3312 Bit16u ebda_seg=read_word(0x0040,0x000E);
3313 Bit16u iobase1, iobase2;
3314 Bit16u lcount, lbefore, lafter, count;
3315 Bit8u channel, slave;
3316 Bit8u status, mode, lmode;
3317 Bit32u total, transfer;
3318
3319 channel = device / 2;
3320 slave = device % 2;
3321
3322 // Data out is not supported yet
3323 if (inout == ATA_DATA_OUT) {
3324 BX_INFO("ata_cmd_packet: DATA_OUT not supported yet\n");
3325 return 1;
3326 }
3327
3328 // The header length must be even
3329 if (header & 1) {
3330 BX_DEBUG_ATA("ata_cmd_packet : header must be even (%04x)\n",header);
3331 return 1;
3332 }
3333
3334 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
3335 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
3336 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
3337 transfer= 0L;
3338
3339 if (cmdlen < 12) cmdlen=12;
3340 if (cmdlen > 12) cmdlen=16;
3341 cmdlen>>=1;
3342
3343 // Reset count of transferred data
3344 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
3345 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
3346
3347 status = inb(iobase1 + ATA_CB_STAT);
3348 if (status & ATA_CB_STAT_BSY) return 2;
3349
3350 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
3351 // outb(iobase1 + ATA_CB_FR, 0x00);
3352 // outb(iobase1 + ATA_CB_SC, 0x00);
3353 // outb(iobase1 + ATA_CB_SN, 0x00);
3354 outb(iobase1 + ATA_CB_CL, 0xfff0 & 0x00ff);
3355 outb(iobase1 + ATA_CB_CH, 0xfff0 >> 8);
3356 outb(iobase1 + ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
3357 outb(iobase1 + ATA_CB_CMD, ATA_CMD_PACKET);
3358
3359 // Device should ok to receive command
3360 while (1) {
3361 status = inb(iobase1 + ATA_CB_STAT);
3362 if ( !(status & ATA_CB_STAT_BSY) ) break;
3363 }
3364
3365 if (status & ATA_CB_STAT_ERR) {
3366 BX_DEBUG_ATA("ata_cmd_packet : error, status is %02x\n",status);
3367#ifdef VBOX
3368 // Enable interrupts
3369 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3370#endif /* VBOX */
3371 return 3;
3372 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
3373 BX_DEBUG_ATA("ata_cmd_packet : DRQ not set (status %02x)\n", (unsigned) status);
3374#ifdef VBOX
3375 // Enable interrupts
3376 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3377#endif /* VBOX */
3378 return 4;
3379 }
3380
3381 // Normalize address
3382 cmdseg += (cmdoff / 16);
3383 cmdoff %= 16;
3384
3385 // Send command to device
3386ASM_START
3387 sti ;; enable higher priority interrupts
3388
3389 push bp
3390 mov bp, sp
3391
3392 mov si, _ata_cmd_packet.cmdoff + 2[bp]
3393 mov ax, _ata_cmd_packet.cmdseg + 2[bp]
3394 mov cx, _ata_cmd_packet.cmdlen + 2[bp]
3395 mov es, ax ;; segment in es
3396
3397 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data write port
3398
3399 seg ES
3400 rep
3401 outsw ;; CX words transferred from port(DX) to ES:[SI]
3402
3403 pop bp
3404ASM_END
3405
3406 if (inout == ATA_DATA_NO) {
3407 status = inb(iobase1 + ATA_CB_STAT);
3408 }
3409 else {
3410 while (1) {
3411
3412#ifdef VBOX
3413 while (1) {
3414 status = inb(iobase1 + ATA_CB_STAT);
3415 if ( !(status & ATA_CB_STAT_BSY) ) break;
3416 }
3417#else /* VBOX */
3418 status = inb(iobase1 + ATA_CB_STAT);
3419#endif /* VBOX */
3420
3421 // Check if command completed
3422 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_DRQ) ) ==0 ) break;
3423
3424 if (status & ATA_CB_STAT_ERR) {
3425 BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status);
3426#ifdef VBOX
3427 // Enable interrupts
3428 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3429#endif /* VBOX */
3430 return 3;
3431 }
3432
3433 // Device must be ready to send data
3434 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3435 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3436 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", status);
3437#ifdef VBOX
3438 // Enable interrupts
3439 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3440#endif /* VBOX */
3441 return 4;
3442 }
3443
3444 // Normalize address
3445 bufseg += (bufoff / 16);
3446 bufoff %= 16;
3447
3448 // Get the byte count
3449 lcount = ((Bit16u)(inb(iobase1 + ATA_CB_CH))<<8)+inb(iobase1 + ATA_CB_CL);
3450
3451 // adjust to read what we want
3452 if(header>lcount) {
3453 lbefore=lcount;
3454 header-=lcount;
3455 lcount=0;
3456 }
3457 else {
3458 lbefore=header;
3459 header=0;
3460 lcount-=lbefore;
3461 }
3462
3463 if(lcount>length) {
3464 lafter=lcount-length;
3465 lcount=length;
3466 length=0;
3467 }
3468 else {
3469 lafter=0;
3470 length-=lcount;
3471 }
3472
3473 // Save byte count
3474 count = lcount;
3475
3476 BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore+lcount+lafter,lbefore,lcount,lafter);
3477 BX_DEBUG_ATA("to 0x%04x:0x%04x\n",bufseg,bufoff);
3478
3479 // If counts not dividable by 4, use 16bits mode
3480 lmode = mode;
3481 if (lbefore & 0x03) lmode=ATA_MODE_PIO16;
3482 if (lcount & 0x03) lmode=ATA_MODE_PIO16;
3483 if (lafter & 0x03) lmode=ATA_MODE_PIO16;
3484
3485 // adds an extra byte if count are odd. before is always even
3486 if (lcount & 0x01) {
3487 lcount+=1;
3488 if ((lafter > 0) && (lafter & 0x01)) {
3489 lafter-=1;
3490 }
3491 }
3492
3493 if (lmode == ATA_MODE_PIO32) {
3494 lcount>>=2; lbefore>>=2; lafter>>=2;
3495 }
3496 else {
3497 lcount>>=1; lbefore>>=1; lafter>>=1;
3498 }
3499
3500 ; // FIXME bcc bug
3501
3502ASM_START
3503 push bp
3504 mov bp, sp
3505
3506 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data read port
3507
3508 mov cx, _ata_cmd_packet.lbefore + 2[bp]
3509 jcxz ata_packet_no_before
3510
3511 mov ah, _ata_cmd_packet.lmode + 2[bp]
3512 cmp ah, #ATA_MODE_PIO32
3513 je ata_packet_in_before_32
3514
3515ata_packet_in_before_16:
3516 in ax, dx
3517 loop ata_packet_in_before_16
3518 jmp ata_packet_no_before
3519
3520ata_packet_in_before_32:
3521 push eax
3522ata_packet_in_before_32_loop:
3523 in eax, dx
3524 loop ata_packet_in_before_32_loop
3525 pop eax
3526
3527ata_packet_no_before:
3528 mov cx, _ata_cmd_packet.lcount + 2[bp]
3529 jcxz ata_packet_after
3530
3531 mov di, _ata_cmd_packet.bufoff + 2[bp]
3532 mov ax, _ata_cmd_packet.bufseg + 2[bp]
3533 mov es, ax
3534
3535 mov ah, _ata_cmd_packet.lmode + 2[bp]
3536 cmp ah, #ATA_MODE_PIO32
3537 je ata_packet_in_32
3538
3539ata_packet_in_16:
3540 rep
3541 insw ;; CX words transferred tp port(DX) to ES:[DI]
3542 jmp ata_packet_after
3543
3544ata_packet_in_32:
3545 rep
3546 insd ;; CX dwords transferred to port(DX) to ES:[DI]
3547
3548ata_packet_after:
3549 mov cx, _ata_cmd_packet.lafter + 2[bp]
3550 jcxz ata_packet_done
3551
3552 mov ah, _ata_cmd_packet.lmode + 2[bp]
3553 cmp ah, #ATA_MODE_PIO32
3554 je ata_packet_in_after_32
3555
3556ata_packet_in_after_16:
3557 in ax, dx
3558 loop ata_packet_in_after_16
3559 jmp ata_packet_done
3560
3561ata_packet_in_after_32:
3562 push eax
3563ata_packet_in_after_32_loop:
3564 in eax, dx
3565 loop ata_packet_in_after_32_loop
3566 pop eax
3567
3568ata_packet_done:
3569 pop bp
3570ASM_END
3571
3572 // Compute new buffer address
3573 bufoff += count;
3574
3575 // Save transferred bytes count
3576 transfer += count;
3577 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,transfer);
3578 }
3579 }
3580
3581 // Final check, device must be ready
3582 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3583 != ATA_CB_STAT_RDY ) {
3584 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", (unsigned) status);
3585#ifdef VBOX
3586 // Enable interrupts
3587 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3588#endif /* VBOX */
3589 return 4;
3590 }
3591
3592 // Enable interrupts
3593 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3594 return 0;
3595}
3596
3597// ---------------------------------------------------------------------------
3598// End of ATA/ATAPI Driver
3599// ---------------------------------------------------------------------------
3600
3601// ---------------------------------------------------------------------------
3602// Start of ATA/ATAPI generic functions
3603// ---------------------------------------------------------------------------
3604
3605#if 0 // currently unused
3606 Bit16u
3607atapi_get_sense(device)
3608 Bit16u device;
3609{
3610 Bit8u atacmd[12];
3611 Bit8u buffer[16];
3612 Bit8u i;
3613
3614 memsetb(get_SS(),atacmd,0,12);
3615
3616 // Request SENSE
3617 atacmd[0]=0x03;
3618 atacmd[4]=0x20;
3619 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 16L, ATA_DATA_IN, get_SS(), buffer) != 0)
3620 return 0x0002;
3621
3622 if ((buffer[0] & 0x7e) == 0x70) {
3623 return (((Bit16u)buffer[2]&0x0f)*0x100)+buffer[12];
3624 }
3625
3626 return 0;
3627}
3628
3629 Bit16u
3630atapi_is_ready(device)
3631 Bit16u device;
3632{
3633 Bit8u atacmd[12];
3634 Bit8u buffer[];
3635
3636 memsetb(get_SS(),atacmd,0,12);
3637
3638 // Test Unit Ready
3639 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3640 return 0x000f;
3641
3642 if (atapi_get_sense(device) !=0 ) {
3643 memsetb(get_SS(),atacmd,0,12);
3644
3645 // try to send Test Unit Ready again
3646 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3647 return 0x000f;
3648
3649 return atapi_get_sense(device);
3650 }
3651 return 0;
3652}
3653#endif
3654
3655 Bit16u
3656atapi_is_cdrom(device)
3657 Bit8u device;
3658{
3659 Bit16u ebda_seg=read_word(0x0040,0x000E);
3660
3661 if (device >= BX_MAX_ATA_DEVICES)
3662 return 0;
3663
3664 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_ATAPI)
3665 return 0;
3666
3667 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].device) != ATA_DEVICE_CDROM)
3668 return 0;
3669
3670 return 1;
3671}
3672
3673// ---------------------------------------------------------------------------
3674// End of ATA/ATAPI generic functions
3675// ---------------------------------------------------------------------------
3676
3677#endif // BX_USE_ATADRV
3678
3679#if BX_ELTORITO_BOOT
3680
3681// ---------------------------------------------------------------------------
3682// Start of El-Torito boot functions
3683// ---------------------------------------------------------------------------
3684
3685 void
3686cdemu_init()
3687{
3688 Bit16u ebda_seg=read_word(0x0040,0x000E);
3689
3690 // the only important data is this one for now
3691 write_byte(ebda_seg,&EbdaData->cdemu.active,0x00);
3692}
3693
3694 Bit8u
3695cdemu_isactive()
3696{
3697 Bit16u ebda_seg=read_word(0x0040,0x000E);
3698
3699 return(read_byte(ebda_seg,&EbdaData->cdemu.active));
3700}
3701
3702 Bit8u
3703cdemu_emulated_drive()
3704{
3705 Bit16u ebda_seg=read_word(0x0040,0x000E);
3706
3707 return(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
3708}
3709
3710static char isotag[6]="CD001";
3711static char eltorito[24]="EL TORITO SPECIFICATION";
3712//
3713// Returns ah: emulated drive, al: error code
3714//
3715 Bit16u
3716cdrom_boot()
3717{
3718 Bit16u ebda_seg=read_word(0x0040,0x000E);
3719 Bit8u atacmd[12], buffer[2048];
3720 Bit32u lba;
3721 Bit16u boot_segment, nbsectors, i, error;
3722 Bit8u device;
3723#ifdef VBOX
3724 Bit8u read_try;
3725#endif /* VBOX */
3726
3727 // Find out the first cdrom
3728 for (device=0; device<BX_MAX_ATA_DEVICES;device++) {
3729 if (atapi_is_cdrom(device)) break;
3730 }
3731
3732 // if not found
3733 if(device >= BX_MAX_ATA_DEVICES) return 2;
3734
3735 // Read the Boot Record Volume Descriptor
3736 memsetb(get_SS(),atacmd,0,12);
3737 atacmd[0]=0x28; // READ command
3738 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3739 atacmd[8]=(0x01 & 0x00ff); // Sectors
3740 atacmd[2]=(0x11 & 0xff000000) >> 24; // LBA
3741 atacmd[3]=(0x11 & 0x00ff0000) >> 16;
3742 atacmd[4]=(0x11 & 0x0000ff00) >> 8;
3743 atacmd[5]=(0x11 & 0x000000ff);
3744#ifdef VBOX
3745 for (read_try = 0; read_try <= 4; read_try++)
3746 {
3747 error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer);
3748 if (!error)
3749 break;
3750 }
3751 if (error)
3752 return 3;
3753#else /* !VBOX */
3754 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3755 return 3;
3756#endif /* !VBOX */
3757
3758 // Validity checks
3759 if(buffer[0]!=0)return 4;
3760 for(i=0;i<5;i++){
3761 if(buffer[1+i]!=read_byte(0xf000,&isotag[i]))return 5;
3762 }
3763 for(i=0;i<23;i++)
3764 if(buffer[7+i]!=read_byte(0xf000,&eltorito[i]))return 6;
3765
3766 // ok, now we calculate the Boot catalog address
3767 lba=buffer[0x4A]*0x1000000+buffer[0x49]*0x10000+buffer[0x48]*0x100+buffer[0x47];
3768
3769 // And we read the Boot Catalog
3770 memsetb(get_SS(),atacmd,0,12);
3771 atacmd[0]=0x28; // READ command
3772 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3773 atacmd[8]=(0x01 & 0x00ff); // Sectors
3774 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3775 atacmd[3]=(lba & 0x00ff0000) >> 16;
3776 atacmd[4]=(lba & 0x0000ff00) >> 8;
3777 atacmd[5]=(lba & 0x000000ff);
3778 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3779 return 7;
3780
3781 // Validation entry
3782 if(buffer[0x00]!=0x01)return 8; // Header
3783 if(buffer[0x01]!=0x00)return 9; // Platform
3784 if(buffer[0x1E]!=0x55)return 10; // key 1
3785 if(buffer[0x1F]!=0xAA)return 10; // key 2
3786
3787 // Initial/Default Entry
3788 if(buffer[0x20]!=0x88)return 11; // Bootable
3789
3790 write_byte(ebda_seg,&EbdaData->cdemu.media,buffer[0x21]);
3791 if(buffer[0x21]==0){
3792 // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
3793 // Win2000 cd boot needs to know it booted from cd
3794 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0xE0);
3795 }
3796 else if(buffer[0x21]<4)
3797 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x00);
3798 else
3799 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x80);
3800
3801 write_byte(ebda_seg,&EbdaData->cdemu.controller_index,device/2);
3802 write_byte(ebda_seg,&EbdaData->cdemu.device_spec,device%2);
3803
3804 boot_segment=buffer[0x23]*0x100+buffer[0x22];
3805 if(boot_segment==0x0000)boot_segment=0x07C0;
3806
3807 write_word(ebda_seg,&EbdaData->cdemu.load_segment,boot_segment);
3808 write_word(ebda_seg,&EbdaData->cdemu.buffer_segment,0x0000);
3809
3810 nbsectors=buffer[0x27]*0x100+buffer[0x26];
3811 write_word(ebda_seg,&EbdaData->cdemu.sector_count,nbsectors);
3812
3813 lba=buffer[0x2B]*0x1000000+buffer[0x2A]*0x10000+buffer[0x29]*0x100+buffer[0x28];
3814 write_dword(ebda_seg,&EbdaData->cdemu.ilba,lba);
3815
3816 // And we read the image in memory
3817 memsetb(get_SS(),atacmd,0,12);
3818 atacmd[0]=0x28; // READ command
3819 atacmd[7]=((1+(nbsectors-1)/4) & 0xff00) >> 8; // Sectors
3820 atacmd[8]=((1+(nbsectors-1)/4) & 0x00ff); // Sectors
3821 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3822 atacmd[3]=(lba & 0x00ff0000) >> 16;
3823 atacmd[4]=(lba & 0x0000ff00) >> 8;
3824 atacmd[5]=(lba & 0x000000ff);
3825 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, nbsectors*512L, ATA_DATA_IN, boot_segment,0)) != 0)
3826 return 12;
3827
3828 // Remember the media type
3829 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
3830 case 0x01: // 1.2M floppy
3831 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,15);
3832 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3833 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3834 break;
3835 case 0x02: // 1.44M floppy
3836 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,18);
3837 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3838 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3839 break;
3840 case 0x03: // 2.88M floppy
3841 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,36);
3842 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3843 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3844 break;
3845 case 0x04: // Harddrive
3846 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,read_byte(boot_segment,446+6)&0x3f);
3847 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,
3848 (read_byte(boot_segment,446+6)<<2) + read_byte(boot_segment,446+7) + 1);
3849 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,read_byte(boot_segment,446+5) + 1);
3850 break;
3851 }
3852
3853 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0) {
3854 // Increase bios installed hardware number of devices
3855 if(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)==0x00)
3856 write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
3857 else
3858 write_byte(ebda_seg, &EbdaData->ata.hdcount, read_byte(ebda_seg, &EbdaData->ata.hdcount) + 1);
3859 }
3860
3861
3862 // everything is ok, so from now on, the emulation is active
3863 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0)
3864 write_byte(ebda_seg,&EbdaData->cdemu.active,0x01);
3865
3866 // return the boot drive + no error
3867 return (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)*0x100)+0;
3868}
3869
3870// ---------------------------------------------------------------------------
3871// End of El-Torito boot functions
3872// ---------------------------------------------------------------------------
3873#endif // BX_ELTORITO_BOOT
3874
3875#ifdef VBOX_WITH_SCSI
3876# include "scsi.c"
3877#endif
3878
3879#ifdef VBOX_WITH_BIOS_AHCI
3880# include "ahci.c"
3881#endif
3882
3883 void
3884int14_function(regs, ds, iret_addr)
3885 pusha_regs_t regs; // regs pushed from PUSHA instruction
3886 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
3887 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
3888{
3889 Bit16u addr,timer,val16;
3890 Bit8u timeout;
3891
3892 ASM_START
3893 sti
3894 ASM_END
3895
3896 addr = read_word(0x0040, (regs.u.r16.dx << 1));
3897 timeout = read_byte(0x0040, 0x007C + regs.u.r16.dx);
3898 if ((regs.u.r16.dx < 4) && (addr > 0)) {
3899 switch (regs.u.r8.ah) {
3900 case 0:
3901 outb(addr+3, inb(addr+3) | 0x80);
3902 if (regs.u.r8.al & 0xE0 == 0) {
3903 outb(addr, 0x17);
3904 outb(addr+1, 0x04);
3905 } else {
3906 val16 = 0x600 >> ((regs.u.r8.al & 0xE0) >> 5);
3907 outb(addr, val16 & 0xFF);
3908 outb(addr+1, val16 >> 8);
3909 }
3910 outb(addr+3, regs.u.r8.al & 0x1F);
3911 regs.u.r8.ah = inb(addr+5);
3912 regs.u.r8.al = inb(addr+6);
3913 ClearCF(iret_addr.flags);
3914 break;
3915 case 1:
3916 timer = read_word(0x0040, 0x006C);
3917 while (((inb(addr+5) & 0x60) != 0x60) && (timeout)) {
3918 val16 = read_word(0x0040, 0x006C);
3919 if (val16 != timer) {
3920 timer = val16;
3921 timeout--;
3922 }
3923 }
3924 if (timeout) outb(addr, regs.u.r8.al);
3925 regs.u.r8.ah = inb(addr+5);
3926 if (!timeout) regs.u.r8.ah |= 0x80;
3927 ClearCF(iret_addr.flags);
3928 break;
3929 case 2:
3930 timer = read_word(0x0040, 0x006C);
3931 while (((inb(addr+5) & 0x01) == 0) && (timeout)) {
3932 val16 = read_word(0x0040, 0x006C);
3933 if (val16 != timer) {
3934 timer = val16;
3935 timeout--;
3936 }
3937 }
3938 if (timeout) {
3939 regs.u.r8.ah = 0;
3940 regs.u.r8.al = inb(addr);
3941 } else {
3942 regs.u.r8.ah = inb(addr+5);
3943 }
3944 ClearCF(iret_addr.flags);
3945 break;
3946 case 3:
3947 regs.u.r8.ah = inb(addr+5);
3948 regs.u.r8.al = inb(addr+6);
3949 ClearCF(iret_addr.flags);
3950 break;
3951 default:
3952 SetCF(iret_addr.flags); // Unsupported
3953 }
3954 } else {
3955 SetCF(iret_addr.flags); // Unsupported
3956 }
3957}
3958
3959 void
3960int15_function(regs, ES, DS, FLAGS)
3961 pusha_regs_t regs; // REGS pushed via pusha
3962 Bit16u ES, DS, FLAGS;
3963{
3964 Bit16u ebda_seg=read_word(0x0040,0x000E);
3965 bx_bool prev_a20_enable;
3966 Bit16u base15_00;
3967 Bit8u base23_16;
3968 Bit16u ss;
3969 Bit16u BX,CX,DX;
3970
3971 Bit16u bRegister;
3972 Bit8u irqDisable;
3973
3974BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
3975
3976 switch (regs.u.r8.ah) {
3977#ifdef VBOX
3978 case 0x00: /* assorted functions */
3979 if (regs.u.r8.al != 0xc0)
3980 goto undecoded;
3981 /* GRUB calls int15 with ax=0x00c0 to get the ROM configuration table,
3982 * which we don't support, but logging that event is annoying. In fact
3983 * it is likely that they just misread some specs, because there is a
3984 * int15 BIOS function AH=0xc0 which sounds quite similar to what GRUB
3985 * wants to achieve. */
3986 SET_CF();
3987 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3988 break;
3989#endif
3990 case 0x24: /* A20 Control */
3991 switch (regs.u.r8.al) {
3992 case 0x00:
3993 set_enable_a20(0);
3994 CLEAR_CF();
3995 regs.u.r8.ah = 0;
3996 break;
3997 case 0x01:
3998 set_enable_a20(1);
3999 CLEAR_CF();
4000 regs.u.r8.ah = 0;
4001 break;
4002 case 0x02:
4003 regs.u.r8.al = (inb(0x92) >> 1) & 0x01;
4004 CLEAR_CF();
4005 regs.u.r8.ah = 0;
4006 break;
4007 case 0x03:
4008 CLEAR_CF();
4009 regs.u.r8.ah = 0;
4010 regs.u.r16.bx = 3;
4011 break;
4012 default:
4013 BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs.u.r8.al);
4014 SET_CF();
4015 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4016 }
4017 break;
4018
4019 case 0x41:
4020 SET_CF();
4021 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4022 break;
4023
4024 case 0x4f:
4025 /* keyboard intercept */
4026#if BX_CPU < 2
4027 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4028#else
4029 // nop
4030#endif
4031 SET_CF();
4032 break;
4033
4034 case 0x52: // removable media eject
4035 CLEAR_CF();
4036 regs.u.r8.ah = 0; // "ok ejection may proceed"
4037 break;
4038
4039 case 0x83: {
4040 if( regs.u.r8.al == 0 ) {
4041 // Set Interval requested.
4042 if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
4043 // Interval not already set.
4044 write_byte( 0x40, 0xA0, 1 ); // Set status byte.
4045 write_word( 0x40, 0x98, ES ); // Byte location, segment
4046 write_word( 0x40, 0x9A, regs.u.r16.bx ); // Byte location, offset
4047 write_word( 0x40, 0x9C, regs.u.r16.dx ); // Low word, delay
4048 write_word( 0x40, 0x9E, regs.u.r16.cx ); // High word, delay.
4049 CLEAR_CF( );
4050 irqDisable = inb( 0xA1 );
4051 outb( 0xA1, irqDisable & 0xFE );
4052 bRegister = inb_cmos( 0xB ); // Unmask IRQ8 so INT70 will get through.
4053 outb_cmos( 0xB, bRegister | 0x40 ); // Turn on the Periodic Interrupt timer
4054 } else {
4055 // Interval already set.
4056 BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
4057 SET_CF();
4058 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4059 }
4060 } else if( regs.u.r8.al == 1 ) {
4061 // Clear Interval requested
4062 write_byte( 0x40, 0xA0, 0 ); // Clear status byte
4063 CLEAR_CF( );
4064 bRegister = inb_cmos( 0xB );
4065 outb_cmos( 0xB, bRegister & ~0x40 ); // Turn off the Periodic Interrupt timer
4066 } else {
4067 BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
4068 SET_CF();
4069 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4070 regs.u.r8.al--;
4071 }
4072
4073 break;
4074 }
4075
4076 case 0x87:
4077#if BX_CPU < 3
4078# error "Int15 function 87h not supported on < 80386"
4079#endif
4080 // +++ should probably have descriptor checks
4081 // +++ should have exception handlers
4082
4083 // turn off interrupts
4084ASM_START
4085 cli
4086ASM_END
4087
4088 prev_a20_enable = set_enable_a20(1); // enable A20 line
4089
4090 // 128K max of transfer on 386+ ???
4091 // source == destination ???
4092
4093 // ES:SI points to descriptor table
4094 // offset use initially comments
4095 // ==============================================
4096 // 00..07 Unused zeros Null descriptor
4097 // 08..0f GDT zeros filled in by BIOS
4098 // 10..17 source ssssssss source of data
4099 // 18..1f dest dddddddd destination of data
4100 // 20..27 CS zeros filled in by BIOS
4101 // 28..2f SS zeros filled in by BIOS
4102
4103 //es:si
4104 //eeee0
4105 //0ssss
4106 //-----
4107
4108// check for access rights of source & dest here
4109
4110 // Initialize GDT descriptor
4111 base15_00 = (ES << 4) + regs.u.r16.si;
4112 base23_16 = ES >> 12;
4113 if (base15_00 < (ES<<4))
4114 base23_16++;
4115 write_word(ES, regs.u.r16.si+0x08+0, 47); // limit 15:00 = 6 * 8bytes/descriptor
4116 write_word(ES, regs.u.r16.si+0x08+2, base15_00);// base 15:00
4117 write_byte(ES, regs.u.r16.si+0x08+4, base23_16);// base 23:16
4118 write_byte(ES, regs.u.r16.si+0x08+5, 0x93); // access
4119 write_word(ES, regs.u.r16.si+0x08+6, 0x0000); // base 31:24/reserved/limit 19:16
4120
4121 // Initialize CS descriptor
4122 write_word(ES, regs.u.r16.si+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
4123 write_word(ES, regs.u.r16.si+0x20+2, 0x0000);// base 15:00
4124 write_byte(ES, regs.u.r16.si+0x20+4, 0x000f);// base 23:16
4125 write_byte(ES, regs.u.r16.si+0x20+5, 0x9b); // access
4126 write_word(ES, regs.u.r16.si+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
4127
4128 // Initialize SS descriptor
4129 ss = get_SS();
4130 base15_00 = ss << 4;
4131 base23_16 = ss >> 12;
4132 write_word(ES, regs.u.r16.si+0x28+0, 0xffff); // limit 15:00 = normal 64K limit
4133 write_word(ES, regs.u.r16.si+0x28+2, base15_00);// base 15:00
4134 write_byte(ES, regs.u.r16.si+0x28+4, base23_16);// base 23:16
4135 write_byte(ES, regs.u.r16.si+0x28+5, 0x93); // access
4136 write_word(ES, regs.u.r16.si+0x28+6, 0x0000); // base 31:24/reserved/limit 19:16
4137
4138 CX = regs.u.r16.cx;
4139ASM_START
4140 // Compile generates locals offset info relative to SP.
4141 // Get CX (word count) from stack.
4142 mov bx, sp
4143 SEG SS
4144 mov cx, _int15_function.CX [bx]
4145
4146 // since we need to set SS:SP, save them to the BDA
4147 // for future restore
4148 push eax
4149 xor eax, eax
4150 mov ds, ax
4151 mov 0x0469, ss
4152 mov 0x0467, sp
4153
4154 SEG ES
4155 lgdt [si + 0x08]
4156 SEG CS
4157 lidt [pmode_IDT_info]
4158 ;; perhaps do something with IDT here
4159
4160 ;; set PE bit in CR0
4161 mov eax, cr0
4162 or al, #0x01
4163 mov cr0, eax
4164 ;; far jump to flush CPU queue after transition to protected mode
4165 JMP_AP(0x0020, protected_mode)
4166
4167protected_mode:
4168 ;; GDT points to valid descriptor table, now load SS, DS, ES
4169 mov ax, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
4170 mov ss, ax
4171 mov ax, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
4172 mov ds, ax
4173 mov ax, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
4174 mov es, ax
4175 xor si, si
4176 xor di, di
4177 cld
4178 rep
4179 movsw ;; move CX words from DS:SI to ES:DI
4180
4181 ;; make sure DS and ES limits are 64KB
4182 mov ax, #0x28
4183 mov ds, ax
4184 mov es, ax
4185
4186 ;; reset PG bit in CR0 ???
4187 mov eax, cr0
4188 and al, #0xFE
4189 mov cr0, eax
4190
4191 ;; far jump to flush CPU queue after transition to real mode
4192 JMP_AP(0xf000, real_mode)
4193
4194real_mode:
4195 ;; restore IDT to normal real-mode defaults
4196 SEG CS
4197 lidt [rmode_IDT_info]
4198
4199 // restore SS:SP from the BDA
4200 xor ax, ax
4201 mov ds, ax
4202 mov ss, 0x0469
4203 mov sp, 0x0467
4204 pop eax
4205ASM_END
4206
4207 set_enable_a20(prev_a20_enable);
4208
4209 // turn back on interrupts
4210ASM_START
4211 sti
4212ASM_END
4213
4214 regs.u.r8.ah = 0;
4215 CLEAR_CF();
4216 break;
4217
4218
4219 case 0x88:
4220 // Get the amount of extended memory (above 1M)
4221#if BX_CPU < 2
4222 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4223 SET_CF();
4224#else
4225 regs.u.r8.al = inb_cmos(0x30);
4226 regs.u.r8.ah = inb_cmos(0x31);
4227
4228 // According to Ralf Brown's interrupt the limit should be 15M,
4229 // but real machines mostly return max. 63M.
4230 if(regs.u.r16.ax > 0xffc0)
4231 regs.u.r16.ax = 0xffc0;
4232
4233 CLEAR_CF();
4234#endif
4235 break;
4236
4237#ifdef VBOX
4238 case 0x89:
4239 // Switch to Protected Mode.
4240 // ES:DI points to user-supplied GDT
4241 // BH/BL contains starting interrupt numbers for PIC0/PIC1
4242 // This subfunction does not return!
4243
4244// turn off interrupts
4245ASM_START
4246 cli
4247ASM_END
4248
4249 set_enable_a20(1); // enable A20 line; we're supposed to fail if that fails
4250
4251 // Initialize CS descriptor for BIOS
4252 write_word(ES, regs.u.r16.si+0x38+0, 0xffff);// limit 15:00 = normal 64K limit
4253 write_word(ES, regs.u.r16.si+0x38+2, 0x0000);// base 15:00
4254 write_byte(ES, regs.u.r16.si+0x38+4, 0x000f);// base 23:16 (hardcoded to f000:0000)
4255 write_byte(ES, regs.u.r16.si+0x38+5, 0x9b); // access
4256 write_word(ES, regs.u.r16.si+0x38+6, 0x0000);// base 31:24/reserved/limit 19:16
4257
4258 BX = regs.u.r16.bx;
4259ASM_START
4260 // Compiler generates locals offset info relative to SP.
4261 // Get BX (PIC offsets) from stack.
4262 mov bx, sp
4263 SEG SS
4264 mov bx, _int15_function.BX [bx]
4265
4266 // Program PICs
4267 mov al, #0x11 ; send initialisation commands
4268 out 0x20, al
4269 out 0xa0, al
4270 mov al, bh
4271 out 0x21, al
4272 mov al, bl
4273 out 0xa1, al
4274 mov al, #0x04
4275 out 0x21, al
4276 mov al, #0x02
4277 out 0xa1, al
4278 mov al, #0x01
4279 out 0x21, al
4280 out 0xa1, al
4281 mov al, #0xff ; mask all IRQs, user must re-enable
4282 out 0x21, al
4283 out 0xa1, al
4284
4285 // Load GDT and IDT from supplied data
4286 SEG ES
4287 lgdt [si + 0x08]
4288 SEG ES
4289 lidt [si + 0x10]
4290
4291 // set PE bit in CR0
4292 mov eax, cr0
4293 or al, #0x01
4294 mov cr0, eax
4295 // far jump to flush CPU queue after transition to protected mode
4296 JMP_AP(0x0038, protmode_switch)
4297
4298protmode_switch:
4299 ;; GDT points to valid descriptor table, now load SS, DS, ES
4300 mov ax, #0x28
4301 mov ss, ax
4302 mov ax, #0x18
4303 mov ds, ax
4304 mov ax, #0x20
4305 mov es, ax
4306
4307 // unwind the stack - this will break if calling sequence changes!
4308 mov sp,bp
4309 add sp,#4 ; skip return address
4310 popa ; restore regs
4311 pop ax ; skip saved es
4312 pop ax ; skip saved ds
4313 pop ax ; skip saved flags
4314
4315 // return to caller - note that we do not use IRET because
4316 // we cannot enable interrupts
4317 pop cx ; get return offset
4318 pop ax ; skip return segment
4319 pop ax ; skip flags
4320 mov ax, #0x30 ; ah must be 0 on successful exit
4321 push ax
4322 push cx ; re-create modified ret address on stack
4323 retf
4324
4325ASM_END
4326
4327 break;
4328#endif /* VBOX */
4329
4330 case 0x90:
4331 /* Device busy interrupt. Called by Int 16h when no key available */
4332 break;
4333
4334 case 0x91:
4335 /* Interrupt complete. Called by Int 16h when key becomes available */
4336 break;
4337
4338 case 0xbf:
4339 BX_INFO("*** int 15h function AH=bf not yet supported!\n");
4340 SET_CF();
4341 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4342 break;
4343
4344 case 0xC0:
4345#if 0
4346 SET_CF();
4347 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4348 break;
4349#endif
4350 CLEAR_CF();
4351 regs.u.r8.ah = 0;
4352 regs.u.r16.bx = BIOS_CONFIG_TABLE;
4353 ES = 0xF000;
4354 break;
4355
4356 case 0xc1:
4357 ES = ebda_seg;
4358 CLEAR_CF();
4359 break;
4360
4361 case 0xd8:
4362 bios_printf(BIOS_PRINTF_DEBUG, "EISA BIOS not present\n");
4363 SET_CF();
4364 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4365 break;
4366
4367#ifdef VBOX
4368 /* Make the BIOS warning for pretty much every Linux kernel start
4369 * disappear - it calls with ax=0xe980 to figure out SMI info. */
4370 case 0xe9: /* SMI functions (SpeedStep and similar things) */
4371 SET_CF();
4372 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4373 break;
4374 case 0xec: /* AMD64 target operating mode callback */
4375 if (regs.u.r8.al != 0)
4376 goto undecoded;
4377 regs.u.r8.ah = 0;
4378 if (regs.u.r8.bl >= 1 && regs.u.r8.bl <= 3)
4379 CLEAR_CF(); /* Accepted value. */
4380 else
4381 SET_CF(); /* Reserved, error. */
4382 break;
4383undecoded:
4384#endif /* VBOX */
4385 default:
4386 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4387 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4388 SET_CF();
4389 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4390 break;
4391 }
4392}
4393
4394#if BX_USE_PS2_MOUSE
4395 void
4396int15_function_mouse(regs, ES, DS, FLAGS)
4397 pusha_regs_t regs; // REGS pushed via pusha
4398 Bit16u ES, DS, FLAGS;
4399{
4400 Bit16u ebda_seg=read_word(0x0040,0x000E);
4401 Bit8u mouse_flags_1, mouse_flags_2;
4402 Bit16u mouse_driver_seg;
4403 Bit16u mouse_driver_offset;
4404 Bit8u mouse_cmd;
4405 Bit8u ret, mouse_data1, mouse_data2, mouse_data3;
4406
4407BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4408
4409 switch (regs.u.r8.ah) {
4410 case 0xC2:
4411 // Return Codes status in AH
4412 // =========================
4413 // 00: success
4414 // 01: invalid subfunction (AL > 7)
4415 // 02: invalid input value (out of allowable range)
4416 // 03: interface error
4417 // 04: resend command received from mouse controller,
4418 // device driver should attempt command again
4419 // 05: cannot enable mouse, since no far call has been installed
4420 // 80/86: mouse service not implemented
4421
4422 if (regs.u.r8.al > 7) {
4423BX_DEBUG_INT15("unsupported subfn\n");
4424 // invalid function
4425 SET_CF();
4426 regs.u.r8.ah = 1;
4427 break;
4428 }
4429
4430 // Valid subfn; disable AUX input and IRQ12, assume no error
4431 set_kbd_command_byte(0x65);
4432 CLEAR_CF();
4433 regs.u.r8.ah = 0;
4434
4435 switch (regs.u.r8.al) {
4436 case 0: // Disable/Enable Mouse
4437BX_DEBUG_INT15("case 0: ");
4438 if (regs.u.r8.bh > 1) {
4439 BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs.u.r8.bh);
4440 // invalid subfunction
4441 SET_CF();
4442 regs.u.r8.ah = 1;
4443 break;
4444 }
4445 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4446 if ( (mouse_flags_2 & 0x80) == 0 ) {
4447 BX_DEBUG_INT15("INT 15h C2 Enable/Disable Mouse, no far call handler\n");
4448 SET_CF();
4449 regs.u.r8.ah = 5; // no far call installed
4450 break;
4451 }
4452 if (regs.u.r8.bh == 0) {
4453BX_DEBUG_INT15("Disable Mouse\n");
4454 mouse_cmd = 0xF5; // disable mouse command
4455 } else {
4456BX_DEBUG_INT15("Enable Mouse\n");
4457 mouse_cmd = 0xF4; // enable mouse command
4458 }
4459
4460 ret = send_to_mouse_ctrl(mouse_cmd); // disable mouse command
4461 if (ret == 0) {
4462 ret = get_mouse_data(&mouse_data1);
4463 if ( (ret == 0) || (mouse_data1 == 0xFA) ) {
4464 // success
4465 break;
4466 }
4467 }
4468
4469 // interface error
4470 SET_CF();
4471 regs.u.r8.ah = 3;
4472 break;
4473
4474 case 5: // Initialize Mouse
4475 // Valid package sizes are 1 to 8
4476 if ( (regs.u.r8.bh < 1) || (regs.u.r8.bh > 8) ) {
4477 SET_CF();
4478 regs.u.r8.ah = 2; // invalid input
4479 break;
4480 }
4481 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4482 mouse_flags_2 = (mouse_flags_2 & 0xf8) | (regs.u.r8.bh - 1);
4483 write_byte(ebda_seg, 0x0027, mouse_flags_2);
4484 // fall through!
4485
4486 case 1: // Reset Mouse
4487BX_DEBUG_INT15("case 1 or 5:\n");
4488 // clear current package byte index
4489 mouse_flags_1 = read_byte(ebda_seg, 0x0026);
4490 mouse_flags_1 = mouse_flags_1 & 0xf8;
4491 write_byte(ebda_seg, 0x0026, mouse_flags_1);
4492 ret = send_to_mouse_ctrl(0xFF); // reset mouse command
4493 if (ret == 0) {
4494 ret = get_mouse_data(&mouse_data3);
4495 // if no mouse attached, it will return RESEND
4496 if (mouse_data3 == 0xfe) {
4497 SET_CF();
4498 regs.u.r8.ah = 4; // resend
4499 break;
4500 }
4501 if (mouse_data3 != 0xfa)
4502 BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3);
4503 if ( ret == 0 ) {
4504 ret = get_mouse_data(&mouse_data1);
4505 if ( ret == 0 ) {
4506 ret = get_mouse_data(&mouse_data2);
4507 if ( ret == 0 ) {
4508 // success
4509 regs.u.r8.bl = mouse_data1;
4510 regs.u.r8.bh = mouse_data2;
4511 break;
4512 }
4513 }
4514 }
4515 }
4516
4517 // interface error
4518 SET_CF();
4519 regs.u.r8.ah = 3;
4520 break;
4521
4522 case 2: // Set Sample Rate
4523BX_DEBUG_INT15("case 2:\n");
4524 switch (regs.u.r8.bh) {
4525 case 0: mouse_data1 = 10; break; // 10 reports/sec
4526 case 1: mouse_data1 = 20; break; // 20 reports/sec
4527 case 2: mouse_data1 = 40; break; // 40 reports/sec
4528 case 3: mouse_data1 = 60; break; // 60 reports/sec
4529 case 4: mouse_data1 = 80; break; // 80 reports/sec
4530 case 5: mouse_data1 = 100; break; // 100 reports/sec (default)
4531 case 6: mouse_data1 = 200; break; // 200 reports/sec
4532 default: mouse_data1 = 0;
4533 }
4534 if (mouse_data1 > 0) {
4535 ret = send_to_mouse_ctrl(0xF3); // set sample rate command
4536 if (ret == 0) {
4537 ret = get_mouse_data(&mouse_data2);
4538 ret = send_to_mouse_ctrl(mouse_data1);
4539 ret = get_mouse_data(&mouse_data2);
4540 // success
4541 } else {
4542 // interface error
4543 SET_CF();
4544 regs.u.r8.ah = 3;
4545 }
4546 } else {
4547 // invalid input
4548 SET_CF();
4549 regs.u.r8.ah = 2;
4550 }
4551 break;
4552
4553 case 3: // Set Resolution
4554BX_DEBUG_INT15("case 3:\n");
4555 // BX:
4556 // 0 = 25 dpi, 1 count per millimeter
4557 // 1 = 50 dpi, 2 counts per millimeter
4558 // 2 = 100 dpi, 4 counts per millimeter
4559 // 3 = 200 dpi, 8 counts per millimeter
4560 if (regs.u.r8.bh < 4) {
4561 ret = send_to_mouse_ctrl(0xE8); // set resolution command
4562 if (ret == 0) {
4563 ret = get_mouse_data(&mouse_data1);
4564 if (mouse_data1 != 0xfa)
4565 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4566 ret = send_to_mouse_ctrl(regs.u.r8.bh);
4567 ret = get_mouse_data(&mouse_data1);
4568 if (mouse_data1 != 0xfa)
4569 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4570 // success
4571 } else {
4572 // interface error
4573 SET_CF();
4574 regs.u.r8.ah = 3;
4575 }
4576 } else {
4577 // invalid input
4578 SET_CF();
4579 regs.u.r8.ah = 2;
4580 }
4581 break;
4582
4583 case 4: // Get Device ID
4584BX_DEBUG_INT15("case 4:\n");
4585 ret = send_to_mouse_ctrl(0xF2); // get mouse ID command
4586 if (ret == 0) {
4587 ret = get_mouse_data(&mouse_data1);
4588 ret = get_mouse_data(&mouse_data2);
4589 regs.u.r8.bh = mouse_data2;
4590 // success
4591 } else {
4592 // interface error
4593 SET_CF();
4594 regs.u.r8.ah = 3;
4595 }
4596 break;
4597
4598 case 6: // Return Status & Set Scaling Factor...
4599BX_DEBUG_INT15("case 6:\n");
4600 switch (regs.u.r8.bh) {
4601 case 0: // Return Status
4602 ret = send_to_mouse_ctrl(0xE9); // get mouse info command
4603 if (ret == 0) {
4604 ret = get_mouse_data(&mouse_data1);
4605 if (mouse_data1 != 0xfa)
4606 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4607 if (ret == 0) {
4608 ret = get_mouse_data(&mouse_data1);
4609 if ( ret == 0 ) {
4610 ret = get_mouse_data(&mouse_data2);
4611 if ( ret == 0 ) {
4612 ret = get_mouse_data(&mouse_data3);
4613 if ( ret == 0 ) {
4614 regs.u.r8.bl = mouse_data1;
4615 regs.u.r8.cl = mouse_data2;
4616 regs.u.r8.dl = mouse_data3;
4617 // success
4618 break;
4619 }
4620 }
4621 }
4622 }
4623 }
4624
4625 // interface error
4626 SET_CF();
4627 regs.u.r8.ah = 3;
4628 break;
4629
4630 case 1: // Set Scaling Factor to 1:1
4631 case 2: // Set Scaling Factor to 2:1
4632 if (regs.u.r8.bh == 1) {
4633 ret = send_to_mouse_ctrl(0xE6);
4634 } else {
4635 ret = send_to_mouse_ctrl(0xE7);
4636 }
4637 if (ret == 0) {
4638 get_mouse_data(&mouse_data1);
4639 ret = (mouse_data1 != 0xFA);
4640 }
4641 if (ret != 0) {
4642 // interface error
4643 SET_CF();
4644 regs.u.r8.ah = 3;
4645 }
4646 break;
4647
4648 default:
4649 BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs.u.r8.bh);
4650 // invalid subfunction
4651 SET_CF();
4652 regs.u.r8.ah = 1;
4653 }
4654 break;
4655
4656 case 7: // Set Mouse Handler Address
4657BX_DEBUG_INT15("case 7:\n");
4658 mouse_driver_seg = ES;
4659 mouse_driver_offset = regs.u.r16.bx;
4660 write_word(ebda_seg, 0x0022, mouse_driver_offset);
4661 write_word(ebda_seg, 0x0024, mouse_driver_seg);
4662 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4663 if (mouse_driver_offset == 0 && mouse_driver_seg == 0) {
4664 /* remove handler */
4665 if ( (mouse_flags_2 & 0x80) != 0 ) {
4666 mouse_flags_2 &= ~0x80;
4667 }
4668 }
4669 else {
4670 /* install handler */
4671 mouse_flags_2 |= 0x80;
4672 }
4673 write_byte(ebda_seg, 0x0027, mouse_flags_2);
4674 break;
4675
4676 default:
4677 BX_PANIC("INT 15h C2 default case entered\n");
4678 // invalid subfunction
4679 SET_CF();
4680 regs.u.r8.ah = 1;
4681 }
4682BX_DEBUG_INT15("returning cf = %u, ah = %02x\n", (unsigned)GET_CF(), (unsigned)regs.u.r8.ah);
4683 // Re-enable AUX input and IRQ12
4684 set_kbd_command_byte(0x47);
4685 break;
4686
4687 default:
4688 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4689 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4690 SET_CF();
4691 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4692 break;
4693 }
4694}
4695#endif // BX_USE_PS2_MOUSE
4696
4697
4698void set_e820_range(ES, DI, start, end, extra_start, extra_end, type)
4699 Bit16u ES;
4700 Bit16u DI;
4701 Bit32u start;
4702 Bit32u end;
4703 Bit8u extra_start;
4704 Bit8u extra_end;
4705 Bit16u type;
4706{
4707 write_word(ES, DI, start);
4708 write_word(ES, DI+2, start >> 16);
4709 write_word(ES, DI+4, extra_start);
4710 write_word(ES, DI+6, 0x00);
4711
4712 end -= start;
4713 extra_end -= extra_start;
4714 write_word(ES, DI+8, end);
4715 write_word(ES, DI+10, end >> 16);
4716 write_word(ES, DI+12, extra_end);
4717 write_word(ES, DI+14, 0x0000);
4718
4719 write_word(ES, DI+16, type);
4720 write_word(ES, DI+18, 0x0);
4721}
4722
4723 void
4724int15_function32(regs, ES, DS, FLAGS)
4725 pushad_regs_t regs; // REGS pushed via pushad
4726 Bit16u ES, DS, FLAGS;
4727{
4728 Bit32u extended_memory_size=0; // 64bits long
4729 Bit32u extra_lowbits_memory_size=0;
4730 Bit16u CX,DX;
4731 Bit8u extra_highbits_memory_size=0;
4732 Bit32u mcfgStart, mcfgSize;
4733
4734BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4735
4736 switch (regs.u.r8.ah) {
4737 case 0x86:
4738 // Wait for CX:DX microseconds. currently using the
4739 // refresh request port 0x61 bit4, toggling every 15usec
4740
4741 CX = regs.u.r16.cx;
4742 DX = regs.u.r16.dx;
4743
4744ASM_START
4745 sti
4746
4747 ;; Get the count in eax
4748 ;; VBOX: corrected _int15_function -> _int15_function32 here.
4749 mov bx, sp
4750 SEG SS
4751 mov ax, _int15_function32.CX [bx]
4752 shl eax, #16
4753 SEG SS
4754 mov ax, _int15_function32.DX [bx]
4755
4756 ;; convert to numbers of 15usec ticks
4757 mov ebx, #15
4758 xor edx, edx
4759 div eax, ebx
4760 mov ecx, eax
4761
4762 ;; wait for ecx number of refresh requests
4763 in al, #0x61
4764 and al,#0x10
4765 mov ah, al
4766
4767 or ecx, ecx
4768 je int1586_tick_end
4769int1586_tick:
4770 in al, #0x61
4771 and al,#0x10
4772 cmp al, ah
4773 je int1586_tick
4774 mov ah, al
4775 dec ecx
4776 jnz int1586_tick
4777int1586_tick_end:
4778ASM_END
4779
4780 break;
4781
4782 case 0xe8:
4783 switch(regs.u.r8.al)
4784 {
4785 case 0x20: // coded by osmaker aka K.J.
4786 if(regs.u.r32.edx == 0x534D4150)
4787 {
4788 extended_memory_size = inb_cmos(0x35);
4789 extended_memory_size <<= 8;
4790 extended_memory_size |= inb_cmos(0x34);
4791 extended_memory_size *= 64;
4792#ifndef VBOX /* The following excludes 0xf0000000 thru 0xffffffff. Trust DevPcBios.cpp to get this right. */
4793 // greater than EFF00000???
4794 if(extended_memory_size > 0x3bc000) {
4795 extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4796 }
4797#endif /* !VBOX */
4798 extended_memory_size *= 1024;
4799 extended_memory_size += (16L * 1024 * 1024);
4800
4801 if(extended_memory_size <= (16L * 1024 * 1024)) {
4802 extended_memory_size = inb_cmos(0x31);
4803 extended_memory_size <<= 8;
4804 extended_memory_size |= inb_cmos(0x30);
4805 extended_memory_size *= 1024;
4806 extended_memory_size += (1L * 1024 * 1024);
4807 }
4808
4809#ifdef VBOX /* We've already used the CMOS entries for SATA.
4810 BTW. This is the amount of memory above 4GB measured in 64KB units. */
4811 extra_lowbits_memory_size = inb_cmos(0x62);
4812 extra_lowbits_memory_size <<= 8;
4813 extra_lowbits_memory_size |= inb_cmos(0x61);
4814 extra_lowbits_memory_size <<= 16;
4815 extra_highbits_memory_size = inb_cmos(0x63);
4816 /* 0x64 and 0x65 can be used if we need to dig 1 TB or more at a later point. */
4817#else
4818 extra_lowbits_memory_size = inb_cmos(0x5c);
4819 extra_lowbits_memory_size <<= 8;
4820 extra_lowbits_memory_size |= inb_cmos(0x5b);
4821 extra_lowbits_memory_size *= 64;
4822 extra_lowbits_memory_size *= 1024;
4823 extra_highbits_memory_size = inb_cmos(0x5d);
4824#endif /* !VBOX */
4825
4826 mcfgStart = 0;
4827 mcfgSize = 0;
4828
4829 switch(regs.u.r16.bx)
4830 {
4831 case 0:
4832 set_e820_range(ES, regs.u.r16.di,
4833#ifndef VBOX /** @todo Upstream suggests the following, needs checking. (see next as well) */
4834 0x0000000L, 0x0009f000L, 0, 0, 1);
4835#else
4836 0x0000000L, 0x0009fc00L, 0, 0, 1);
4837#endif
4838 regs.u.r32.ebx = 1;
4839 break;
4840 case 1:
4841 set_e820_range(ES, regs.u.r16.di,
4842#ifndef VBOX /** @todo Upstream suggests the following, needs checking. (see next as well) */
4843 0x0009f000L, 0x000a0000L, 0, 0, 2);
4844#else
4845 0x0009fc00L, 0x000a0000L, 0, 0, 2);
4846#endif
4847 regs.u.r32.ebx = 2;
4848 break;
4849 case 2:
4850#ifdef VBOX
4851 /* Mark the BIOS as reserved. VBox doesn't currently
4852 * use the 0xe0000-0xeffff area. It does use the
4853 * 0xd0000-0xdffff area for the BIOS logo, but it's
4854 * not worth marking it as reserved. (this is not
4855 * true anymore because the VGA adapter handles the logo stuff)
4856 * The whole 0xe0000-0xfffff can be used for the BIOS.
4857 * Note that various
4858 * Windows versions don't accept (read: in debug builds
4859 * they trigger the "Too many similar traps" assertion)
4860 * a single reserved range from 0xd0000 to 0xffffff.
4861 * A 128K area starting from 0xd0000 works. */
4862 set_e820_range(ES, regs.u.r16.di,
4863 0x000f0000L, 0x00100000L, 0, 0, 2);
4864#else /* !VBOX */
4865 set_e820_range(ES, regs.u.r16.di,
4866 0x000e8000L, 0x00100000L, 0, 0, 2);
4867#endif /* !VBOX */
4868 regs.u.r32.ebx = 3;
4869 break;
4870 case 3:
4871#if BX_ROMBIOS32 || defined(VBOX)
4872 set_e820_range(ES, regs.u.r16.di,
4873 0x00100000L,
4874 extended_memory_size - ACPI_DATA_SIZE, 0, 0, 1);
4875 regs.u.r32.ebx = 4;
4876#else
4877 set_e820_range(ES, regs.u.r16.di,
4878 0x00100000L,
4879 extended_memory_size, 1);
4880 regs.u.r32.ebx = 5;
4881#endif
4882 break;
4883 case 4:
4884 set_e820_range(ES, regs.u.r16.di,
4885 extended_memory_size - ACPI_DATA_SIZE,
4886 extended_memory_size, 0, 0, 3); // ACPI RAM
4887 regs.u.r32.ebx = 5;
4888 break;
4889 case 5:
4890 /* 256KB BIOS area at the end of 4 GB */
4891#ifdef VBOX
4892 /* We don't set the end to 1GB here and rely on the 32-bit
4893 unsigned wrap around effect (0-0xfffc0000L). */
4894#endif
4895 set_e820_range(ES, regs.u.r16.di,
4896 0xfffc0000L, 0x00000000L, 0, 0, 2);
4897 if (mcfgStart != 0)
4898 regs.u.r32.ebx = 6;
4899 else
4900 {
4901 if (extra_highbits_memory_size || extra_lowbits_memory_size)
4902 regs.u.r32.ebx = 7;
4903 else
4904 regs.u.r32.ebx = 0;
4905 }
4906 break;
4907 case 6:
4908 /* PCI MMIO config space (MCFG) */
4909 set_e820_range(ES, regs.u.r16.di,
4910 mcfgStart, mcfgStart + mcfgSize, 0, 0, 2);
4911
4912 if (extra_highbits_memory_size || extra_lowbits_memory_size)
4913 regs.u.r32.ebx = 7;
4914 else
4915 regs.u.r32.ebx = 0;
4916 break;
4917 case 7:
4918#ifdef VBOX /* Don't succeeded if no memory above 4 GB. */
4919 /* Mapping of memory above 4 GB if present.
4920 Note: set_e820_range needs do no borrowing in the
4921 subtraction because of the nice numbers. */
4922 if (extra_highbits_memory_size || extra_lowbits_memory_size)
4923 {
4924 set_e820_range(ES, regs.u.r16.di,
4925 0x00000000L, extra_lowbits_memory_size,
4926 1 /*GB*/, extra_highbits_memory_size + 1 /*GB*/, 1);
4927 regs.u.r32.ebx = 0;
4928 }
4929 break;
4930 /* fall thru */
4931#else /* !VBOX */
4932 /* Mapping of memory above 4 GB */
4933 set_e820_range(ES, regs.u.r16.di, 0x00000000L,
4934 extra_lowbits_memory_size, 1, extra_highbits_memory_size
4935 + 1, 1);
4936 regs.u.r32.ebx = 0;
4937 break;
4938#endif /* !VBOX */
4939 default: /* AX=E820, DX=534D4150, BX unrecognized */
4940 goto int15_unimplemented;
4941 break;
4942 }
4943 regs.u.r32.eax = 0x534D4150;
4944 regs.u.r32.ecx = 0x14;
4945 CLEAR_CF();
4946 } else {
4947 // if DX != 0x534D4150)
4948 goto int15_unimplemented;
4949 }
4950 break;
4951
4952 case 0x01:
4953 // do we have any reason to fail here ?
4954 CLEAR_CF();
4955
4956 // my real system sets ax and bx to 0
4957 // this is confirmed by Ralph Brown list
4958 // but syslinux v1.48 is known to behave
4959 // strangely if ax is set to 0
4960 // regs.u.r16.ax = 0;
4961 // regs.u.r16.bx = 0;
4962
4963 // Get the amount of extended memory (above 1M)
4964 regs.u.r8.cl = inb_cmos(0x30);
4965 regs.u.r8.ch = inb_cmos(0x31);
4966
4967 // limit to 15M
4968 if(regs.u.r16.cx > 0x3c00)
4969 {
4970 regs.u.r16.cx = 0x3c00;
4971 }
4972
4973 // Get the amount of extended memory above 16M in 64k blocs
4974 regs.u.r8.dl = inb_cmos(0x34);
4975 regs.u.r8.dh = inb_cmos(0x35);
4976
4977 // Set configured memory equal to extended memory
4978 regs.u.r16.ax = regs.u.r16.cx;
4979 regs.u.r16.bx = regs.u.r16.dx;
4980 break;
4981 default: /* AH=0xE8?? but not implemented */
4982 goto int15_unimplemented;
4983 }
4984 break;
4985 int15_unimplemented:
4986 // fall into the default
4987 default:
4988 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4989 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4990 SET_CF();
4991 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4992 break;
4993 }
4994}
4995
4996 void
4997int16_function(DI, SI, BP, SP, BX, DX, CX, AX, FLAGS)
4998 Bit16u DI, SI, BP, SP, BX, DX, CX, AX, FLAGS;
4999{
5000 Bit8u scan_code, ascii_code, shift_flags, led_flags, count;
5001 Bit16u kbd_code, max;
5002
5003 BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX, BX, CX, DX);
5004
5005 shift_flags = read_byte(0x0040, 0x17);
5006 led_flags = read_byte(0x0040, 0x97);
5007 if ((((shift_flags >> 4) & 0x07) ^ (led_flags & 0x07)) != 0) {
5008ASM_START
5009 cli
5010ASM_END
5011 outb(0x60, 0xed);
5012 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
5013 if ((inb(0x60) == 0xfa)) {
5014 led_flags &= 0xf8;
5015 led_flags |= ((shift_flags >> 4) & 0x07);
5016 outb(0x60, led_flags & 0x07);
5017 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
5018 inb(0x60);
5019 write_byte(0x0040, 0x97, led_flags);
5020 }
5021ASM_START
5022 sti
5023ASM_END
5024 }
5025
5026 switch (GET_AH()) {
5027 case 0x00: /* read keyboard input */
5028
5029 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
5030 BX_PANIC("KBD: int16h: out of keyboard input\n");
5031 }
5032 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
5033 else if (ascii_code == 0xE0) ascii_code = 0;
5034 AX = (scan_code << 8) | ascii_code;
5035 break;
5036
5037 case 0x01: /* check keyboard status */
5038 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
5039 SET_ZF();
5040 return;
5041 }
5042 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
5043 else if (ascii_code == 0xE0) ascii_code = 0;
5044 AX = (scan_code << 8) | ascii_code;
5045 CLEAR_ZF();
5046 break;
5047
5048 case 0x02: /* get shift flag status */
5049 shift_flags = read_byte(0x0040, 0x17);
5050 SET_AL(shift_flags);
5051 break;
5052
5053 case 0x05: /* store key-stroke into buffer */
5054 if ( !enqueue_key(GET_CH(), GET_CL()) ) {
5055 SET_AL(1);
5056 }
5057 else {
5058 SET_AL(0);
5059 }
5060 break;
5061
5062 case 0x09: /* GET KEYBOARD FUNCTIONALITY */
5063 // bit Bochs Description
5064 // 7 0 reserved
5065 // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
5066 // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
5067 // 4 1 INT 16/AH=0Ah supported
5068 // 3 0 INT 16/AX=0306h supported
5069 // 2 0 INT 16/AX=0305h supported
5070 // 1 0 INT 16/AX=0304h supported
5071 // 0 0 INT 16/AX=0300h supported
5072 //
5073 SET_AL(0x30);
5074 break;
5075
5076 case 0x0A: /* GET KEYBOARD ID */
5077 count = 2;
5078 kbd_code = 0x0;
5079ASM_START
5080 cli // avoid racing the interrupt handler
5081ASM_END
5082 outb(0x60, 0xf2);
5083 /* Wait for data */
5084 max=0xffff;
5085 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
5086 if (max>0x0) {
5087 if ((inb(0x60) == 0xfa)) {
5088 do {
5089 max=0xffff;
5090 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
5091 if (max>0x0) {
5092 kbd_code >>= 8;
5093 kbd_code |= (inb(0x60) << 8);
5094 }
5095 } while (--count>0);
5096 }
5097 }
5098 BX=kbd_code;
5099 break;
5100
5101 case 0x10: /* read MF-II keyboard input */
5102
5103 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
5104 BX_PANIC("KBD: int16h: out of keyboard input\n");
5105 }
5106 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
5107 AX = (scan_code << 8) | ascii_code;
5108 break;
5109
5110 case 0x11: /* check MF-II keyboard status */
5111 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
5112 SET_ZF();
5113 return;
5114 }
5115 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
5116 AX = (scan_code << 8) | ascii_code;
5117 CLEAR_ZF();
5118 break;
5119
5120 case 0x12: /* get extended keyboard status */
5121 shift_flags = read_byte(0x0040, 0x17);
5122 SET_AL(shift_flags);
5123 shift_flags = read_byte(0x0040, 0x18) & 0x73;
5124 shift_flags |= read_byte(0x0040, 0x96) & 0x0c;
5125 SET_AH(shift_flags);
5126 BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX);
5127 break;
5128
5129 case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
5130 SET_AH(0x80); // function int16 ah=0x10-0x12 supported
5131 break;
5132
5133 case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
5134 // don't change AH : function int16 ah=0x20-0x22 NOT supported
5135 break;
5136
5137 case 0x6F:
5138 if (GET_AL() == 0x08)
5139 SET_AH(0x02); // unsupported, aka normal keyboard
5140
5141 default:
5142 BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
5143 }
5144}
5145
5146 unsigned int
5147dequeue_key(scan_code, ascii_code, incr)
5148 Bit8u *scan_code;
5149 Bit8u *ascii_code;
5150 unsigned int incr;
5151{
5152 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail;
5153 Bit16u ss;
5154 Bit8u acode, scode;
5155
5156#if BX_CPU < 2
5157 buffer_start = 0x001E;
5158 buffer_end = 0x003E;
5159#else
5160 buffer_start = read_word(0x0040, 0x0080);
5161 buffer_end = read_word(0x0040, 0x0082);
5162#endif
5163
5164 buffer_head = read_word(0x0040, 0x001a);
5165 buffer_tail = read_word(0x0040, 0x001c);
5166
5167 if (buffer_head != buffer_tail) {
5168 ss = get_SS();
5169 acode = read_byte(0x0040, buffer_head);
5170 scode = read_byte(0x0040, buffer_head+1);
5171 write_byte(ss, ascii_code, acode);
5172 write_byte(ss, scan_code, scode);
5173
5174 if (incr) {
5175 buffer_head += 2;
5176 if (buffer_head >= buffer_end)
5177 buffer_head = buffer_start;
5178 write_word(0x0040, 0x001a, buffer_head);
5179 }
5180 return(1);
5181 }
5182 else {
5183 return(0);
5184 }
5185}
5186
5187static char panic_msg_keyb_buffer_full[] = "%s: keyboard input buffer full\n";
5188
5189 Bit8u
5190send_to_mouse_ctrl(sendbyte)
5191 Bit8u sendbyte;
5192{
5193 Bit8u response;
5194
5195 // wait for chance to write to ctrl
5196 if ( inb(0x64) & 0x02 )
5197 BX_PANIC(panic_msg_keyb_buffer_full,"sendmouse");
5198 outb(0x64, 0xD4);
5199 outb(0x60, sendbyte);
5200 return(0);
5201}
5202
5203
5204 Bit8u
5205get_mouse_data(data)
5206 Bit8u *data;
5207{
5208 Bit8u response;
5209 Bit16u ss;
5210
5211 while ( (inb(0x64) & 0x21) != 0x21 ) {
5212 }
5213
5214 response = inb(0x60);
5215
5216 ss = get_SS();
5217 write_byte(ss, data, response);
5218 return(0);
5219}
5220
5221 void
5222set_kbd_command_byte(command_byte)
5223 Bit8u command_byte;
5224{
5225 if ( inb(0x64) & 0x02 )
5226 BX_PANIC(panic_msg_keyb_buffer_full,"setkbdcomm");
5227
5228 outb(0x64, 0x60); // write command byte
5229 outb(0x60, command_byte);
5230}
5231
5232 void
5233int09_function(DI, SI, BP, SP, BX, DX, CX, AX)
5234 Bit16u DI, SI, BP, SP, BX, DX, CX, AX;
5235{
5236 Bit8u scancode, asciicode, shift_flags;
5237 Bit8u mf2_flags, mf2_state, flag;
5238
5239 //
5240 // DS has been set to F000 before call
5241 //
5242
5243
5244 scancode = GET_AL();
5245
5246 if (scancode == 0) {
5247 BX_INFO("KBD: int09 handler: AL=0\n");
5248 return;
5249 }
5250
5251
5252 shift_flags = read_byte(0x0040, 0x17);
5253 mf2_flags = read_byte(0x0040, 0x18);
5254 mf2_state = read_byte(0x0040, 0x96);
5255 asciicode = 0;
5256
5257 switch (scancode) {
5258 case 0x3a: /* Caps Lock press */
5259 shift_flags ^= 0x40;
5260 write_byte(0x0040, 0x17, shift_flags);
5261 mf2_flags |= 0x40;
5262 write_byte(0x0040, 0x18, mf2_flags);
5263 break;
5264 case 0xba: /* Caps Lock release */
5265 mf2_flags &= ~0x40;
5266 write_byte(0x0040, 0x18, mf2_flags);
5267 break;
5268
5269 case 0x2a: /* L Shift press */
5270 case 0xaa: /* L Shift release */
5271 case 0x36: /* R Shift press */
5272 case 0xb6: /* R Shift release */
5273 /* If this was an extended (i.e. faked) key, leave flags alone. */
5274 if (!(mf2_state & 0x02)) {
5275 flag = (scancode & 0x7f) == 0x2a ? 0x02 : 0x01;
5276 if (scancode & 0x80)
5277 shift_flags &= ~flag;
5278 else
5279 shift_flags |= flag;
5280 write_byte(0x0040, 0x17, shift_flags);
5281 }
5282 break;
5283
5284 case 0x1d: /* Ctrl press */
5285 if ((mf2_state & 0x01) == 0) {
5286 shift_flags |= 0x04;
5287 write_byte(0x0040, 0x17, shift_flags);
5288 if (mf2_state & 0x02) {
5289 mf2_state |= 0x04;
5290 write_byte(0x0040, 0x96, mf2_state);
5291 } else {
5292 mf2_flags |= 0x01;
5293 write_byte(0x0040, 0x18, mf2_flags);
5294 }
5295 }
5296 break;
5297 case 0x9d: /* Ctrl release */
5298 if ((mf2_state & 0x01) == 0) {
5299 shift_flags &= ~0x04;
5300 write_byte(0x0040, 0x17, shift_flags);
5301 if (mf2_state & 0x02) {
5302 mf2_state &= ~0x04;
5303 write_byte(0x0040, 0x96, mf2_state);
5304 } else {
5305 mf2_flags &= ~0x01;
5306 write_byte(0x0040, 0x18, mf2_flags);
5307 }
5308 }
5309 break;
5310
5311 case 0x38: /* Alt press */
5312 shift_flags |= 0x08;
5313 write_byte(0x0040, 0x17, shift_flags);
5314 if (mf2_state & 0x02) {
5315 mf2_state |= 0x08;
5316 write_byte(0x0040, 0x96, mf2_state);
5317 } else {
5318 mf2_flags |= 0x02;
5319 write_byte(0x0040, 0x18, mf2_flags);
5320 }
5321 break;
5322 case 0xb8: /* Alt release */
5323 shift_flags &= ~0x08;
5324 write_byte(0x0040, 0x17, shift_flags);
5325 if (mf2_state & 0x02) {
5326 mf2_state &= ~0x08;
5327 write_byte(0x0040, 0x96, mf2_state);
5328 } else {
5329 mf2_flags &= ~0x02;
5330 write_byte(0x0040, 0x18, mf2_flags);
5331 }
5332 break;
5333
5334 case 0x45: /* Num Lock press */
5335 if ((mf2_state & 0x03) == 0) {
5336 mf2_flags |= 0x20;
5337 write_byte(0x0040, 0x18, mf2_flags);
5338 shift_flags ^= 0x20;
5339 write_byte(0x0040, 0x17, shift_flags);
5340 }
5341 break;
5342 case 0xc5: /* Num Lock release */
5343 if ((mf2_state & 0x03) == 0) {
5344 mf2_flags &= ~0x20;
5345 write_byte(0x0040, 0x18, mf2_flags);
5346 }
5347 break;
5348
5349 case 0x46: /* Scroll Lock press */
5350 mf2_flags |= 0x10;
5351 write_byte(0x0040, 0x18, mf2_flags);
5352 shift_flags ^= 0x10;
5353 write_byte(0x0040, 0x17, shift_flags);
5354 break;
5355
5356 case 0xc6: /* Scroll Lock release */
5357 mf2_flags &= ~0x10;
5358 write_byte(0x0040, 0x18, mf2_flags);
5359 break;
5360
5361#ifdef VBOX
5362 case 0x53: /* Del press */
5363 if ((shift_flags & 0x0c) == 0x0c)
5364 {
5365ASM_START
5366 /* Ctrl+Alt+Del => Reboot */
5367 jmp 0xf000:post
5368ASM_END
5369 }
5370 /* fall through */
5371#endif
5372
5373 default:
5374 if (scancode & 0x80) {
5375 break; /* toss key releases ... */
5376 }
5377 if (scancode > MAX_SCAN_CODE) {
5378 BX_INFO("KBD: int09h_handler(): unknown scancode read: 0x%02x!\n", scancode);
5379 return;
5380 }
5381 if (shift_flags & 0x08) { /* ALT */
5382 asciicode = scan_to_scanascii[scancode].alt;
5383 scancode = scan_to_scanascii[scancode].alt >> 8;
5384 } else if (shift_flags & 0x04) { /* CONTROL */
5385 asciicode = scan_to_scanascii[scancode].control;
5386 scancode = scan_to_scanascii[scancode].control >> 8;
5387 } else if (((mf2_state & 0x02) > 0) && ((scancode >= 0x47) && (scancode <= 0x53))) {
5388 /* extended keys handling */
5389 asciicode = 0xe0;
5390 scancode = scan_to_scanascii[scancode].normal >> 8;
5391 } else if (shift_flags & 0x03) { /* LSHIFT + RSHIFT */
5392 /* check if lock state should be ignored
5393 * because a SHIFT key are pressed */
5394
5395 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
5396 asciicode = scan_to_scanascii[scancode].normal;
5397 scancode = scan_to_scanascii[scancode].normal >> 8;
5398 } else {
5399 asciicode = scan_to_scanascii[scancode].shift;
5400 scancode = scan_to_scanascii[scancode].shift >> 8;
5401 }
5402 } else {
5403 /* check if lock is on */
5404 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
5405 asciicode = scan_to_scanascii[scancode].shift;
5406 scancode = scan_to_scanascii[scancode].shift >> 8;
5407 } else {
5408 asciicode = scan_to_scanascii[scancode].normal;
5409 scancode = scan_to_scanascii[scancode].normal >> 8;
5410 }
5411 }
5412 if (scancode==0 && asciicode==0) {
5413 BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
5414 }
5415 enqueue_key(scancode, asciicode);
5416 break;
5417 }
5418 if ((scancode & 0x7f) != 0x1d) {
5419 mf2_state &= ~0x01;
5420 }
5421 mf2_state &= ~0x02;
5422 write_byte(0x0040, 0x96, mf2_state);
5423}
5424
5425 unsigned int
5426enqueue_key(scan_code, ascii_code)
5427 Bit8u scan_code, ascii_code;
5428{
5429 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail, temp_tail;
5430
5431#if BX_CPU < 2
5432 buffer_start = 0x001E;
5433 buffer_end = 0x003E;
5434#else
5435 buffer_start = read_word(0x0040, 0x0080);
5436 buffer_end = read_word(0x0040, 0x0082);
5437#endif
5438
5439 buffer_head = read_word(0x0040, 0x001A);
5440 buffer_tail = read_word(0x0040, 0x001C);
5441
5442 temp_tail = buffer_tail;
5443 buffer_tail += 2;
5444 if (buffer_tail >= buffer_end)
5445 buffer_tail = buffer_start;
5446
5447 if (buffer_tail == buffer_head) {
5448 return(0);
5449 }
5450
5451 write_byte(0x0040, temp_tail, ascii_code);
5452 write_byte(0x0040, temp_tail+1, scan_code);
5453 write_word(0x0040, 0x001C, buffer_tail);
5454 return(1);
5455}
5456
5457
5458 void
5459int74_function(make_farcall, Z, Y, X, status)
5460 Bit16u make_farcall, Z, Y, X, status;
5461{
5462 Bit16u ebda_seg=read_word(0x0040,0x000E);
5463 Bit8u in_byte, index, package_count;
5464 Bit8u mouse_flags_1, mouse_flags_2;
5465
5466BX_DEBUG_INT74("entering int74_function\n");
5467 make_farcall = 0;
5468
5469 in_byte = inb(0x64);
5470 if ( (in_byte & 0x21) != 0x21 ) {
5471 return;
5472 }
5473 in_byte = inb(0x60);
5474BX_DEBUG_INT74("int74: read byte %02x\n", in_byte);
5475
5476 mouse_flags_1 = read_byte(ebda_seg, 0x0026);
5477 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
5478
5479 if ( (mouse_flags_2 & 0x80) != 0x80 ) {
5480 return;
5481 }
5482
5483 package_count = mouse_flags_2 & 0x07;
5484 index = mouse_flags_1 & 0x07;
5485 write_byte(ebda_seg, 0x28 + index, in_byte);
5486
5487 if ( index >= package_count ) {
5488BX_DEBUG_INT74("int74_function: make_farcall=1\n");
5489 status = read_byte(ebda_seg, 0x0028 + 0);
5490 X = read_byte(ebda_seg, 0x0028 + 1);
5491 Y = read_byte(ebda_seg, 0x0028 + 2);
5492 Z = 0;
5493 mouse_flags_1 = 0;
5494 // check if far call handler installed
5495 if (mouse_flags_2 & 0x80)
5496 make_farcall = 1;
5497 }
5498 else {
5499 mouse_flags_1++;
5500 }
5501 write_byte(ebda_seg, 0x0026, mouse_flags_1);
5502}
5503
5504#define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
5505
5506#if BX_USE_ATADRV
5507
5508 void
5509int13_harddisk(EHBX, EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5510 Bit16u EHBX, EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5511{
5512 Bit32u lba;
5513 Bit16u ebda_seg=read_word(0x0040,0x000E);
5514 Bit16u cylinder, head, sector;
5515 Bit16u segment, offset;
5516 Bit16u npc, nph, npspt, nlc, nlh, nlspt;
5517 Bit16u size, count;
5518 Bit8u device, status;
5519
5520 BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5521
5522 write_byte(0x0040, 0x008e, 0); // clear completion flag
5523
5524 // basic check : device has to be defined
5525 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_STORAGE_DEVICES) ) {
5526 BX_DEBUG("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5527 goto int13_fail;
5528 }
5529
5530 // Get the ata channel
5531 device=read_byte(ebda_seg,&EbdaData->ata.hdidmap[GET_ELDL()-0x80]);
5532
5533 // basic check : device has to be valid
5534 if (device >= BX_MAX_STORAGE_DEVICES) {
5535 BX_DEBUG("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5536 goto int13_fail;
5537 }
5538
5539 switch (GET_AH()) {
5540
5541 case 0x00: /* disk controller reset */
5542#ifdef VBOX_WITH_SCSI
5543 /* SCSI controller does not need a reset. */
5544 if (!VBOX_IS_SCSI_DEVICE(device))
5545#endif
5546 ata_reset (device);
5547 goto int13_success;
5548 break;
5549
5550 case 0x01: /* read disk status */
5551 status = read_byte(0x0040, 0x0074);
5552 SET_AH(status);
5553 SET_DISK_RET_STATUS(0);
5554 /* set CF if error status read */
5555 if (status) goto int13_fail_nostatus;
5556 else goto int13_success_noah;
5557 break;
5558
5559 case 0x02: // read disk sectors
5560 case 0x03: // write disk sectors
5561 case 0x04: // verify disk sectors
5562
5563 count = GET_AL();
5564 cylinder = GET_CH();
5565 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
5566 sector = (GET_CL() & 0x3f);
5567 head = GET_DH();
5568
5569 segment = ES;
5570 offset = BX;
5571
5572 if ( (count > 128) || (count == 0) ) {
5573 BX_INFO("int13_harddisk: function %02x, count out of range!\n",GET_AH());
5574 goto int13_fail;
5575 }
5576
5577#ifdef VBOX_WITH_SCSI
5578 if (!VBOX_IS_SCSI_DEVICE(device))
5579#endif
5580 {
5581 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
5582 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
5583 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
5584 }
5585#ifdef VBOX_WITH_SCSI
5586 else
5587 {
5588 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5589
5590 nlc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.cylinders);
5591 nlh = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.heads);
5592 nlspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.spt);
5593 }
5594#endif
5595
5596 // sanity check on cyl heads, sec
5597 if( (cylinder >= nlc) || (head >= nlh) || (sector > nlspt )) {
5598 BX_INFO("int13_harddisk: function %02x, disk %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), GET_DL(), cylinder, head, sector);
5599 goto int13_fail;
5600 }
5601
5602 // FIXME verify
5603 if ( GET_AH() == 0x04 ) goto int13_success;
5604
5605#ifdef VBOX_WITH_SCSI
5606 if (!VBOX_IS_SCSI_DEVICE(device))
5607#endif
5608 {
5609 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5610 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5611 }
5612#ifdef VBOX_WITH_SCSI
5613 else
5614 {
5615 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5616 nph = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.heads);
5617 npspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.spt);
5618 }
5619#endif
5620
5621 // if needed, translate lchs to lba, and execute command
5622#ifdef VBOX_WITH_SCSI
5623 if (( (nph != nlh) || (npspt != nlspt)) || VBOX_IS_SCSI_DEVICE(device)) {
5624 lba = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
5625 sector = 0; // this forces the command to be lba
5626 }
5627#else
5628 if (( (nph != nlh) || (npspt != nlspt)) ) {
5629 lba = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
5630 sector = 0; // this forces the command to be lba
5631 }
5632#endif
5633
5634 if ( GET_AH() == 0x02 )
5635 {
5636#ifdef VBOX_WITH_SCSI
5637 if (VBOX_IS_SCSI_DEVICE(device))
5638 status=scsi_read_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5639 else
5640#endif
5641 {
5642 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,count * 0x200);
5643 status=ata_cmd_data_in(device, ATA_CMD_READ_MULTIPLE, count, cylinder, head, sector, lba, segment, offset);
5644 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,0x200);
5645 }
5646 }
5647 else
5648 {
5649#ifdef VBOX_WITH_SCSI
5650 if (VBOX_IS_SCSI_DEVICE(device))
5651 status=scsi_write_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5652 else
5653#endif
5654 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, cylinder, head, sector, lba, segment, offset);
5655 }
5656
5657 // Set nb of sector transferred
5658 SET_AL(read_word(ebda_seg, &EbdaData->ata.trsfsectors));
5659
5660 if (status != 0) {
5661 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5662 SET_AH(0x0c);
5663 goto int13_fail_noah;
5664 }
5665
5666 goto int13_success;
5667 break;
5668
5669 case 0x05: /* format disk track */
5670 BX_INFO("format disk track called\n");
5671 goto int13_success;
5672 return;
5673 break;
5674
5675 case 0x08: /* read disk drive parameters */
5676
5677 // Get logical geometry from table
5678#ifdef VBOX_WITH_SCSI
5679 if (!VBOX_IS_SCSI_DEVICE(device))
5680#endif
5681 {
5682 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
5683 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
5684 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
5685 }
5686#ifdef VBOX_WITH_SCSI
5687 else
5688 {
5689 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5690 nlc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.cylinders);
5691 nlh = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.heads);
5692 nlspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.spt);
5693 }
5694#endif
5695
5696 count = read_byte(ebda_seg, &EbdaData->ata.hdcount);
5697#ifndef VBOX
5698 nlc = nlc - 2; /* 0 based , last sector not used */
5699#else /* VBOX */
5700 /* Maximum cylinder number is just one less than the number of cylinders. */
5701 nlc = nlc - 1; /* 0 based , last sector not used */
5702#endif /* VBOX */
5703 SET_AL(0);
5704 SET_CH(nlc & 0xff);
5705 SET_CL(((nlc >> 2) & 0xc0) | (nlspt & 0x3f));
5706 SET_DH(nlh - 1);
5707 SET_DL(count); /* FIXME returns 0, 1, or n hard drives */
5708
5709 // FIXME should set ES & DI
5710
5711 goto int13_success;
5712 break;
5713
5714 case 0x10: /* check drive ready */
5715 // should look at 40:8E also???
5716
5717 // Read the status from controller
5718 status = inb(read_word(ebda_seg, &EbdaData->ata.channels[device/2].iobase1) + ATA_CB_STAT);
5719 if ( (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY ) {
5720 goto int13_success;
5721 }
5722 else {
5723 SET_AH(0xAA);
5724 goto int13_fail_noah;
5725 }
5726 break;
5727
5728 case 0x15: /* read disk drive size */
5729
5730 // Get physical geometry from table
5731#ifdef VBOX_WITH_SCSI
5732 if (!VBOX_IS_SCSI_DEVICE(device))
5733#endif
5734 {
5735 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5736 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5737 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5738 }
5739#ifdef VBOX_WITH_SCSI
5740 else
5741 {
5742 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5743 npc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.cylinders);
5744 nph = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.heads);
5745 npspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.spt);
5746 }
5747#endif
5748
5749 // Compute sector count seen by int13
5750#ifndef VBOX
5751 lba = (Bit32u)(npc - 1) * (Bit32u)nph * (Bit32u)npspt;
5752#else /* VBOX */
5753 /* Is it so hard to multiply a couple of counts (without introducing
5754 * arbitrary off by one errors)? */
5755 lba = (Bit32u)npc * (Bit32u)nph * (Bit32u)npspt;
5756#endif /* VBOX */
5757 CX = lba >> 16;
5758 DX = lba & 0xffff;
5759
5760 SET_AH(3); // hard disk accessible
5761 goto int13_success_noah;
5762 break;
5763
5764 case 0x41: // IBM/MS installation check
5765 BX=0xaa55; // install check
5766 SET_AH(0x30); // EDD 3.0
5767 CX=0x0007; // ext disk access and edd, removable supported
5768 goto int13_success_noah;
5769 break;
5770
5771 case 0x42: // IBM/MS extended read
5772 case 0x43: // IBM/MS extended write
5773 case 0x44: // IBM/MS verify
5774 case 0x47: // IBM/MS extended seek
5775
5776 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5777 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5778 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5779
5780 // Can't use 64 bits lba
5781 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5782 if (lba != 0L) {
5783 BX_PANIC("int13_harddisk: function %02x. Can't use 64bits lba\n",GET_AH());
5784 goto int13_fail;
5785 }
5786
5787 // Get 32 bits lba and check
5788 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5789
5790#ifdef VBOX_WITH_SCSI
5791 if (VBOX_IS_SCSI_DEVICE(device))
5792 {
5793 if (lba >= read_dword(ebda_seg, &EbdaData->scsi.devices[VBOX_GET_SCSI_DEVICE(device)].device_info.sectors) ) {
5794 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5795 goto int13_fail;
5796 }
5797 }
5798 else
5799#endif
5800 if (lba >= read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors) ) {
5801 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5802 goto int13_fail;
5803 }
5804
5805
5806 // If verify or seek
5807 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5808 goto int13_success;
5809
5810 // Execute the command
5811 if ( GET_AH() == 0x42 )
5812#ifdef VBOX
5813 {
5814#ifdef VBOX_WITH_SCSI
5815 if (VBOX_IS_SCSI_DEVICE(device))
5816 status=scsi_read_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5817 else
5818#endif
5819 {
5820 if (lba + count >= 268435456)
5821 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS_EXT, count, 0, 0, 0, lba, segment, offset);
5822 else {
5823 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,count * 0x200);
5824 status=ata_cmd_data_in(device, ATA_CMD_READ_MULTIPLE, count, 0, 0, 0, lba, segment, offset);
5825 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,0x200);
5826 }
5827 }
5828 }
5829#else /* !VBOX */
5830 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba, segment, offset);
5831#endif /* VBOX */
5832 else
5833#ifdef VBOX
5834 {
5835#ifdef VBOX_WITH_SCSI
5836 if (VBOX_IS_SCSI_DEVICE(device))
5837 status=scsi_write_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5838 else
5839#endif
5840 {
5841 if (lba + count >= 268435456)
5842 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS_EXT, count, 0, 0, 0, lba, segment, offset);
5843 else
5844 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
5845 }
5846 }
5847#else /* !VBOX */
5848 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
5849#endif /* VBOX */
5850
5851 count=read_word(ebda_seg, &EbdaData->ata.trsfsectors);
5852 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5853
5854 if (status != 0) {
5855 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5856 SET_AH(0x0c);
5857 goto int13_fail_noah;
5858 }
5859
5860 goto int13_success;
5861 break;
5862
5863 case 0x45: // IBM/MS lock/unlock drive
5864 case 0x49: // IBM/MS extended media change
5865 goto int13_success; // Always success for HD
5866 break;
5867
5868 case 0x46: // IBM/MS eject media
5869 SET_AH(0xb2); // Volume Not Removable
5870 goto int13_fail_noah; // Always fail for HD
5871 break;
5872
5873 case 0x48: // IBM/MS get drive parameters
5874 size=read_word(DS,SI+(Bit16u)&Int13DPT->size);
5875
5876 // Buffer is too small
5877 if(size < 0x1a)
5878 goto int13_fail;
5879
5880 // EDD 1.x
5881 if(size >= 0x1a) {
5882 Bit16u blksize;
5883
5884#ifdef VBOX_WITH_SCSI
5885 if (!VBOX_IS_SCSI_DEVICE(device))
5886#endif
5887 {
5888 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5889 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5890 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5891 lba = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors);
5892 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5893 }
5894#ifdef VBOX_WITH_SCSI
5895 else
5896 {
5897 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5898 npc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.cylinders);
5899 nph = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.heads);
5900 npspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.spt);
5901 lba = read_dword(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.sectors);
5902 blksize = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.blksize);
5903 }
5904#endif
5905
5906 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5907 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x02); // geometry is valid
5908 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, (Bit32u)npc);
5909 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, (Bit32u)nph);
5910 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, (Bit32u)npspt);
5911 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, lba); // FIXME should be Bit64
5912 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0L);
5913 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5914 }
5915
5916 // EDD 2.x
5917 if(size >= 0x1e) {
5918 Bit8u channel, dev, irq, mode, checksum, i, translation;
5919 Bit16u iobase1, iobase2, options;
5920
5921 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5922
5923 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5924 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5925
5926 // Fill in dpte
5927 channel = device / 2;
5928 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5929 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5930 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5931 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5932 translation = read_byte(ebda_seg, &EbdaData->ata.devices[device].translation);
5933
5934 options = (translation==ATA_TRANSLATION_NONE?0:1<<3); // chs translation
5935 options |= (1<<4); // lba translation
5936 options |= (mode==ATA_MODE_PIO32?1:0<<7);
5937 options |= (translation==ATA_TRANSLATION_LBA?1:0<<9);
5938 options |= (translation==ATA_TRANSLATION_RECHS?3:0<<9);
5939
5940 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5941 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5942 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5943 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5944 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5945 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5946 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5947 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5948 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5949 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5950 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5951
5952 checksum=0;
5953 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5954 checksum = -checksum;
5955 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5956 }
5957
5958 // EDD 3.x
5959 if(size >= 0x42) {
5960 Bit8u channel, iface, checksum, i;
5961 Bit16u iobase1;
5962
5963 channel = device / 2;
5964 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5965 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5966
5967 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5968 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5969 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5970 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5971 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5972
5973 if (iface==ATA_IFACE_ISA) {
5974 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5975 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5976 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5977 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], ' ');
5978 }
5979 else {
5980 // FIXME PCI
5981 }
5982 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5983 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5984 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5985 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], ' ');
5986 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[4], ' ');
5987 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[5], ' ');
5988 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[6], ' ');
5989 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[7], ' ');
5990
5991 if (iface==ATA_IFACE_ISA) {
5992 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5993 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5994 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5995 }
5996 else {
5997 // FIXME PCI
5998 }
5999 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
6000 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
6001 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
6002 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
6003
6004 checksum=0;
6005 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
6006 checksum = -checksum;
6007 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
6008 }
6009
6010 goto int13_success;
6011 break;
6012
6013 case 0x4e: // // IBM/MS set hardware configuration
6014 // DMA, prefetch, PIO maximum not supported
6015 switch (GET_AL()) {
6016 case 0x01:
6017 case 0x03:
6018 case 0x04:
6019 case 0x06:
6020 goto int13_success;
6021 break;
6022 default :
6023 goto int13_fail;
6024 }
6025 break;
6026
6027 case 0x09: /* initialize drive parameters */
6028 case 0x0c: /* seek to specified cylinder */
6029 case 0x0d: /* alternate disk reset */
6030 case 0x11: /* recalibrate */
6031 case 0x14: /* controller internal diagnostic */
6032 BX_INFO("int13_harddisk: function %02xh unimplemented, returns success\n", GET_AH());
6033 goto int13_success;
6034 break;
6035
6036 case 0x0a: /* read disk sectors with ECC */
6037 case 0x0b: /* write disk sectors with ECC */
6038 case 0x18: // set media type for format
6039 case 0x50: // IBM/MS send packet command
6040 default:
6041 BX_INFO("int13_harddisk: function %02xh unsupported, returns fail\n", GET_AH());
6042 goto int13_fail;
6043 break;
6044 }
6045
6046int13_fail:
6047 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6048int13_fail_noah:
6049 SET_DISK_RET_STATUS(GET_AH());
6050int13_fail_nostatus:
6051 SET_CF(); // error occurred
6052 return;
6053
6054int13_success:
6055 SET_AH(0x00); // no error
6056int13_success_noah:
6057 SET_DISK_RET_STATUS(0x00);
6058 CLEAR_CF(); // no error
6059 return;
6060}
6061
6062// ---------------------------------------------------------------------------
6063// Start of int13 for cdrom
6064// ---------------------------------------------------------------------------
6065
6066 void
6067int13_cdrom(EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
6068 Bit16u EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
6069{
6070 Bit16u ebda_seg=read_word(0x0040,0x000E);
6071 Bit8u device, status, locks;
6072 Bit8u atacmd[12];
6073 Bit32u lba;
6074 Bit16u count, segment, offset, i, size;
6075
6076 BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6077
6078 SET_DISK_RET_STATUS(0x00);
6079
6080 /* basic check : device should be 0xE0+ */
6081 if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES) ) {
6082 BX_DEBUG("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
6083 goto int13_fail;
6084 }
6085
6086 // Get the ata channel
6087 device=read_byte(ebda_seg,&EbdaData->ata.cdidmap[GET_ELDL()-0xE0]);
6088
6089 /* basic check : device has to be valid */
6090 if (device >= BX_MAX_ATA_DEVICES) {
6091 BX_DEBUG("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
6092 goto int13_fail;
6093 }
6094
6095 switch (GET_AH()) {
6096
6097 // all those functions return SUCCESS
6098 case 0x00: /* disk controller reset */
6099 case 0x09: /* initialize drive parameters */
6100 case 0x0c: /* seek to specified cylinder */
6101 case 0x0d: /* alternate disk reset */
6102 case 0x10: /* check drive ready */
6103 case 0x11: /* recalibrate */
6104 case 0x14: /* controller internal diagnostic */
6105 case 0x16: /* detect disk change */
6106 goto int13_success;
6107 break;
6108
6109 // all those functions return disk write-protected
6110 case 0x03: /* write disk sectors */
6111 case 0x05: /* format disk track */
6112 case 0x43: // IBM/MS extended write
6113 SET_AH(0x03);
6114 goto int13_fail_noah;
6115 break;
6116
6117 case 0x01: /* read disk status */
6118 status = read_byte(0x0040, 0x0074);
6119 SET_AH(status);
6120 SET_DISK_RET_STATUS(0);
6121
6122 /* set CF if error status read */
6123 if (status) goto int13_fail_nostatus;
6124 else goto int13_success_noah;
6125 break;
6126
6127 case 0x15: /* read disk drive size */
6128 SET_AH(0x02);
6129 goto int13_fail_noah;
6130 break;
6131
6132 case 0x41: // IBM/MS installation check
6133 BX=0xaa55; // install check
6134 SET_AH(0x30); // EDD 2.1
6135 CX=0x0007; // ext disk access, removable and edd
6136 goto int13_success_noah;
6137 break;
6138
6139 case 0x42: // IBM/MS extended read
6140 case 0x44: // IBM/MS verify sectors
6141 case 0x47: // IBM/MS extended seek
6142
6143 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
6144 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
6145 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
6146
6147 // Can't use 64 bits lba
6148 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
6149 if (lba != 0L) {
6150 BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
6151 goto int13_fail;
6152 }
6153
6154 // Get 32 bits lba
6155 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
6156
6157 // If verify or seek
6158 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
6159 goto int13_success;
6160
6161 memsetb(get_SS(),atacmd,0,12);
6162 atacmd[0]=0x28; // READ command
6163 atacmd[7]=(count & 0xff00) >> 8; // Sectors
6164 atacmd[8]=(count & 0x00ff); // Sectors
6165 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
6166 atacmd[3]=(lba & 0x00ff0000) >> 16;
6167 atacmd[4]=(lba & 0x0000ff00) >> 8;
6168 atacmd[5]=(lba & 0x000000ff);
6169 status = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, count*2048L, ATA_DATA_IN, segment,offset);
6170
6171 count = (Bit16u)(read_dword(ebda_seg, &EbdaData->ata.trsfbytes) >> 11);
6172 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
6173
6174 if (status != 0) {
6175 BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status);
6176 SET_AH(0x0c);
6177 goto int13_fail_noah;
6178 }
6179
6180 goto int13_success;
6181 break;
6182
6183 case 0x45: // IBM/MS lock/unlock drive
6184 if (GET_AL() > 2) goto int13_fail;
6185
6186 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
6187
6188 switch (GET_AL()) {
6189 case 0 : // lock
6190 if (locks == 0xff) {
6191 SET_AH(0xb4);
6192 SET_AL(1);
6193 goto int13_fail_noah;
6194 }
6195 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, ++locks);
6196 SET_AL(1);
6197 break;
6198 case 1 : // unlock
6199 if (locks == 0x00) {
6200 SET_AH(0xb0);
6201 SET_AL(0);
6202 goto int13_fail_noah;
6203 }
6204 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, --locks);
6205 SET_AL(locks==0?0:1);
6206 break;
6207 case 2 : // status
6208 SET_AL(locks==0?0:1);
6209 break;
6210 }
6211 goto int13_success;
6212 break;
6213
6214 case 0x46: // IBM/MS eject media
6215 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
6216
6217 if (locks != 0) {
6218 SET_AH(0xb1); // media locked
6219 goto int13_fail_noah;
6220 }
6221 // FIXME should handle 0x31 no media in device
6222 // FIXME should handle 0xb5 valid request failed
6223
6224 // Call removable media eject
6225 ASM_START
6226 push bp
6227 mov bp, sp
6228
6229 mov ah, #0x52
6230 int #0x15
6231 mov _int13_cdrom.status + 2[bp], ah
6232 jnc int13_cdrom_rme_end
6233 mov _int13_cdrom.status, #1
6234int13_cdrom_rme_end:
6235 pop bp
6236 ASM_END
6237
6238 if (status != 0) {
6239 SET_AH(0xb1); // media locked
6240 goto int13_fail_noah;
6241 }
6242
6243 goto int13_success;
6244 break;
6245
6246 case 0x48: // IBM/MS get drive parameters
6247 size = read_word(DS,SI+(Bit16u)&Int13Ext->size);
6248
6249 // Buffer is too small
6250 if(size < 0x1a)
6251 goto int13_fail;
6252
6253 // EDD 1.x
6254 if(size >= 0x1a) {
6255 Bit16u cylinders, heads, spt, blksize;
6256
6257 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
6258
6259 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
6260 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x74); // removable, media change, lockable, max values
6261 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, 0xffffffff);
6262 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, 0xffffffff);
6263 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, 0xffffffff);
6264 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, 0xffffffff); // FIXME should be Bit64
6265 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0xffffffff);
6266 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
6267 }
6268
6269 // EDD 2.x
6270 if(size >= 0x1e) {
6271 Bit8u channel, dev, irq, mode, checksum, i;
6272 Bit16u iobase1, iobase2, options;
6273
6274 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
6275
6276 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
6277 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
6278
6279 // Fill in dpte
6280 channel = device / 2;
6281 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
6282 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
6283 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
6284 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
6285
6286 // FIXME atapi device
6287 options = (1<<4); // lba translation
6288 options |= (1<<5); // removable device
6289 options |= (1<<6); // atapi device
6290 options |= (mode==ATA_MODE_PIO32?1:0<<7);
6291
6292 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
6293 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
6294 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
6295 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
6296 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
6297 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
6298 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
6299 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
6300 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
6301 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
6302 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
6303
6304 checksum=0;
6305 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
6306 checksum = -checksum;
6307 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
6308 }
6309
6310 // EDD 3.x
6311 if(size >= 0x42) {
6312 Bit8u channel, iface, checksum, i;
6313 Bit16u iobase1;
6314
6315 channel = device / 2;
6316 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
6317 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
6318
6319 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
6320 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
6321 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
6322 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
6323 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
6324
6325 if (iface==ATA_IFACE_ISA) {
6326 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
6327 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
6328 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
6329 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
6330 }
6331 else {
6332 // FIXME PCI
6333 }
6334 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
6335 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
6336 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
6337 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
6338
6339 if (iface==ATA_IFACE_ISA) {
6340 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
6341 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
6342 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
6343 }
6344 else {
6345 // FIXME PCI
6346 }
6347 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
6348 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
6349 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
6350 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
6351
6352 checksum=0;
6353 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
6354 checksum = -checksum;
6355 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
6356 }
6357
6358 goto int13_success;
6359 break;
6360
6361 case 0x49: // IBM/MS extended media change
6362 // always send changed ??
6363 SET_AH(06);
6364 goto int13_fail_nostatus;
6365 break;
6366
6367 case 0x4e: // // IBM/MS set hardware configuration
6368 // DMA, prefetch, PIO maximum not supported
6369 switch (GET_AL()) {
6370 case 0x01:
6371 case 0x03:
6372 case 0x04:
6373 case 0x06:
6374 goto int13_success;
6375 break;
6376 default :
6377 goto int13_fail;
6378 }
6379 break;
6380
6381 // all those functions return unimplemented
6382 case 0x02: /* read sectors */
6383 case 0x04: /* verify sectors */
6384 case 0x08: /* read disk drive parameters */
6385 case 0x0a: /* read disk sectors with ECC */
6386 case 0x0b: /* write disk sectors with ECC */
6387 case 0x18: /* set media type for format */
6388 case 0x50: // ? - send packet command
6389 default:
6390 BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
6391 goto int13_fail;
6392 break;
6393 }
6394
6395int13_fail:
6396 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6397int13_fail_noah:
6398 SET_DISK_RET_STATUS(GET_AH());
6399int13_fail_nostatus:
6400 SET_CF(); // error occurred
6401 return;
6402
6403int13_success:
6404 SET_AH(0x00); // no error
6405int13_success_noah:
6406 SET_DISK_RET_STATUS(0x00);
6407 CLEAR_CF(); // no error
6408 return;
6409}
6410
6411// ---------------------------------------------------------------------------
6412// End of int13 for cdrom
6413// ---------------------------------------------------------------------------
6414
6415#if BX_ELTORITO_BOOT
6416// ---------------------------------------------------------------------------
6417// Start of int13 for eltorito functions
6418// ---------------------------------------------------------------------------
6419
6420 void
6421int13_eltorito(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
6422 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
6423{
6424 Bit16u ebda_seg=read_word(0x0040,0x000E);
6425
6426 BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6427 // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
6428
6429 switch (GET_AH()) {
6430
6431 // FIXME ElTorito Various. Should be implemented
6432 case 0x4a: // ElTorito - Initiate disk emu
6433 case 0x4c: // ElTorito - Initiate disk emu and boot
6434 case 0x4d: // ElTorito - Return Boot catalog
6435 BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX);
6436 goto int13_fail;
6437 break;
6438
6439 case 0x4b: // ElTorito - Terminate disk emu
6440 // FIXME ElTorito Hardcoded
6441 write_byte(DS,SI+0x00,0x13);
6442 write_byte(DS,SI+0x01,read_byte(ebda_seg,&EbdaData->cdemu.media));
6443 write_byte(DS,SI+0x02,read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
6444 write_byte(DS,SI+0x03,read_byte(ebda_seg,&EbdaData->cdemu.controller_index));
6445 write_dword(DS,SI+0x04,read_dword(ebda_seg,&EbdaData->cdemu.ilba));
6446 write_word(DS,SI+0x08,read_word(ebda_seg,&EbdaData->cdemu.device_spec));
6447 write_word(DS,SI+0x0a,read_word(ebda_seg,&EbdaData->cdemu.buffer_segment));
6448 write_word(DS,SI+0x0c,read_word(ebda_seg,&EbdaData->cdemu.load_segment));
6449 write_word(DS,SI+0x0e,read_word(ebda_seg,&EbdaData->cdemu.sector_count));
6450 write_byte(DS,SI+0x10,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.cylinders));
6451 write_byte(DS,SI+0x11,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.spt));
6452 write_byte(DS,SI+0x12,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.heads));
6453
6454 // If we have to terminate emulation
6455 if(GET_AL() == 0x00) {
6456 // FIXME ElTorito Various. Should be handled accordingly to spec
6457 write_byte(ebda_seg,&EbdaData->cdemu.active, 0x00); // bye bye
6458 }
6459
6460 goto int13_success;
6461 break;
6462
6463 default:
6464 BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
6465 goto int13_fail;
6466 break;
6467 }
6468
6469int13_fail:
6470 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6471 SET_DISK_RET_STATUS(GET_AH());
6472 SET_CF(); // error occurred
6473 return;
6474
6475int13_success:
6476 SET_AH(0x00); // no error
6477 SET_DISK_RET_STATUS(0x00);
6478 CLEAR_CF(); // no error
6479 return;
6480}
6481
6482// ---------------------------------------------------------------------------
6483// End of int13 for eltorito functions
6484// ---------------------------------------------------------------------------
6485
6486// ---------------------------------------------------------------------------
6487// Start of int13 when emulating a device from the cd
6488// ---------------------------------------------------------------------------
6489
6490 void
6491int13_cdemu(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
6492 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
6493{
6494 Bit16u ebda_seg=read_word(0x0040,0x000E);
6495 Bit8u device, status;
6496 Bit16u vheads, vspt, vcylinders;
6497 Bit16u head, sector, cylinder, nbsectors;
6498 Bit32u vlba, ilba, slba, elba;
6499 Bit16u before, segment, offset;
6500 Bit8u atacmd[12];
6501
6502 BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6503
6504 /* at this point, we are emulating a floppy/harddisk */
6505
6506 // Recompute the device number
6507 device = read_byte(ebda_seg,&EbdaData->cdemu.controller_index) * 2;
6508 device += read_byte(ebda_seg,&EbdaData->cdemu.device_spec);
6509
6510 SET_DISK_RET_STATUS(0x00);
6511
6512 /* basic checks : emulation should be active, dl should equal the emulated drive */
6513 if( (read_byte(ebda_seg,&EbdaData->cdemu.active) ==0 )
6514 || (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive ) != GET_DL())) {
6515 BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
6516 goto int13_fail;
6517 }
6518
6519 switch (GET_AH()) {
6520
6521 // all those functions return SUCCESS
6522 case 0x00: /* disk controller reset */
6523 case 0x09: /* initialize drive parameters */
6524 case 0x0c: /* seek to specified cylinder */
6525 case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
6526 case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
6527 case 0x11: /* recalibrate */
6528 case 0x14: /* controller internal diagnostic */
6529 case 0x16: /* detect disk change */
6530 goto int13_success;
6531 break;
6532
6533 // all those functions return disk write-protected
6534 case 0x03: /* write disk sectors */
6535 case 0x05: /* format disk track */
6536 SET_AH(0x03);
6537 goto int13_fail_noah;
6538 break;
6539
6540 case 0x01: /* read disk status */
6541 status=read_byte(0x0040, 0x0074);
6542 SET_AH(status);
6543 SET_DISK_RET_STATUS(0);
6544
6545 /* set CF if error status read */
6546 if (status) goto int13_fail_nostatus;
6547 else goto int13_success_noah;
6548 break;
6549
6550 case 0x02: // read disk sectors
6551 case 0x04: // verify disk sectors
6552 vspt = read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
6553 vcylinders = read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders);
6554 vheads = read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads);
6555
6556 ilba = read_dword(ebda_seg,&EbdaData->cdemu.ilba);
6557
6558 sector = GET_CL() & 0x003f;
6559 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
6560 head = GET_DH();
6561 nbsectors = GET_AL();
6562 segment = ES;
6563 offset = BX;
6564
6565 // no sector to read ?
6566 if(nbsectors==0) goto int13_success;
6567
6568 // sanity checks sco openserver needs this!
6569 if ((sector > vspt)
6570 || (cylinder >= vcylinders)
6571 || (head >= vheads)) {
6572 goto int13_fail;
6573 }
6574
6575 // After controls, verify do nothing
6576 if (GET_AH() == 0x04) goto int13_success;
6577
6578 segment = ES+(BX / 16);
6579 offset = BX % 16;
6580
6581 // calculate the virtual lba inside the image
6582 vlba=((((Bit32u)cylinder*(Bit32u)vheads)+(Bit32u)head)*(Bit32u)vspt)+((Bit32u)(sector-1));
6583
6584 // In advance so we don't loose the count
6585 SET_AL(nbsectors);
6586
6587 // start lba on cd
6588 slba = (Bit32u)vlba/4;
6589 before= (Bit16u)vlba%4;
6590
6591 // end lba on cd
6592 elba = (Bit32u)(vlba+nbsectors-1)/4;
6593
6594 memsetb(get_SS(),atacmd,0,12);
6595 atacmd[0]=0x28; // READ command
6596 atacmd[7]=((Bit16u)(elba-slba+1) & 0xff00) >> 8; // Sectors
6597 atacmd[8]=((Bit16u)(elba-slba+1) & 0x00ff); // Sectors
6598 atacmd[2]=(ilba+slba & 0xff000000) >> 24; // LBA
6599 atacmd[3]=(ilba+slba & 0x00ff0000) >> 16;
6600 atacmd[4]=(ilba+slba & 0x0000ff00) >> 8;
6601 atacmd[5]=(ilba+slba & 0x000000ff);
6602 if((status = ata_cmd_packet(device, 12, get_SS(), atacmd, before*512, nbsectors*512L, ATA_DATA_IN, segment,offset)) != 0) {
6603 BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status);
6604 SET_AH(0x02);
6605 SET_AL(0);
6606 goto int13_fail_noah;
6607 }
6608
6609 goto int13_success;
6610 break;
6611
6612 case 0x08: /* read disk drive parameters */
6613 vspt=read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
6614 vcylinders=read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders) - 1;
6615 vheads=read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads) - 1;
6616
6617 SET_AL( 0x00 );
6618 SET_BL( 0x00 );
6619 SET_CH( vcylinders & 0xff );
6620 SET_CL((( vcylinders >> 2) & 0xc0) | ( vspt & 0x3f ));
6621 SET_DH( vheads );
6622 SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2
6623 // FIXME ElTorito Harddisk. should send the HD count
6624
6625 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
6626 case 0x01: SET_BL( 0x02 ); break;
6627 case 0x02: SET_BL( 0x04 ); break;
6628 case 0x03: SET_BL( 0x06 ); break;
6629 }
6630
6631ASM_START
6632 push bp
6633 mov bp, sp
6634 mov ax, #diskette_param_table2
6635 mov _int13_cdemu.DI+2[bp], ax
6636 mov _int13_cdemu.ES+2[bp], cs
6637 pop bp
6638ASM_END
6639 goto int13_success;
6640 break;
6641
6642 case 0x15: /* read disk drive size */
6643 // FIXME ElTorito Harddisk. What geometry to send ?
6644 SET_AH(0x03);
6645 goto int13_success_noah;
6646 break;
6647
6648 // all those functions return unimplemented
6649 case 0x0a: /* read disk sectors with ECC */
6650 case 0x0b: /* write disk sectors with ECC */
6651 case 0x18: /* set media type for format */
6652 case 0x41: // IBM/MS installation check
6653 // FIXME ElTorito Harddisk. Darwin would like to use EDD
6654 case 0x42: // IBM/MS extended read
6655 case 0x43: // IBM/MS extended write
6656 case 0x44: // IBM/MS verify sectors
6657 case 0x45: // IBM/MS lock/unlock drive
6658 case 0x46: // IBM/MS eject media
6659 case 0x47: // IBM/MS extended seek
6660 case 0x48: // IBM/MS get drive parameters
6661 case 0x49: // IBM/MS extended media change
6662 case 0x4e: // ? - set hardware configuration
6663 case 0x50: // ? - send packet command
6664 default:
6665 BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
6666 goto int13_fail;
6667 break;
6668 }
6669
6670int13_fail:
6671 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6672int13_fail_noah:
6673 SET_DISK_RET_STATUS(GET_AH());
6674int13_fail_nostatus:
6675 SET_CF(); // error occurred
6676 return;
6677
6678int13_success:
6679 SET_AH(0x00); // no error
6680int13_success_noah:
6681 SET_DISK_RET_STATUS(0x00);
6682 CLEAR_CF(); // no error
6683 return;
6684}
6685
6686// ---------------------------------------------------------------------------
6687// End of int13 when emulating a device from the cd
6688// ---------------------------------------------------------------------------
6689
6690#endif // BX_ELTORITO_BOOT
6691
6692#else //BX_USE_ATADRV
6693
6694 void
6695outLBA(cylinder,hd_heads,head,hd_sectors,sector,dl)
6696 Bit16u cylinder;
6697 Bit16u hd_heads;
6698 Bit16u head;
6699 Bit16u hd_sectors;
6700 Bit16u sector;
6701 Bit16u dl;
6702{
6703ASM_START
6704 push bp
6705 mov bp, sp
6706 push eax
6707 push ebx
6708 push edx
6709 xor eax,eax
6710 mov ax,4[bp] // cylinder
6711 xor ebx,ebx
6712 mov bl,6[bp] // hd_heads
6713 imul ebx
6714
6715 mov bl,8[bp] // head
6716 add eax,ebx
6717 mov bl,10[bp] // hd_sectors
6718 imul ebx
6719 mov bl,12[bp] // sector
6720 add eax,ebx
6721
6722 dec eax
6723 mov dx,#0x1f3
6724 out dx,al
6725 mov dx,#0x1f4
6726 mov al,ah
6727 out dx,al
6728 shr eax,#16
6729 mov dx,#0x1f5
6730 out dx,al
6731 and ah,#0xf
6732 mov bl,14[bp] // dl
6733 and bl,#1
6734 shl bl,#4
6735 or ah,bl
6736 or ah,#0xe0
6737 mov al,ah
6738 mov dx,#0x01f6
6739 out dx,al
6740 pop edx
6741 pop ebx
6742 pop eax
6743 pop bp
6744ASM_END
6745}
6746
6747 void
6748int13_harddisk(EHBX, EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
6749 Bit16u EHBX, EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
6750{
6751 Bit8u drive, num_sectors, sector, head, status, mod;
6752 Bit8u drive_map;
6753 Bit8u n_drives;
6754 Bit16u cyl_mod, ax;
6755 Bit16u max_cylinder, cylinder, total_sectors;
6756 Bit16u hd_cylinders;
6757 Bit8u hd_heads, hd_sectors;
6758 Bit16u val16;
6759 Bit8u sector_count;
6760 unsigned int i;
6761 Bit16u tempbx;
6762 Bit16u dpsize;
6763
6764 Bit16u count, segment, offset;
6765 Bit32u lba;
6766 Bit16u error;
6767
6768 BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6769
6770 write_byte(0x0040, 0x008e, 0); // clear completion flag
6771
6772 /* at this point, DL is >= 0x80 to be passed from the floppy int13h
6773 handler code */
6774 /* check how many disks first (cmos reg 0x12), return an error if
6775 drive not present */
6776 drive_map = inb_cmos(0x12);
6777 drive_map = (((drive_map & 0xf0)==0) ? 0 : 1) |
6778 (((drive_map & 0x0f)==0) ? 0 : 2);
6779 n_drives = (drive_map==0) ? 0 :
6780 ((drive_map==3) ? 2 : 1);
6781
6782 if (!(drive_map & (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
6783 SET_AH(0x01);
6784 SET_DISK_RET_STATUS(0x01);
6785 SET_CF(); /* error occurred */
6786 return;
6787 }
6788
6789 switch (GET_AH()) {
6790
6791 case 0x00: /* disk controller reset */
6792BX_DEBUG_INT13_HD("int13_f00\n");
6793
6794 SET_AH(0);
6795 SET_DISK_RET_STATUS(0);
6796 set_diskette_ret_status(0);
6797 set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
6798 set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
6799 CLEAR_CF(); /* successful */
6800 return;
6801 break;
6802
6803 case 0x01: /* read disk status */
6804BX_DEBUG_INT13_HD("int13_f01\n");
6805 status = read_byte(0x0040, 0x0074);
6806 SET_AH(status);
6807 SET_DISK_RET_STATUS(0);
6808 /* set CF if error status read */
6809 if (status) SET_CF();
6810 else CLEAR_CF();
6811 return;
6812 break;
6813
6814 case 0x04: // verify disk sectors
6815 case 0x02: // read disk sectors
6816 drive = GET_ELDL();
6817 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6818
6819 num_sectors = GET_AL();
6820 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
6821 sector = (GET_CL() & 0x3f);
6822 head = GET_DH();
6823
6824
6825 if (hd_cylinders > 1024) {
6826 if (hd_cylinders <= 2048) {
6827 cylinder <<= 1;
6828 }
6829 else if (hd_cylinders <= 4096) {
6830 cylinder <<= 2;
6831 }
6832 else if (hd_cylinders <= 8192) {
6833 cylinder <<= 3;
6834 }
6835 else { // hd_cylinders <= 16384
6836 cylinder <<= 4;
6837 }
6838
6839 ax = head / hd_heads;
6840 cyl_mod = ax & 0xff;
6841 head = ax >> 8;
6842 cylinder |= cyl_mod;
6843 }
6844
6845 if ( (cylinder >= hd_cylinders) ||
6846 (sector > hd_sectors) ||
6847 (head >= hd_heads) ) {
6848 SET_AH(1);
6849 SET_DISK_RET_STATUS(1);
6850 SET_CF(); /* error occurred */
6851 return;
6852 }
6853
6854 if ( (num_sectors > 128) || (num_sectors == 0) )
6855 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6856
6857 if (head > 15)
6858 BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
6859
6860 if ( GET_AH() == 0x04 ) {
6861 SET_AH(0);
6862 SET_DISK_RET_STATUS(0);
6863 CLEAR_CF();
6864 return;
6865 }
6866
6867 status = inb(0x1f7);
6868 if (status & 0x80) {
6869 BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
6870 }
6871 outb(0x01f2, num_sectors);
6872 /* activate LBA? (tomv) */
6873 if (hd_heads > 16) {
6874BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder, head, sector);
6875 outLBA(cylinder,hd_heads,head,hd_sectors,sector,drive);
6876 }
6877 else {
6878 outb(0x01f3, sector);
6879 outb(0x01f4, cylinder & 0x00ff);
6880 outb(0x01f5, cylinder >> 8);
6881 outb(0x01f6, 0xa0 | ((drive & 0x01)<<4) | (head & 0x0f));
6882 }
6883 outb(0x01f7, 0x20);
6884
6885 while (1) {
6886 status = inb(0x1f7);
6887 if ( !(status & 0x80) ) break;
6888 }
6889
6890 if (status & 0x01) {
6891 BX_PANIC("hard drive BIOS:(read/verify) read error\n");
6892 } else if ( !(status & 0x08) ) {
6893 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6894 BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
6895 }
6896
6897 sector_count = 0;
6898 tempbx = BX;
6899
6900ASM_START
6901 sti ;; enable higher priority interrupts
6902ASM_END
6903
6904 while (1) {
6905ASM_START
6906 ;; store temp bx in real DI register
6907 push bp
6908 mov bp, sp
6909 mov di, _int13_harddisk.tempbx + 2 [bp]
6910 pop bp
6911
6912 ;; adjust if there will be an overrun
6913 cmp di, #0xfe00
6914 jbe i13_f02_no_adjust
6915i13_f02_adjust:
6916 sub di, #0x0200 ; sub 512 bytes from offset
6917 mov ax, es
6918 add ax, #0x0020 ; add 512 to segment
6919 mov es, ax
6920
6921i13_f02_no_adjust:
6922 mov cx, #0x0100 ;; counter (256 words = 512b)
6923 mov dx, #0x01f0 ;; AT data read port
6924
6925 rep
6926 insw ;; CX words transferred from port(DX) to ES:[DI]
6927
6928i13_f02_done:
6929 ;; store real DI register back to temp bx
6930 push bp
6931 mov bp, sp
6932 mov _int13_harddisk.tempbx + 2 [bp], di
6933 pop bp
6934ASM_END
6935
6936 sector_count++;
6937 num_sectors--;
6938 if (num_sectors == 0) {
6939 status = inb(0x1f7);
6940 if ( (status & 0xc9) != 0x40 )
6941 BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status);
6942 break;
6943 }
6944 else {
6945 status = inb(0x1f7);
6946 if ( (status & 0xc9) != 0x48 )
6947 BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status);
6948 continue;
6949 }
6950 }
6951
6952 SET_AH(0);
6953 SET_DISK_RET_STATUS(0);
6954 SET_AL(sector_count);
6955 CLEAR_CF(); /* successful */
6956 return;
6957 break;
6958
6959
6960 case 0x03: /* write disk sectors */
6961BX_DEBUG_INT13_HD("int13_f03\n");
6962 drive = GET_ELDL ();
6963 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6964
6965 num_sectors = GET_AL();
6966 cylinder = GET_CH();
6967 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
6968 sector = (GET_CL() & 0x3f);
6969 head = GET_DH();
6970
6971 if (hd_cylinders > 1024) {
6972 if (hd_cylinders <= 2048) {
6973 cylinder <<= 1;
6974 }
6975 else if (hd_cylinders <= 4096) {
6976 cylinder <<= 2;
6977 }
6978 else if (hd_cylinders <= 8192) {
6979 cylinder <<= 3;
6980 }
6981 else { // hd_cylinders <= 16384
6982 cylinder <<= 4;
6983 }
6984
6985 ax = head / hd_heads;
6986 cyl_mod = ax & 0xff;
6987 head = ax >> 8;
6988 cylinder |= cyl_mod;
6989 }
6990
6991 if ( (cylinder >= hd_cylinders) ||
6992 (sector > hd_sectors) ||
6993 (head >= hd_heads) ) {
6994 SET_AH( 1);
6995 SET_DISK_RET_STATUS(1);
6996 SET_CF(); /* error occurred */
6997 return;
6998 }
6999
7000 if ( (num_sectors > 128) || (num_sectors == 0) )
7001 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
7002
7003 if (head > 15)
7004 BX_PANIC("hard drive BIOS:(read) head > 15\n");
7005
7006 status = inb(0x1f7);
7007 if (status & 0x80) {
7008 BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
7009 }
7010// should check for Drive Ready Bit also in status reg
7011 outb(0x01f2, num_sectors);
7012
7013 /* activate LBA? (tomv) */
7014 if (hd_heads > 16) {
7015BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder, head, sector);
7016 outLBA(cylinder,hd_heads,head,hd_sectors,sector,GET_ELDL());
7017 }
7018 else {
7019 outb(0x01f3, sector);
7020 outb(0x01f4, cylinder & 0x00ff);
7021 outb(0x01f5, cylinder >> 8);
7022 outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head & 0x0f));
7023 }
7024 outb(0x01f7, 0x30);
7025
7026 // wait for busy bit to turn off after seeking
7027 while (1) {
7028 status = inb(0x1f7);
7029 if ( !(status & 0x80) ) break;
7030 }
7031
7032 if ( !(status & 0x08) ) {
7033 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
7034 BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
7035 }
7036
7037 sector_count = 0;
7038 tempbx = BX;
7039
7040ASM_START
7041 sti ;; enable higher priority interrupts
7042ASM_END
7043
7044 while (1) {
7045ASM_START
7046 ;; store temp bx in real SI register
7047 push bp
7048 mov bp, sp
7049 mov si, _int13_harddisk.tempbx + 2 [bp]
7050 pop bp
7051
7052 ;; adjust if there will be an overrun
7053 cmp si, #0xfe00
7054 jbe i13_f03_no_adjust
7055i13_f03_adjust:
7056 sub si, #0x0200 ; sub 512 bytes from offset
7057 mov ax, es
7058 add ax, #0x0020 ; add 512 to segment
7059 mov es, ax
7060
7061i13_f03_no_adjust:
7062 mov cx, #0x0100 ;; counter (256 words = 512b)
7063 mov dx, #0x01f0 ;; AT data read port
7064
7065 seg ES
7066 rep
7067 outsw ;; CX words transferred from ES:[SI] to port(DX)
7068
7069 ;; store real SI register back to temp bx
7070 push bp
7071 mov bp, sp
7072 mov _int13_harddisk.tempbx + 2 [bp], si
7073 pop bp
7074ASM_END
7075
7076 sector_count++;
7077 num_sectors--;
7078 if (num_sectors == 0) {
7079 status = inb(0x1f7);
7080 if ( (status & 0xe9) != 0x40 )
7081 BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status);
7082 break;
7083 }
7084 else {
7085 status = inb(0x1f7);
7086 if ( (status & 0xc9) != 0x48 )
7087 BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status);
7088 continue;
7089 }
7090 }
7091
7092 SET_AH(0);
7093 SET_DISK_RET_STATUS(0);
7094 SET_AL(sector_count);
7095 CLEAR_CF(); /* successful */
7096 return;
7097 break;
7098
7099 case 0x05: /* format disk track */
7100BX_DEBUG_INT13_HD("int13_f05\n");
7101 BX_PANIC("format disk track called\n");
7102 /* nop */
7103 SET_AH(0);
7104 SET_DISK_RET_STATUS(0);
7105 CLEAR_CF(); /* successful */
7106 return;
7107 break;
7108
7109 case 0x08: /* read disk drive parameters */
7110BX_DEBUG_INT13_HD("int13_f08\n");
7111
7112 drive = GET_ELDL ();
7113 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
7114
7115 // translate CHS
7116 //
7117 if (hd_cylinders <= 1024) {
7118 // hd_cylinders >>= 0;
7119 // hd_heads <<= 0;
7120 }
7121 else if (hd_cylinders <= 2048) {
7122 hd_cylinders >>= 1;
7123 hd_heads <<= 1;
7124 }
7125 else if (hd_cylinders <= 4096) {
7126 hd_cylinders >>= 2;
7127 hd_heads <<= 2;
7128 }
7129 else if (hd_cylinders <= 8192) {
7130 hd_cylinders >>= 3;
7131 hd_heads <<= 3;
7132 }
7133 else { // hd_cylinders <= 16384
7134 hd_cylinders >>= 4;
7135 hd_heads <<= 4;
7136 }
7137
7138 max_cylinder = hd_cylinders - 2; /* 0 based */
7139 SET_AL(0);
7140 SET_CH(max_cylinder & 0xff);
7141 SET_CL(((max_cylinder >> 2) & 0xc0) | (hd_sectors & 0x3f));
7142 SET_DH(hd_heads - 1);
7143 SET_DL(n_drives); /* returns 0, 1, or 2 hard drives */
7144 SET_AH(0);
7145 SET_DISK_RET_STATUS(0);
7146 CLEAR_CF(); /* successful */
7147
7148 return;
7149 break;
7150
7151 case 0x09: /* initialize drive parameters */
7152BX_DEBUG_INT13_HD("int13_f09\n");
7153 SET_AH(0);
7154 SET_DISK_RET_STATUS(0);
7155 CLEAR_CF(); /* successful */
7156 return;
7157 break;
7158
7159 case 0x0a: /* read disk sectors with ECC */
7160BX_DEBUG_INT13_HD("int13_f0a\n");
7161 case 0x0b: /* write disk sectors with ECC */
7162BX_DEBUG_INT13_HD("int13_f0b\n");
7163 BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
7164 return;
7165 break;
7166
7167 case 0x0c: /* seek to specified cylinder */
7168BX_DEBUG_INT13_HD("int13_f0c\n");
7169 BX_INFO("int13h function 0ch (seek) not implemented!\n");
7170 SET_AH(0);
7171 SET_DISK_RET_STATUS(0);
7172 CLEAR_CF(); /* successful */
7173 return;
7174 break;
7175
7176 case 0x0d: /* alternate disk reset */
7177BX_DEBUG_INT13_HD("int13_f0d\n");
7178 SET_AH(0);
7179 SET_DISK_RET_STATUS(0);
7180 CLEAR_CF(); /* successful */
7181 return;
7182 break;
7183
7184 case 0x10: /* check drive ready */
7185BX_DEBUG_INT13_HD("int13_f10\n");
7186 //SET_AH(0);
7187 //SET_DISK_RET_STATUS(0);
7188 //CLEAR_CF(); /* successful */
7189 //return;
7190 //break;
7191
7192 // should look at 40:8E also???
7193 status = inb(0x01f7);
7194 if ( (status & 0xc0) == 0x40 ) {
7195 SET_AH(0);
7196 SET_DISK_RET_STATUS(0);
7197 CLEAR_CF(); // drive ready
7198 return;
7199 }
7200 else {
7201 SET_AH(0xAA);
7202 SET_DISK_RET_STATUS(0xAA);
7203 SET_CF(); // not ready
7204 return;
7205 }
7206 break;
7207
7208 case 0x11: /* recalibrate */
7209BX_DEBUG_INT13_HD("int13_f11\n");
7210 SET_AH(0);
7211 SET_DISK_RET_STATUS(0);
7212 CLEAR_CF(); /* successful */
7213 return;
7214 break;
7215
7216 case 0x14: /* controller internal diagnostic */
7217BX_DEBUG_INT13_HD("int13_f14\n");
7218 SET_AH(0);
7219 SET_DISK_RET_STATUS(0);
7220 CLEAR_CF(); /* successful */
7221 SET_AL(0);
7222 return;
7223 break;
7224
7225 case 0x15: /* read disk drive size */
7226 drive = GET_ELDL();
7227 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
7228ASM_START
7229 push bp
7230 mov bp, sp
7231 mov al, _int13_harddisk.hd_heads + 2 [bp]
7232 mov ah, _int13_harddisk.hd_sectors + 2 [bp]
7233 mul al, ah ;; ax = heads * sectors
7234 mov bx, _int13_harddisk.hd_cylinders + 2 [bp]
7235 dec bx ;; use (cylinders - 1) ???
7236 mul ax, bx ;; dx:ax = (cylinders -1) * (heads * sectors)
7237 ;; now we need to move the 32bit result dx:ax to what the
7238 ;; BIOS wants which is cx:dx.
7239 ;; and then into CX:DX on the stack
7240 mov _int13_harddisk.CX + 2 [bp], dx
7241 mov _int13_harddisk.DX + 2 [bp], ax
7242 pop bp
7243ASM_END
7244 SET_AH(3); // hard disk accessible
7245 SET_DISK_RET_STATUS(0); // ??? should this be 0
7246 CLEAR_CF(); // successful
7247 return;
7248 break;
7249
7250 case 0x18: // set media type for format
7251 case 0x41: // IBM/MS
7252 case 0x42: // IBM/MS
7253 case 0x43: // IBM/MS
7254 case 0x44: // IBM/MS
7255 case 0x45: // IBM/MS lock/unlock drive
7256 case 0x46: // IBM/MS eject media
7257 case 0x47: // IBM/MS extended seek
7258 case 0x49: // IBM/MS extended media change
7259 case 0x50: // IBM/MS send packet command
7260 default:
7261 BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
7262
7263 SET_AH(1); // code=invalid function in AH or invalid parameter
7264 SET_DISK_RET_STATUS(1);
7265 SET_CF(); /* unsuccessful */
7266 return;
7267 break;
7268 }
7269}
7270
7271static char panic_msg_reg12h[] = "HD%d cmos reg 12h not type F\n";
7272static char panic_msg_reg19h[] = "HD%d cmos reg %02xh not user definable type 47\n";
7273
7274 void
7275get_hd_geometry(drive, hd_cylinders, hd_heads, hd_sectors)
7276 Bit8u drive;
7277 Bit16u *hd_cylinders;
7278 Bit8u *hd_heads;
7279 Bit8u *hd_sectors;
7280{
7281 Bit8u hd_type;
7282 Bit16u ss;
7283 Bit16u cylinders;
7284 Bit8u iobase;
7285
7286 ss = get_SS();
7287 if (drive == 0x80) {
7288 hd_type = inb_cmos(0x12) & 0xf0;
7289 if (hd_type != 0xf0)
7290 BX_INFO(panic_msg_reg12h,0);
7291 hd_type = inb_cmos(0x19); // HD0: extended type
7292 if (hd_type != 47)
7293 BX_INFO(panic_msg_reg19h,0,0x19);
7294 iobase = 0x1b;
7295 } else {
7296 hd_type = inb_cmos(0x12) & 0x0f;
7297 if (hd_type != 0x0f)
7298 BX_INFO(panic_msg_reg12h,1);
7299 hd_type = inb_cmos(0x1a); // HD1: extended type
7300 if (hd_type != 47)
7301 BX_INFO(panic_msg_reg19h,0,0x1a);
7302 iobase = 0x24;
7303 }
7304
7305 // cylinders
7306 cylinders = inb_cmos(iobase) | (inb_cmos(iobase+1) << 8);
7307 write_word(ss, hd_cylinders, cylinders);
7308
7309 // heads
7310 write_byte(ss, hd_heads, inb_cmos(iobase+2));
7311
7312 // sectors per track
7313 write_byte(ss, hd_sectors, inb_cmos(iobase+8));
7314}
7315
7316#endif //else BX_USE_ATADRV
7317
7318#if BX_SUPPORT_FLOPPY
7319
7320//////////////////////
7321// FLOPPY functions //
7322//////////////////////
7323
7324void floppy_reset_controller()
7325{
7326 Bit8u val8;
7327
7328 // Reset controller
7329 val8 = inb(0x03f2);
7330 outb(0x03f2, val8 & ~0x04);
7331 outb(0x03f2, val8 | 0x04);
7332
7333 // Wait for controller to come out of reset
7334 do {
7335 val8 = inb(0x3f4);
7336 } while ( (val8 & 0xc0) != 0x80 );
7337}
7338
7339void floppy_prepare_controller(drive)
7340 Bit16u drive;
7341{
7342 Bit8u val8, dor, prev_reset;
7343
7344 // set 40:3e bit 7 to 0
7345 val8 = read_byte(0x0040, 0x003e);
7346 val8 &= 0x7f;
7347 write_byte(0x0040, 0x003e, val8);
7348
7349 // turn on motor of selected drive, DMA & int enabled, normal operation
7350 prev_reset = inb(0x03f2) & 0x04;
7351 if (drive)
7352 dor = 0x20;
7353 else
7354 dor = 0x10;
7355 dor |= 0x0c;
7356 dor |= drive;
7357 outb(0x03f2, dor);
7358
7359 // reset the disk motor timeout value of INT 08
7360 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
7361
7362#ifdef VBOX
7363 // program data rate
7364 val8 = read_byte(0x0040, 0x008b);
7365 val8 >>= 6;
7366 outb(0x03f7, val8);
7367#endif
7368
7369 // wait for drive readiness
7370 do {
7371 val8 = inb(0x3f4);
7372 } while ( (val8 & 0xc0) != 0x80 );
7373
7374 if (prev_reset == 0) {
7375 // turn on interrupts
7376ASM_START
7377 sti
7378ASM_END
7379 // wait on 40:3e bit 7 to become 1
7380 do {
7381 val8 = read_byte(0x0040, 0x003e);
7382 } while ( (val8 & 0x80) == 0 );
7383 val8 &= 0x7f;
7384ASM_START
7385 cli
7386ASM_END
7387 write_byte(0x0040, 0x003e, val8);
7388 }
7389}
7390
7391 bx_bool
7392floppy_media_known(drive)
7393 Bit16u drive;
7394{
7395 Bit8u val8;
7396 Bit16u media_state_offset;
7397
7398 val8 = read_byte(0x0040, 0x003e); // diskette recal status
7399 if (drive)
7400 val8 >>= 1;
7401 val8 &= 0x01;
7402 if (val8 == 0)
7403 return(0);
7404
7405 media_state_offset = 0x0090;
7406 if (drive)
7407 media_state_offset += 1;
7408
7409 val8 = read_byte(0x0040, media_state_offset);
7410 val8 = (val8 >> 4) & 0x01;
7411 if (val8 == 0)
7412 return(0);
7413
7414 // check pass, return KNOWN
7415 return(1);
7416}
7417
7418 bx_bool
7419floppy_read_id(drive)
7420 Bit16u drive;
7421{
7422 Bit8u val8;
7423 Bit8u return_status[7];
7424
7425 floppy_prepare_controller(drive);
7426
7427 // send Read ID command (2 bytes) to controller
7428 outb(0x03f5, 0x4a); // 4a: Read ID (MFM)
7429 outb(0x03f5, drive); // 0=drive0, 1=drive1, head always 0
7430
7431 // turn on interrupts
7432ASM_START
7433 sti
7434ASM_END
7435
7436 // wait on 40:3e bit 7 to become 1
7437 do {
7438 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7439 } while ( val8 == 0 );
7440
7441 val8 = 0; // separate asm from while() loop
7442 // turn off interrupts
7443ASM_START
7444 cli
7445ASM_END
7446
7447 // read 7 return status bytes from controller
7448 return_status[0] = inb(0x3f5);
7449 return_status[1] = inb(0x3f5);
7450 return_status[2] = inb(0x3f5);
7451 return_status[3] = inb(0x3f5);
7452 return_status[4] = inb(0x3f5);
7453 return_status[5] = inb(0x3f5);
7454 return_status[6] = inb(0x3f5);
7455
7456 if ( (return_status[0] & 0xc0) != 0 )
7457 return(0);
7458 else
7459 return(1);
7460}
7461
7462 bx_bool
7463floppy_media_sense(drive)
7464 Bit16u drive;
7465{
7466 bx_bool retval;
7467 Bit16u media_state_offset;
7468 Bit8u drive_type, config_data, media_state;
7469
7470 if (floppy_drive_recal(drive) == 0) {
7471 return(0);
7472 }
7473
7474 // Try the diskette data rates in the following order:
7475 // 1 Mbps -> 500 Kbps -> 300 Kbps -> 250 Kbps
7476 // The 1 Mbps rate is only tried for 2.88M drives.
7477
7478 // ** config_data **
7479 // Bitfields for diskette media control:
7480 // Bit(s) Description (Table M0028)
7481 // 7-6 last data rate set by controller
7482 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
7483 // 5-4 last diskette drive step rate selected
7484 // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
7485 // 3-2 {data rate at start of operation}
7486 // 1-0 reserved
7487
7488 // ** media_state **
7489 // Bitfields for diskette drive media state:
7490 // Bit(s) Description (Table M0030)
7491 // 7-6 data rate
7492 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
7493 // 5 double stepping required (e.g. 360kB in 1.2MB)
7494 // 4 media type established
7495 // 3 drive capable of supporting 4MB media
7496 // 2-0 on exit from BIOS, contains
7497 // 000 trying 360kB in 360kB
7498 // 001 trying 360kB in 1.2MB
7499 // 010 trying 1.2MB in 1.2MB
7500 // 011 360kB in 360kB established
7501 // 100 360kB in 1.2MB established
7502 // 101 1.2MB in 1.2MB established
7503 // 110 reserved
7504 // 111 all other formats/drives
7505
7506 drive_type = inb_cmos(0x10);
7507 if (drive == 0)
7508 drive_type >>= 4;
7509 else
7510 drive_type &= 0x0f;
7511 if ( drive_type == 1 ) {
7512 // 360K 5.25" drive
7513 config_data = 0x00; // 0000 0000
7514 media_state = 0x15; // 0001 0101
7515 retval = 1;
7516 }
7517 else if ( drive_type == 2 ) {
7518 // 1.2 MB 5.25" drive
7519 config_data = 0x00; // 0000 0000
7520 media_state = 0x35; // 0011 0101 // need double stepping??? (bit 5)
7521 retval = 1;
7522 }
7523 else if ( drive_type == 3 ) {
7524 // 720K 3.5" drive
7525 config_data = 0x00; // 0000 0000 ???
7526 media_state = 0x17; // 0001 0111
7527 retval = 1;
7528 }
7529 else if ( drive_type == 4 ) {
7530 // 1.44 MB 3.5" drive
7531 config_data = 0x00; // 0000 0000
7532 media_state = 0x17; // 0001 0111
7533 retval = 1;
7534 }
7535 else if ( drive_type == 5 ) {
7536 // 2.88 MB 3.5" drive
7537 config_data = 0xCC; // 1100 1100
7538 media_state = 0xD7; // 1101 0111
7539 retval = 1;
7540 }
7541 //
7542 // Extended floppy size uses special cmos setting
7543 else if ( drive_type == 6 ) {
7544 // 160k 5.25" drive
7545 config_data = 0x00; // 0000 0000
7546 media_state = 0x27; // 0010 0111
7547 retval = 1;
7548 }
7549 else if ( drive_type == 7 ) {
7550 // 180k 5.25" drive
7551 config_data = 0x00; // 0000 0000
7552 media_state = 0x27; // 0010 0111
7553 retval = 1;
7554 }
7555 else if ( drive_type == 8 ) {
7556 // 320k 5.25" drive
7557 config_data = 0x00; // 0000 0000
7558 media_state = 0x27; // 0010 0111
7559 retval = 1;
7560 }
7561
7562 else {
7563 // not recognized
7564 config_data = 0x00; // 0000 0000
7565 media_state = 0x00; // 0000 0000
7566 retval = 0;
7567 }
7568
7569 write_byte(0x0040, 0x008B, config_data);
7570 while (!floppy_read_id(drive)) {
7571 if ((config_data & 0xC0) == 0x80) {
7572 // If even 250 Kbps failed, we can't do much
7573 break;
7574 }
7575 switch (config_data & 0xC0) {
7576 case 0xC0: // 1 Mbps
7577 config_data = config_data & 0x3F | 0x00;
7578 break;
7579 case 0x00: // 500 Kbps
7580 config_data = config_data & 0x3F | 0x40;
7581 break;
7582 case 0x40: // 300 Kbps
7583 config_data = config_data & 0x3F | 0x80;
7584 break;
7585 }
7586 write_byte(0x0040, 0x008B, config_data);
7587 }
7588
7589 if (drive == 0)
7590 media_state_offset = 0x0090;
7591 else
7592 media_state_offset = 0x0091;
7593 write_byte(0x0040, 0x008B, config_data);
7594 write_byte(0x0040, media_state_offset, media_state);
7595
7596 return(retval);
7597}
7598
7599 bx_bool
7600floppy_drive_recal(drive)
7601 Bit16u drive;
7602{
7603 Bit8u val8;
7604 Bit16u curr_cyl_offset;
7605
7606 floppy_prepare_controller(drive);
7607
7608 // send Recalibrate command (2 bytes) to controller
7609 outb(0x03f5, 0x07); // 07: Recalibrate
7610 outb(0x03f5, drive); // 0=drive0, 1=drive1
7611
7612 // turn on interrupts
7613ASM_START
7614 sti
7615ASM_END
7616
7617 // wait on 40:3e bit 7 to become 1
7618 do {
7619 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7620 } while ( val8 == 0 );
7621
7622 val8 = 0; // separate asm from while() loop
7623 // turn off interrupts
7624ASM_START
7625 cli
7626ASM_END
7627
7628 // set 40:3e bit 7 to 0, and calibrated bit
7629 val8 = read_byte(0x0040, 0x003e);
7630 val8 &= 0x7f;
7631 if (drive) {
7632 val8 |= 0x02; // Drive 1 calibrated
7633 curr_cyl_offset = 0x0095;
7634 } else {
7635 val8 |= 0x01; // Drive 0 calibrated
7636 curr_cyl_offset = 0x0094;
7637 }
7638 write_byte(0x0040, 0x003e, val8);
7639 write_byte(0x0040, curr_cyl_offset, 0); // current cylinder is 0
7640
7641 return(1);
7642}
7643
7644
7645
7646 bx_bool
7647floppy_drive_exists(drive)
7648 Bit16u drive;
7649{
7650 Bit8u drive_type;
7651
7652 // check CMOS to see if drive exists
7653 drive_type = inb_cmos(0x10);
7654 if (drive == 0)
7655 drive_type >>= 4;
7656 else
7657 drive_type &= 0x0f;
7658 if ( drive_type == 0 )
7659 return(0);
7660 else
7661 return(1);
7662}
7663
7664 void
7665int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
7666 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
7667{
7668 Bit8u drive, num_sectors, track, sector, head, status;
7669 Bit16u base_address, base_count, base_es;
7670 Bit8u page, mode_register, val8, dor;
7671 Bit8u return_status[7];
7672 Bit8u drive_type, num_floppies, ah;
7673 Bit16u es, last_addr;
7674
7675 BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
7676
7677 ah = GET_AH();
7678
7679 switch ( ah ) {
7680 case 0x00: // diskette controller reset
7681BX_DEBUG_INT13_FL("floppy f00\n");
7682 drive = GET_ELDL();
7683 if (drive > 1) {
7684 SET_AH(1); // invalid param
7685 set_diskette_ret_status(1);
7686 SET_CF();
7687 return;
7688 }
7689 drive_type = inb_cmos(0x10);
7690
7691 if (drive == 0)
7692 drive_type >>= 4;
7693 else
7694 drive_type &= 0x0f;
7695 if (drive_type == 0) {
7696 SET_AH(0x80); // drive not responding
7697 set_diskette_ret_status(0x80);
7698 SET_CF();
7699 return;
7700 }
7701
7702 // force re-calibration etc.
7703 write_byte(0x0040, 0x003e, 0);
7704
7705 SET_AH(0);
7706 set_diskette_ret_status(0);
7707 CLEAR_CF(); // successful
7708 set_diskette_current_cyl(drive, 0); // current cylinder
7709 return;
7710
7711 case 0x01: // Read Diskette Status
7712 CLEAR_CF();
7713 val8 = read_byte(0x0000, 0x0441);
7714 SET_AH(val8);
7715 if (val8) {
7716 SET_CF();
7717 }
7718 return;
7719
7720 case 0x02: // Read Diskette Sectors
7721 case 0x03: // Write Diskette Sectors
7722 case 0x04: // Verify Diskette Sectors
7723 num_sectors = GET_AL();
7724 track = GET_CH();
7725 sector = GET_CL();
7726 head = GET_DH();
7727 drive = GET_ELDL();
7728
7729 if ( (drive > 1) || (head > 1) ||
7730 (num_sectors == 0) || (num_sectors > 72) ) {
7731BX_INFO("floppy: drive>1 || head>1 ...\n");
7732 SET_AH(1);
7733 set_diskette_ret_status(1);
7734 SET_AL(0); // no sectors read
7735 SET_CF(); // error occurred
7736 return;
7737 }
7738
7739 // see if drive exists
7740 if (floppy_drive_exists(drive) == 0) {
7741 SET_AH(0x80); // not responding
7742 set_diskette_ret_status(0x80);
7743 SET_AL(0); // no sectors read
7744 SET_CF(); // error occurred
7745 return;
7746 }
7747
7748 // see if media in drive, and type is known
7749 if (floppy_media_known(drive) == 0) {
7750 if (floppy_media_sense(drive) == 0) {
7751 SET_AH(0x0C); // Media type not found
7752 set_diskette_ret_status(0x0C);
7753 SET_AL(0); // no sectors read
7754 SET_CF(); // error occurred
7755 return;
7756 }
7757 }
7758
7759 if (ah == 0x02) {
7760 // Read Diskette Sectors
7761
7762 //-----------------------------------
7763 // set up DMA controller for transfer
7764 //-----------------------------------
7765
7766 // es:bx = pointer to where to place information from diskette
7767 // port 04: DMA-1 base and current address, channel 2
7768 // port 05: DMA-1 base and current count, channel 2
7769 page = (ES >> 12); // upper 4 bits
7770 base_es = (ES << 4); // lower 16bits contributed by ES
7771 base_address = base_es + BX; // lower 16 bits of address
7772 // contributed by ES:BX
7773 if ( base_address < base_es ) {
7774 // in case of carry, adjust page by 1
7775 page++;
7776 }
7777 base_count = (num_sectors * 512) - 1;
7778
7779 // check for 64K boundary overrun
7780 last_addr = base_address + base_count;
7781 if (last_addr < base_address) {
7782 SET_AH(0x09);
7783 set_diskette_ret_status(0x09);
7784 SET_AL(0); // no sectors read
7785 SET_CF(); // error occurred
7786 return;
7787 }
7788
7789 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7790 outb(0x000a, 0x06);
7791
7792 BX_DEBUG_INT13_FL("clear flip-flop\n");
7793 outb(0x000c, 0x00); // clear flip-flop
7794 outb(0x0004, base_address);
7795 outb(0x0004, base_address>>8);
7796 BX_DEBUG_INT13_FL("clear flip-flop\n");
7797 outb(0x000c, 0x00); // clear flip-flop
7798 outb(0x0005, base_count);
7799 outb(0x0005, base_count>>8);
7800
7801 // port 0b: DMA-1 Mode Register
7802 mode_register = 0x46; // single mode, increment, autoinit disable,
7803 // transfer type=write, channel 2
7804 BX_DEBUG_INT13_FL("setting mode register\n");
7805 outb(0x000b, mode_register);
7806
7807 BX_DEBUG_INT13_FL("setting page register\n");
7808 // port 81: DMA-1 Page Register, channel 2
7809 outb(0x0081, page);
7810
7811 BX_DEBUG_INT13_FL("unmask chan 2\n");
7812 outb(0x000a, 0x02); // unmask channel 2
7813
7814 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7815 outb(0x000a, 0x02);
7816
7817 //--------------------------------------
7818 // set up floppy controller for transfer
7819 //--------------------------------------
7820 floppy_prepare_controller(drive);
7821
7822 // send read-normal-data command (9 bytes) to controller
7823 outb(0x03f5, 0xe6); // e6: read normal data
7824 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7825 outb(0x03f5, track);
7826 outb(0x03f5, head);
7827 outb(0x03f5, sector);
7828 outb(0x03f5, 2); // 512 byte sector size
7829 outb(0x03f5, sector + num_sectors - 1); // last sector to read on track
7830 outb(0x03f5, 0); // Gap length
7831 outb(0x03f5, 0xff); // Gap length
7832
7833 // turn on interrupts
7834 ASM_START
7835 sti
7836 ASM_END
7837
7838 // wait on 40:3e bit 7 to become 1
7839 do {
7840 val8 = read_byte(0x0040, 0x0040);
7841 if (val8 == 0) {
7842 floppy_reset_controller();
7843 SET_AH(0x80); // drive not ready (timeout)
7844 set_diskette_ret_status(0x80);
7845 SET_AL(0); // no sectors read
7846 SET_CF(); // error occurred
7847 return;
7848 }
7849 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7850 } while ( val8 == 0 );
7851
7852 val8 = 0; // separate asm from while() loop
7853 // turn off interrupts
7854 ASM_START
7855 cli
7856 ASM_END
7857
7858 // set 40:3e bit 7 to 0
7859 val8 = read_byte(0x0040, 0x003e);
7860 val8 &= 0x7f;
7861 write_byte(0x0040, 0x003e, val8);
7862
7863 // check port 3f4 for accessibility to status bytes
7864 val8 = inb(0x3f4);
7865 if ( (val8 & 0xc0) != 0xc0 )
7866 BX_PANIC("int13_diskette: ctrl not ready\n");
7867
7868 // read 7 return status bytes from controller
7869 // using loop index broken, have to unroll...
7870 return_status[0] = inb(0x3f5);
7871 return_status[1] = inb(0x3f5);
7872 return_status[2] = inb(0x3f5);
7873 return_status[3] = inb(0x3f5);
7874 return_status[4] = inb(0x3f5);
7875 return_status[5] = inb(0x3f5);
7876 return_status[6] = inb(0x3f5);
7877 // record in BIOS Data Area
7878 write_byte(0x0040, 0x0042, return_status[0]);
7879 write_byte(0x0040, 0x0043, return_status[1]);
7880 write_byte(0x0040, 0x0044, return_status[2]);
7881 write_byte(0x0040, 0x0045, return_status[3]);
7882 write_byte(0x0040, 0x0046, return_status[4]);
7883 write_byte(0x0040, 0x0047, return_status[5]);
7884 write_byte(0x0040, 0x0048, return_status[6]);
7885
7886 if ( (return_status[0] & 0xc0) != 0 ) {
7887 SET_AH(0x20);
7888 set_diskette_ret_status(0x20);
7889 SET_AL(0); // no sectors read
7890 SET_CF(); // error occurred
7891 return;
7892 }
7893
7894 // ??? should track be new val from return_status[3] ?
7895 set_diskette_current_cyl(drive, track);
7896 // AL = number of sectors read (same value as passed)
7897 SET_AH(0x00); // success
7898 CLEAR_CF(); // success
7899 return;
7900 } else if (ah == 0x03) {
7901 // Write Diskette Sectors
7902
7903 //-----------------------------------
7904 // set up DMA controller for transfer
7905 //-----------------------------------
7906
7907 // es:bx = pointer to where to place information from diskette
7908 // port 04: DMA-1 base and current address, channel 2
7909 // port 05: DMA-1 base and current count, channel 2
7910 page = (ES >> 12); // upper 4 bits
7911 base_es = (ES << 4); // lower 16bits contributed by ES
7912 base_address = base_es + BX; // lower 16 bits of address
7913 // contributed by ES:BX
7914 if ( base_address < base_es ) {
7915 // in case of carry, adjust page by 1
7916 page++;
7917 }
7918 base_count = (num_sectors * 512) - 1;
7919
7920 // check for 64K boundary overrun
7921 last_addr = base_address + base_count;
7922 if (last_addr < base_address) {
7923 SET_AH(0x09);
7924 set_diskette_ret_status(0x09);
7925 SET_AL(0); // no sectors read
7926 SET_CF(); // error occurred
7927 return;
7928 }
7929
7930 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7931 outb(0x000a, 0x06);
7932
7933 outb(0x000c, 0x00); // clear flip-flop
7934 outb(0x0004, base_address);
7935 outb(0x0004, base_address>>8);
7936 outb(0x000c, 0x00); // clear flip-flop
7937 outb(0x0005, base_count);
7938 outb(0x0005, base_count>>8);
7939
7940 // port 0b: DMA-1 Mode Register
7941 mode_register = 0x4a; // single mode, increment, autoinit disable,
7942 // transfer type=read, channel 2
7943 outb(0x000b, mode_register);
7944
7945 // port 81: DMA-1 Page Register, channel 2
7946 outb(0x0081, page);
7947
7948 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7949 outb(0x000a, 0x02);
7950
7951 //--------------------------------------
7952 // set up floppy controller for transfer
7953 //--------------------------------------
7954 floppy_prepare_controller(drive);
7955
7956 // send write-normal-data command (9 bytes) to controller
7957 outb(0x03f5, 0xc5); // c5: write normal data
7958 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7959 outb(0x03f5, track);
7960 outb(0x03f5, head);
7961 outb(0x03f5, sector);
7962 outb(0x03f5, 2); // 512 byte sector size
7963 outb(0x03f5, sector + num_sectors - 1); // last sector to write on track
7964 outb(0x03f5, 0); // Gap length
7965 outb(0x03f5, 0xff); // Gap length
7966
7967 // turn on interrupts
7968 ASM_START
7969 sti
7970 ASM_END
7971
7972 // wait on 40:3e bit 7 to become 1
7973 do {
7974 val8 = read_byte(0x0040, 0x0040);
7975 if (val8 == 0) {
7976 floppy_reset_controller();
7977 SET_AH(0x80); // drive not ready (timeout)
7978 set_diskette_ret_status(0x80);
7979 SET_AL(0); // no sectors written
7980 SET_CF(); // error occurred
7981 return;
7982 }
7983 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7984 } while ( val8 == 0 );
7985
7986 val8 = 0; // separate asm from while() loop
7987 // turn off interrupts
7988 ASM_START
7989 cli
7990 ASM_END
7991
7992 // set 40:3e bit 7 to 0
7993 val8 = read_byte(0x0040, 0x003e);
7994 val8 &= 0x7f;
7995 write_byte(0x0040, 0x003e, val8);
7996
7997 // check port 3f4 for accessibility to status bytes
7998 val8 = inb(0x3f4);
7999 if ( (val8 & 0xc0) != 0xc0 )
8000 BX_PANIC("int13_diskette: ctrl not ready\n");
8001
8002 // read 7 return status bytes from controller
8003 // using loop index broken, have to unroll...
8004 return_status[0] = inb(0x3f5);
8005 return_status[1] = inb(0x3f5);
8006 return_status[2] = inb(0x3f5);
8007 return_status[3] = inb(0x3f5);
8008 return_status[4] = inb(0x3f5);
8009 return_status[5] = inb(0x3f5);
8010 return_status[6] = inb(0x3f5);
8011 // record in BIOS Data Area
8012 write_byte(0x0040, 0x0042, return_status[0]);
8013 write_byte(0x0040, 0x0043, return_status[1]);
8014 write_byte(0x0040, 0x0044, return_status[2]);
8015 write_byte(0x0040, 0x0045, return_status[3]);
8016 write_byte(0x0040, 0x0046, return_status[4]);
8017 write_byte(0x0040, 0x0047, return_status[5]);
8018 write_byte(0x0040, 0x0048, return_status[6]);
8019
8020 if ( (return_status[0] & 0xc0) != 0 ) {
8021 if ( (return_status[1] & 0x02) != 0 ) {
8022 // diskette not writable.
8023 // AH=status code=0x03 (tried to write on write-protected disk)
8024 // AL=number of sectors written=0
8025 AX = 0x0300;
8026 SET_CF();
8027 return;
8028 } else {
8029 BX_PANIC("int13_diskette_function: read error\n");
8030 }
8031 }
8032
8033 // ??? should track be new val from return_status[3] ?
8034 set_diskette_current_cyl(drive, track);
8035 // AL = number of sectors read (same value as passed)
8036 SET_AH(0x00); // success
8037 CLEAR_CF(); // success
8038 return;
8039 } else { // if (ah == 0x04)
8040 // Verify Diskette Sectors
8041
8042 // ??? should track be new val from return_status[3] ?
8043 set_diskette_current_cyl(drive, track);
8044 // AL = number of sectors verified (same value as passed)
8045 CLEAR_CF(); // success
8046 SET_AH(0x00); // success
8047 return;
8048 }
8049 break;
8050
8051 case 0x05: // format diskette track
8052BX_DEBUG_INT13_FL("floppy f05\n");
8053
8054 num_sectors = GET_AL();
8055 track = GET_CH();
8056 head = GET_DH();
8057 drive = GET_ELDL();
8058
8059 if ((drive > 1) || (head > 1) || (track > 79) ||
8060 (num_sectors == 0) || (num_sectors > 18)) {
8061 SET_AH(1);
8062 set_diskette_ret_status(1);
8063 SET_CF(); // error occurred
8064 }
8065
8066 // see if drive exists
8067 if (floppy_drive_exists(drive) == 0) {
8068 SET_AH(0x80); // drive not responding
8069 set_diskette_ret_status(0x80);
8070 SET_CF(); // error occurred
8071 return;
8072 }
8073
8074 // see if media in drive, and type is known
8075 if (floppy_media_known(drive) == 0) {
8076 if (floppy_media_sense(drive) == 0) {
8077 SET_AH(0x0C); // Media type not found
8078 set_diskette_ret_status(0x0C);
8079 SET_AL(0); // no sectors read
8080 SET_CF(); // error occurred
8081 return;
8082 }
8083 }
8084
8085 // set up DMA controller for transfer
8086 page = (ES >> 12); // upper 4 bits
8087 base_es = (ES << 4); // lower 16bits contributed by ES
8088 base_address = base_es + BX; // lower 16 bits of address
8089 // contributed by ES:BX
8090 if ( base_address < base_es ) {
8091 // in case of carry, adjust page by 1
8092 page++;
8093 }
8094 base_count = (num_sectors * 4) - 1;
8095
8096 // check for 64K boundary overrun
8097 last_addr = base_address + base_count;
8098 if (last_addr < base_address) {
8099 SET_AH(0x09);
8100 set_diskette_ret_status(0x09);
8101 SET_AL(0); // no sectors read
8102 SET_CF(); // error occurred
8103 return;
8104 }
8105
8106 outb(0x000a, 0x06);
8107 outb(0x000c, 0x00); // clear flip-flop
8108 outb(0x0004, base_address);
8109 outb(0x0004, base_address>>8);
8110 outb(0x000c, 0x00); // clear flip-flop
8111 outb(0x0005, base_count);
8112 outb(0x0005, base_count>>8);
8113 mode_register = 0x4a; // single mode, increment, autoinit disable,
8114 // transfer type=read, channel 2
8115 outb(0x000b, mode_register);
8116 // port 81: DMA-1 Page Register, channel 2
8117 outb(0x0081, page);
8118 outb(0x000a, 0x02);
8119
8120 // set up floppy controller for transfer
8121 floppy_prepare_controller(drive);
8122
8123 // send format-track command (6 bytes) to controller
8124 outb(0x03f5, 0x4d); // 4d: format track
8125 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
8126 outb(0x03f5, 2); // 512 byte sector size
8127 outb(0x03f5, num_sectors); // number of sectors per track
8128 outb(0x03f5, 0); // Gap length
8129 outb(0x03f5, 0xf6); // Fill byte
8130 // turn on interrupts
8131 ASM_START
8132 sti
8133 ASM_END
8134
8135 // wait on 40:3e bit 7 to become 1
8136 do {
8137 val8 = read_byte(0x0040, 0x0040);
8138 if (val8 == 0) {
8139 floppy_reset_controller();
8140 SET_AH(0x80); // drive not ready (timeout)
8141 set_diskette_ret_status(0x80);
8142 SET_CF(); // error occurred
8143 return;
8144 }
8145 val8 = (read_byte(0x0040, 0x003e) & 0x80);
8146 } while ( val8 == 0 );
8147
8148 val8 = 0; // separate asm from while() loop
8149 // turn off interrupts
8150 ASM_START
8151 cli
8152 ASM_END
8153 // set 40:3e bit 7 to 0
8154 val8 = read_byte(0x0040, 0x003e);
8155 val8 &= 0x7f;
8156 write_byte(0x0040, 0x003e, val8);
8157 // check port 3f4 for accessibility to status bytes
8158 val8 = inb(0x3f4);
8159 if ( (val8 & 0xc0) != 0xc0 )
8160 BX_PANIC("int13_diskette: ctrl not ready\n");
8161
8162 // read 7 return status bytes from controller
8163 // using loop index broken, have to unroll...
8164 return_status[0] = inb(0x3f5);
8165 return_status[1] = inb(0x3f5);
8166 return_status[2] = inb(0x3f5);
8167 return_status[3] = inb(0x3f5);
8168 return_status[4] = inb(0x3f5);
8169 return_status[5] = inb(0x3f5);
8170 return_status[6] = inb(0x3f5);
8171 // record in BIOS Data Area
8172 write_byte(0x0040, 0x0042, return_status[0]);
8173 write_byte(0x0040, 0x0043, return_status[1]);
8174 write_byte(0x0040, 0x0044, return_status[2]);
8175 write_byte(0x0040, 0x0045, return_status[3]);
8176 write_byte(0x0040, 0x0046, return_status[4]);
8177 write_byte(0x0040, 0x0047, return_status[5]);
8178 write_byte(0x0040, 0x0048, return_status[6]);
8179
8180 if ( (return_status[0] & 0xc0) != 0 ) {
8181 if ( (return_status[1] & 0x02) != 0 ) {
8182 // diskette not writable.
8183 // AH=status code=0x03 (tried to write on write-protected disk)
8184 // AL=number of sectors written=0
8185 AX = 0x0300;
8186 SET_CF();
8187 return;
8188 } else {
8189 BX_PANIC("int13_diskette_function: write error\n");
8190 }
8191 }
8192
8193 SET_AH(0);
8194 set_diskette_ret_status(0);
8195 set_diskette_current_cyl(drive, 0);
8196 CLEAR_CF(); // successful
8197 return;
8198
8199
8200 case 0x08: // read diskette drive parameters
8201BX_DEBUG_INT13_FL("floppy f08\n");
8202 drive = GET_ELDL();
8203
8204 if (drive > 1) {
8205 AX = 0;
8206 BX = 0;
8207 CX = 0;
8208 DX = 0;
8209 ES = 0;
8210 DI = 0;
8211 SET_DL(num_floppies);
8212 SET_CF();
8213 return;
8214 }
8215
8216 drive_type = inb_cmos(0x10);
8217 num_floppies = 0;
8218 if (drive_type & 0xf0)
8219 num_floppies++;
8220 if (drive_type & 0x0f)
8221 num_floppies++;
8222
8223 if (drive == 0)
8224 drive_type >>= 4;
8225 else
8226 drive_type &= 0x0f;
8227
8228 SET_BH(0);
8229 SET_BL(drive_type);
8230 SET_AH(0);
8231 SET_AL(0);
8232 SET_DL(num_floppies);
8233
8234 switch (drive_type) {
8235 case 0: // none
8236 CX = 0;
8237 SET_DH(0); // max head #
8238 break;
8239
8240 case 1: // 360KB, 5.25"
8241 CX = 0x2709; // 40 tracks, 9 sectors
8242 SET_DH(1); // max head #
8243 break;
8244
8245 case 2: // 1.2MB, 5.25"
8246 CX = 0x4f0f; // 80 tracks, 15 sectors
8247 SET_DH(1); // max head #
8248 break;
8249
8250 case 3: // 720KB, 3.5"
8251 CX = 0x4f09; // 80 tracks, 9 sectors
8252 SET_DH(1); // max head #
8253 break;
8254
8255 case 4: // 1.44MB, 3.5"
8256 CX = 0x4f12; // 80 tracks, 18 sectors
8257 SET_DH(1); // max head #
8258 break;
8259
8260 case 5: // 2.88MB, 3.5"
8261 CX = 0x4f24; // 80 tracks, 36 sectors
8262 SET_DH(1); // max head #
8263 break;
8264
8265 case 6: // 160k, 5.25"
8266 CX = 0x2708; // 40 tracks, 8 sectors
8267 SET_DH(0); // max head #
8268 break;
8269
8270 case 7: // 180k, 5.25"
8271 CX = 0x2709; // 40 tracks, 9 sectors
8272 SET_DH(0); // max head #
8273 break;
8274
8275 case 8: // 320k, 5.25"
8276 CX = 0x2708; // 40 tracks, 8 sectors
8277 SET_DH(1); // max head #
8278 break;
8279
8280 default: // ?
8281 BX_PANIC("floppy: int13: bad floppy type\n");
8282 }
8283
8284 /* set es & di to point to 11 byte diskette param table in ROM */
8285ASM_START
8286 push bp
8287 mov bp, sp
8288 mov ax, #diskette_param_table2
8289 mov _int13_diskette_function.DI+2[bp], ax
8290 mov _int13_diskette_function.ES+2[bp], cs
8291 pop bp
8292ASM_END
8293 CLEAR_CF(); // success
8294 /* disk status not changed upon success */
8295 return;
8296
8297
8298 case 0x15: // read diskette drive type
8299BX_DEBUG_INT13_FL("floppy f15\n");
8300 drive = GET_ELDL();
8301 if (drive > 1) {
8302 SET_AH(0); // only 2 drives supported
8303 // set_diskette_ret_status here ???
8304 SET_CF();
8305 return;
8306 }
8307 drive_type = inb_cmos(0x10);
8308
8309 if (drive == 0)
8310 drive_type >>= 4;
8311 else
8312 drive_type &= 0x0f;
8313 CLEAR_CF(); // successful, not present
8314 if (drive_type==0) {
8315 SET_AH(0); // drive not present
8316 }
8317 else {
8318 SET_AH(1); // drive present, does not support change line
8319 }
8320
8321 return;
8322
8323 case 0x16: // get diskette change line status
8324BX_DEBUG_INT13_FL("floppy f16\n");
8325 drive = GET_ELDL();
8326 if (drive > 1) {
8327 SET_AH(0x01); // invalid drive
8328 set_diskette_ret_status(0x01);
8329 SET_CF();
8330 return;
8331 }
8332
8333 SET_AH(0x06); // change line not supported
8334 set_diskette_ret_status(0x06);
8335 SET_CF();
8336 return;
8337
8338 case 0x17: // set diskette type for format(old)
8339BX_DEBUG_INT13_FL("floppy f17\n");
8340 /* not used for 1.44M floppies */
8341 SET_AH(0x01); // not supported
8342 set_diskette_ret_status(1); /* not supported */
8343 SET_CF();
8344 return;
8345
8346 case 0x18: // set diskette type for format(new)
8347BX_DEBUG_INT13_FL("floppy f18\n");
8348 SET_AH(0x01); // do later
8349 set_diskette_ret_status(1);
8350 SET_CF();
8351 return;
8352
8353 default:
8354 BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
8355
8356 // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
8357 SET_AH(0x01); // ???
8358 set_diskette_ret_status(1);
8359 SET_CF();
8360 return;
8361 // }
8362 }
8363}
8364#else // #if BX_SUPPORT_FLOPPY
8365 void
8366int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
8367 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
8368{
8369 Bit8u val8;
8370
8371 switch ( GET_AH() ) {
8372
8373 case 0x01: // Read Diskette Status
8374 CLEAR_CF();
8375 val8 = read_byte(0x0000, 0x0441);
8376 SET_AH(val8);
8377 if (val8) {
8378 SET_CF();
8379 }
8380 return;
8381
8382 default:
8383 SET_CF();
8384 write_byte(0x0000, 0x0441, 0x01);
8385 SET_AH(0x01);
8386 }
8387}
8388#endif // #if BX_SUPPORT_FLOPPY
8389
8390 void
8391set_diskette_ret_status(value)
8392 Bit8u value;
8393{
8394 write_byte(0x0040, 0x0041, value);
8395}
8396
8397 void
8398set_diskette_current_cyl(drive, cyl)
8399 Bit8u drive;
8400 Bit8u cyl;
8401{
8402 if (drive > 1)
8403 BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
8404 write_byte(0x0040, 0x0094+drive, cyl);
8405}
8406
8407 void
8408determine_floppy_media(drive)
8409 Bit16u drive;
8410{
8411#if 0
8412 Bit8u val8, DOR, ctrl_info;
8413
8414 ctrl_info = read_byte(0x0040, 0x008F);
8415 if (drive==1)
8416 ctrl_info >>= 4;
8417 else
8418 ctrl_info &= 0x0f;
8419
8420#if 0
8421 if (drive == 0) {
8422 DOR = 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
8423 }
8424 else {
8425 DOR = 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
8426 }
8427#endif
8428
8429 if ( (ctrl_info & 0x04) != 0x04 ) {
8430 // Drive not determined means no drive exists, done.
8431 return;
8432 }
8433
8434#if 0
8435 // check Main Status Register for readiness
8436 val8 = inb(0x03f4) & 0x80; // Main Status Register
8437 if (val8 != 0x80)
8438 BX_PANIC("d_f_m: MRQ bit not set\n");
8439
8440 // change line
8441
8442 // existing BDA values
8443
8444 // turn on drive motor
8445 outb(0x03f2, DOR); // Digital Output Register
8446 //
8447#endif
8448 BX_PANIC("d_f_m: OK so far\n");
8449#endif
8450}
8451
8452 void
8453int17_function(regs, ds, iret_addr)
8454 pusha_regs_t regs; // regs pushed from PUSHA instruction
8455 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8456 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8457{
8458 Bit16u addr,timeout;
8459 Bit8u val8;
8460
8461 ASM_START
8462 sti
8463 ASM_END
8464
8465 addr = read_word(0x0040, (regs.u.r16.dx << 1) + 8);
8466 if ((regs.u.r8.ah < 3) && (regs.u.r16.dx < 3) && (addr > 0)) {
8467 timeout = read_byte(0x0040, 0x0078 + regs.u.r16.dx) << 8;
8468 if (regs.u.r8.ah == 0) {
8469 outb(addr, regs.u.r8.al);
8470 val8 = inb(addr+2);
8471 outb(addr+2, val8 | 0x01); // send strobe
8472 ASM_START
8473 nop
8474 ASM_END
8475 outb(addr+2, val8 & ~0x01);
8476 while (((inb(addr+1) & 0x40) == 0x40) && (timeout)) {
8477 timeout--;
8478 }
8479 }
8480 if (regs.u.r8.ah == 1) {
8481 val8 = inb(addr+2);
8482 outb(addr+2, val8 & ~0x04); // send init
8483 ASM_START
8484 nop
8485 ASM_END
8486 outb(addr+2, val8 | 0x04);
8487 }
8488 val8 = inb(addr+1);
8489 regs.u.r8.ah = (val8 ^ 0x48);
8490 if (!timeout) regs.u.r8.ah |= 0x01;
8491 ClearCF(iret_addr.flags);
8492 } else {
8493 SetCF(iret_addr.flags); // Unsupported
8494 }
8495}
8496
8497// returns bootsegment in ax, drive in bl
8498 Bit32u
8499int19_function(bseqnr)
8500Bit8u bseqnr;
8501{
8502 Bit16u ebda_seg=read_word(0x0040,0x000E);
8503 Bit16u bootseq;
8504 Bit8u bootdrv;
8505 Bit8u bootcd;
8506#ifdef VBOX
8507 Bit8u bootlan;
8508#endif /* VBOX */
8509 Bit8u bootchk;
8510 Bit16u bootseg;
8511 Bit16u status;
8512 Bit8u lastdrive=0;
8513
8514 // if BX_ELTORITO_BOOT is not defined, old behavior
8515 // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
8516 // in preparation for the initial INT 13h (0=floppy A:, 0x80=C:)
8517 // 0: system boot sequence, first drive C: then A:
8518 // 1: system boot sequence, first drive A: then C:
8519 // else BX_ELTORITO_BOOT is defined
8520 // CMOS regs 0x3D and 0x38 contain the boot sequence:
8521 // CMOS reg 0x3D & 0x0f : 1st boot device
8522 // CMOS reg 0x3D & 0xf0 : 2nd boot device
8523 // CMOS reg 0x38 & 0xf0 : 3rd boot device
8524#ifdef VBOX
8525 // CMOS reg 0x3C & 0x0f : 4th boot device
8526#endif /* VBOX */
8527 // boot device codes:
8528 // 0x00 : not defined
8529 // 0x01 : first floppy
8530 // 0x02 : first harddrive
8531 // 0x03 : first cdrom
8532#ifdef VBOX
8533 // 0x04 : local area network
8534#endif /* VBOX */
8535 // else : boot failure
8536
8537 // Get the boot sequence
8538#if BX_ELTORITO_BOOT
8539 bootseq=inb_cmos(0x3d);
8540 bootseq|=((inb_cmos(0x38) & 0xf0) << 4);
8541#ifdef VBOX
8542 bootseq|=((inb_cmos(0x3c) & 0x0f) << 12);
8543 if (read_byte(ebda_seg, &EbdaData->uForceBootDevice))
8544 bootseq = read_byte(ebda_seg, &EbdaData->uForceBootDevice);
8545 /* Boot delay hack. */
8546 if (bseqnr == 1)
8547 delay_boot((inb_cmos(0x3c) & 0xf0) >> 4); /* Implemented in logo.c */
8548#endif /* VBOX */
8549
8550 if (bseqnr==2) bootseq >>= 4;
8551 if (bseqnr==3) bootseq >>= 8;
8552#ifdef VBOX
8553 if (bseqnr==4) bootseq >>= 12;
8554#endif /* VBOX */
8555 if (bootseq<0x10) lastdrive = 1;
8556 bootdrv=0x00; bootcd=0;
8557#ifdef VBOX
8558 bootlan=0;
8559#endif /* VBOX */
8560
8561 switch(bootseq & 0x0f) {
8562 case 0x01:
8563 bootdrv=0x00;
8564 bootcd=0;
8565 break;
8566 case 0x02:
8567 {
8568 // Get the Boot drive.
8569 Bit8u boot_drive = read_byte(ebda_seg, &EbdaData->uForceBootDrive);
8570
8571 bootdrv = boot_drive + 0x80;
8572 bootcd=0;
8573 break;
8574 }
8575 case 0x03:
8576 bootdrv=0x00;
8577 bootcd=1;
8578 break;
8579#ifdef VBOX
8580 case 0x04: bootlan=1; break;
8581#endif /* VBOX */
8582 default: return 0x00000000;
8583 }
8584#else
8585 bootseq=inb_cmos(0x2d);
8586
8587 if (bseqnr==2) {
8588 bootseq ^= 0x20;
8589 lastdrive = 1;
8590 }
8591 bootdrv=0x00; bootcd=0;
8592 if((bootseq&0x20)==0) bootdrv=0x80;
8593#endif // BX_ELTORITO_BOOT
8594
8595#if BX_ELTORITO_BOOT
8596 // We have to boot from cd
8597 if (bootcd != 0) {
8598 status = cdrom_boot();
8599
8600 // If failure
8601 if ( (status & 0x00ff) !=0 ) {
8602 print_cdromboot_failure(status);
8603#ifdef VBOX
8604 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
8605#else /* !VBOX */
8606 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
8607#endif /* !VBOX */
8608 return 0x00000000;
8609 }
8610
8611 bootseg = read_word(ebda_seg,&EbdaData->cdemu.load_segment);
8612 bootdrv = (Bit8u)(status>>8);
8613 }
8614
8615#endif // BX_ELTORITO_BOOT
8616
8617#ifdef VBOX
8618 // Check for boot from LAN first
8619 if (bootlan == 1) {
8620 if (read_word(VBOX_LANBOOT_SEG,0) == 0xaa55) {
8621 Bit16u pnpoff;
8622 Bit32u manuf;
8623 // This is NOT a generic PnP implementation, but an Etherboot-specific hack.
8624 pnpoff = read_word(VBOX_LANBOOT_SEG,0x1a);
8625 if (read_dword(VBOX_LANBOOT_SEG,pnpoff) == 0x506e5024) {
8626 // Found PnP signature
8627 manuf = read_dword(VBOX_LANBOOT_SEG,read_word(VBOX_LANBOOT_SEG,pnpoff+0xe));
8628 if (manuf == 0x65687445) {
8629 // Found Etherboot ROM
8630 print_boot_device(bootcd, bootlan, bootdrv);
8631ASM_START
8632 push ds
8633 push es
8634 pusha
8635 calli 0x0006,VBOX_LANBOOT_SEG
8636 popa
8637 pop es
8638 pop ds
8639ASM_END
8640 } else if (manuf == 0x65746E49) {
8641 // Found Intel PXE ROM
8642 print_boot_device(bootcd, bootlan, bootdrv);
8643ASM_START
8644 push ds
8645 push es
8646 pusha
8647 sti ; Why are interrupts disabled now? Because we were called through an INT!
8648 push #VBOX_LANBOOT_SEG
8649 pop ds
8650 mov bx,#0x1a ; PnP header offset
8651 mov bx,[bx]
8652 add bx,#0x1a ; BEV offset in PnP header
8653 mov ax,[bx]
8654 test ax,ax
8655 jz no_rom
8656bev_jump:
8657 push cs
8658 push #no_rom
8659 push #VBOX_LANBOOT_SEG
8660 push ax
8661 retf ; call Boot Entry Vector
8662no_rom:
8663 popa
8664 pop es
8665 pop ds
8666ASM_END
8667 }
8668 }
8669 }
8670
8671 // boot from LAN will not return if successful.
8672 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
8673 return 0x00000000;
8674 }
8675#endif /* VBOX */
8676 // We have to boot from harddisk or floppy
8677#ifdef VBOX
8678 if (bootcd == 0 && bootlan == 0) {
8679#else /* !VBOX */
8680 if (bootcd == 0) {
8681#endif /* !VBOX */
8682 bootseg=0x07c0;
8683
8684ASM_START
8685 push bp
8686 mov bp, sp
8687
8688 xor ax, ax
8689 mov _int19_function.status + 2[bp], ax
8690 mov dl, _int19_function.bootdrv + 2[bp]
8691 mov ax, _int19_function.bootseg + 2[bp]
8692 mov es, ax ;; segment
8693 xor bx, bx ;; offset
8694 mov ah, #0x02 ;; function 2, read diskette sector
8695 mov al, #0x01 ;; read 1 sector
8696 mov ch, #0x00 ;; track 0
8697 mov cl, #0x01 ;; sector 1
8698 mov dh, #0x00 ;; head 0
8699 int #0x13 ;; read sector
8700 jnc int19_load_done
8701 mov ax, #0x0001
8702 mov _int19_function.status + 2[bp], ax
8703
8704int19_load_done:
8705 pop bp
8706ASM_END
8707
8708 if (status != 0) {
8709#ifdef VBOX
8710 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
8711#else /* !VBOX */
8712 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
8713#endif /* !VBOX */
8714 return 0x00000000;
8715 }
8716 }
8717
8718#ifdef VBOX
8719 // Don't check boot sectors on floppies and don't read CMOS - byte
8720 // 0x38 in CMOS always has the low bit clear.
8721 // There is *no* requirement whatsoever for a valid boot sector to
8722 // have a 55AAh signature. UNIX boot floppies typically have no such
8723 // signature. In general, it is impossible to tell a valid bootsector
8724 // from an invalid one.
8725 // NB: It is somewhat common for failed OS installs to have the
8726 // 0x55AA signature and a valid partition table but zeros in the
8727 // rest of the boot sector. We do a quick check by comparing the first
8728 // two words of boot sector; if identical, the boot sector is
8729 // extremely unlikely to be valid.
8730#endif
8731 // check signature if instructed by cmos reg 0x38, only for floppy
8732 // bootchk = 1 : signature check disabled
8733 // bootchk = 0 : signature check enabled
8734 if (bootdrv != 0) bootchk = 0;
8735#ifdef VBOX
8736 else bootchk = 1; /* disable 0x55AA signature check on drive A: */
8737#else
8738 else bootchk = inb_cmos(0x38) & 0x01;
8739#endif
8740
8741#if BX_ELTORITO_BOOT
8742 // if boot from cd, no signature check
8743 if (bootcd != 0)
8744 bootchk = 1;
8745#endif // BX_ELTORITO_BOOT
8746
8747 if (bootchk == 0) {
8748 if (read_word(bootseg,0x1fe) != 0xaa55 ||
8749 read_word(bootseg,0) == read_word(bootseg,2)) {
8750#ifdef VBOX
8751 print_boot_failure(bootcd, bootlan, bootdrv, 0, lastdrive);
8752#else /* !VBOX */
8753 print_boot_failure(bootcd, bootdrv, 0, lastdrive);
8754#endif /* VBOX */
8755 return 0x00000000;
8756 }
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 eax, cr0
11375 and al, #0xfe
11376 mov cr0, eax
11377 JMP_AP(0xF000, really_exit_pm)
11378really_exit_pm:
11379 ret
11380
11381pmbios_gdt_desc:
11382 dw 0x30
11383 dw pmbios_gdt
11384 dw 0x000f
11385
11386pmbios_gdt:
11387 dw 0, 0, 0, 0
11388 dw 0, 0, 0, 0
11389 dw 0xffff, 0, 0x9b00, 0x00cf ; 32 bit flat code segment (0x10)
11390 dw 0xffff, 0, 0x9300, 0x00cf ; 32 bit flat data segment (0x18)
11391 dw 0xffff, 0, 0x9b0f, 0x0000 ; 16 bit code segment base=0xf0000 limit=0xffff
11392 dw 0xffff, 0, 0x9300, 0x0000 ; 16 bit data segment base=0x0 limit=0xffff
11393
11394;; for 'C' strings and other data, insert them here with
11395;; a the following hack:
11396;; DATA_SEG_DEFS_HERE
11397
11398
11399;; the following area can be used to write dynamically generated tables
11400 .align 16
11401bios_table_area_start:
11402 dd 0xaafb4442
11403 dd bios_table_area_end - bios_table_area_start - 8;
11404
11405;--------
11406;- POST -
11407;--------
11408.org 0xe05b ; POST Entry Point
11409bios_table_area_end:
11410post:
11411
11412 xor ax, ax
11413
11414 ;; first reset the DMA controllers
11415 out 0x0d,al
11416 out 0xda,al
11417
11418 ;; then initialize the DMA controllers
11419 mov al, #0xC0
11420 out 0xD6, al ; cascade mode of channel 4 enabled
11421 mov al, #0x00
11422 out 0xD4, al ; unmask channel 4
11423
11424 ;; Examine CMOS shutdown status.
11425 mov AL, #0x0f
11426 out 0x70, AL
11427 in AL, 0x71
11428
11429 ;; backup status
11430 mov bl, al
11431
11432 ;; Reset CMOS shutdown status.
11433 mov AL, #0x0f
11434 out 0x70, AL ; select CMOS register Fh
11435 mov AL, #0x00
11436 out 0x71, AL ; set shutdown action to normal
11437
11438 ;; Examine CMOS shutdown status.
11439 mov al, bl
11440
11441 ;; 0x00, 0x09, 0x0D+ = normal startup
11442 cmp AL, #0x00
11443 jz normal_post
11444 cmp AL, #0x0d
11445 jae normal_post
11446 cmp AL, #0x09
11447 je normal_post
11448
11449 ;; 0x05 = eoi + jmp via [0x40:0x67] jump
11450 cmp al, #0x05
11451 je eoi_jmp_post
11452
11453#ifdef VBOX
11454 ;; just ignore all other CMOS shutdown status values (OpenSolaris sets it to 0xA for some reason in certain cases)
11455 ;; (shutdown_status_panic just crashes the VM as it calls int 0x10 before the IDT table has been initialized)
11456 jmp normal_post
11457#else
11458 ;; Examine CMOS shutdown status.
11459 ;; 0x01,0x02,0x03,0x04,0x06,0x07,0x08, 0x0a, 0x0b, 0x0c = Unimplemented shutdown status.
11460 push bx
11461 call _shutdown_status_panic
11462#endif
11463
11464#if 0
11465 HALT(__LINE__)
11466 ;
11467 ;#if 0
11468 ; 0xb0, 0x20, /* mov al, #0x20 */
11469 ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */
11470 ;#endif
11471 ;
11472 pop es
11473 pop ds
11474 popa
11475 iret
11476#endif
11477
11478normal_post:
11479 ; case 0: normal startup
11480
11481 cli
11482 mov ax, #0x7C00
11483 mov sp, ax
11484 xor ax, ax
11485 mov ds, ax
11486 mov ss, ax
11487
11488#ifndef VBOX
11489 ;; zero out BIOS data area (40:00..40:ff)
11490 mov es, ax
11491 mov cx, #0x0080 ;; 128 words
11492 mov di, #0x0400
11493 cld
11494 rep
11495 stosw
11496#else /* VBOX */
11497 ;; zero out segment 0 (includes BIOS data area) except word at 40:72
11498 mov es, ax
11499 xor di, di
11500 cld
11501 mov cx, #0x0239 ;; 569 words
11502 rep
11503 stosw
11504 inc di
11505 inc di
11506 mov cx, #0x7dc6 ;; 32198 words
11507 rep
11508 stosw
11509 ;; zero out remaining base memory except the last 16 bytes of the EBDA
11510 ;; because we store the MP table there
11511 xor eax, eax
11512 xor bx, bx
11513memory_zero_loop:
11514 add bx, #0x1000
11515 cmp bx, #0x9000
11516 jae memory_cleared
11517 mov es, bx
11518 xor di, di
11519 mov cx, #0x4000
11520 rep
11521 stosd
11522 jmp memory_zero_loop
11523memory_cleared:
11524 mov es, bx
11525 xor di, di
11526 mov cx, #0x3f00
11527 rep
11528 stosd
11529 xor bx, bx
11530#endif
11531
11532 call _log_bios_start
11533
11534 call pmode_setup
11535
11536 ;; set all interrupts to default handler
11537 xor bx, bx ;; offset index
11538 mov cx, #0x0078 ;; leave the rest as zeros
11539 mov ax, #dummy_iret_handler
11540 mov dx, #0xF000
11541
11542post_default_ints:
11543 mov [bx], ax
11544 add bx, #2
11545 mov [bx], dx
11546 add bx, #2
11547 loop post_default_ints
11548
11549 ;; set vector 0x79 to zero
11550 ;; this is used by 'guardian angel' protection system
11551 SET_INT_VECTOR(0x79, #0, #0)
11552
11553 ;; base memory in K 40:13 (word)
11554 mov ax, #BASE_MEM_IN_K
11555 mov 0x0413, ax
11556
11557
11558 ;; Manufacturing Test 40:12
11559 ;; zerod out above
11560
11561#ifndef VBOX
11562 ;; Warm Boot Flag 0040:0072
11563 ;; value of 1234h = skip memory checks
11564 ;; zerod out above
11565#endif /* !VBOX */
11566
11567
11568 ;; Printer Services vector
11569 SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
11570
11571 ;; Bootstrap failure vector
11572 SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
11573
11574 ;; Bootstrap Loader vector
11575 SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
11576
11577 ;; User Timer Tick vector
11578 SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
11579
11580 ;; Memory Size Check vector
11581 SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
11582
11583 ;; Equipment Configuration Check vector
11584 SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
11585
11586 ;; System Services
11587 SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
11588
11589 ;; EBDA setup
11590 call ebda_post
11591
11592 ;; PIT setup
11593 SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
11594 ;; int 1C already points at dummy_iret_handler (above)
11595 mov al, #0x34 ; timer0: binary count, 16bit count, mode 2
11596 out 0x43, al
11597 mov al, #0x00 ; maximum count of 0000H = 18.2Hz
11598 out 0x40, al
11599 out 0x40, al
11600
11601 ;; Keyboard
11602 SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
11603 SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
11604
11605 xor ax, ax
11606 mov ds, ax
11607 mov 0x0417, al /* keyboard shift flags, set 1 */
11608 mov 0x0418, al /* keyboard shift flags, set 2 */
11609 mov 0x0419, al /* keyboard alt-numpad work area */
11610 mov 0x0471, al /* keyboard ctrl-break flag */
11611 mov 0x0497, al /* keyboard status flags 4 */
11612 mov al, #0x10
11613 mov 0x0496, al /* keyboard status flags 3 */
11614
11615
11616 /* keyboard head of buffer pointer */
11617 mov bx, #0x001E
11618 mov 0x041A, bx
11619
11620 /* keyboard end of buffer pointer */
11621 mov 0x041C, bx
11622
11623 /* keyboard pointer to start of buffer */
11624 mov bx, #0x001E
11625 mov 0x0480, bx
11626
11627 /* keyboard pointer to end of buffer */
11628 mov bx, #0x003E
11629 mov 0x0482, bx
11630
11631 /* init the keyboard */
11632 call _keyboard_init
11633
11634 ;; mov CMOS Equipment Byte to BDA Equipment Word
11635 mov ax, 0x0410
11636 mov al, #0x14
11637 out 0x70, al
11638 in al, 0x71
11639 mov 0x0410, ax
11640
11641
11642 ;; Parallel setup
11643 SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
11644 xor ax, ax
11645 mov ds, ax
11646 xor bx, bx
11647 mov cl, #0x14 ; timeout value
11648 mov dx, #0x378 ; Parallel I/O address, port 1
11649 call detect_parport
11650 mov dx, #0x278 ; Parallel I/O address, port 2
11651 call detect_parport
11652 shl bx, #0x0e
11653 mov ax, 0x410 ; Equipment word bits 14..15 determine # parallel ports
11654 and ax, #0x3fff
11655 or ax, bx ; set number of parallel ports
11656 mov 0x410, ax
11657
11658 ;; Serial setup
11659 SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
11660 SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
11661 xor bx, bx
11662 mov cl, #0x0a ; timeout value
11663 mov dx, #0x03f8 ; Serial I/O address, port 1
11664 call detect_serial
11665 mov dx, #0x02f8 ; Serial I/O address, port 2
11666 call detect_serial
11667 mov dx, #0x03e8 ; Serial I/O address, port 3
11668 call detect_serial
11669 mov dx, #0x02e8 ; Serial I/O address, port 4
11670 call detect_serial
11671 shl bx, #0x09
11672 mov ax, 0x410 ; Equipment word bits 9..11 determine # serial ports
11673 and ax, #0xf1ff
11674 or ax, bx ; set number of serial port
11675 mov 0x410, ax
11676
11677 ;; CMOS RTC
11678 SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
11679 SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
11680 SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
11681 ;; BIOS DATA AREA 0x4CE ???
11682 call timer_tick_post
11683
11684 ;; PS/2 mouse setup
11685 SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
11686
11687 ;; IRQ13 (FPU exception) setup
11688 SET_INT_VECTOR(0x75, #0xF000, #int75_handler)
11689
11690 ;; Video setup
11691 SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
11692
11693#ifdef VBOX
11694 ;; moved the PIC initialization to another place as we need
11695 ;; some space for additions init calls. Otherwise this code
11696 ;; overlaps with the NMI handler at 0xe2c3 (fixed BIOS entry)
11697 call init_pic
11698#else /* !VBOX */
11699 ;; PIC
11700 mov al, #0x11 ; send initialisation commands
11701 out 0x20, al
11702 out 0xa0, al
11703 mov al, #0x08
11704 out 0x21, al
11705 mov al, #0x70
11706 out 0xa1, al
11707 mov al, #0x04
11708 out 0x21, al
11709 mov al, #0x02
11710 out 0xa1, al
11711 mov al, #0x01
11712 out 0x21, al
11713 out 0xa1, al
11714 mov al, #0xb8
11715 out 0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6
11716#if BX_USE_PS2_MOUSE
11717 mov al, #0x8f
11718#else
11719 mov al, #0x9f
11720#endif
11721 out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14
11722#endif /* !VBOX */
11723
11724#if BX_ROMBIOS32
11725 call rombios32_init
11726#else
11727 call pcibios_init_iomem_bases
11728 call pcibios_init_irqs
11729#endif
11730 call rom_scan
11731
11732#if BX_USE_ATADRV
11733 ;;
11734 ;; ATA/ATAPI driver setup
11735 ;;
11736 call _ata_init
11737 call _ata_detect
11738 ;;
11739#endif
11740
11741#ifdef VBOX_WITH_SCSI
11742 ;;
11743 ;; SCSI driver setup
11744 ;;
11745 call _scsi_init
11746 ;;
11747#endif
11748
11749 call _print_bios_banner
11750
11751 ;;
11752 ;; Floppy setup
11753 ;;
11754 call floppy_drive_post
11755
11756 ;;
11757 ;; Hard Drive setup
11758 ;;
11759 call hard_drive_post
11760
11761#ifdef VBOX_WITH_BIOS_AHCI
11762 ;;
11763 ;; AHCI driver setup
11764 ;;
11765 call _ahci_init
11766 ;;
11767#endif
11768
11769#if BX_ELTORITO_BOOT
11770 ;;
11771 ;; eltorito floppy/harddisk emulation from cd
11772 ;;
11773 call _cdemu_init
11774 ;;
11775#endif // BX_ELTORITO_BOOT
11776
11777 sti ;; enable interrupts
11778 int #0x19
11779
11780.org 0xe2c3 ; NMI Handler Entry Point
11781nmi:
11782 ;; FIXME the NMI handler should not panic
11783 ;; but iret when called from int75 (fpu exception)
11784 call _nmi_handler_msg
11785 iret
11786
11787int75_handler:
11788 out 0xf0, al // clear irq13
11789 call eoi_both_pics // clear interrupt
11790 int 2 // legacy nmi call
11791 iret
11792
11793;-------------------------------------------
11794;- INT 13h Fixed Disk Services Entry Point -
11795;-------------------------------------------
11796.org 0xe3fe ; INT 13h Fixed Disk Services Entry Point
11797int13_handler:
11798 //JMPL(int13_relocated)
11799 jmp int13_relocated
11800
11801.org 0xe401 ; Fixed Disk Parameter Table
11802
11803;----------
11804;- INT19h -
11805;----------
11806.org 0xe6f2 ; INT 19h Boot Load Service Entry Point
11807int19_handler:
11808
11809 jmp int19_relocated
11810;-------------------------------------------
11811;- System BIOS Configuration Data Table
11812;-------------------------------------------
11813.org BIOS_CONFIG_TABLE
11814db 0x08 ; Table size (bytes) -Lo
11815db 0x00 ; Table size (bytes) -Hi
11816db SYS_MODEL_ID
11817db SYS_SUBMODEL_ID
11818db BIOS_REVISION
11819; Feature byte 1
11820; b7: 1=DMA channel 3 used by hard disk
11821; b6: 1=2 interrupt controllers present
11822; b5: 1=RTC present
11823; b4: 1=BIOS calls int 15h/4Fh every key
11824; b3: 1=wait for extern event supported (Int 15h/41h)
11825; b2: 1=extended BIOS data area used
11826; b1: 0=AT or ESDI bus, 1=MicroChannel
11827; b0: 1=Dual bus (MicroChannel + ISA)
11828db (0 << 7) | \
11829 (1 << 6) | \
11830 (1 << 5) | \
11831 (BX_CALL_INT15_4F << 4) | \
11832 (0 << 3) | \
11833 (BX_USE_EBDA << 2) | \
11834 (0 << 1) | \
11835 (0 << 0)
11836; Feature byte 2
11837; b7: 1=32-bit DMA supported
11838; b6: 1=int16h, function 9 supported
11839; b5: 1=int15h/C6h (get POS data) supported
11840; b4: 1=int15h/C7h (get mem map info) supported
11841; b3: 1=int15h/C8h (en/dis CPU) supported
11842; b2: 1=non-8042 kb controller
11843; b1: 1=data streaming supported
11844; b0: reserved
11845db (0 << 7) | \
11846 (1 << 6) | \
11847 (0 << 5) | \
11848 (0 << 4) | \
11849 (0 << 3) | \
11850 (0 << 2) | \
11851 (0 << 1) | \
11852 (0 << 0)
11853; Feature byte 3
11854; b7: not used
11855; b6: reserved
11856; b5: reserved
11857; b4: POST supports ROM-to-RAM enable/disable
11858; b3: SCSI on system board
11859; b2: info panel installed
11860; b1: Initial Machine Load (IML) system - BIOS on disk
11861; b0: SCSI supported in IML
11862db 0x00
11863; Feature byte 4
11864; b7: IBM private
11865; b6: EEPROM present
11866; b5-3: ABIOS presence (011 = not supported)
11867; b2: private
11868; b1: memory split above 16Mb supported
11869; b0: POSTEXT directly supported by POST
11870db 0x00
11871; Feature byte 5 (IBM)
11872; b1: enhanced mouse
11873; b0: flash EPROM
11874db 0x00
11875
11876
11877
11878.org 0xe729 ; Baud Rate Generator Table
11879
11880;----------
11881;- INT14h -
11882;----------
11883.org 0xe739 ; INT 14h Serial Communications Service Entry Point
11884int14_handler:
11885 push ds
11886 pusha
11887 xor ax, ax
11888 mov ds, ax
11889 call _int14_function
11890 popa
11891 pop ds
11892 iret
11893
11894
11895;----------------------------------------
11896;- INT 16h Keyboard Service Entry Point -
11897;----------------------------------------
11898.org 0xe82e
11899int16_handler:
11900
11901 sti
11902 push ds
11903 pushf
11904 pusha
11905
11906 cmp ah, #0x00
11907 je int16_F00
11908 cmp ah, #0x10
11909 je int16_F00
11910
11911 mov bx, #0xf000
11912 mov ds, bx
11913 call _int16_function
11914 popa
11915 popf
11916 pop ds
11917 jz int16_zero_set
11918
11919int16_zero_clear:
11920 push bp
11921 mov bp, sp
11922 //SEG SS
11923 and BYTE [bp + 0x06], #0xbf
11924 pop bp
11925 iret
11926
11927int16_zero_set:
11928 push bp
11929 mov bp, sp
11930 //SEG SS
11931 or BYTE [bp + 0x06], #0x40
11932 pop bp
11933 iret
11934
11935int16_F00:
11936 mov bx, #0x0040
11937 mov ds, bx
11938
11939int16_wait_for_key:
11940 cli
11941 mov bx, 0x001a
11942 cmp bx, 0x001c
11943 jne int16_key_found
11944 sti
11945 nop
11946#if 0
11947 /* no key yet, call int 15h, function AX=9002 */
11948 0x50, /* push AX */
11949 0xb8, 0x02, 0x90, /* mov AX, #0x9002 */
11950 0xcd, 0x15, /* int 15h */
11951 0x58, /* pop AX */
11952 0xeb, 0xea, /* jmp WAIT_FOR_KEY */
11953#endif
11954 jmp int16_wait_for_key
11955
11956int16_key_found:
11957 mov bx, #0xf000
11958 mov ds, bx
11959 call _int16_function
11960 popa
11961 popf
11962 pop ds
11963#if 0
11964 /* notify int16 complete w/ int 15h, function AX=9102 */
11965 0x50, /* push AX */
11966 0xb8, 0x02, 0x91, /* mov AX, #0x9102 */
11967 0xcd, 0x15, /* int 15h */
11968 0x58, /* pop AX */
11969#endif
11970 iret
11971
11972
11973
11974;-------------------------------------------------
11975;- INT09h : Keyboard Hardware Service Entry Point -
11976;-------------------------------------------------
11977.org 0xe987
11978int09_handler:
11979 cli
11980 push ax
11981
11982 mov al, #0xAD ;;disable keyboard
11983 out #0x64, al
11984
11985 mov al, #0x0B
11986 out #0x20, al
11987 in al, #0x20
11988 and al, #0x02
11989 jz int09_finish
11990
11991 in al, #0x60 ;;read key from keyboard controller
11992 sti
11993 push ds
11994 pusha
11995#ifdef BX_CALL_INT15_4F
11996 mov ah, #0x4f ;; allow for keyboard intercept
11997 stc
11998 int #0x15
11999 jnc int09_done
12000#endif
12001
12002 ;; check for extended key
12003 cmp al, #0xe0
12004 jne int09_check_pause
12005 xor ax, ax
12006 mov ds, ax
12007 mov al, BYTE [0x496] ;; mf2_state |= 0x02
12008 or al, #0x02
12009 mov BYTE [0x496], al
12010 jmp int09_done
12011
12012int09_check_pause: ;; check for pause key
12013 cmp al, #0xe1
12014 jne int09_process_key
12015 xor ax, ax
12016 mov ds, ax
12017 mov al, BYTE [0x496] ;; mf2_state |= 0x01
12018 or al, #0x01
12019 mov BYTE [0x496], al
12020 jmp int09_done
12021
12022int09_process_key:
12023 mov bx, #0xf000
12024 mov ds, bx
12025 call _int09_function
12026
12027int09_done:
12028 popa
12029 pop ds
12030 cli
12031 call eoi_master_pic
12032
12033int09_finish:
12034 mov al, #0xAE ;;enable keyboard
12035 out #0x64, al
12036 pop ax
12037 iret
12038
12039
12040;----------------------------------------
12041;- INT 13h Diskette Service Entry Point -
12042;----------------------------------------
12043.org 0xec59
12044int13_diskette:
12045 jmp int13_noeltorito
12046
12047;---------------------------------------------
12048;- INT 0Eh Diskette Hardware ISR Entry Point -
12049;---------------------------------------------
12050.org 0xef57 ; INT 0Eh Diskette Hardware ISR Entry Point
12051int0e_handler:
12052 push ax
12053 push dx
12054 mov dx, #0x03f4
12055 in al, dx
12056 and al, #0xc0
12057 cmp al, #0xc0
12058 je int0e_normal
12059 mov dx, #0x03f5
12060 mov al, #0x08 ; sense interrupt status
12061 out dx, al
12062int0e_loop1:
12063 mov dx, #0x03f4
12064 in al, dx
12065 and al, #0xc0
12066 cmp al, #0xc0
12067 jne int0e_loop1
12068int0e_loop2:
12069 mov dx, #0x03f5
12070 in al, dx
12071 mov dx, #0x03f4
12072 in al, dx
12073 and al, #0xc0
12074 cmp al, #0xc0
12075 je int0e_loop2
12076int0e_normal:
12077 push ds
12078 xor ax, ax ;; segment 0000
12079 mov ds, ax
12080 call eoi_master_pic
12081 mov al, 0x043e
12082 or al, #0x80 ;; diskette interrupt has occurred
12083 mov 0x043e, al
12084 pop ds
12085 pop dx
12086 pop ax
12087 iret
12088
12089
12090.org 0xefc7 ; Diskette Controller Parameter Table
12091diskette_param_table:
12092;; Since no provisions are made for multiple drive types, most
12093;; values in this table are ignored. I set parameters for 1.44M
12094;; floppy here
12095db 0xAF
12096db 0x02 ;; head load time 0000001, DMA used
12097db 0x25
12098db 0x02
12099db 18
12100db 0x1B
12101db 0xFF
12102db 0x6C
12103db 0xF6
12104db 0x0F
12105db 0x08
12106
12107
12108;----------------------------------------
12109;- INT17h : Printer Service Entry Point -
12110;----------------------------------------
12111.org 0xefd2
12112int17_handler:
12113 push ds
12114 pusha
12115 xor ax, ax
12116 mov ds, ax
12117 call _int17_function
12118 popa
12119 pop ds
12120 iret
12121
12122diskette_param_table2:
12123;; New diskette parameter table adding 3 parameters from IBM
12124;; Since no provisions are made for multiple drive types, most
12125;; values in this table are ignored. I set parameters for 1.44M
12126;; floppy here
12127db 0xAF
12128db 0x02 ;; head load time 0000001, DMA used
12129db 0x25
12130db 0x02
12131db 18
12132db 0x1B
12133db 0xFF
12134db 0x6C
12135db 0xF6
12136db 0x0F
12137db 0x08
12138db 79 ;; maximum track
12139db 0 ;; data transfer rate
12140db 4 ;; drive type in cmos
12141
12142.org 0xf045 ; INT 10 Functions 0-Fh Entry Point
12143 HALT(__LINE__)
12144 iret
12145
12146;----------
12147;- INT10h -
12148;----------
12149.org 0xf065 ; INT 10h Video Support Service Entry Point
12150int10_handler:
12151 ;; dont do anything, since the VGA BIOS handles int10h requests
12152 iret
12153
12154.org 0xf0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
12155
12156;----------
12157;- INT12h -
12158;----------
12159.org 0xf841 ; INT 12h Memory Size Service Entry Point
12160; ??? different for Pentium (machine check)?
12161int12_handler:
12162 push ds
12163 mov ax, #0x0040
12164 mov ds, ax
12165 mov ax, 0x0013
12166 pop ds
12167 iret
12168
12169;----------
12170;- INT11h -
12171;----------
12172.org 0xf84d ; INT 11h Equipment List Service Entry Point
12173int11_handler:
12174 push ds
12175 mov ax, #0x0040
12176 mov ds, ax
12177 mov ax, 0x0010
12178 pop ds
12179 iret
12180
12181;----------
12182;- INT15h -
12183;----------
12184.org 0xf859 ; INT 15h System Services Entry Point
12185int15_handler:
12186 pushf
12187#if BX_APM
12188 cmp ah, #0x53
12189 je apm_call
12190#endif
12191 push ds
12192 push es
12193 cmp ah, #0x86
12194 je int15_handler32
12195 cmp ah, #0xE8
12196 je int15_handler32
12197 pusha
12198#if BX_USE_PS2_MOUSE
12199 cmp ah, #0xC2
12200 je int15_handler_mouse
12201#endif
12202 call _int15_function
12203int15_handler_mouse_ret:
12204 popa
12205int15_handler32_ret:
12206 pop es
12207 pop ds
12208 popf
12209 jmp iret_modify_cf
12210#if BX_APM
12211apm_call:
12212 jmp _apmreal_entry
12213#endif
12214
12215#if BX_USE_PS2_MOUSE
12216int15_handler_mouse:
12217 call _int15_function_mouse
12218 jmp int15_handler_mouse_ret
12219#endif
12220
12221int15_handler32:
12222 pushad
12223 call _int15_function32
12224 popad
12225 jmp int15_handler32_ret
12226
12227;; Protected mode IDT descriptor
12228;;
12229;; I just make the limit 0, so the machine will shutdown
12230;; if an exception occurs during protected mode memory
12231;; transfers.
12232;;
12233;; Set base to f0000 to correspond to beginning of BIOS,
12234;; in case I actually define an IDT later
12235;; Set limit to 0
12236
12237pmode_IDT_info:
12238dw 0x0000 ;; limit 15:00
12239dw 0x0000 ;; base 15:00
12240dw 0x0f ;; base 23:16
12241
12242;; Real mode IDT descriptor
12243;;
12244;; Set to typical real-mode values.
12245;; base = 000000
12246;; limit = 03ff
12247
12248rmode_IDT_info:
12249dw 0x03ff ;; limit 15:00
12250dw 0x0000 ;; base 15:00
12251dw 0x00 ;; base 23:16
12252
12253;;
12254;; Handler for unexpected hardware interrupts
12255;;
12256dummy_isr:
12257 push ds
12258 pushad
12259 xor ax, ax
12260 mov ds, ax
12261 call _dummy_isr_function
12262 popad
12263 pop ds
12264 iret
12265
12266;----------
12267;- INT1Ah -
12268;----------
12269.org 0xfe6e ; INT 1Ah Time-of-day Service Entry Point
12270int1a_handler:
12271#if BX_PCIBIOS
12272 cmp ah, #0xb1
12273 jne int1a_normal
12274 call pcibios_real
12275 jc pcibios_error
12276 jmp iret_modify_cf ; preserve old flags!
12277pcibios_error:
12278 mov bl, ah
12279 mov ah, #0xb1
12280 push ds
12281 pusha
12282 mov ax, ss ; set readable descriptor to ds, for calling pcibios
12283 mov ds, ax ; on 16bit protected mode.
12284 jmp int1a_callfunction
12285int1a_normal:
12286#endif
12287 push ds
12288 pusha
12289 xor ax, ax
12290 mov ds, ax
12291int1a_callfunction:
12292 call _int1a_function
12293 popa
12294 pop ds
12295 iret
12296
12297;;
12298;; int70h: IRQ8 - CMOS RTC
12299;;
12300int70_handler:
12301 push ds
12302 pushad
12303 xor ax, ax
12304 mov ds, ax
12305 call _int70_function
12306 popad
12307 pop ds
12308 iret
12309
12310;---------
12311;- INT08 -
12312;---------
12313.org 0xfea5 ; INT 08h System Timer ISR Entry Point
12314int08_handler:
12315 sti
12316 push eax
12317 push ds
12318 xor ax, ax
12319 mov ds, ax
12320
12321 ;; time to turn off drive(s)?
12322 mov al,0x0440
12323 or al,al
12324 jz int08_floppy_off
12325 dec al
12326 mov 0x0440,al
12327 jnz int08_floppy_off
12328 ;; turn motor(s) off
12329 push dx
12330 mov dx,#0x03f2
12331 in al,dx
12332 and al,#0xcf
12333 out dx,al
12334 pop dx
12335int08_floppy_off:
12336
12337 mov eax, 0x046c ;; get ticks dword
12338 inc eax
12339
12340 ;; compare eax to one days worth of timer ticks at 18.2 hz
12341 cmp eax, #0x001800B0
12342 jb int08_store_ticks
12343 ;; there has been a midnight rollover at this point
12344 xor eax, eax ;; zero out counter
12345 inc BYTE 0x0470 ;; increment rollover flag
12346
12347int08_store_ticks:
12348 mov 0x046c, eax ;; store new ticks dword
12349 ;; chain to user timer tick INT #0x1c
12350 //pushf
12351 //;; call_ep [ds:loc]
12352 //CALL_EP( 0x1c << 2 )
12353 int #0x1c
12354 cli
12355 call eoi_master_pic
12356 pop ds
12357 pop eax
12358 iret
12359
12360.org 0xfef3 ; Initial Interrupt Vector Offsets Loaded by POST
12361
12362
12363.org 0xff00
12364.ascii BIOS_COPYRIGHT_STRING
12365
12366#ifdef VBOX
12367// The SMBIOS header
12368.org 0xff30
12369.align 16
12370 db 0x5f, 0x53, 0x4d, 0x5f ; "_SM_" signature
12371 db 0x00 ; checksum (set by biossums)
12372 db 0x1f ; EPS length, defined by standard
12373 db VBOX_SMBIOS_MAJOR_VER ; SMBIOS major version
12374 db VBOX_SMBIOS_MINOR_VER ; SMBIOS minor version
12375 dw VBOX_SMBIOS_MAXSS ; Maximum structure size
12376 db 0x00 ; Entry point revision
12377 db 0x00, 0x00, 0x00, 0x00, 0x00
12378
12379// The DMI header
12380 db 0x5f, 0x44, 0x4d, 0x49, 0x5f ; "_DMI_" signature
12381 db 0x00 ; checksum (set by biossums)
12382 dw VBOX_DMI_TABLE_SIZE ; DMI tables length
12383 dd VBOX_DMI_TABLE_BASE ; DMI tables base
12384 dw VBOX_DMI_TABLE_ENTR ; DMI tables entries
12385 db VBOX_DMI_TABLE_VER ; DMI version
12386 db 0x00 ; Just for alignment
12387#endif
12388
12389;------------------------------------------------
12390;- IRET Instruction for Dummy Interrupt Handler -
12391;------------------------------------------------
12392.org 0xff53 ; IRET Instruction for Dummy Interrupt Handler
12393dummy_iret_handler:
12394 iret
12395
12396.org 0xff54 ; INT 05h Print Screen Service Entry Point
12397 HALT(__LINE__)
12398 iret
12399
12400.org 0xfff0 ; Power-up Entry Point
12401 jmp 0xf000:post
12402
12403.org 0xfff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
12404.ascii BIOS_BUILD_DATE
12405
12406.org 0xfffe ; System Model ID
12407db SYS_MODEL_ID
12408db 0x00 ; filler
12409
12410.org 0xfa6e ;; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
12411ASM_END
12412/*
12413 * This font comes from the fntcol16.zip package (c) by Joseph Gil
12414 * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
12415 * This font is public domain
12416 */
12417static Bit8u vgafont8[128*8]=
12418{
12419 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
12420 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
12421 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
12422 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
12423 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
12424 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
12425 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
12426 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
12427 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
12428 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
12429 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
12430 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
12431 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
12432 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
12433 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
12434 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
12435 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
12436 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
12437 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
12438 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
12439 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
12440 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
12441 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
12442 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
12443 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
12444 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
12445 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
12446 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
12447 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
12448 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
12449 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
12450 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
12451 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
12452 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
12453 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
12454 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
12455 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
12456 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
12457 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
12458 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
12459 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
12460 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
12461 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
12462 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
12463 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
12464 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
12465 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
12466 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
12467 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
12468 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
12469 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
12470 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
12471 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
12472 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
12473 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
12474 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
12475 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
12476 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
12477 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
12478 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
12479 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
12480 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
12481 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
12482 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
12483 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
12484 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
12485 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
12486 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
12487 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
12488 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
12489 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
12490 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
12491 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
12492 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
12493 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
12494 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
12495 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
12496 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
12497 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
12498 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
12499 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
12500 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
12501 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
12502 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
12503 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
12504 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
12505 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
12506 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
12507 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
12508 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
12509 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
12510 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
12511 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
12512 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
12513 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
12514 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
12515 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
12516 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
12517 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
12518 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
12519 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
12520 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
12521 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
12522 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
12523 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
12524 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
12525 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
12526 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
12527 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
12528 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
12529 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
12530 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
12531 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
12532 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
12533 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
12534 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
12535 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
12536 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
12537 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
12538 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
12539 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
12540 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
12541 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
12542 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
12543 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
12544 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
12545 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
12546 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
12547};
12548
12549ASM_START
12550.org 0xcc00
12551// bcc-generated data will be placed here
12552ASM_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