VirtualBox

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

Last change on this file since 26187 was 24523, checked in by vboxsync, 15 years ago

More comments

  • Property svn:eol-style set to native
File size: 334.4 KB
Line 
1/////////////////////////////////////////////////////////////////////////
2// $Id: rombios.c,v 1.176 2006/12/30 17:13:17 vruppert Exp $
3/////////////////////////////////////////////////////////////////////////
4//
5// Copyright (C) 2002 MandrakeSoft S.A.
6//
7// MandrakeSoft S.A.
8// 43, rue d'Aboukir
9// 75002 Paris - France
10// http://www.linux-mandrake.com/
11// http://www.mandrakesoft.com/
12//
13// This library is free software; you can redistribute it and/or
14// modify it under the terms of the GNU Lesser General Public
15// License as published by the Free Software Foundation; either
16// version 2 of the License, or (at your option) any later version.
17//
18// This library is distributed in the hope that it will be useful,
19// but WITHOUT ANY WARRANTY; without even the implied warranty of
20// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21// Lesser General Public License for more details.
22//
23// You should have received a copy of the GNU Lesser General Public
24// License along with this library; if not, write to the Free Software
25// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
26
27
28/*
29 * Sun 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, Sun 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// ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
37
38
39// ROM BIOS compatability entry points:
40// ===================================
41// $e05b ; POST Entry Point
42// $e2c3 ; NMI Handler Entry Point
43// $e3fe ; INT 13h Fixed Disk Services Entry Point
44// $e401 ; Fixed Disk Parameter Table
45// $e6f2 ; INT 19h Boot Load Service Entry Point
46// $e6f5 ; Configuration Data Table
47// $e729 ; Baud Rate Generator Table
48// $e739 ; INT 14h Serial Communications Service Entry Point
49// $e82e ; INT 16h Keyboard Service Entry Point
50// $e987 ; INT 09h Keyboard Service Entry Point
51// $ec59 ; INT 13h Diskette Service Entry Point
52// $ef57 ; INT 0Eh Diskette Hardware ISR Entry Point
53// $efc7 ; Diskette Controller Parameter Table
54// $efd2 ; INT 17h Printer Service Entry Point
55// $f045 ; INT 10 Functions 0-Fh Entry Point
56// $f065 ; INT 10h Video Support Service Entry Point
57// $f0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
58// $f841 ; INT 12h Memory Size Service Entry Point
59// $f84d ; INT 11h Equipment List Service Entry Point
60// $f859 ; INT 15h System Services Entry Point
61// $fa6e ; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
62// $fe6e ; INT 1Ah Time-of-day Service Entry Point
63// $fea5 ; INT 08h System Timer ISR Entry Point
64// $fef3 ; Initial Interrupt Vector Offsets Loaded by POST
65// $ff53 ; IRET Instruction for Dummy Interrupt Handler
66// $ff54 ; INT 05h Print Screen Service Entry Point
67// $fff0 ; Power-up Entry Point
68// $fff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
69// $fffe ; System Model ID
70
71// NOTES for ATA/ATAPI driver (cbbochs@free.fr)
72// Features
73// - supports up to 4 ATA interfaces
74// - device/geometry detection
75// - 16bits/32bits device access
76// - pchs/lba access
77// - datain/dataout/packet command support
78//
79// NOTES for El-Torito Boot (cbbochs@free.fr)
80// - CD-ROM booting is only available if ATA/ATAPI Driver is available
81// - Current code is only able to boot mono-session cds
82// - Current code can not boot and emulate a hard-disk
83// the bios will panic otherwise
84// - Current code also use memory in EBDA segement.
85// - I used cmos byte 0x3D to store extended information on boot-device
86// - Code has to be modified modified to handle multiple cdrom drives
87// - Here are the cdrom boot failure codes:
88// 1 : no atapi device found
89// 2 : no atapi cdrom found
90// 3 : can not read cd - BRVD
91// 4 : cd is not eltorito (BRVD)
92// 5 : cd is not eltorito (ISO TAG)
93// 6 : cd is not eltorito (ELTORITO TAG)
94// 7 : can not read cd - boot catalog
95// 8 : boot catalog : bad header
96// 9 : boot catalog : bad platform
97// 10 : boot catalog : bad signature
98// 11 : boot catalog : bootable flag not set
99// 12 : can not read cd - boot image
100//
101// ATA driver
102// - EBDA segment.
103// I used memory starting at 0x121 in the segment
104#ifndef VBOX
105// - the translation policy is defined in cmos regs 0x39 & 0x3a
106#endif /* !VBOX */
107//
108// TODO :
109//
110// int74
111// - needs to be reworked. Uses direct [bp] offsets. (?)
112//
113// int13:
114// - f04 (verify sectors) isn't complete (?)
115// - f02/03/04 should set current cyl,etc in BDA (?)
116// - rewrite int13_relocated & clean up int13 entry code
117//
118// NOTES:
119// - NMI access (bit7 of addr written to 70h)
120//
121// ATA driver
122// - should handle the "don't detect" bit (cmos regs 0x3b & 0x3c)
123// - could send the multiple-sector read/write commands
124//
125// El-Torito
126// - Emulate a Hard-disk (currently only diskette can be emulated) see "FIXME ElTorito Harddisk"
127// - Implement remaining int13_cdemu functions (as defined by El-Torito specs)
128// - cdrom drive is hardcoded to ide 0 device 1 in several places. see "FIXME ElTorito Hardcoded"
129// - int13 Fix DL when emulating a cd. In that case DL is decremented before calling real int13.
130// This is ok. But DL should be reincremented afterwards.
131// - Fix all "FIXME ElTorito Various"
132// - should be able to boot any cdrom instead of the first one
133//
134// BCC Bug: find a generic way to handle the bug of #asm after an "if" (fixed in 0.16.7)
135
136#ifdef VBOX
137#include "DevPcBios.h"
138#include <VBox/version.h>
139#endif
140
141#define BX_ROMBIOS32 0
142#define DEBUG_ROMBIOS 0
143
144#define DEBUG_ATA 0
145#define DEBUG_INT13_HD 0
146#define DEBUG_INT13_CD 0
147#define DEBUG_INT13_ET 0
148#define DEBUG_INT13_FL 0
149#define DEBUG_INT15 0
150#define DEBUG_INT16 0
151#define DEBUG_INT1A 0
152#define DEBUG_INT74 0
153#define DEBUG_APM 0
154
155#define BX_CPU 3
156#define BX_USE_PS2_MOUSE 1
157#define BX_CALL_INT15_4F 1
158#define BX_USE_EBDA 1
159#define BX_SUPPORT_FLOPPY 1
160#define BX_FLOPPY_ON_CNT 37 /* 2 seconds */
161#define BX_PCIBIOS 1
162#define BX_APM 1
163
164#define BX_USE_ATADRV 1
165#define BX_ELTORITO_BOOT 1
166
167#define BX_MAX_ATA_INTERFACES 4
168#define BX_MAX_ATA_DEVICES (BX_MAX_ATA_INTERFACES*2)
169
170#define BX_VIRTUAL_PORTS 1 /* normal output to Bochs ports */
171#define BX_DEBUG_SERIAL 0 /* output to COM1 */
172
173 /* model byte 0xFC = AT */
174#define SYS_MODEL_ID 0xFC
175#define SYS_SUBMODEL_ID 0x00
176#define BIOS_REVISION 1
177#define BIOS_CONFIG_TABLE 0xe6f5
178
179#ifndef BIOS_BUILD_DATE
180# define BIOS_BUILD_DATE "06/23/99"
181#endif
182
183 // 1K of base memory used for Extended Bios Data Area (EBDA)
184 // EBDA is used for PS/2 mouse support, and IDE BIOS, etc.
185#define EBDA_SEG 0x9FC0
186#define EBDA_SIZE 1 // In KiB
187#define BASE_MEM_IN_K (640 - EBDA_SIZE)
188
189#define ACPI_DATA_SIZE 0x00010000L
190
191 // Define the application NAME
192#if defined(BX_QEMU)
193# define BX_APPNAME "QEMU"
194#elif defined(PLEX86)
195# define BX_APPNAME "Plex86"
196#else
197# define BX_APPNAME "Bochs"
198#endif
199
200 // Sanity Checks
201#if BX_USE_ATADRV && BX_CPU<3
202# error The ATA/ATAPI Driver can only to be used with a 386+ cpu
203#endif
204#if BX_USE_ATADRV && !BX_USE_EBDA
205# error ATA/ATAPI Driver can only be used if EBDA is available
206#endif
207#if BX_ELTORITO_BOOT && !BX_USE_ATADRV
208# error El-Torito Boot can only be use if ATA/ATAPI Driver is available
209#endif
210#if BX_PCIBIOS && BX_CPU<3
211# error PCI BIOS can only be used with 386+ cpu
212#endif
213#if BX_APM && BX_CPU<3
214# error APM BIOS can only be used with 386+ cpu
215#endif
216
217#if defined(VBOX) && !BX_USE_ATADRV
218# error VBOX requires enabling the ATA/ATAPI driver
219#endif
220
221#ifdef VBOX_WITH_SCSI
222/* Enough for now */
223# define BX_MAX_SCSI_DEVICES 4
224# define BX_MAX_STORAGE_DEVICES (BX_MAX_ATA_DEVICES + BX_MAX_SCSI_DEVICES)
225
226/* A SCSI device starts always at BX_MAX_ATA_DEVICES. */
227# define VBOX_IS_SCSI_DEVICE(device_id) (device_id >= BX_MAX_ATA_DEVICES)
228# define VBOX_GET_SCSI_DEVICE(device_id) (device_id - BX_MAX_ATA_DEVICES)
229#endif
230
231#ifndef VBOX
232#define PANIC_PORT 0x400
233#define PANIC_PORT2 0x401
234#define INFO_PORT 0x402
235#define DEBUG_PORT 0x403
236#else /* VBOX */
237/* Redirect INFO output to backdoor logging port. */
238#define PANIC_PORT 0x400
239#define PANIC_PORT2 0x401
240#define INFO_PORT 0x504
241#define DEBUG_PORT 0x403
242#endif /* VBOX */
243
244// define this if you want to make PCIBIOS working on a specific bridge only
245// undef enables PCIBIOS when at least one PCI device is found
246// i440FX is emulated by Bochs and QEMU
247#define PCI_FIXED_HOST_BRIDGE 0x12378086 ;; i440FX PCI bridge
248
249// #20 is dec 20
250// #$20 is hex 20 = 32
251// #0x20 is hex 20 = 32
252// LDA #$20
253// JSR $E820
254// LDD .i,S
255// JSR $C682
256// mov al, #$20
257
258// all hex literals should be prefixed with '0x'
259// grep "#[0-9a-fA-F][0-9a-fA-F]" rombios.c
260// no mov SEG-REG, #value, must mov register into seg-reg
261// grep -i "mov[ ]*.s" rombios.c
262
263// This is for compiling with gcc2 and gcc3
264#define ASM_START #asm
265#define ASM_END #endasm
266
267ASM_START
268.rom
269
270.org 0x0000
271
272#if BX_CPU >= 3
273use16 386
274#else
275use16 286
276#endif
277
278MACRO HALT
279 ;; the HALT macro is called with the line number of the HALT call.
280 ;; The line number is then sent to the PANIC_PORT, causing Bochs/Plex
281 ;; to print a BX_PANIC message. This will normally halt the simulation
282 ;; with a message such as "BIOS panic at rombios.c, line 4091".
283 ;; However, users can choose to make panics non-fatal and continue.
284#if BX_VIRTUAL_PORTS
285 mov dx,#PANIC_PORT
286 mov ax,#?1
287 out dx,ax
288#else
289 mov dx,#0x80
290 mov ax,#?1
291 out dx,al
292#endif
293MEND
294
295MACRO JMP_AP
296 db 0xea
297 dw ?2
298 dw ?1
299MEND
300
301MACRO SET_INT_VECTOR
302 mov ax, ?3
303 mov ?1*4, ax
304 mov ax, ?2
305 mov ?1*4+2, ax
306MEND
307
308ASM_END
309
310typedef unsigned char Bit8u;
311typedef unsigned short Bit16u;
312typedef unsigned short bx_bool;
313typedef unsigned long Bit32u;
314
315#if BX_USE_ATADRV
316
317 void memsetb(seg,offset,value,count);
318 void memcpyb(dseg,doffset,sseg,soffset,count);
319 void memcpyd(dseg,doffset,sseg,soffset,count);
320
321 // memset of count bytes
322 void
323 memsetb(seg,offset,value,count)
324 Bit16u seg;
325 Bit16u offset;
326 Bit16u value;
327 Bit16u count;
328 {
329 ASM_START
330 push bp
331 mov bp, sp
332
333 push ax
334 push cx
335 push es
336 push di
337
338 mov cx, 10[bp] ; count
339 test cx, cx
340 je memsetb_end
341 mov ax, 4[bp] ; segment
342 mov es, ax
343 mov ax, 6[bp] ; offset
344 mov di, ax
345 mov al, 8[bp] ; value
346 cld
347 rep
348 stosb
349
350 memsetb_end:
351 pop di
352 pop es
353 pop cx
354 pop ax
355
356 pop bp
357 ASM_END
358 }
359
360#if 0
361 // memcpy of count bytes
362 void
363 memcpyb(dseg,doffset,sseg,soffset,count)
364 Bit16u dseg;
365 Bit16u doffset;
366 Bit16u sseg;
367 Bit16u soffset;
368 Bit16u count;
369 {
370 ASM_START
371 push bp
372 mov bp, sp
373
374 push ax
375 push cx
376 push es
377 push di
378 push ds
379 push si
380
381 mov cx, 12[bp] ; count
382 cmp cx, #0x0000
383 je memcpyb_end
384 mov ax, 4[bp] ; dsegment
385 mov es, ax
386 mov ax, 6[bp] ; doffset
387 mov di, ax
388 mov ax, 8[bp] ; ssegment
389 mov ds, ax
390 mov ax, 10[bp] ; soffset
391 mov si, ax
392 cld
393 rep
394 movsb
395
396 memcpyb_end:
397 pop si
398 pop ds
399 pop di
400 pop es
401 pop cx
402 pop ax
403
404 pop bp
405 ASM_END
406 }
407
408 // memcpy of count dword
409 void
410 memcpyd(dseg,doffset,sseg,soffset,count)
411 Bit16u dseg;
412 Bit16u doffset;
413 Bit16u sseg;
414 Bit16u soffset;
415 Bit16u count;
416 {
417 ASM_START
418 push bp
419 mov bp, sp
420
421 push ax
422 push cx
423 push es
424 push di
425 push ds
426 push si
427
428 mov cx, 12[bp] ; count
429 test cx, cx
430 je memcpyd_end
431 mov ax, 4[bp] ; dsegment
432 mov es, ax
433 mov ax, 6[bp] ; doffset
434 mov di, ax
435 mov ax, 8[bp] ; ssegment
436 mov ds, ax
437 mov ax, 10[bp] ; soffset
438 mov si, ax
439 cld
440 rep
441 movsd
442
443 memcpyd_end:
444 pop si
445 pop ds
446 pop di
447 pop es
448 pop cx
449 pop ax
450
451 pop bp
452 ASM_END
453 }
454#endif
455#endif //BX_USE_ATADRV
456
457 // read_dword and write_dword functions
458 static Bit32u read_dword();
459 static void write_dword();
460
461 Bit32u
462 read_dword(seg, offset)
463 Bit16u seg;
464 Bit16u offset;
465 {
466 ASM_START
467 push bp
468 mov bp, sp
469
470 push bx
471 push ds
472 mov ax, 4[bp] ; segment
473 mov ds, ax
474 mov bx, 6[bp] ; offset
475 mov ax, [bx]
476 add bx, #2
477 mov dx, [bx]
478 ;; ax = return value (word)
479 ;; dx = return value (word)
480 pop ds
481 pop bx
482
483 pop bp
484 ASM_END
485 }
486
487 void
488 write_dword(seg, offset, data)
489 Bit16u seg;
490 Bit16u offset;
491 Bit32u data;
492 {
493 ASM_START
494 push bp
495 mov bp, sp
496
497 push ax
498 push bx
499 push ds
500 mov ax, 4[bp] ; segment
501 mov ds, ax
502 mov bx, 6[bp] ; offset
503 mov ax, 8[bp] ; data word
504 mov [bx], ax ; write data word
505 add bx, #2
506 mov ax, 10[bp] ; data word
507 mov [bx], ax ; write data word
508 pop ds
509 pop bx
510 pop ax
511
512 pop bp
513 ASM_END
514 }
515
516 // Bit32u (unsigned long) and long helper functions
517 ASM_START
518
519 ;; and function
520 landl:
521 landul:
522 SEG SS
523 and ax,[di]
524 SEG SS
525 and bx,2[di]
526 ret
527
528 ;; add function
529 laddl:
530 laddul:
531 SEG SS
532 add ax,[di]
533 SEG SS
534 adc bx,2[di]
535 ret
536
537 ;; cmp function
538 lcmpl:
539 lcmpul:
540 and eax, #0x0000FFFF
541 shl ebx, #16
542 or eax, ebx
543 shr ebx, #16
544 SEG SS
545 cmp eax, dword ptr [di]
546 ret
547
548 ;; sub function
549 lsubl:
550 lsubul:
551 SEG SS
552 sub ax,[di]
553 SEG SS
554 sbb bx,2[di]
555 ret
556
557 ;; mul function
558 lmull:
559 lmulul:
560 and eax, #0x0000FFFF
561 shl ebx, #16
562 or eax, ebx
563 SEG SS
564 mul eax, dword ptr [di]
565 mov ebx, eax
566 shr ebx, #16
567 ret
568
569 ;; dec function
570 ldecl:
571 ldecul:
572 SEG SS
573 dec dword ptr [bx]
574 ret
575
576 ;; or function
577 lorl:
578 lorul:
579 SEG SS
580 or ax,[di]
581 SEG SS
582 or bx,2[di]
583 ret
584
585 ;; inc function
586 lincl:
587 lincul:
588 SEG SS
589 inc dword ptr [bx]
590 ret
591
592 ;; tst function
593 ltstl:
594 ltstul:
595 and eax, #0x0000FFFF
596 shl ebx, #16
597 or eax, ebx
598 shr ebx, #16
599 test eax, eax
600 ret
601
602 ;; sr function
603 lsrul:
604 mov cx,di
605 jcxz lsr_exit
606 and eax, #0x0000FFFF
607 shl ebx, #16
608 or eax, ebx
609 lsr_loop:
610 shr eax, #1
611 loop lsr_loop
612 mov ebx, eax
613 shr ebx, #16
614 lsr_exit:
615 ret
616
617 ;; sl function
618 lsll:
619 lslul:
620 mov cx,di
621 jcxz lsl_exit
622 and eax, #0x0000FFFF
623 shl ebx, #16
624 or eax, ebx
625 lsl_loop:
626 shl eax, #1
627 loop lsl_loop
628 mov ebx, eax
629 shr ebx, #16
630 lsl_exit:
631 ret
632
633 idiv_:
634 cwd
635 idiv bx
636 ret
637
638 idiv_u:
639 xor dx,dx
640 div bx
641 ret
642
643 ldivul:
644 and eax, #0x0000FFFF
645 shl ebx, #16
646 or eax, ebx
647 xor edx, edx
648 SEG SS
649 mov bx, 2[di]
650 shl ebx, #16
651 SEG SS
652 mov bx, [di]
653 div ebx
654 mov ebx, eax
655 shr ebx, #16
656 ret
657
658 ASM_END
659
660// for access to RAM area which is used by interrupt vectors
661// and BIOS Data Area
662
663typedef struct {
664 unsigned char filler1[0x400];
665 unsigned char filler2[0x6c];
666 Bit16u ticks_low;
667 Bit16u ticks_high;
668 Bit8u midnight_flag;
669 } bios_data_t;
670
671#define BiosData ((bios_data_t *) 0)
672
673#if BX_USE_ATADRV
674 typedef struct {
675 Bit16u heads; // # heads
676 Bit16u cylinders; // # cylinders
677 Bit16u spt; // # sectors / track
678 } chs_t;
679
680 // DPTE definition
681 typedef struct {
682 Bit16u iobase1;
683 Bit16u iobase2;
684 Bit8u prefix;
685 Bit8u unused;
686 Bit8u irq;
687 Bit8u blkcount;
688 Bit8u dma;
689 Bit8u pio;
690 Bit16u options;
691 Bit16u reserved;
692 Bit8u revision;
693 Bit8u checksum;
694 } dpte_t;
695
696 typedef struct {
697 Bit8u iface; // ISA or PCI
698 Bit16u iobase1; // IO Base 1
699 Bit16u iobase2; // IO Base 2
700 Bit8u irq; // IRQ
701 } ata_channel_t;
702
703 typedef struct {
704 Bit8u type; // Detected type of ata (ata/atapi/none/unknown/scsi)
705 Bit8u device; // Detected type of attached devices (hd/cd/none)
706 Bit8u removable; // Removable device flag
707 Bit8u lock; // Locks for removable devices
708 Bit8u mode; // transfer mode : PIO 16/32 bits - IRQ - ISADMA - PCIDMA
709 Bit16u blksize; // block size
710
711 Bit8u translation; // type of translation
712 chs_t lchs; // Logical CHS
713 chs_t pchs; // Physical CHS
714
715 Bit32u sectors; // Total sectors count
716 } ata_device_t;
717
718 typedef struct {
719 // ATA channels info
720 ata_channel_t channels[BX_MAX_ATA_INTERFACES];
721
722 // ATA devices info
723 ata_device_t devices[BX_MAX_ATA_DEVICES];
724 //
725 // map between (bios hd id - 0x80) and ata channels and scsi disks.
726#ifdef VBOX_WITH_SCSI
727 Bit8u hdcount, hdidmap[BX_MAX_ATA_DEVICES+BX_MAX_SCSI_DEVICES];
728#else
729 Bit8u hdcount, hdidmap[BX_MAX_ATA_DEVICES];
730#endif
731
732 // map between (bios cd id - 0xE0) and ata channels
733 Bit8u cdcount, cdidmap[BX_MAX_ATA_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 splitted in 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 unsigned char uForceBootDrive;
809 unsigned char uForceBootDevice;
810#endif /* VBOX */
811
812 } ebda_data_t;
813
814#ifdef VBOX
815 // the last 16 bytes of the EBDA segment are used for the MPS floating
816 // pointer structure (only if an IOAPIC is present)
817#endif
818
819 #define EbdaData ((ebda_data_t *) 0)
820
821 // for access to the int13ext structure
822 typedef struct {
823 Bit8u size;
824 Bit8u reserved;
825 Bit16u count;
826 Bit16u offset;
827 Bit16u segment;
828 Bit32u lba1;
829 Bit32u lba2;
830 } int13ext_t;
831
832 #define Int13Ext ((int13ext_t *) 0)
833
834 // Disk Physical Table definition
835 typedef struct {
836 Bit16u size;
837 Bit16u infos;
838 Bit32u cylinders;
839 Bit32u heads;
840 Bit32u spt;
841 Bit32u sector_count1;
842 Bit32u sector_count2;
843 Bit16u blksize;
844 Bit16u dpte_offset;
845 Bit16u dpte_segment;
846 Bit16u key;
847 Bit8u dpi_length;
848 Bit8u reserved1;
849 Bit16u reserved2;
850 Bit8u host_bus[4];
851 Bit8u iface_type[8];
852 Bit8u iface_path[8];
853 Bit8u device_path[8];
854 Bit8u reserved3;
855 Bit8u checksum;
856 } dpt_t;
857
858 #define Int13DPT ((dpt_t *) 0)
859
860#endif // BX_USE_ATADRV
861
862typedef struct {
863 union {
864 struct {
865 Bit16u di, si, bp, sp;
866 Bit16u bx, dx, cx, ax;
867 } r16;
868 struct {
869 Bit16u filler[4];
870 Bit8u bl, bh, dl, dh, cl, ch, al, ah;
871 } r8;
872 } u;
873 } pusha_regs_t;
874
875typedef struct {
876 union {
877 struct {
878 Bit32u edi, esi, ebp, esp;
879 Bit32u ebx, edx, ecx, eax;
880 } r32;
881 struct {
882 Bit16u di, filler1, si, filler2, bp, filler3, sp, filler4;
883 Bit16u bx, filler5, dx, filler6, cx, filler7, ax, filler8;
884 } r16;
885 struct {
886 Bit32u filler[4];
887 Bit8u bl, bh;
888 Bit16u filler1;
889 Bit8u dl, dh;
890 Bit16u filler2;
891 Bit8u cl, ch;
892 Bit16u filler3;
893 Bit8u al, ah;
894 Bit16u filler4;
895 } r8;
896 } u;
897} pushad_regs_t;
898
899typedef struct {
900 union {
901 struct {
902 Bit16u flags;
903 } r16;
904 struct {
905 Bit8u flagsl;
906 Bit8u flagsh;
907 } r8;
908 } u;
909 } flags_t;
910
911#define SetCF(x) x.u.r8.flagsl |= 0x01
912#define SetZF(x) x.u.r8.flagsl |= 0x40
913#define ClearCF(x) x.u.r8.flagsl &= 0xfe
914#define ClearZF(x) x.u.r8.flagsl &= 0xbf
915#define GetCF(x) (x.u.r8.flagsl & 0x01)
916
917typedef struct {
918 Bit16u ip;
919 Bit16u cs;
920 flags_t flags;
921 } iret_addr_t;
922
923
924
925static Bit8u inb();
926static Bit8u inb_cmos();
927static void outb();
928static void outb_cmos();
929static Bit16u inw();
930static void outw();
931static void init_rtc();
932static bx_bool rtc_updating();
933
934static Bit8u read_byte();
935static Bit16u read_word();
936static void write_byte();
937static void write_word();
938static void bios_printf();
939
940static Bit8u send_to_mouse_ctrl();
941static Bit8u get_mouse_data();
942static void set_kbd_command_byte();
943
944static void int09_function();
945static void int13_harddisk();
946static void int13_cdrom();
947static void int13_cdemu();
948static void int13_eltorito();
949static void int13_diskette_function();
950static void int14_function();
951static void int15_function();
952static void int16_function();
953static void int17_function();
954static Bit32u int19_function();
955static void int1a_function();
956static void int70_function();
957static void int74_function();
958static void dummy_isr_function();
959static Bit16u get_CS();
960static Bit16u get_SS();
961static unsigned int enqueue_key();
962static unsigned int dequeue_key();
963static void get_hd_geometry();
964static void set_diskette_ret_status();
965static void set_diskette_current_cyl();
966static void determine_floppy_media();
967static bx_bool floppy_drive_exists();
968static bx_bool floppy_drive_recal();
969static bx_bool floppy_media_known();
970static bx_bool floppy_media_sense();
971static bx_bool set_enable_a20();
972static void debugger_on();
973static void debugger_off();
974static void keyboard_init();
975static void keyboard_panic();
976static void shutdown_status_panic();
977static void nmi_handler_msg();
978
979static void print_bios_banner();
980static void print_boot_device();
981static void print_boot_failure();
982static void print_cdromboot_failure();
983
984# if BX_USE_ATADRV
985
986// ATA / ATAPI driver
987void ata_init();
988void ata_detect();
989void ata_reset();
990
991Bit16u ata_cmd_non_data();
992Bit16u ata_cmd_data_in();
993Bit16u ata_cmd_data_out();
994Bit16u ata_cmd_packet();
995
996Bit16u atapi_get_sense();
997Bit16u atapi_is_ready();
998Bit16u atapi_is_cdrom();
999
1000#endif // BX_USE_ATADRV
1001
1002#if BX_ELTORITO_BOOT
1003
1004void cdemu_init();
1005Bit8u cdemu_isactive();
1006Bit8u cdemu_emulated_drive();
1007
1008Bit16u cdrom_boot();
1009
1010#endif // BX_ELTORITO_BOOT
1011
1012#ifdef VBOX
1013static char bios_prefix_string[] = "BIOS: ";
1014/* Do not use build timestamps in this string. Otherwise even rebuilding the
1015 * very same code will lead to compare errors when restoring saved state. */
1016static char bios_cvs_version_string[] = "VirtualBox " VBOX_VERSION_STRING;
1017#define BIOS_COPYRIGHT_STRING "Sun VirtualBox BIOS"
1018#else /* !VBOX */
1019static char bios_cvs_version_string[] = "$Revision: 1.176 $ $Date: 2006/12/30 17:13:17 $";
1020
1021#define BIOS_COPYRIGHT_STRING "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team."
1022#endif /* !VBOX */
1023
1024#define BIOS_PRINTF_HALT 1
1025#define BIOS_PRINTF_SCREEN 2
1026#define BIOS_PRINTF_INFO 4
1027#define BIOS_PRINTF_DEBUG 8
1028#define BIOS_PRINTF_ALL (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO)
1029#define BIOS_PRINTF_DEBHALT (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO | BIOS_PRINTF_HALT)
1030
1031#define printf(format, p...) bios_printf(BIOS_PRINTF_SCREEN, format, ##p)
1032
1033// Defines the output macros.
1034// BX_DEBUG goes to INFO port until we can easily choose debug info on a
1035// per-device basis. Debug info are sent only in debug mode
1036#if DEBUG_ROMBIOS
1037# define BX_DEBUG(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
1038#else
1039# define BX_DEBUG(format, p...)
1040#endif
1041#ifdef VBOX
1042#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)
1043#else /* !VBOX */
1044#define BX_INFO(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
1045#endif /* !VBOX */
1046#define BX_PANIC(format, p...) bios_printf(BIOS_PRINTF_DEBHALT, format, ##p)
1047
1048#if DEBUG_ATA
1049# define BX_DEBUG_ATA(a...) BX_DEBUG(a)
1050#else
1051# define BX_DEBUG_ATA(a...)
1052#endif
1053#if DEBUG_INT13_HD
1054# define BX_DEBUG_INT13_HD(a...) BX_DEBUG(a)
1055#else
1056# define BX_DEBUG_INT13_HD(a...)
1057#endif
1058#if DEBUG_INT13_CD
1059# define BX_DEBUG_INT13_CD(a...) BX_DEBUG(a)
1060#else
1061# define BX_DEBUG_INT13_CD(a...)
1062#endif
1063#if DEBUG_INT13_ET
1064# define BX_DEBUG_INT13_ET(a...) BX_DEBUG(a)
1065#else
1066# define BX_DEBUG_INT13_ET(a...)
1067#endif
1068#if DEBUG_INT13_FL
1069# define BX_DEBUG_INT13_FL(a...) BX_DEBUG(a)
1070#else
1071# define BX_DEBUG_INT13_FL(a...)
1072#endif
1073#if DEBUG_INT15
1074# define BX_DEBUG_INT15(a...) BX_DEBUG(a)
1075#else
1076# define BX_DEBUG_INT15(a...)
1077#endif
1078#if DEBUG_INT16
1079# define BX_DEBUG_INT16(a...) BX_DEBUG(a)
1080#else
1081# define BX_DEBUG_INT16(a...)
1082#endif
1083#if DEBUG_INT1A
1084# define BX_DEBUG_INT1A(a...) BX_DEBUG(a)
1085#else
1086# define BX_DEBUG_INT1A(a...)
1087#endif
1088#if DEBUG_INT74
1089# define BX_DEBUG_INT74(a...) BX_DEBUG(a)
1090#else
1091# define BX_DEBUG_INT74(a...)
1092#endif
1093
1094#define SET_AL(val8) AX = ((AX & 0xff00) | (val8))
1095#define SET_BL(val8) BX = ((BX & 0xff00) | (val8))
1096#define SET_CL(val8) CX = ((CX & 0xff00) | (val8))
1097#define SET_DL(val8) DX = ((DX & 0xff00) | (val8))
1098#define SET_AH(val8) AX = ((AX & 0x00ff) | ((val8) << 8))
1099#define SET_BH(val8) BX = ((BX & 0x00ff) | ((val8) << 8))
1100#define SET_CH(val8) CX = ((CX & 0x00ff) | ((val8) << 8))
1101#define SET_DH(val8) DX = ((DX & 0x00ff) | ((val8) << 8))
1102
1103#define GET_AL() ( AX & 0x00ff )
1104#define GET_BL() ( BX & 0x00ff )
1105#define GET_CL() ( CX & 0x00ff )
1106#define GET_DL() ( DX & 0x00ff )
1107#define GET_AH() ( AX >> 8 )
1108#define GET_BH() ( BX >> 8 )
1109#define GET_CH() ( CX >> 8 )
1110#define GET_DH() ( DX >> 8 )
1111
1112#define GET_ELDL() ( ELDX & 0x00ff )
1113#define GET_ELDH() ( ELDX >> 8 )
1114
1115#define SET_CF() FLAGS |= 0x0001
1116#define CLEAR_CF() FLAGS &= 0xfffe
1117#define GET_CF() (FLAGS & 0x0001)
1118
1119#define SET_ZF() FLAGS |= 0x0040
1120#define CLEAR_ZF() FLAGS &= 0xffbf
1121#define GET_ZF() (FLAGS & 0x0040)
1122
1123#define UNSUPPORTED_FUNCTION 0x86
1124
1125#define none 0
1126#define MAX_SCAN_CODE 0x58
1127
1128static struct {
1129 Bit16u normal;
1130 Bit16u shift;
1131 Bit16u control;
1132 Bit16u alt;
1133 Bit8u lock_flags;
1134 } scan_to_scanascii[MAX_SCAN_CODE + 1] = {
1135 { none, none, none, none, none },
1136 { 0x011b, 0x011b, 0x011b, 0x0100, none }, /* escape */
1137 { 0x0231, 0x0221, none, 0x7800, none }, /* 1! */
1138 { 0x0332, 0x0340, 0x0300, 0x7900, none }, /* 2@ */
1139 { 0x0433, 0x0423, none, 0x7a00, none }, /* 3# */
1140 { 0x0534, 0x0524, none, 0x7b00, none }, /* 4$ */
1141 { 0x0635, 0x0625, none, 0x7c00, none }, /* 5% */
1142 { 0x0736, 0x075e, 0x071e, 0x7d00, none }, /* 6^ */
1143 { 0x0837, 0x0826, none, 0x7e00, none }, /* 7& */
1144 { 0x0938, 0x092a, none, 0x7f00, none }, /* 8* */
1145 { 0x0a39, 0x0a28, none, 0x8000, none }, /* 9( */
1146 { 0x0b30, 0x0b29, none, 0x8100, none }, /* 0) */
1147 { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200, none }, /* -_ */
1148 { 0x0d3d, 0x0d2b, none, 0x8300, none }, /* =+ */
1149 { 0x0e08, 0x0e08, 0x0e7f, none, none }, /* backspace */
1150 { 0x0f09, 0x0f00, none, none, none }, /* tab */
1151 { 0x1071, 0x1051, 0x1011, 0x1000, 0x40 }, /* Q */
1152 { 0x1177, 0x1157, 0x1117, 0x1100, 0x40 }, /* W */
1153 { 0x1265, 0x1245, 0x1205, 0x1200, 0x40 }, /* E */
1154 { 0x1372, 0x1352, 0x1312, 0x1300, 0x40 }, /* R */
1155 { 0x1474, 0x1454, 0x1414, 0x1400, 0x40 }, /* T */
1156 { 0x1579, 0x1559, 0x1519, 0x1500, 0x40 }, /* Y */
1157 { 0x1675, 0x1655, 0x1615, 0x1600, 0x40 }, /* U */
1158 { 0x1769, 0x1749, 0x1709, 0x1700, 0x40 }, /* I */
1159 { 0x186f, 0x184f, 0x180f, 0x1800, 0x40 }, /* O */
1160 { 0x1970, 0x1950, 0x1910, 0x1900, 0x40 }, /* P */
1161 { 0x1a5b, 0x1a7b, 0x1a1b, none, none }, /* [{ */
1162 { 0x1b5d, 0x1b7d, 0x1b1d, none, none }, /* ]} */
1163 { 0x1c0d, 0x1c0d, 0x1c0a, none, none }, /* Enter */
1164 { none, none, none, none, none }, /* L Ctrl */
1165 { 0x1e61, 0x1e41, 0x1e01, 0x1e00, 0x40 }, /* A */
1166 { 0x1f73, 0x1f53, 0x1f13, 0x1f00, 0x40 }, /* S */
1167 { 0x2064, 0x2044, 0x2004, 0x2000, 0x40 }, /* D */
1168 { 0x2166, 0x2146, 0x2106, 0x2100, 0x40 }, /* F */
1169 { 0x2267, 0x2247, 0x2207, 0x2200, 0x40 }, /* G */
1170 { 0x2368, 0x2348, 0x2308, 0x2300, 0x40 }, /* H */
1171 { 0x246a, 0x244a, 0x240a, 0x2400, 0x40 }, /* J */
1172 { 0x256b, 0x254b, 0x250b, 0x2500, 0x40 }, /* K */
1173 { 0x266c, 0x264c, 0x260c, 0x2600, 0x40 }, /* L */
1174 { 0x273b, 0x273a, none, none, none }, /* ;: */
1175 { 0x2827, 0x2822, none, none, none }, /* '" */
1176 { 0x2960, 0x297e, none, none, none }, /* `~ */
1177 { none, none, none, none, none }, /* L shift */
1178 { 0x2b5c, 0x2b7c, 0x2b1c, none, none }, /* |\ */
1179 { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, 0x40 }, /* Z */
1180 { 0x2d78, 0x2d58, 0x2d18, 0x2d00, 0x40 }, /* X */
1181 { 0x2e63, 0x2e43, 0x2e03, 0x2e00, 0x40 }, /* C */
1182 { 0x2f76, 0x2f56, 0x2f16, 0x2f00, 0x40 }, /* V */
1183 { 0x3062, 0x3042, 0x3002, 0x3000, 0x40 }, /* B */
1184 { 0x316e, 0x314e, 0x310e, 0x3100, 0x40 }, /* N */
1185 { 0x326d, 0x324d, 0x320d, 0x3200, 0x40 }, /* M */
1186 { 0x332c, 0x333c, none, none, none }, /* ,< */
1187 { 0x342e, 0x343e, none, none, none }, /* .> */
1188 { 0x352f, 0x353f, none, none, none }, /* /? */
1189 { none, none, none, none, none }, /* R Shift */
1190 { 0x372a, 0x372a, none, none, none }, /* * */
1191 { none, none, none, none, none }, /* L Alt */
1192 { 0x3920, 0x3920, 0x3920, 0x3920, none }, /* space */
1193 { none, none, none, none, none }, /* caps lock */
1194 { 0x3b00, 0x5400, 0x5e00, 0x6800, none }, /* F1 */
1195 { 0x3c00, 0x5500, 0x5f00, 0x6900, none }, /* F2 */
1196 { 0x3d00, 0x5600, 0x6000, 0x6a00, none }, /* F3 */
1197 { 0x3e00, 0x5700, 0x6100, 0x6b00, none }, /* F4 */
1198 { 0x3f00, 0x5800, 0x6200, 0x6c00, none }, /* F5 */
1199 { 0x4000, 0x5900, 0x6300, 0x6d00, none }, /* F6 */
1200 { 0x4100, 0x5a00, 0x6400, 0x6e00, none }, /* F7 */
1201 { 0x4200, 0x5b00, 0x6500, 0x6f00, none }, /* F8 */
1202 { 0x4300, 0x5c00, 0x6600, 0x7000, none }, /* F9 */
1203 { 0x4400, 0x5d00, 0x6700, 0x7100, none }, /* F10 */
1204 { none, none, none, none, none }, /* Num Lock */
1205 { none, none, none, none, none }, /* Scroll Lock */
1206 { 0x4700, 0x4737, 0x7700, none, 0x20 }, /* 7 Home */
1207 { 0x4800, 0x4838, none, none, 0x20 }, /* 8 UP */
1208 { 0x4900, 0x4939, 0x8400, none, 0x20 }, /* 9 PgUp */
1209 { 0x4a2d, 0x4a2d, none, none, none }, /* - */
1210 { 0x4b00, 0x4b34, 0x7300, none, 0x20 }, /* 4 Left */
1211 { 0x4c00, 0x4c35, none, none, 0x20 }, /* 5 */
1212 { 0x4d00, 0x4d36, 0x7400, none, 0x20 }, /* 6 Right */
1213 { 0x4e2b, 0x4e2b, none, none, none }, /* + */
1214 { 0x4f00, 0x4f31, 0x7500, none, 0x20 }, /* 1 End */
1215 { 0x5000, 0x5032, none, none, 0x20 }, /* 2 Down */
1216 { 0x5100, 0x5133, 0x7600, none, 0x20 }, /* 3 PgDn */
1217 { 0x5200, 0x5230, none, none, 0x20 }, /* 0 Ins */
1218 { 0x5300, 0x532e, none, none, 0x20 }, /* Del */
1219 { none, none, none, none, none },
1220 { none, none, none, none, none },
1221 { 0x565c, 0x567c, none, none, none }, /* \| */
1222#ifndef VBOX
1223 { 0x5700, 0x5700, none, none, none }, /* F11 */
1224 { 0x5800, 0x5800, none, none, none } /* F12 */
1225#else
1226 { 0x8500, 0x8700, 0x8900, 0x8b00, none }, /* F11 */
1227 { 0x8600, 0x8800, 0x8a00, 0x8c00, none } /* F12 */
1228#endif
1229 };
1230
1231 Bit8u
1232inb(port)
1233 Bit16u port;
1234{
1235ASM_START
1236 push bp
1237 mov bp, sp
1238
1239 push dx
1240 mov dx, 4[bp]
1241 in al, dx
1242 pop dx
1243
1244 pop bp
1245ASM_END
1246}
1247
1248#if BX_USE_ATADRV
1249 Bit16u
1250inw(port)
1251 Bit16u port;
1252{
1253ASM_START
1254 push bp
1255 mov bp, sp
1256
1257 push dx
1258 mov dx, 4[bp]
1259 in ax, dx
1260 pop dx
1261
1262 pop bp
1263ASM_END
1264}
1265#endif
1266
1267 void
1268outb(port, val)
1269 Bit16u port;
1270 Bit8u val;
1271{
1272ASM_START
1273 push bp
1274 mov bp, sp
1275
1276 push ax
1277 push dx
1278 mov dx, 4[bp]
1279 mov al, 6[bp]
1280 out dx, al
1281 pop dx
1282 pop ax
1283
1284 pop bp
1285ASM_END
1286}
1287
1288#if BX_USE_ATADRV
1289 void
1290outw(port, val)
1291 Bit16u port;
1292 Bit16u val;
1293{
1294ASM_START
1295 push bp
1296 mov bp, sp
1297
1298 push ax
1299 push dx
1300 mov dx, 4[bp]
1301 mov ax, 6[bp]
1302 out dx, ax
1303 pop dx
1304 pop ax
1305
1306 pop bp
1307ASM_END
1308}
1309#endif
1310
1311 void
1312outb_cmos(cmos_reg, val)
1313 Bit8u cmos_reg;
1314 Bit8u val;
1315{
1316ASM_START
1317 push bp
1318 mov bp, sp
1319
1320 mov al, 4[bp] ;; cmos_reg
1321 out 0x70, al
1322 mov al, 6[bp] ;; val
1323 out 0x71, al
1324
1325 pop bp
1326ASM_END
1327}
1328
1329 Bit8u
1330inb_cmos(cmos_reg)
1331 Bit8u cmos_reg;
1332{
1333ASM_START
1334 push bp
1335 mov bp, sp
1336
1337 mov al, 4[bp] ;; cmos_reg
1338 out 0x70, al
1339 in al, 0x71
1340
1341 pop bp
1342ASM_END
1343}
1344
1345 void
1346init_rtc()
1347{
1348 outb_cmos(0x0a, 0x26);
1349 outb_cmos(0x0b, 0x02);
1350 inb_cmos(0x0c);
1351 inb_cmos(0x0d);
1352}
1353
1354 bx_bool
1355rtc_updating()
1356{
1357 // This function checks to see if the update-in-progress bit
1358 // is set in CMOS Status Register A. If not, it returns 0.
1359 // If it is set, it tries to wait until there is a transition
1360 // to 0, and will return 0 if such a transition occurs. A 1
1361 // is returned only after timing out. The maximum period
1362 // that this bit should be set is constrained to 244useconds.
1363 // The count I use below guarantees coverage or more than
1364 // this time, with any reasonable IPS setting.
1365
1366 Bit16u count;
1367
1368 count = 25000;
1369 while (--count != 0) {
1370 if ( (inb_cmos(0x0a) & 0x80) == 0 )
1371 return(0);
1372 }
1373 return(1); // update-in-progress never transitioned to 0
1374}
1375
1376
1377 Bit8u
1378read_byte(seg, offset)
1379 Bit16u seg;
1380 Bit16u offset;
1381{
1382ASM_START
1383 push bp
1384 mov bp, sp
1385
1386 push bx
1387 push ds
1388 mov ax, 4[bp] ; segment
1389 mov ds, ax
1390 mov bx, 6[bp] ; offset
1391 mov al, [bx]
1392 ;; al = return value (byte)
1393 pop ds
1394 pop bx
1395
1396 pop bp
1397ASM_END
1398}
1399
1400 Bit16u
1401read_word(seg, offset)
1402 Bit16u seg;
1403 Bit16u offset;
1404{
1405ASM_START
1406 push bp
1407 mov bp, sp
1408
1409 push bx
1410 push ds
1411 mov ax, 4[bp] ; segment
1412 mov ds, ax
1413 mov bx, 6[bp] ; offset
1414 mov ax, [bx]
1415 ;; ax = return value (word)
1416 pop ds
1417 pop bx
1418
1419 pop bp
1420ASM_END
1421}
1422
1423 void
1424write_byte(seg, offset, data)
1425 Bit16u seg;
1426 Bit16u offset;
1427 Bit8u data;
1428{
1429ASM_START
1430 push bp
1431 mov bp, sp
1432
1433 push ax
1434 push bx
1435 push ds
1436 mov ax, 4[bp] ; segment
1437 mov ds, ax
1438 mov bx, 6[bp] ; offset
1439 mov al, 8[bp] ; data byte
1440 mov [bx], al ; write data byte
1441 pop ds
1442 pop bx
1443 pop ax
1444
1445 pop bp
1446ASM_END
1447}
1448
1449 void
1450write_word(seg, offset, data)
1451 Bit16u seg;
1452 Bit16u offset;
1453 Bit16u data;
1454{
1455ASM_START
1456 push bp
1457 mov bp, sp
1458
1459 push ax
1460 push bx
1461 push ds
1462 mov ax, 4[bp] ; segment
1463 mov ds, ax
1464 mov bx, 6[bp] ; offset
1465 mov ax, 8[bp] ; data word
1466 mov [bx], ax ; write data word
1467 pop ds
1468 pop bx
1469 pop ax
1470
1471 pop bp
1472ASM_END
1473}
1474
1475 Bit16u
1476get_CS()
1477{
1478ASM_START
1479 mov ax, cs
1480ASM_END
1481}
1482
1483 Bit16u
1484get_SS()
1485{
1486ASM_START
1487 mov ax, ss
1488ASM_END
1489}
1490
1491#if BX_DEBUG_SERIAL
1492/* serial debug port*/
1493#define BX_DEBUG_PORT 0x03f8
1494
1495/* data */
1496#define UART_RBR 0x00
1497#define UART_THR 0x00
1498
1499/* control */
1500#define UART_IER 0x01
1501#define UART_IIR 0x02
1502#define UART_FCR 0x02
1503#define UART_LCR 0x03
1504#define UART_MCR 0x04
1505#define UART_DLL 0x00
1506#define UART_DLM 0x01
1507
1508/* status */
1509#define UART_LSR 0x05
1510#define UART_MSR 0x06
1511#define UART_SCR 0x07
1512
1513int uart_can_tx_byte(base_port)
1514 Bit16u base_port;
1515{
1516 return inb(base_port + UART_LSR) & 0x20;
1517}
1518
1519void uart_wait_to_tx_byte(base_port)
1520 Bit16u base_port;
1521{
1522 while (!uart_can_tx_byte(base_port));
1523}
1524
1525void uart_wait_until_sent(base_port)
1526 Bit16u base_port;
1527{
1528 while (!(inb(base_port + UART_LSR) & 0x40));
1529}
1530
1531void uart_tx_byte(base_port, data)
1532 Bit16u base_port;
1533 Bit8u data;
1534{
1535 uart_wait_to_tx_byte(base_port);
1536 outb(base_port + UART_THR, data);
1537 uart_wait_until_sent(base_port);
1538}
1539#endif
1540
1541 void
1542wrch(c)
1543 Bit8u c;
1544{
1545 ASM_START
1546 push bp
1547 mov bp, sp
1548
1549 push bx
1550 mov ah, #0x0e
1551 mov al, 4[bp]
1552 xor bx,bx
1553 int #0x10
1554 pop bx
1555
1556 pop bp
1557 ASM_END
1558}
1559
1560 void
1561send(action, c)
1562 Bit16u action;
1563 Bit8u c;
1564{
1565#if BX_DEBUG_SERIAL
1566 if (c == '\n') uart_tx_byte(BX_DEBUG_PORT, '\r');
1567 uart_tx_byte(BX_DEBUG_PORT, c);
1568#endif
1569#if BX_VIRTUAL_PORTS
1570 if (action & BIOS_PRINTF_DEBUG) outb(DEBUG_PORT, c);
1571 if (action & BIOS_PRINTF_INFO) outb(INFO_PORT, c);
1572#endif
1573 if (action & BIOS_PRINTF_SCREEN) {
1574 if (c == '\n') wrch('\r');
1575 wrch(c);
1576 }
1577}
1578
1579 void
1580put_int(action, val, width, neg)
1581 Bit16u action;
1582 short val, width;
1583 bx_bool neg;
1584{
1585 short nval = val / 10;
1586 if (nval)
1587 put_int(action, nval, width - 1, neg);
1588 else {
1589 while (--width > 0) send(action, ' ');
1590 if (neg) send(action, '-');
1591 }
1592 send(action, val - (nval * 10) + '0');
1593}
1594
1595 void
1596put_uint(action, val, width, neg)
1597 Bit16u action;
1598 unsigned short val;
1599 short width;
1600 bx_bool neg;
1601{
1602 unsigned short nval = val / 10;
1603 if (nval)
1604 put_uint(action, nval, width - 1, neg);
1605 else {
1606 while (--width > 0) send(action, ' ');
1607 if (neg) send(action, '-');
1608 }
1609 send(action, val - (nval * 10) + '0');
1610}
1611
1612 void
1613put_luint(action, val, width, neg)
1614 Bit16u action;
1615 unsigned long val;
1616 short width;
1617 bx_bool neg;
1618{
1619 unsigned long nval = val / 10;
1620 if (nval)
1621 put_luint(action, nval, width - 1, neg);
1622 else {
1623 while (--width > 0) send(action, ' ');
1624 if (neg) send(action, '-');
1625 }
1626 send(action, val - (nval * 10) + '0');
1627}
1628
1629void put_str(action, segment, offset)
1630 Bit16u action;
1631 Bit16u segment;
1632 Bit16u offset;
1633{
1634 Bit8u c;
1635
1636 while (c = read_byte(segment, offset)) {
1637 send(action, c);
1638 offset++;
1639 }
1640}
1641
1642
1643//--------------------------------------------------------------------------
1644// bios_printf()
1645// A compact variable argument printf function.
1646//
1647// Supports %[format_width][length]format
1648// where format can be x,X,u,d,s,S,c
1649// and the optional length modifier is l (ell)
1650//--------------------------------------------------------------------------
1651 void
1652bios_printf(action, s)
1653 Bit16u action;
1654 Bit8u *s;
1655{
1656 Bit8u c, format_char;
1657 bx_bool in_format;
1658 short i;
1659 Bit16u *arg_ptr;
1660 Bit16u arg_seg, arg, nibble, hibyte, shift_count, format_width, hexadd;
1661
1662 arg_ptr = &s;
1663 arg_seg = get_SS();
1664
1665 in_format = 0;
1666 format_width = 0;
1667
1668 if ((action & BIOS_PRINTF_DEBHALT) == BIOS_PRINTF_DEBHALT) {
1669#if BX_VIRTUAL_PORTS
1670 outb(PANIC_PORT2, 0x00);
1671#endif
1672 bios_printf (BIOS_PRINTF_SCREEN, "FATAL: ");
1673 }
1674
1675 while (c = read_byte(get_CS(), s)) {
1676 if ( c == '%' ) {
1677 in_format = 1;
1678 format_width = 0;
1679 }
1680 else if (in_format) {
1681 if ( (c>='0') && (c<='9') ) {
1682 format_width = (format_width * 10) + (c - '0');
1683 }
1684 else {
1685 arg_ptr++; // increment to next arg
1686 arg = read_word(arg_seg, arg_ptr);
1687 if (c == 'x' || c == 'X') {
1688 if (format_width == 0)
1689 format_width = 4;
1690 if (c == 'x')
1691 hexadd = 'a';
1692 else
1693 hexadd = 'A';
1694 for (i=format_width-1; i>=0; i--) {
1695 nibble = (arg >> (4 * i)) & 0x000f;
1696 send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd));
1697 }
1698 }
1699 else if (c == 'u') {
1700 put_uint(action, arg, format_width, 0);
1701 }
1702 else if (c == 'l') {
1703 s++;
1704 c = read_byte(get_CS(), s); /* is it ld,lx,lu? */
1705 arg_ptr++; /* increment to next arg */
1706 hibyte = read_word(arg_seg, arg_ptr);
1707 if (c == 'd') {
1708 if (hibyte & 0x8000)
1709 put_luint(action, 0L-(((Bit32u) hibyte << 16) | arg), format_width-1, 1);
1710 else
1711 put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
1712 }
1713 else if (c == 'u') {
1714 put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
1715 }
1716 else if (c == 'x' || c == 'X')
1717 {
1718 if (format_width == 0)
1719 format_width = 8;
1720 if (c == 'x')
1721 hexadd = 'a';
1722 else
1723 hexadd = 'A';
1724 for (i=format_width-1; i>=0; i--) {
1725 nibble = ((((Bit32u) hibyte <<16) | arg) >> (4 * i)) & 0x000f;
1726 send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd));
1727 }
1728 }
1729 }
1730 else if (c == 'd') {
1731 if (arg & 0x8000)
1732 put_int(action, -arg, format_width - 1, 1);
1733 else
1734 put_int(action, arg, format_width, 0);
1735 }
1736 else if (c == 's') {
1737 put_str(action, get_CS(), arg);
1738 }
1739 else if (c == 'S') {
1740 hibyte = arg;
1741 arg_ptr++;
1742 arg = read_word(arg_seg, arg_ptr);
1743 put_str(action, hibyte, arg);
1744 }
1745 else if (c == 'c') {
1746 send(action, arg);
1747 }
1748 else
1749 BX_PANIC("bios_printf: unknown format\n");
1750 in_format = 0;
1751 }
1752 }
1753 else {
1754 send(action, c);
1755 }
1756 s ++;
1757 }
1758
1759 if (action & BIOS_PRINTF_HALT) {
1760 // freeze in a busy loop.
1761ASM_START
1762 cli
1763 halt2_loop:
1764 hlt
1765 jmp halt2_loop
1766ASM_END
1767 }
1768}
1769
1770//--------------------------------------------------------------------------
1771// keyboard_init
1772//--------------------------------------------------------------------------
1773// this file is based on LinuxBIOS implementation of keyboard.c
1774// could convert to #asm to gain space
1775 void
1776keyboard_init()
1777{
1778 Bit16u max;
1779
1780 /* ------------------- Flush buffers ------------------------*/
1781 /* Wait until buffer is empty */
1782 max=0xffff;
1783 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
1784
1785 /* flush incoming keys */
1786 max=0x2000;
1787 while (--max > 0) {
1788 outb(0x80, 0x00);
1789 if (inb(0x64) & 0x01) {
1790 inb(0x60);
1791 max = 0x2000;
1792 }
1793 }
1794
1795 // Due to timer issues, and if the IPS setting is > 15000000,
1796 // the incoming keys might not be flushed here. That will
1797 // cause a panic a few lines below. See sourceforge bug report :
1798 // [ 642031 ] FATAL: Keyboard RESET error:993
1799
1800 /* ------------------- controller side ----------------------*/
1801 /* send cmd = 0xAA, self test 8042 */
1802 outb(0x64, 0xaa);
1803
1804 /* Wait until buffer is empty */
1805 max=0xffff;
1806 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
1807 if (max==0x0) keyboard_panic(00);
1808
1809 /* Wait for data */
1810 max=0xffff;
1811 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x01);
1812 if (max==0x0) keyboard_panic(01);
1813
1814 /* read self-test result, 0x55 should be returned from 0x60 */
1815 if ((inb(0x60) != 0x55)){
1816 keyboard_panic(991);
1817 }
1818
1819 /* send cmd = 0xAB, keyboard interface test */
1820 outb(0x64,0xab);
1821
1822 /* Wait until buffer is empty */
1823 max=0xffff;
1824 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x10);
1825 if (max==0x0) keyboard_panic(10);
1826
1827 /* Wait for data */
1828 max=0xffff;
1829 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x11);
1830 if (max==0x0) keyboard_panic(11);
1831
1832 /* read keyboard interface test result, */
1833 /* 0x00 should be returned form 0x60 */
1834 if ((inb(0x60) != 0x00)) {
1835 keyboard_panic(992);
1836 }
1837
1838 /* Enable Keyboard clock */
1839 outb(0x64,0xae);
1840 outb(0x64,0xa8);
1841
1842 /* ------------------- keyboard side ------------------------*/
1843 /* reset kerboard and self test (keyboard side) */
1844 outb(0x60, 0xff);
1845
1846 /* Wait until buffer is empty */
1847 max=0xffff;
1848 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x20);
1849 if (max==0x0) keyboard_panic(20);
1850
1851 /* Wait for data */
1852 max=0xffff;
1853 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x21);
1854 if (max==0x0) keyboard_panic(21);
1855
1856 /* keyboard should return ACK */
1857 if ((inb(0x60) != 0xfa)) {
1858 keyboard_panic(993);
1859 }
1860
1861 /* Wait for data */
1862 max=0xffff;
1863 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x31);
1864 if (max==0x0) keyboard_panic(31);
1865
1866 if ((inb(0x60) != 0xaa)) {
1867 keyboard_panic(994);
1868 }
1869
1870 /* Disable keyboard */
1871 outb(0x60, 0xf5);
1872
1873 /* Wait until buffer is empty */
1874 max=0xffff;
1875 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x40);
1876 if (max==0x0) keyboard_panic(40);
1877
1878 /* Wait for data */
1879 max=0xffff;
1880 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x41);
1881 if (max==0x0) keyboard_panic(41);
1882
1883 /* keyboard should return ACK */
1884 if ((inb(0x60) != 0xfa)) {
1885 keyboard_panic(995);
1886 }
1887
1888 /* Write Keyboard Mode */
1889 outb(0x64, 0x60);
1890
1891 /* Wait until buffer is empty */
1892 max=0xffff;
1893 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x50);
1894 if (max==0x0) keyboard_panic(50);
1895
1896 /* send cmd: scan code convert, disable mouse, enable IRQ 1 */
1897 outb(0x60, 0x65);
1898
1899 /* Wait until buffer is empty */
1900 max=0xffff;
1901 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x60);
1902 if (max==0x0) keyboard_panic(60);
1903
1904 /* Enable keyboard */
1905 outb(0x60, 0xf4);
1906
1907 /* Wait until buffer is empty */
1908 max=0xffff;
1909 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x70);
1910 if (max==0x0) keyboard_panic(70);
1911
1912 /* Wait for data */
1913 max=0xffff;
1914 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x71);
1915 if (max==0x0) keyboard_panic(70);
1916
1917 /* keyboard should return ACK */
1918 if ((inb(0x60) != 0xfa)) {
1919 keyboard_panic(996);
1920 }
1921
1922 outb(0x80, 0x77);
1923}
1924
1925//--------------------------------------------------------------------------
1926// keyboard_panic
1927//--------------------------------------------------------------------------
1928 void
1929keyboard_panic(status)
1930 Bit16u status;
1931{
1932 // If you're getting a 993 keyboard panic here,
1933 // please see the comment in keyboard_init
1934
1935 BX_PANIC("Keyboard error:%u\n",status);
1936}
1937
1938//--------------------------------------------------------------------------
1939// shutdown_status_panic
1940// called when the shutdown statsu is not implemented, displays the status
1941//--------------------------------------------------------------------------
1942 void
1943shutdown_status_panic(status)
1944 Bit16u status;
1945{
1946 BX_PANIC("Unimplemented shutdown status: %02x\n",(Bit8u)status);
1947}
1948
1949#ifdef VBOX
1950#include "logo.c"
1951#endif /* VBOX */
1952
1953//--------------------------------------------------------------------------
1954// print_bios_banner
1955// displays a the bios version
1956//--------------------------------------------------------------------------
1957void
1958print_bios_banner()
1959{
1960#ifdef VBOX
1961 // Skip the logo if a warm boot is requested.
1962 Bit16u warm_boot = read_word(0x0040,0x0072);
1963 write_word(0x0040,0x0072, 0);
1964 if (warm_boot == 0x1234)
1965 return;
1966#if !defined(DEBUG) || defined(DEBUG_sunlover)
1967 /* show graphical logo */
1968 show_logo();
1969#else
1970 /* set text mode */
1971 ASM_START
1972 mov ax, #0x0003
1973 int #0x10
1974 ASM_END
1975#endif /* !DEBUG */
1976#else /* !VBOX */
1977 printf(BX_APPNAME" BIOS - build: %s\n%s\nOptions: ",
1978 BIOS_BUILD_DATE, bios_cvs_version_string);
1979 printf(
1980#if BX_APM
1981 "apmbios "
1982#endif
1983#if BX_PCIBIOS
1984 "pcibios "
1985#endif
1986#if BX_ELTORITO_BOOT
1987 "eltorito "
1988#endif
1989#if BX_ROMBIOS32
1990 "rombios32 "
1991#endif
1992 "\n\n");
1993#endif /* VBOX */
1994}
1995
1996//--------------------------------------------------------------------------
1997// print_boot_device
1998// displays the boot device
1999//--------------------------------------------------------------------------
2000
2001#ifdef VBOX
2002static char drivetypes[][10]={"Floppy","Hard Disk","CD-ROM","LAN"};
2003#else /* !VBOX */
2004static char drivetypes[][10]={"Floppy","Hard Disk","CD-Rom"};
2005#endif /* !VBOX */
2006
2007#ifdef VBOX
2008void
2009print_boot_device(cdboot, lanboot, drive)
2010 Bit8u cdboot; Bit8u lanboot; Bit16u drive;
2011#else /* !VBOX */
2012void
2013print_boot_device(cdboot, drive)
2014 Bit8u cdboot; Bit16u drive;
2015#endif /* !VBOX */
2016{
2017 Bit8u i;
2018
2019#ifdef VBOX
2020 // cdboot contains 0 if lan/floppy/harddisk, 1 otherwise
2021 // lanboot contains 0 if floppy/harddisk, 1 otherwise
2022#else /* !VBOX */
2023 // cdboot contains 0 if floppy/harddisk, 1 otherwise
2024#endif /* !VBOX */
2025 // drive contains real/emulated boot drive
2026
2027 if(cdboot)i=2; // CD-Rom
2028#ifdef VBOX
2029 else if(lanboot)i=3; // LAN
2030#endif /* VBOX */
2031 else if((drive&0x0080)==0x00)i=0; // Floppy
2032 else if((drive&0x0080)==0x80)i=1; // Hard drive
2033 else return;
2034
2035#ifdef VBOX
2036 BX_INFO("Booting from %s...\n",drivetypes[i]);
2037#else /* !VBOX */
2038 printf("Booting from %s...\n",drivetypes[i]);
2039#endif /* !VBOX */
2040}
2041
2042//--------------------------------------------------------------------------
2043// print_boot_failure
2044// displays the reason why boot failed
2045//--------------------------------------------------------------------------
2046#ifdef VBOX
2047 void
2048print_boot_failure(cdboot, lanboot, drive, reason, lastdrive)
2049 Bit8u cdboot; Bit8u lanboot; Bit8u drive; Bit8u reason; Bit8u lastdrive;
2050#else /* !VBOX */
2051 void
2052print_boot_failure(cdboot, drive, reason, lastdrive)
2053 Bit8u cdboot; Bit8u drive; Bit8u lastdrive;
2054#endif /* !VBOX */
2055{
2056 Bit16u drivenum = drive&0x7f;
2057
2058 // cdboot: 1 if boot from cd, 0 otherwise
2059#ifdef VBOX
2060 // lanboot: 1 if boot from lan, 0 otherwise
2061#endif /* VBOX */
2062 // drive : drive number
2063 // reason: 0 signature check failed, 1 read error
2064 // lastdrive: 1 boot drive is the last one in boot sequence
2065
2066 if (cdboot)
2067#ifndef VBOX
2068 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s failed\n",drivetypes[2]);
2069#else /* VBOX */
2070 BX_INFO("Boot from %s failed\n",drivetypes[2]);
2071 else if (lanboot)
2072 BX_INFO("Boot from %s failed\n",drivetypes[3]);
2073#endif /* VBOX */
2074 else if (drive & 0x80)
2075#ifndef VBOX
2076 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[1],drivenum);
2077#else /* VBOX */
2078 BX_INFO("Boot from %s %d failed\n", drivetypes[1],drivenum);
2079#endif /* VBOX */
2080 else
2081#ifndef VBOX
2082 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[0],drivenum);
2083#else /* VBOX */
2084 BX_INFO("Boot from %s %d failed\n", drivetypes[0],drivenum);
2085#endif /* VBOX */
2086
2087 if (lastdrive==1) {
2088 if (reason==0)
2089#ifndef VBOX
2090 BX_PANIC("Not a bootable disk\n");
2091#else /* VBOX */
2092 BX_PANIC("No bootable medium found! System halted.\n");
2093#endif /* VBOX */
2094 else
2095#ifndef VBOX
2096 BX_PANIC("Could not read the boot disk\n");
2097#else /* VBOX */
2098 BX_PANIC("Could not read from the boot medium! System halted.\n");
2099#endif /* VBOX */
2100 }
2101}
2102
2103//--------------------------------------------------------------------------
2104// print_cdromboot_failure
2105// displays the reason why boot failed
2106//--------------------------------------------------------------------------
2107 void
2108print_cdromboot_failure( code )
2109 Bit16u code;
2110{
2111#ifndef VBOX
2112 bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "CDROM boot failure code : %04x\n",code);
2113#else /* VBOX */
2114 BX_INFO("CDROM boot failure code : %04x\n",code);
2115#endif /* VBOX */
2116
2117 return;
2118}
2119
2120void
2121nmi_handler_msg()
2122{
2123 BX_PANIC("NMI Handler called\n");
2124}
2125
2126void
2127int18_panic_msg()
2128{
2129 BX_PANIC("INT18: BOOT FAILURE\n");
2130}
2131
2132void
2133log_bios_start()
2134{
2135#if BX_DEBUG_SERIAL
2136 outb(BX_DEBUG_PORT+UART_LCR, 0x03); /* setup for serial logging: 8N1 */
2137#endif
2138 BX_INFO("%s\n", bios_cvs_version_string);
2139}
2140
2141 bx_bool
2142set_enable_a20(val)
2143 bx_bool val;
2144{
2145 Bit8u oldval;
2146
2147 // Use PS2 System Control port A to set A20 enable
2148
2149 // get current setting first
2150 oldval = inb(0x92);
2151
2152 // change A20 status
2153 if (val)
2154 outb(0x92, oldval | 0x02);
2155 else
2156 outb(0x92, oldval & 0xfd);
2157
2158 return((oldval & 0x02) != 0);
2159}
2160
2161 void
2162debugger_on()
2163{
2164 outb(0xfedc, 0x01);
2165}
2166
2167 void
2168debugger_off()
2169{
2170 outb(0xfedc, 0x00);
2171}
2172
2173#if BX_USE_ATADRV
2174
2175// ---------------------------------------------------------------------------
2176// Start of ATA/ATAPI Driver
2177// ---------------------------------------------------------------------------
2178
2179// Global defines -- ATA register and register bits.
2180// command block & control block regs
2181#define ATA_CB_DATA 0 // data reg in/out pio_base_addr1+0
2182#define ATA_CB_ERR 1 // error in pio_base_addr1+1
2183#define ATA_CB_FR 1 // feature reg out pio_base_addr1+1
2184#define ATA_CB_SC 2 // sector count in/out pio_base_addr1+2
2185#define ATA_CB_SN 3 // sector number in/out pio_base_addr1+3
2186#define ATA_CB_CL 4 // cylinder low in/out pio_base_addr1+4
2187#define ATA_CB_CH 5 // cylinder high in/out pio_base_addr1+5
2188#define ATA_CB_DH 6 // device head in/out pio_base_addr1+6
2189#define ATA_CB_STAT 7 // primary status in pio_base_addr1+7
2190#define ATA_CB_CMD 7 // command out pio_base_addr1+7
2191#define ATA_CB_ASTAT 6 // alternate status in pio_base_addr2+6
2192#define ATA_CB_DC 6 // device control out pio_base_addr2+6
2193#define ATA_CB_DA 7 // device address in pio_base_addr2+7
2194
2195#define ATA_CB_ER_ICRC 0x80 // ATA Ultra DMA bad CRC
2196#define ATA_CB_ER_BBK 0x80 // ATA bad block
2197#define ATA_CB_ER_UNC 0x40 // ATA uncorrected error
2198#define ATA_CB_ER_MC 0x20 // ATA media change
2199#define ATA_CB_ER_IDNF 0x10 // ATA id not found
2200#define ATA_CB_ER_MCR 0x08 // ATA media change request
2201#define ATA_CB_ER_ABRT 0x04 // ATA command aborted
2202#define ATA_CB_ER_NTK0 0x02 // ATA track 0 not found
2203#define ATA_CB_ER_NDAM 0x01 // ATA address mark not found
2204
2205#define ATA_CB_ER_P_SNSKEY 0xf0 // ATAPI sense key (mask)
2206#define ATA_CB_ER_P_MCR 0x08 // ATAPI Media Change Request
2207#define ATA_CB_ER_P_ABRT 0x04 // ATAPI command abort
2208#define ATA_CB_ER_P_EOM 0x02 // ATAPI End of Media
2209#define ATA_CB_ER_P_ILI 0x01 // ATAPI Illegal Length Indication
2210
2211// ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC)
2212#define ATA_CB_SC_P_TAG 0xf8 // ATAPI tag (mask)
2213#define ATA_CB_SC_P_REL 0x04 // ATAPI release
2214#define ATA_CB_SC_P_IO 0x02 // ATAPI I/O
2215#define ATA_CB_SC_P_CD 0x01 // ATAPI C/D
2216
2217// bits 7-4 of the device/head (CB_DH) reg
2218#define ATA_CB_DH_DEV0 0xa0 // select device 0
2219#define ATA_CB_DH_DEV1 0xb0 // select device 1
2220
2221// status reg (CB_STAT and CB_ASTAT) bits
2222#define ATA_CB_STAT_BSY 0x80 // busy
2223#define ATA_CB_STAT_RDY 0x40 // ready
2224#define ATA_CB_STAT_DF 0x20 // device fault
2225#define ATA_CB_STAT_WFT 0x20 // write fault (old name)
2226#define ATA_CB_STAT_SKC 0x10 // seek complete
2227#define ATA_CB_STAT_SERV 0x10 // service
2228#define ATA_CB_STAT_DRQ 0x08 // data request
2229#define ATA_CB_STAT_CORR 0x04 // corrected
2230#define ATA_CB_STAT_IDX 0x02 // index
2231#define ATA_CB_STAT_ERR 0x01 // error (ATA)
2232#define ATA_CB_STAT_CHK 0x01 // check (ATAPI)
2233
2234// device control reg (CB_DC) bits
2235#define ATA_CB_DC_HD15 0x08 // bit should always be set to one
2236#define ATA_CB_DC_SRST 0x04 // soft reset
2237#define ATA_CB_DC_NIEN 0x02 // disable interrupts
2238
2239// Most mandtory and optional ATA commands (from ATA-3),
2240#define ATA_CMD_CFA_ERASE_SECTORS 0xC0
2241#define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03
2242#define ATA_CMD_CFA_TRANSLATE_SECTOR 0x87
2243#define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD
2244#define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38
2245#define ATA_CMD_CHECK_POWER_MODE1 0xE5
2246#define ATA_CMD_CHECK_POWER_MODE2 0x98
2247#define ATA_CMD_DEVICE_RESET 0x08
2248#define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90
2249#define ATA_CMD_FLUSH_CACHE 0xE7
2250#define ATA_CMD_FORMAT_TRACK 0x50
2251#define ATA_CMD_IDENTIFY_DEVICE 0xEC
2252#define ATA_CMD_IDENTIFY_DEVICE_PACKET 0xA1
2253#define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xA1
2254#define ATA_CMD_IDLE1 0xE3
2255#define ATA_CMD_IDLE2 0x97
2256#define ATA_CMD_IDLE_IMMEDIATE1 0xE1
2257#define ATA_CMD_IDLE_IMMEDIATE2 0x95
2258#define ATA_CMD_INITIALIZE_DRIVE_PARAMETERS 0x91
2259#define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
2260#define ATA_CMD_NOP 0x00
2261#define ATA_CMD_PACKET 0xA0
2262#define ATA_CMD_READ_BUFFER 0xE4
2263#define ATA_CMD_READ_DMA 0xC8
2264#define ATA_CMD_READ_DMA_QUEUED 0xC7
2265#define ATA_CMD_READ_MULTIPLE 0xC4
2266#define ATA_CMD_READ_SECTORS 0x20
2267#ifdef VBOX
2268#define ATA_CMD_READ_SECTORS_EXT 0x24
2269#endif /* VBOX */
2270#define ATA_CMD_READ_VERIFY_SECTORS 0x40
2271#define ATA_CMD_RECALIBRATE 0x10
2272#define ATA_CMD_SEEK 0x70
2273#define ATA_CMD_SET_FEATURES 0xEF
2274#define ATA_CMD_SET_MULTIPLE_MODE 0xC6
2275#define ATA_CMD_SLEEP1 0xE6
2276#define ATA_CMD_SLEEP2 0x99
2277#define ATA_CMD_STANDBY1 0xE2
2278#define ATA_CMD_STANDBY2 0x96
2279#define ATA_CMD_STANDBY_IMMEDIATE1 0xE0
2280#define ATA_CMD_STANDBY_IMMEDIATE2 0x94
2281#define ATA_CMD_WRITE_BUFFER 0xE8
2282#define ATA_CMD_WRITE_DMA 0xCA
2283#define ATA_CMD_WRITE_DMA_QUEUED 0xCC
2284#define ATA_CMD_WRITE_MULTIPLE 0xC5
2285#define ATA_CMD_WRITE_SECTORS 0x30
2286#ifdef VBOX
2287#define ATA_CMD_WRITE_SECTORS_EXT 0x34
2288#endif /* VBOX */
2289#define ATA_CMD_WRITE_VERIFY 0x3C
2290
2291#define ATA_IFACE_NONE 0x00
2292#define ATA_IFACE_ISA 0x00
2293#define ATA_IFACE_PCI 0x01
2294
2295#define ATA_TYPE_NONE 0x00
2296#define ATA_TYPE_UNKNOWN 0x01
2297#define ATA_TYPE_ATA 0x02
2298#define ATA_TYPE_ATAPI 0x03
2299#ifdef VBOX
2300#define ATA_TYPE_SCSI 0x04 // SCSI disk
2301#endif
2302
2303#define ATA_DEVICE_NONE 0x00
2304#define ATA_DEVICE_HD 0xFF
2305#define ATA_DEVICE_CDROM 0x05
2306
2307#define ATA_MODE_NONE 0x00
2308#define ATA_MODE_PIO16 0x00
2309#define ATA_MODE_PIO32 0x01
2310#define ATA_MODE_ISADMA 0x02
2311#define ATA_MODE_PCIDMA 0x03
2312#define ATA_MODE_USEIRQ 0x10
2313
2314#define ATA_TRANSLATION_NONE 0
2315#define ATA_TRANSLATION_LBA 1
2316#define ATA_TRANSLATION_LARGE 2
2317#define ATA_TRANSLATION_RECHS 3
2318
2319#define ATA_DATA_NO 0x00
2320#define ATA_DATA_IN 0x01
2321#define ATA_DATA_OUT 0x02
2322
2323// ---------------------------------------------------------------------------
2324// ATA/ATAPI driver : initialization
2325// ---------------------------------------------------------------------------
2326void ata_init( )
2327{
2328 Bit16u ebda_seg=read_word(0x0040,0x000E);
2329 Bit8u channel, device;
2330
2331 // Channels info init.
2332 for (channel=0; channel<BX_MAX_ATA_INTERFACES; channel++) {
2333 write_byte(ebda_seg,&EbdaData->ata.channels[channel].iface,ATA_IFACE_NONE);
2334 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1,0x0);
2335 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2,0x0);
2336 write_byte(ebda_seg,&EbdaData->ata.channels[channel].irq,0);
2337 }
2338
2339 // Devices info init.
2340 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2341 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
2342 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_NONE);
2343 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable,0);
2344 write_byte(ebda_seg,&EbdaData->ata.devices[device].lock,0);
2345 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode,ATA_MODE_NONE);
2346 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,0);
2347 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation,ATA_TRANSLATION_NONE);
2348 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads,0);
2349 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders,0);
2350 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt,0);
2351 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads,0);
2352 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders,0);
2353 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt,0);
2354
2355 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors,0L);
2356 }
2357
2358 // hdidmap and cdidmap init.
2359 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2360 write_byte(ebda_seg,&EbdaData->ata.hdidmap[device],BX_MAX_STORAGE_DEVICES);
2361 write_byte(ebda_seg,&EbdaData->ata.cdidmap[device],BX_MAX_STORAGE_DEVICES);
2362 }
2363
2364 write_byte(ebda_seg,&EbdaData->ata.hdcount,0);
2365 write_byte(ebda_seg,&EbdaData->ata.cdcount,0);
2366}
2367
2368// ---------------------------------------------------------------------------
2369// ATA/ATAPI driver : device detection
2370// ---------------------------------------------------------------------------
2371
2372void ata_detect( )
2373{
2374 Bit16u ebda_seg=read_word(0x0040,0x000E);
2375 Bit8u hdcount, cdcount, device, type;
2376 Bit8u buffer[0x0200];
2377
2378#if BX_MAX_ATA_INTERFACES > 0
2379 write_byte(ebda_seg,&EbdaData->ata.channels[0].iface,ATA_IFACE_ISA);
2380 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase1,0x1f0);
2381 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase2,0x3f0);
2382 write_byte(ebda_seg,&EbdaData->ata.channels[0].irq,14);
2383#endif
2384#if BX_MAX_ATA_INTERFACES > 1
2385 write_byte(ebda_seg,&EbdaData->ata.channels[1].iface,ATA_IFACE_ISA);
2386 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase1,0x170);
2387 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase2,0x370);
2388 write_byte(ebda_seg,&EbdaData->ata.channels[1].irq,15);
2389#endif
2390#if BX_MAX_ATA_INTERFACES > 2
2391 write_byte(ebda_seg,&EbdaData->ata.channels[2].iface,ATA_IFACE_ISA);
2392 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase1,0x1e8);
2393 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase2,0x3e0);
2394 write_byte(ebda_seg,&EbdaData->ata.channels[2].irq,12);
2395#endif
2396#if BX_MAX_ATA_INTERFACES > 3
2397 write_byte(ebda_seg,&EbdaData->ata.channels[3].iface,ATA_IFACE_ISA);
2398 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase1,0x168);
2399 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase2,0x360);
2400 write_byte(ebda_seg,&EbdaData->ata.channels[3].irq,11);
2401#endif
2402#if BX_MAX_ATA_INTERFACES > 4
2403#error Please fill the ATA interface informations
2404#endif
2405
2406 // Device detection
2407 hdcount=cdcount=0;
2408
2409 for(device=0; device<BX_MAX_ATA_DEVICES; device++) {
2410 Bit16u iobase1, iobase2;
2411 Bit8u channel, slave, shift;
2412 Bit8u sc, sn, cl, ch, st;
2413
2414 channel = device / 2;
2415 slave = device % 2;
2416
2417 iobase1 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1);
2418 iobase2 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2);
2419
2420 // Disable interrupts
2421 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2422
2423 // Look for device
2424 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2425 outb(iobase1+ATA_CB_SC, 0x55);
2426 outb(iobase1+ATA_CB_SN, 0xaa);
2427 outb(iobase1+ATA_CB_SC, 0xaa);
2428 outb(iobase1+ATA_CB_SN, 0x55);
2429 outb(iobase1+ATA_CB_SC, 0x55);
2430 outb(iobase1+ATA_CB_SN, 0xaa);
2431
2432 // If we found something
2433 sc = inb(iobase1+ATA_CB_SC);
2434 sn = inb(iobase1+ATA_CB_SN);
2435
2436 if ( (sc == 0x55) && (sn == 0xaa) ) {
2437 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_UNKNOWN);
2438
2439 // reset the channel
2440 ata_reset(device);
2441
2442 // check for ATA or ATAPI
2443 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2444 sc = inb(iobase1+ATA_CB_SC);
2445 sn = inb(iobase1+ATA_CB_SN);
2446 if ((sc==0x01) && (sn==0x01)) {
2447 cl = inb(iobase1+ATA_CB_CL);
2448 ch = inb(iobase1+ATA_CB_CH);
2449 st = inb(iobase1+ATA_CB_STAT);
2450
2451 if ((cl==0x14) && (ch==0xeb)) {
2452 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATAPI);
2453 } else if ((cl==0x00) && (ch==0x00) && (st!=0x00)) {
2454 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATA);
2455 } else if ((cl==0xff) && (ch==0xff)) {
2456 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
2457 }
2458 }
2459 }
2460
2461#ifdef VBOX
2462 // Enable interrupts
2463 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2464#endif /* VBOX */
2465
2466 type=read_byte(ebda_seg,&EbdaData->ata.devices[device].type);
2467
2468 // Now we send a IDENTIFY command to ATA device
2469 if(type == ATA_TYPE_ATA) {
2470 Bit32u sectors;
2471 Bit16u cylinders, heads, spt, blksize;
2472#ifdef VBOX
2473 Bit16u lcylinders, lheads, lspt;
2474 Bit8u chsgeo_base;
2475#endif /* VBOX */
2476 Bit8u translation, removable, mode;
2477
2478 //Temporary values to do the transfer
2479 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2480 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2481
2482 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE, 1, 0, 0, 0, 0L, get_SS(),buffer) !=0 )
2483 BX_PANIC("ata-detect: Failed to detect ATA device\n");
2484
2485 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2486 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2487#ifdef VBOX
2488 blksize = 512; /* There is no sector size field any more. */
2489#else /* !VBOX */
2490 blksize = read_word(get_SS(),buffer+10);
2491#endif /* !VBOX */
2492
2493 cylinders = read_word(get_SS(),buffer+(1*2)); // word 1
2494 heads = read_word(get_SS(),buffer+(3*2)); // word 3
2495 spt = read_word(get_SS(),buffer+(6*2)); // word 6
2496
2497 sectors = read_dword(get_SS(),buffer+(60*2)); // word 60 and word 61
2498#ifdef VBOX
2499 /** @todo update sectors to be a 64 bit number (also lba...). */
2500 if (sectors == 268435455)
2501 sectors = read_dword(get_SS(),buffer+(100*2)); // words 100 to 103 (someday)
2502 switch (device)
2503 {
2504 case 0:
2505 chsgeo_base = 0x1e;
2506 break;
2507 case 1:
2508 chsgeo_base = 0x26;
2509 break;
2510 case 2:
2511 chsgeo_base = 0x67;
2512 break;
2513 case 3:
2514 chsgeo_base = 0x70;
2515 break;
2516 case 4:
2517 chsgeo_base = 0x40;
2518 break;
2519 case 5:
2520 chsgeo_base = 0x48;
2521 break;
2522 case 6:
2523 chsgeo_base = 0x50;
2524 break;
2525 case 7:
2526 chsgeo_base = 0x58;
2527 break;
2528 default:
2529 chsgeo_base = 0;
2530 }
2531 if (chsgeo_base != 0)
2532 {
2533 lcylinders = inb_cmos(chsgeo_base) + (inb_cmos(chsgeo_base+1) << 8);
2534 lheads = inb_cmos(chsgeo_base+2);
2535 lspt = inb_cmos(chsgeo_base+7);
2536 }
2537 else
2538 {
2539 lcylinders = 0;
2540 lheads = 0;
2541 lspt = 0;
2542 }
2543 BX_INFO("ata%d-%d: PCHS=%u/%d/%d LCHS=%u/%u/%u\n", channel, slave, cylinders, heads, spt, lcylinders, lheads, lspt);
2544#endif /* VBOX */
2545
2546 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2547 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2548 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2549 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2550 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads, heads);
2551 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders, cylinders);
2552 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt, spt);
2553 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors, sectors);
2554#ifdef VBOX
2555 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, lheads);
2556 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, lcylinders);
2557 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, lspt);
2558 if (device < 2)
2559 {
2560 Bit8u sum, i;
2561 unsigned char *fdpt;
2562 if (device == 0)
2563 fdpt = &EbdaData->fdpt0;
2564 else
2565 fdpt = &EbdaData->fdpt1;
2566
2567 /* Update the DPT for drive 0/1 pointed to by Int41/46. This used
2568 * to be done at POST time with lots of ugly assembler code, which
2569 * isn't worth the effort of converting from AMI to Award CMOS
2570 * format. Just do it here. */
2571 write_word(ebda_seg, fdpt + 0x00, lcylinders);
2572 write_byte(ebda_seg, fdpt + 0x02, lheads);
2573 write_byte(ebda_seg, fdpt + 0x0e, lspt);
2574 write_word(ebda_seg, fdpt + 0x09, cylinders);
2575 write_byte(ebda_seg, fdpt + 0x0b, heads);
2576 write_byte(ebda_seg, fdpt + 0x04, spt);
2577 write_byte(ebda_seg, fdpt + 0x03, 0xa0);
2578 sum = 0;
2579 for (i = 0; i < 0xf; i++)
2580 sum += read_byte(ebda_seg, fdpt + i);
2581 sum = 1 - sum;
2582 write_byte(ebda_seg, fdpt + 0x0f, sum);
2583 }
2584#else /* !VBOX */
2585 BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel, slave,cylinders, heads, spt);
2586
2587 translation = inb_cmos(0x39 + channel/2);
2588 for (shift=device%4; shift>0; shift--) translation >>= 2;
2589 translation &= 0x03;
2590
2591 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation, translation);
2592
2593 switch (translation) {
2594 case ATA_TRANSLATION_NONE:
2595 BX_INFO("none");
2596 break;
2597 case ATA_TRANSLATION_LBA:
2598 BX_INFO("lba");
2599 break;
2600 case ATA_TRANSLATION_LARGE:
2601 BX_INFO("large");
2602 break;
2603 case ATA_TRANSLATION_RECHS:
2604 BX_INFO("r-echs");
2605 break;
2606 }
2607 switch (translation) {
2608 case ATA_TRANSLATION_NONE:
2609 break;
2610 case ATA_TRANSLATION_LBA:
2611 spt = 63;
2612 sectors /= 63;
2613 heads = sectors / 1024;
2614 if (heads>128) heads = 255;
2615 else if (heads>64) heads = 128;
2616 else if (heads>32) heads = 64;
2617 else if (heads>16) heads = 32;
2618 else heads=16;
2619 cylinders = sectors / heads;
2620 break;
2621 case ATA_TRANSLATION_RECHS:
2622 // Take care not to overflow
2623 if (heads==16) {
2624 if(cylinders>61439) cylinders=61439;
2625 heads=15;
2626 cylinders = (Bit16u)((Bit32u)(cylinders)*16/15);
2627 }
2628 // then go through the large bitshift process
2629 case ATA_TRANSLATION_LARGE:
2630 while(cylinders > 1024) {
2631 cylinders >>= 1;
2632 heads <<= 1;
2633
2634 // If we max out the head count
2635 if (heads > 127) break;
2636 }
2637 break;
2638 }
2639 // clip to 1024 cylinders in lchs
2640 if (cylinders > 1024) cylinders=1024;
2641 BX_INFO(" LCHS=%d/%d/%d\n", cylinders, heads, spt);
2642
2643 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, heads);
2644 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, cylinders);
2645 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, spt);
2646#endif /* VBOX */
2647
2648 // fill hdidmap
2649 write_byte(ebda_seg,&EbdaData->ata.hdidmap[hdcount], device);
2650 hdcount++;
2651 }
2652
2653 // Now we send a IDENTIFY command to ATAPI device
2654 if(type == ATA_TYPE_ATAPI) {
2655
2656 Bit8u type, removable, mode;
2657 Bit16u blksize;
2658
2659 //Temporary values to do the transfer
2660 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_CDROM);
2661 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2662
2663 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE_PACKET, 1, 0, 0, 0, 0L, get_SS(),buffer) != 0)
2664 BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
2665
2666 type = read_byte(get_SS(),buffer+1) & 0x1f;
2667 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2668 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2669 blksize = 2048;
2670
2671 write_byte(ebda_seg,&EbdaData->ata.devices[device].device, type);
2672 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2673 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2674 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2675
2676 // fill cdidmap
2677 write_byte(ebda_seg,&EbdaData->ata.cdidmap[cdcount], device);
2678 cdcount++;
2679 }
2680
2681 {
2682 Bit32u sizeinmb;
2683 Bit16u ataversion;
2684 Bit8u c, i, version, model[41];
2685
2686 switch (type) {
2687 case ATA_TYPE_ATA:
2688 sizeinmb = read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors);
2689 sizeinmb >>= 11;
2690 case ATA_TYPE_ATAPI:
2691 // Read ATA/ATAPI version
2692 ataversion=((Bit16u)(read_byte(get_SS(),buffer+161))<<8)|read_byte(get_SS(),buffer+160);
2693 for(version=15;version>0;version--) {
2694 if((ataversion&(1<<version))!=0)
2695 break;
2696 }
2697
2698 // Read model name
2699 for(i=0;i<20;i++){
2700 write_byte(get_SS(),model+(i*2),read_byte(get_SS(),buffer+(i*2)+54+1));
2701 write_byte(get_SS(),model+(i*2)+1,read_byte(get_SS(),buffer+(i*2)+54));
2702 }
2703
2704 // Reformat
2705 write_byte(get_SS(),model+40,0x00);
2706 for(i=39;i>0;i--){
2707 if(read_byte(get_SS(),model+i)==0x20)
2708 write_byte(get_SS(),model+i,0x00);
2709 else break;
2710 }
2711 break;
2712 }
2713
2714#ifdef VBOX
2715 // we don't want any noisy output for now
2716#else /* !VBOX */
2717 switch (type) {
2718 case ATA_TYPE_ATA:
2719 printf("ata%d %s: ",channel,slave?" slave":"master");
2720 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2721 printf(" ATA-%d Hard-Disk (%lu MBytes)\n", version, sizeinmb);
2722 break;
2723 case ATA_TYPE_ATAPI:
2724 printf("ata%d %s: ",channel,slave?" slave":"master");
2725 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2726 if(read_byte(ebda_seg,&EbdaData->ata.devices[device].device)==ATA_DEVICE_CDROM)
2727 printf(" ATAPI-%d CD-Rom/DVD-Rom\n",version);
2728 else
2729 printf(" ATAPI-%d Device\n",version);
2730 break;
2731 case ATA_TYPE_UNKNOWN:
2732 printf("ata%d %s: Unknown device\n",channel,slave?" slave":"master");
2733 break;
2734 }
2735#endif /* !VBOX */
2736 }
2737 }
2738
2739 // Store the devices counts
2740 write_byte(ebda_seg,&EbdaData->ata.hdcount, hdcount);
2741 write_byte(ebda_seg,&EbdaData->ata.cdcount, cdcount);
2742 write_byte(0x40,0x75, hdcount);
2743
2744#ifdef VBOX
2745 // we don't want any noisy output for now
2746#else /* !VBOX */
2747 printf("\n");
2748#endif /* !VBOX */
2749
2750 // FIXME : should use bios=cmos|auto|disable bits
2751 // FIXME : should know about translation bits
2752 // FIXME : move hard_drive_post here
2753
2754}
2755
2756// ---------------------------------------------------------------------------
2757// ATA/ATAPI driver : software reset
2758// ---------------------------------------------------------------------------
2759// ATA-3
2760// 8.2.1 Software reset - Device 0
2761
2762void ata_reset(device)
2763Bit16u device;
2764{
2765 Bit16u ebda_seg=read_word(0x0040,0x000E);
2766 Bit16u iobase1, iobase2;
2767 Bit8u channel, slave, sn, sc;
2768 Bit16u max;
2769#ifdef VBOX
2770 Bit16u pdelay;
2771#endif /* VBOX */
2772
2773 channel = device / 2;
2774 slave = device % 2;
2775
2776 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2777 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2778
2779 // Reset
2780
2781// 8.2.1 (a) -- set SRST in DC
2782 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN | ATA_CB_DC_SRST);
2783
2784// 8.2.1 (b) -- wait for BSY
2785 max=0xff;
2786 while(--max>0) {
2787 Bit8u status = inb(iobase1+ATA_CB_STAT);
2788 if ((status & ATA_CB_STAT_BSY) != 0) break;
2789 }
2790
2791// 8.2.1 (f) -- clear SRST
2792 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2793
2794 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_NONE) {
2795
2796// 8.2.1 (g) -- check for sc==sn==0x01
2797 // select device
2798 outb(iobase1+ATA_CB_DH, slave?ATA_CB_DH_DEV1:ATA_CB_DH_DEV0);
2799 sc = inb(iobase1+ATA_CB_SC);
2800 sn = inb(iobase1+ATA_CB_SN);
2801
2802 if ( (sc==0x01) && (sn==0x01) ) {
2803
2804// 8.2.1 (h) -- wait for not BSY
2805#ifdef VBOX
2806 max=0xffff; /* The ATA specification says that the drive may be busy for up to 30 seconds. */
2807#else /* !VBOX */
2808 max=0xff;
2809#endif /* !VBOX */
2810 while(--max>0) {
2811 Bit8u status = inb(iobase1+ATA_CB_STAT);
2812 if ((status & ATA_CB_STAT_BSY) == 0) break;
2813#ifdef VBOX
2814 pdelay=0xffff;
2815 while (--pdelay>0) {
2816 /* nothing */
2817 }
2818#endif /* VBOX */
2819 }
2820 }
2821 }
2822
2823// 8.2.1 (i) -- wait for DRDY
2824#ifdef VBOX
2825 max=0x10; /* Speed up for virtual drives. Disks are immediately ready, CDs never */
2826#else /* !VBOX */
2827 max=0xfff;
2828#endif /* !VBOX */
2829 while(--max>0) {
2830 Bit8u status = inb(iobase1+ATA_CB_STAT);
2831 if ((status & ATA_CB_STAT_RDY) != 0) break;
2832 }
2833
2834 // Enable interrupts
2835 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2836}
2837
2838// ---------------------------------------------------------------------------
2839// ATA/ATAPI driver : execute a non data command
2840// ---------------------------------------------------------------------------
2841
2842Bit16u ata_cmd_non_data()
2843{return 0;}
2844
2845// ---------------------------------------------------------------------------
2846// ATA/ATAPI driver : execute a data-in command
2847// ---------------------------------------------------------------------------
2848 // returns
2849 // 0 : no error
2850 // 1 : BUSY bit set
2851 // 2 : read error
2852 // 3 : expected DRQ=1
2853 // 4 : no sectors left to read/verify
2854 // 5 : more sectors to read/verify
2855 // 6 : no sectors left to write
2856 // 7 : more sectors to write
2857Bit16u ata_cmd_data_in(device, command, count, cylinder, head, sector, lba, segment, offset)
2858Bit16u device, command, count, cylinder, head, sector, segment, offset;
2859Bit32u lba;
2860{
2861 Bit16u ebda_seg=read_word(0x0040,0x000E);
2862 Bit16u iobase1, iobase2, blksize;
2863 Bit8u channel, slave;
2864 Bit8u status, current, mode;
2865
2866 channel = device / 2;
2867 slave = device % 2;
2868
2869 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2870 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2871 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2872 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2873 if (mode == ATA_MODE_PIO32) blksize>>=2;
2874 else blksize>>=1;
2875
2876#ifdef VBOX
2877 status = inb(iobase1 + ATA_CB_STAT);
2878 if (status & ATA_CB_STAT_BSY)
2879 {
2880 // Enable interrupts
2881 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2882 return 1;
2883 }
2884#endif /* VBOX */
2885
2886 // sector will be 0 only on lba access. Convert to lba-chs
2887 if (sector == 0) {
2888#ifdef VBOX
2889 if (count >= 256 || lba + count >= 268435456)
2890 {
2891 sector = (lba & 0xff000000L) >> 24;
2892 cylinder = 0; /* The parameter lba is just a 32 bit value. */
2893 outb(iobase1 + ATA_CB_SC, (count & 0xff00) >> 8);
2894 outb(iobase1 + ATA_CB_SN, sector);
2895 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2896 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2897 /* Leave the bottom 24 bits as is, they are treated correctly by the
2898 * LBA28 code path. */
2899 lba &= 0xffffff;
2900 }
2901#endif /* VBOX */
2902 sector = (Bit16u) (lba & 0x000000ffL);
2903 lba >>= 8;
2904 cylinder = (Bit16u) (lba & 0x0000ffffL);
2905 lba >>= 16;
2906 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
2907 }
2908
2909 // Reset count of transferred data
2910 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2911 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2912 current = 0;
2913
2914#ifndef VBOX
2915 status = inb(iobase1 + ATA_CB_STAT);
2916 if (status & ATA_CB_STAT_BSY) return 1;
2917#endif /* !VBOX */
2918
2919 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2920 outb(iobase1 + ATA_CB_FR, 0x00);
2921 outb(iobase1 + ATA_CB_SC, count);
2922 outb(iobase1 + ATA_CB_SN, sector);
2923 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2924 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2925 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
2926 outb(iobase1 + ATA_CB_CMD, command);
2927
2928 while (1) {
2929 status = inb(iobase1 + ATA_CB_STAT);
2930 if ( !(status & ATA_CB_STAT_BSY) ) break;
2931 }
2932
2933 if (status & ATA_CB_STAT_ERR) {
2934 BX_DEBUG_ATA("ata_cmd_data_in : read error\n");
2935#ifdef VBOX
2936 // Enable interrupts
2937 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2938#endif /* VBOX */
2939 return 2;
2940 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2941 BX_DEBUG_ATA("ata_cmd_data_in : DRQ not set (status %02x)\n", (unsigned) status);
2942#ifdef VBOX
2943 // Enable interrupts
2944 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2945#endif /* VBOX */
2946 return 3;
2947 }
2948
2949 // FIXME : move seg/off translation here
2950
2951ASM_START
2952 sti ;; enable higher priority interrupts
2953ASM_END
2954
2955 while (1) {
2956
2957ASM_START
2958 push bp
2959 mov bp, sp
2960 mov di, _ata_cmd_data_in.offset + 2[bp]
2961 mov ax, _ata_cmd_data_in.segment + 2[bp]
2962 mov cx, _ata_cmd_data_in.blksize + 2[bp]
2963
2964 ;; adjust if there will be an overrun. 2K max sector size
2965 cmp di, #0xf800 ;;
2966 jbe ata_in_no_adjust
2967
2968ata_in_adjust:
2969 sub di, #0x0800 ;; sub 2 kbytes from offset
2970 add ax, #0x0080 ;; add 2 Kbytes to segment
2971
2972ata_in_no_adjust:
2973 mov es, ax ;; segment in es
2974
2975 mov dx, _ata_cmd_data_in.iobase1 + 2[bp] ;; ATA data read port
2976
2977 mov ah, _ata_cmd_data_in.mode + 2[bp]
2978 cmp ah, #ATA_MODE_PIO32
2979 je ata_in_32
2980
2981ata_in_16:
2982 rep
2983 insw ;; CX words transfered from port(DX) to ES:[DI]
2984 jmp ata_in_done
2985
2986ata_in_32:
2987 rep
2988 insd ;; CX dwords transfered from port(DX) to ES:[DI]
2989
2990ata_in_done:
2991 mov _ata_cmd_data_in.offset + 2[bp], di
2992 mov _ata_cmd_data_in.segment + 2[bp], es
2993 pop bp
2994ASM_END
2995
2996 current++;
2997 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
2998 count--;
2999#ifdef VBOX
3000 while (1) {
3001 status = inb(iobase1 + ATA_CB_STAT);
3002 if ( !(status & ATA_CB_STAT_BSY) ) break;
3003 }
3004#else /* !VBOX */
3005 status = inb(iobase1 + ATA_CB_STAT);
3006#endif /* !VBOX */
3007 if (count == 0) {
3008 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3009 != ATA_CB_STAT_RDY ) {
3010 BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n", (unsigned) status);
3011#ifdef VBOX
3012 // Enable interrupts
3013 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3014#endif /* VBOX */
3015 return 4;
3016 }
3017 break;
3018 }
3019 else {
3020 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3021 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3022 BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n", (unsigned) status);
3023#ifdef VBOX
3024 // Enable interrupts
3025 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3026#endif /* VBOX */
3027 return 5;
3028 }
3029 continue;
3030 }
3031 }
3032 // Enable interrupts
3033 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3034 return 0;
3035}
3036
3037// ---------------------------------------------------------------------------
3038// ATA/ATAPI driver : execute a data-out command
3039// ---------------------------------------------------------------------------
3040 // returns
3041 // 0 : no error
3042 // 1 : BUSY bit set
3043 // 2 : read error
3044 // 3 : expected DRQ=1
3045 // 4 : no sectors left to read/verify
3046 // 5 : more sectors to read/verify
3047 // 6 : no sectors left to write
3048 // 7 : more sectors to write
3049Bit16u ata_cmd_data_out(device, command, count, cylinder, head, sector, lba, segment, offset)
3050Bit16u device, command, count, cylinder, head, sector, segment, offset;
3051Bit32u lba;
3052{
3053 Bit16u ebda_seg=read_word(0x0040,0x000E);
3054 Bit16u iobase1, iobase2, blksize;
3055 Bit8u channel, slave;
3056 Bit8u status, current, mode;
3057
3058 channel = device / 2;
3059 slave = device % 2;
3060
3061 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
3062 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
3063 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
3064 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
3065 if (mode == ATA_MODE_PIO32) blksize>>=2;
3066 else blksize>>=1;
3067
3068#ifdef VBOX
3069 status = inb(iobase1 + ATA_CB_STAT);
3070 if (status & ATA_CB_STAT_BSY)
3071 {
3072 // Enable interrupts
3073 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3074 return 1;
3075 }
3076#endif /* VBOX */
3077
3078 // sector will be 0 only on lba access. Convert to lba-chs
3079 if (sector == 0) {
3080#ifdef VBOX
3081 if (count >= 256 || lba + count >= 268435456)
3082 {
3083 sector = (lba & 0xff000000L) >> 24;
3084 cylinder = 0; /* The parameter lba is just a 32 bit value. */
3085 outb(iobase1 + ATA_CB_SC, (count & 0xff00) >> 8);
3086 outb(iobase1 + ATA_CB_SN, sector);
3087 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
3088 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
3089 /* Leave the bottom 24 bits as is, they are treated correctly by the
3090 * LBA28 code path. */
3091 lba &= 0xffffff;
3092 }
3093#endif /* VBOX */
3094 sector = (Bit16u) (lba & 0x000000ffL);
3095 lba >>= 8;
3096 cylinder = (Bit16u) (lba & 0x0000ffffL);
3097 lba >>= 16;
3098 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
3099 }
3100
3101 // Reset count of transferred data
3102 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
3103 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
3104 current = 0;
3105
3106#ifndef VBOX
3107 status = inb(iobase1 + ATA_CB_STAT);
3108 if (status & ATA_CB_STAT_BSY) return 1;
3109#endif /* !VBOX */
3110
3111 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
3112 outb(iobase1 + ATA_CB_FR, 0x00);
3113 outb(iobase1 + ATA_CB_SC, count);
3114 outb(iobase1 + ATA_CB_SN, sector);
3115 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
3116 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
3117 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
3118 outb(iobase1 + ATA_CB_CMD, command);
3119
3120 while (1) {
3121 status = inb(iobase1 + ATA_CB_STAT);
3122 if ( !(status & ATA_CB_STAT_BSY) ) break;
3123 }
3124
3125 if (status & ATA_CB_STAT_ERR) {
3126 BX_DEBUG_ATA("ata_cmd_data_out : read error\n");
3127#ifdef VBOX
3128 // Enable interrupts
3129 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3130#endif /* VBOX */
3131 return 2;
3132 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
3133 BX_DEBUG_ATA("ata_cmd_data_out : DRQ not set (status %02x)\n", (unsigned) status);
3134#ifdef VBOX
3135 // Enable interrupts
3136 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3137#endif /* VBOX */
3138 return 3;
3139 }
3140
3141 // FIXME : move seg/off translation here
3142
3143ASM_START
3144 sti ;; enable higher priority interrupts
3145ASM_END
3146
3147 while (1) {
3148
3149ASM_START
3150 push bp
3151 mov bp, sp
3152 mov si, _ata_cmd_data_out.offset + 2[bp]
3153 mov ax, _ata_cmd_data_out.segment + 2[bp]
3154 mov cx, _ata_cmd_data_out.blksize + 2[bp]
3155
3156 ;; adjust if there will be an overrun. 2K max sector size
3157 cmp si, #0xf800 ;;
3158 jbe ata_out_no_adjust
3159
3160ata_out_adjust:
3161 sub si, #0x0800 ;; sub 2 kbytes from offset
3162 add ax, #0x0080 ;; add 2 Kbytes to segment
3163
3164ata_out_no_adjust:
3165 mov es, ax ;; segment in es
3166
3167 mov dx, _ata_cmd_data_out.iobase1 + 2[bp] ;; ATA data write port
3168
3169 mov ah, _ata_cmd_data_out.mode + 2[bp]
3170 cmp ah, #ATA_MODE_PIO32
3171 je ata_out_32
3172
3173ata_out_16:
3174 seg ES
3175 rep
3176 outsw ;; CX words transfered from port(DX) to ES:[SI]
3177 jmp ata_out_done
3178
3179ata_out_32:
3180 seg ES
3181 rep
3182 outsd ;; CX dwords transfered from port(DX) to ES:[SI]
3183
3184ata_out_done:
3185 mov _ata_cmd_data_out.offset + 2[bp], si
3186 mov _ata_cmd_data_out.segment + 2[bp], es
3187 pop bp
3188ASM_END
3189
3190 current++;
3191 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
3192 count--;
3193#ifdef VBOX
3194 while (1) {
3195 status = inb(iobase1 + ATA_CB_STAT);
3196 if ( !(status & ATA_CB_STAT_BSY) ) break;
3197 }
3198#else /* !VBOX */
3199 status = inb(iobase1 + ATA_CB_STAT);
3200#endif /* VBOX */
3201 if (count == 0) {
3202 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3203 != ATA_CB_STAT_RDY ) {
3204 BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n", (unsigned) status);
3205#ifdef VBOX
3206 // Enable interrupts
3207 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3208#endif /* VBOX */
3209 return 6;
3210 }
3211 break;
3212 }
3213 else {
3214 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3215 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3216 BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n", (unsigned) status);
3217#ifdef VBOX
3218 // Enable interrupts
3219 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3220#endif /* VBOX */
3221 return 7;
3222 }
3223 continue;
3224 }
3225 }
3226 // Enable interrupts
3227 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3228 return 0;
3229}
3230
3231// ---------------------------------------------------------------------------
3232// ATA/ATAPI driver : execute a packet command
3233// ---------------------------------------------------------------------------
3234 // returns
3235 // 0 : no error
3236 // 1 : error in parameters
3237 // 2 : BUSY bit set
3238 // 3 : error
3239 // 4 : not ready
3240Bit16u ata_cmd_packet(device, cmdlen, cmdseg, cmdoff, header, length, inout, bufseg, bufoff)
3241Bit8u cmdlen,inout;
3242Bit16u device,cmdseg, cmdoff, bufseg, bufoff;
3243Bit16u header;
3244Bit32u length;
3245{
3246 Bit16u ebda_seg=read_word(0x0040,0x000E);
3247 Bit16u iobase1, iobase2;
3248 Bit16u lcount, lbefore, lafter, count;
3249 Bit8u channel, slave;
3250 Bit8u status, mode, lmode;
3251 Bit32u total, transfer;
3252
3253 channel = device / 2;
3254 slave = device % 2;
3255
3256 // Data out is not supported yet
3257 if (inout == ATA_DATA_OUT) {
3258 BX_INFO("ata_cmd_packet: DATA_OUT not supported yet\n");
3259 return 1;
3260 }
3261
3262 // The header length must be even
3263 if (header & 1) {
3264 BX_DEBUG_ATA("ata_cmd_packet : header must be even (%04x)\n",header);
3265 return 1;
3266 }
3267
3268 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
3269 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
3270 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
3271 transfer= 0L;
3272
3273 if (cmdlen < 12) cmdlen=12;
3274 if (cmdlen > 12) cmdlen=16;
3275 cmdlen>>=1;
3276
3277 // Reset count of transferred data
3278 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
3279 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
3280
3281 status = inb(iobase1 + ATA_CB_STAT);
3282 if (status & ATA_CB_STAT_BSY) return 2;
3283
3284 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
3285 // outb(iobase1 + ATA_CB_FR, 0x00);
3286 // outb(iobase1 + ATA_CB_SC, 0x00);
3287 // outb(iobase1 + ATA_CB_SN, 0x00);
3288 outb(iobase1 + ATA_CB_CL, 0xfff0 & 0x00ff);
3289 outb(iobase1 + ATA_CB_CH, 0xfff0 >> 8);
3290 outb(iobase1 + ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
3291 outb(iobase1 + ATA_CB_CMD, ATA_CMD_PACKET);
3292
3293 // Device should ok to receive command
3294 while (1) {
3295 status = inb(iobase1 + ATA_CB_STAT);
3296 if ( !(status & ATA_CB_STAT_BSY) ) break;
3297 }
3298
3299 if (status & ATA_CB_STAT_ERR) {
3300 BX_DEBUG_ATA("ata_cmd_packet : error, status is %02x\n",status);
3301#ifdef VBOX
3302 // Enable interrupts
3303 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3304#endif /* VBOX */
3305 return 3;
3306 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
3307 BX_DEBUG_ATA("ata_cmd_packet : DRQ not set (status %02x)\n", (unsigned) status);
3308#ifdef VBOX
3309 // Enable interrupts
3310 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3311#endif /* VBOX */
3312 return 4;
3313 }
3314
3315 // Normalize address
3316 cmdseg += (cmdoff / 16);
3317 cmdoff %= 16;
3318
3319 // Send command to device
3320ASM_START
3321 sti ;; enable higher priority interrupts
3322
3323 push bp
3324 mov bp, sp
3325
3326 mov si, _ata_cmd_packet.cmdoff + 2[bp]
3327 mov ax, _ata_cmd_packet.cmdseg + 2[bp]
3328 mov cx, _ata_cmd_packet.cmdlen + 2[bp]
3329 mov es, ax ;; segment in es
3330
3331 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data write port
3332
3333 seg ES
3334 rep
3335 outsw ;; CX words transfered from port(DX) to ES:[SI]
3336
3337 pop bp
3338ASM_END
3339
3340 if (inout == ATA_DATA_NO) {
3341 status = inb(iobase1 + ATA_CB_STAT);
3342 }
3343 else {
3344 while (1) {
3345
3346#ifdef VBOX
3347 while (1) {
3348 status = inb(iobase1 + ATA_CB_STAT);
3349 if ( !(status & ATA_CB_STAT_BSY) ) break;
3350 }
3351#else /* VBOX */
3352 status = inb(iobase1 + ATA_CB_STAT);
3353#endif /* VBOX */
3354
3355 // Check if command completed
3356 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_DRQ) ) ==0 ) break;
3357
3358 if (status & ATA_CB_STAT_ERR) {
3359 BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status);
3360#ifdef VBOX
3361 // Enable interrupts
3362 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3363#endif /* VBOX */
3364 return 3;
3365 }
3366
3367 // Device must be ready to send data
3368 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3369 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3370 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", status);
3371#ifdef VBOX
3372 // Enable interrupts
3373 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3374#endif /* VBOX */
3375 return 4;
3376 }
3377
3378 // Normalize address
3379 bufseg += (bufoff / 16);
3380 bufoff %= 16;
3381
3382 // Get the byte count
3383 lcount = ((Bit16u)(inb(iobase1 + ATA_CB_CH))<<8)+inb(iobase1 + ATA_CB_CL);
3384
3385 // adjust to read what we want
3386 if(header>lcount) {
3387 lbefore=lcount;
3388 header-=lcount;
3389 lcount=0;
3390 }
3391 else {
3392 lbefore=header;
3393 header=0;
3394 lcount-=lbefore;
3395 }
3396
3397 if(lcount>length) {
3398 lafter=lcount-length;
3399 lcount=length;
3400 length=0;
3401 }
3402 else {
3403 lafter=0;
3404 length-=lcount;
3405 }
3406
3407 // Save byte count
3408 count = lcount;
3409
3410 BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore+lcount+lafter,lbefore,lcount,lafter);
3411 BX_DEBUG_ATA("to 0x%04x:0x%04x\n",bufseg,bufoff);
3412
3413 // If counts not dividable by 4, use 16bits mode
3414 lmode = mode;
3415 if (lbefore & 0x03) lmode=ATA_MODE_PIO16;
3416 if (lcount & 0x03) lmode=ATA_MODE_PIO16;
3417 if (lafter & 0x03) lmode=ATA_MODE_PIO16;
3418
3419 // adds an extra byte if count are odd. before is always even
3420 if (lcount & 0x01) {
3421 lcount+=1;
3422 if ((lafter > 0) && (lafter & 0x01)) {
3423 lafter-=1;
3424 }
3425 }
3426
3427 if (lmode == ATA_MODE_PIO32) {
3428 lcount>>=2; lbefore>>=2; lafter>>=2;
3429 }
3430 else {
3431 lcount>>=1; lbefore>>=1; lafter>>=1;
3432 }
3433
3434 ; // FIXME bcc bug
3435
3436ASM_START
3437 push bp
3438 mov bp, sp
3439
3440 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data read port
3441
3442 mov cx, _ata_cmd_packet.lbefore + 2[bp]
3443 jcxz ata_packet_no_before
3444
3445 mov ah, _ata_cmd_packet.lmode + 2[bp]
3446 cmp ah, #ATA_MODE_PIO32
3447 je ata_packet_in_before_32
3448
3449ata_packet_in_before_16:
3450 in ax, dx
3451 loop ata_packet_in_before_16
3452 jmp ata_packet_no_before
3453
3454ata_packet_in_before_32:
3455 push eax
3456ata_packet_in_before_32_loop:
3457 in eax, dx
3458 loop ata_packet_in_before_32_loop
3459 pop eax
3460
3461ata_packet_no_before:
3462 mov cx, _ata_cmd_packet.lcount + 2[bp]
3463 jcxz ata_packet_after
3464
3465 mov di, _ata_cmd_packet.bufoff + 2[bp]
3466 mov ax, _ata_cmd_packet.bufseg + 2[bp]
3467 mov es, ax
3468
3469 mov ah, _ata_cmd_packet.lmode + 2[bp]
3470 cmp ah, #ATA_MODE_PIO32
3471 je ata_packet_in_32
3472
3473ata_packet_in_16:
3474 rep
3475 insw ;; CX words transfered tp port(DX) to ES:[DI]
3476 jmp ata_packet_after
3477
3478ata_packet_in_32:
3479 rep
3480 insd ;; CX dwords transfered to port(DX) to ES:[DI]
3481
3482ata_packet_after:
3483 mov cx, _ata_cmd_packet.lafter + 2[bp]
3484 jcxz ata_packet_done
3485
3486 mov ah, _ata_cmd_packet.lmode + 2[bp]
3487 cmp ah, #ATA_MODE_PIO32
3488 je ata_packet_in_after_32
3489
3490ata_packet_in_after_16:
3491 in ax, dx
3492 loop ata_packet_in_after_16
3493 jmp ata_packet_done
3494
3495ata_packet_in_after_32:
3496 push eax
3497ata_packet_in_after_32_loop:
3498 in eax, dx
3499 loop ata_packet_in_after_32_loop
3500 pop eax
3501
3502ata_packet_done:
3503 pop bp
3504ASM_END
3505
3506 // Compute new buffer address
3507 bufoff += count;
3508
3509 // Save transferred bytes count
3510 transfer += count;
3511 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,transfer);
3512 }
3513 }
3514
3515 // Final check, device must be ready
3516 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3517 != ATA_CB_STAT_RDY ) {
3518 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", (unsigned) status);
3519#ifdef VBOX
3520 // Enable interrupts
3521 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3522#endif /* VBOX */
3523 return 4;
3524 }
3525
3526 // Enable interrupts
3527 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3528 return 0;
3529}
3530
3531// ---------------------------------------------------------------------------
3532// End of ATA/ATAPI Driver
3533// ---------------------------------------------------------------------------
3534
3535// ---------------------------------------------------------------------------
3536// Start of ATA/ATAPI generic functions
3537// ---------------------------------------------------------------------------
3538
3539 Bit16u
3540atapi_get_sense(device)
3541 Bit16u device;
3542{
3543 Bit8u atacmd[12];
3544 Bit8u buffer[16];
3545 Bit8u i;
3546
3547 memsetb(get_SS(),atacmd,0,12);
3548
3549 // Request SENSE
3550 atacmd[0]=0x03;
3551 atacmd[4]=0x20;
3552 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 16L, ATA_DATA_IN, get_SS(), buffer) != 0)
3553 return 0x0002;
3554
3555 if ((buffer[0] & 0x7e) == 0x70) {
3556 return (((Bit16u)buffer[2]&0x0f)*0x100)+buffer[12];
3557 }
3558
3559 return 0;
3560}
3561
3562 Bit16u
3563atapi_is_ready(device)
3564 Bit16u device;
3565{
3566 Bit8u atacmd[12];
3567 Bit8u buffer[];
3568
3569 memsetb(get_SS(),atacmd,0,12);
3570
3571 // Test Unit Ready
3572 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3573 return 0x000f;
3574
3575 if (atapi_get_sense(device) !=0 ) {
3576 memsetb(get_SS(),atacmd,0,12);
3577
3578 // try to send Test Unit Ready again
3579 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3580 return 0x000f;
3581
3582 return atapi_get_sense(device);
3583 }
3584 return 0;
3585}
3586
3587 Bit16u
3588atapi_is_cdrom(device)
3589 Bit8u device;
3590{
3591 Bit16u ebda_seg=read_word(0x0040,0x000E);
3592
3593 if (device >= BX_MAX_ATA_DEVICES)
3594 return 0;
3595
3596 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_ATAPI)
3597 return 0;
3598
3599 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].device) != ATA_DEVICE_CDROM)
3600 return 0;
3601
3602 return 1;
3603}
3604
3605// ---------------------------------------------------------------------------
3606// End of ATA/ATAPI generic functions
3607// ---------------------------------------------------------------------------
3608
3609#endif // BX_USE_ATADRV
3610
3611#if BX_ELTORITO_BOOT
3612
3613// ---------------------------------------------------------------------------
3614// Start of El-Torito boot functions
3615// ---------------------------------------------------------------------------
3616
3617 void
3618cdemu_init()
3619{
3620 Bit16u ebda_seg=read_word(0x0040,0x000E);
3621
3622 // the only important data is this one for now
3623 write_byte(ebda_seg,&EbdaData->cdemu.active,0x00);
3624}
3625
3626 Bit8u
3627cdemu_isactive()
3628{
3629 Bit16u ebda_seg=read_word(0x0040,0x000E);
3630
3631 return(read_byte(ebda_seg,&EbdaData->cdemu.active));
3632}
3633
3634 Bit8u
3635cdemu_emulated_drive()
3636{
3637 Bit16u ebda_seg=read_word(0x0040,0x000E);
3638
3639 return(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
3640}
3641
3642static char isotag[6]="CD001";
3643static char eltorito[24]="EL TORITO SPECIFICATION";
3644//
3645// Returns ah: emulated drive, al: error code
3646//
3647 Bit16u
3648cdrom_boot()
3649{
3650 Bit16u ebda_seg=read_word(0x0040,0x000E);
3651 Bit8u atacmd[12], buffer[2048];
3652 Bit32u lba;
3653 Bit16u boot_segment, nbsectors, i, error;
3654 Bit8u device;
3655#ifdef VBOX
3656 Bit8u read_try;
3657#endif /* VBOX */
3658
3659 // Find out the first cdrom
3660 for (device=0; device<BX_MAX_ATA_DEVICES;device++) {
3661 if (atapi_is_cdrom(device)) break;
3662 }
3663
3664 // if not found
3665 if(device >= BX_MAX_ATA_DEVICES) return 2;
3666
3667 // Read the Boot Record Volume Descriptor
3668 memsetb(get_SS(),atacmd,0,12);
3669 atacmd[0]=0x28; // READ command
3670 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3671 atacmd[8]=(0x01 & 0x00ff); // Sectors
3672 atacmd[2]=(0x11 & 0xff000000) >> 24; // LBA
3673 atacmd[3]=(0x11 & 0x00ff0000) >> 16;
3674 atacmd[4]=(0x11 & 0x0000ff00) >> 8;
3675 atacmd[5]=(0x11 & 0x000000ff);
3676#ifdef VBOX
3677 for (read_try = 0; read_try <= 4; read_try++)
3678 {
3679 error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer);
3680 if (!error)
3681 break;
3682 }
3683 if (error)
3684 return 3;
3685#else /* !VBOX */
3686 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3687 return 3;
3688#endif /* !VBOX */
3689
3690 // Validity checks
3691 if(buffer[0]!=0)return 4;
3692 for(i=0;i<5;i++){
3693 if(buffer[1+i]!=read_byte(0xf000,&isotag[i]))return 5;
3694 }
3695 for(i=0;i<23;i++)
3696 if(buffer[7+i]!=read_byte(0xf000,&eltorito[i]))return 6;
3697
3698 // ok, now we calculate the Boot catalog address
3699 lba=buffer[0x4A]*0x1000000+buffer[0x49]*0x10000+buffer[0x48]*0x100+buffer[0x47];
3700
3701 // And we read the Boot Catalog
3702 memsetb(get_SS(),atacmd,0,12);
3703 atacmd[0]=0x28; // READ command
3704 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3705 atacmd[8]=(0x01 & 0x00ff); // Sectors
3706 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3707 atacmd[3]=(lba & 0x00ff0000) >> 16;
3708 atacmd[4]=(lba & 0x0000ff00) >> 8;
3709 atacmd[5]=(lba & 0x000000ff);
3710 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3711 return 7;
3712
3713 // Validation entry
3714 if(buffer[0x00]!=0x01)return 8; // Header
3715 if(buffer[0x01]!=0x00)return 9; // Platform
3716 if(buffer[0x1E]!=0x55)return 10; // key 1
3717 if(buffer[0x1F]!=0xAA)return 10; // key 2
3718
3719 // Initial/Default Entry
3720 if(buffer[0x20]!=0x88)return 11; // Bootable
3721
3722 write_byte(ebda_seg,&EbdaData->cdemu.media,buffer[0x21]);
3723 if(buffer[0x21]==0){
3724 // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
3725 // Win2000 cd boot needs to know it booted from cd
3726 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0xE0);
3727 }
3728 else if(buffer[0x21]<4)
3729 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x00);
3730 else
3731 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x80);
3732
3733 write_byte(ebda_seg,&EbdaData->cdemu.controller_index,device/2);
3734 write_byte(ebda_seg,&EbdaData->cdemu.device_spec,device%2);
3735
3736 boot_segment=buffer[0x23]*0x100+buffer[0x22];
3737 if(boot_segment==0x0000)boot_segment=0x07C0;
3738
3739 write_word(ebda_seg,&EbdaData->cdemu.load_segment,boot_segment);
3740 write_word(ebda_seg,&EbdaData->cdemu.buffer_segment,0x0000);
3741
3742 nbsectors=buffer[0x27]*0x100+buffer[0x26];
3743 write_word(ebda_seg,&EbdaData->cdemu.sector_count,nbsectors);
3744
3745 lba=buffer[0x2B]*0x1000000+buffer[0x2A]*0x10000+buffer[0x29]*0x100+buffer[0x28];
3746 write_dword(ebda_seg,&EbdaData->cdemu.ilba,lba);
3747
3748 // And we read the image in memory
3749 memsetb(get_SS(),atacmd,0,12);
3750 atacmd[0]=0x28; // READ command
3751 atacmd[7]=((1+(nbsectors-1)/4) & 0xff00) >> 8; // Sectors
3752 atacmd[8]=((1+(nbsectors-1)/4) & 0x00ff); // Sectors
3753 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3754 atacmd[3]=(lba & 0x00ff0000) >> 16;
3755 atacmd[4]=(lba & 0x0000ff00) >> 8;
3756 atacmd[5]=(lba & 0x000000ff);
3757 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, nbsectors*512L, ATA_DATA_IN, boot_segment,0)) != 0)
3758 return 12;
3759
3760 // Remember the media type
3761 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
3762 case 0x01: // 1.2M floppy
3763 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,15);
3764 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3765 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3766 break;
3767 case 0x02: // 1.44M floppy
3768 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,18);
3769 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3770 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3771 break;
3772 case 0x03: // 2.88M floppy
3773 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,36);
3774 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3775 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3776 break;
3777 case 0x04: // Harddrive
3778 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,read_byte(boot_segment,446+6)&0x3f);
3779 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,
3780 (read_byte(boot_segment,446+6)<<2) + read_byte(boot_segment,446+7) + 1);
3781 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,read_byte(boot_segment,446+5) + 1);
3782 break;
3783 }
3784
3785 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0) {
3786 // Increase bios installed hardware number of devices
3787 if(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)==0x00)
3788 write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
3789 else
3790 write_byte(ebda_seg, &EbdaData->ata.hdcount, read_byte(ebda_seg, &EbdaData->ata.hdcount) + 1);
3791 }
3792
3793
3794 // everything is ok, so from now on, the emulation is active
3795 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0)
3796 write_byte(ebda_seg,&EbdaData->cdemu.active,0x01);
3797
3798 // return the boot drive + no error
3799 return (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)*0x100)+0;
3800}
3801
3802// ---------------------------------------------------------------------------
3803// End of El-Torito boot functions
3804// ---------------------------------------------------------------------------
3805#endif // BX_ELTORITO_BOOT
3806
3807#ifdef VBOX_WITH_SCSI
3808# include "scsi.c"
3809#endif
3810
3811 void
3812int14_function(regs, ds, iret_addr)
3813 pusha_regs_t regs; // regs pushed from PUSHA instruction
3814 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
3815 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
3816{
3817 Bit16u addr,timer,val16;
3818 Bit8u timeout;
3819
3820 ASM_START
3821 sti
3822 ASM_END
3823
3824 addr = read_word(0x0040, (regs.u.r16.dx << 1));
3825 timeout = read_byte(0x0040, 0x007C + regs.u.r16.dx);
3826 if ((regs.u.r16.dx < 4) && (addr > 0)) {
3827 switch (regs.u.r8.ah) {
3828 case 0:
3829 outb(addr+3, inb(addr+3) | 0x80);
3830 if (regs.u.r8.al & 0xE0 == 0) {
3831 outb(addr, 0x17);
3832 outb(addr+1, 0x04);
3833 } else {
3834 val16 = 0x600 >> ((regs.u.r8.al & 0xE0) >> 5);
3835 outb(addr, val16 & 0xFF);
3836 outb(addr+1, val16 >> 8);
3837 }
3838 outb(addr+3, regs.u.r8.al & 0x1F);
3839 regs.u.r8.ah = inb(addr+5);
3840 regs.u.r8.al = inb(addr+6);
3841 ClearCF(iret_addr.flags);
3842 break;
3843 case 1:
3844 timer = read_word(0x0040, 0x006C);
3845 while (((inb(addr+5) & 0x60) != 0x60) && (timeout)) {
3846 val16 = read_word(0x0040, 0x006C);
3847 if (val16 != timer) {
3848 timer = val16;
3849 timeout--;
3850 }
3851 }
3852 if (timeout) outb(addr, regs.u.r8.al);
3853 regs.u.r8.ah = inb(addr+5);
3854 if (!timeout) regs.u.r8.ah |= 0x80;
3855 ClearCF(iret_addr.flags);
3856 break;
3857 case 2:
3858 timer = read_word(0x0040, 0x006C);
3859 while (((inb(addr+5) & 0x01) == 0) && (timeout)) {
3860 val16 = read_word(0x0040, 0x006C);
3861 if (val16 != timer) {
3862 timer = val16;
3863 timeout--;
3864 }
3865 }
3866 if (timeout) {
3867 regs.u.r8.ah = 0;
3868 regs.u.r8.al = inb(addr);
3869 } else {
3870 regs.u.r8.ah = inb(addr+5);
3871 }
3872 ClearCF(iret_addr.flags);
3873 break;
3874 case 3:
3875 regs.u.r8.ah = inb(addr+5);
3876 regs.u.r8.al = inb(addr+6);
3877 ClearCF(iret_addr.flags);
3878 break;
3879 default:
3880 SetCF(iret_addr.flags); // Unsupported
3881 }
3882 } else {
3883 SetCF(iret_addr.flags); // Unsupported
3884 }
3885}
3886
3887 void
3888int15_function(regs, ES, DS, FLAGS)
3889 pusha_regs_t regs; // REGS pushed via pusha
3890 Bit16u ES, DS, FLAGS;
3891{
3892 Bit16u ebda_seg=read_word(0x0040,0x000E);
3893 bx_bool prev_a20_enable;
3894 Bit16u base15_00;
3895 Bit8u base23_16;
3896 Bit16u ss;
3897 Bit16u BX,CX,DX;
3898
3899 Bit16u bRegister;
3900 Bit8u irqDisable;
3901
3902BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
3903
3904 switch (regs.u.r8.ah) {
3905#ifdef VBOX
3906 case 0x00: /* assorted functions */
3907 if (regs.u.r8.al != 0xc0)
3908 goto undecoded;
3909 /* GRUB calls int15 with ax=0x00c0 to get the ROM configuration table,
3910 * which we don't support, but logging that event is annoying. In fact
3911 * it is likely that they just misread some specs, because there is a
3912 * int15 BIOS function AH=0xc0 which sounds quite similar to what GRUB
3913 * wants to achieve. */
3914 SET_CF();
3915 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3916 break;
3917#endif
3918 case 0x24: /* A20 Control */
3919 switch (regs.u.r8.al) {
3920 case 0x00:
3921 set_enable_a20(0);
3922 CLEAR_CF();
3923 regs.u.r8.ah = 0;
3924 break;
3925 case 0x01:
3926 set_enable_a20(1);
3927 CLEAR_CF();
3928 regs.u.r8.ah = 0;
3929 break;
3930 case 0x02:
3931 regs.u.r8.al = (inb(0x92) >> 1) & 0x01;
3932 CLEAR_CF();
3933 regs.u.r8.ah = 0;
3934 break;
3935 case 0x03:
3936 CLEAR_CF();
3937 regs.u.r8.ah = 0;
3938 regs.u.r16.bx = 3;
3939 break;
3940 default:
3941 BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs.u.r8.al);
3942 SET_CF();
3943 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3944 }
3945 break;
3946
3947 case 0x41:
3948 SET_CF();
3949 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3950 break;
3951
3952 case 0x4f:
3953 /* keyboard intercept */
3954#if BX_CPU < 2
3955 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3956#else
3957 // nop
3958#endif
3959 SET_CF();
3960 break;
3961
3962 case 0x52: // removable media eject
3963 CLEAR_CF();
3964 regs.u.r8.ah = 0; // "ok ejection may proceed"
3965 break;
3966
3967 case 0x83: {
3968 if( regs.u.r8.al == 0 ) {
3969 // Set Interval requested.
3970 if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
3971 // Interval not already set.
3972 write_byte( 0x40, 0xA0, 1 ); // Set status byte.
3973 write_word( 0x40, 0x98, ES ); // Byte location, segment
3974 write_word( 0x40, 0x9A, regs.u.r16.bx ); // Byte location, offset
3975 write_word( 0x40, 0x9C, regs.u.r16.dx ); // Low word, delay
3976 write_word( 0x40, 0x9E, regs.u.r16.cx ); // High word, delay.
3977 CLEAR_CF( );
3978 irqDisable = inb( 0xA1 );
3979 outb( 0xA1, irqDisable & 0xFE );
3980 bRegister = inb_cmos( 0xB ); // Unmask IRQ8 so INT70 will get through.
3981 outb_cmos( 0xB, bRegister | 0x40 ); // Turn on the Periodic Interrupt timer
3982 } else {
3983 // Interval already set.
3984 BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
3985 SET_CF();
3986 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3987 }
3988 } else if( regs.u.r8.al == 1 ) {
3989 // Clear Interval requested
3990 write_byte( 0x40, 0xA0, 0 ); // Clear status byte
3991 CLEAR_CF( );
3992 bRegister = inb_cmos( 0xB );
3993 outb_cmos( 0xB, bRegister & ~0x40 ); // Turn off the Periodic Interrupt timer
3994 } else {
3995 BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
3996 SET_CF();
3997 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3998 regs.u.r8.al--;
3999 }
4000
4001 break;
4002 }
4003
4004 case 0x87:
4005#if BX_CPU < 3
4006# error "Int15 function 87h not supported on < 80386"
4007#endif
4008 // +++ should probably have descriptor checks
4009 // +++ should have exception handlers
4010
4011 // turn off interrupts
4012ASM_START
4013 cli
4014ASM_END
4015
4016 prev_a20_enable = set_enable_a20(1); // enable A20 line
4017
4018 // 128K max of transfer on 386+ ???
4019 // source == destination ???
4020
4021 // ES:SI points to descriptor table
4022 // offset use initially comments
4023 // ==============================================
4024 // 00..07 Unused zeros Null descriptor
4025 // 08..0f GDT zeros filled in by BIOS
4026 // 10..17 source ssssssss source of data
4027 // 18..1f dest dddddddd destination of data
4028 // 20..27 CS zeros filled in by BIOS
4029 // 28..2f SS zeros filled in by BIOS
4030
4031 //es:si
4032 //eeee0
4033 //0ssss
4034 //-----
4035
4036// check for access rights of source & dest here
4037
4038 // Initialize GDT descriptor
4039 base15_00 = (ES << 4) + regs.u.r16.si;
4040 base23_16 = ES >> 12;
4041 if (base15_00 < (ES<<4))
4042 base23_16++;
4043 write_word(ES, regs.u.r16.si+0x08+0, 47); // limit 15:00 = 6 * 8bytes/descriptor
4044 write_word(ES, regs.u.r16.si+0x08+2, base15_00);// base 15:00
4045 write_byte(ES, regs.u.r16.si+0x08+4, base23_16);// base 23:16
4046 write_byte(ES, regs.u.r16.si+0x08+5, 0x93); // access
4047 write_word(ES, regs.u.r16.si+0x08+6, 0x0000); // base 31:24/reserved/limit 19:16
4048
4049 // Initialize CS descriptor
4050 write_word(ES, regs.u.r16.si+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
4051 write_word(ES, regs.u.r16.si+0x20+2, 0x0000);// base 15:00
4052 write_byte(ES, regs.u.r16.si+0x20+4, 0x000f);// base 23:16
4053 write_byte(ES, regs.u.r16.si+0x20+5, 0x9b); // access
4054 write_word(ES, regs.u.r16.si+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
4055
4056 // Initialize SS descriptor
4057 ss = get_SS();
4058 base15_00 = ss << 4;
4059 base23_16 = ss >> 12;
4060 write_word(ES, regs.u.r16.si+0x28+0, 0xffff); // limit 15:00 = normal 64K limit
4061 write_word(ES, regs.u.r16.si+0x28+2, base15_00);// base 15:00
4062 write_byte(ES, regs.u.r16.si+0x28+4, base23_16);// base 23:16
4063 write_byte(ES, regs.u.r16.si+0x28+5, 0x93); // access
4064 write_word(ES, regs.u.r16.si+0x28+6, 0x0000); // base 31:24/reserved/limit 19:16
4065
4066 CX = regs.u.r16.cx;
4067ASM_START
4068 // Compile generates locals offset info relative to SP.
4069 // Get CX (word count) from stack.
4070 mov bx, sp
4071 SEG SS
4072 mov cx, _int15_function.CX [bx]
4073
4074 // since we need to set SS:SP, save them to the BDA
4075 // for future restore
4076 push eax
4077 xor eax, eax
4078 mov ds, ax
4079 mov 0x0469, ss
4080 mov 0x0467, sp
4081
4082 SEG ES
4083 lgdt [si + 0x08]
4084 SEG CS
4085 lidt [pmode_IDT_info]
4086 ;; perhaps do something with IDT here
4087
4088 ;; set PE bit in CR0
4089 mov eax, cr0
4090 or al, #0x01
4091 mov cr0, eax
4092 ;; far jump to flush CPU queue after transition to protected mode
4093 JMP_AP(0x0020, protected_mode)
4094
4095protected_mode:
4096 ;; GDT points to valid descriptor table, now load SS, DS, ES
4097 mov ax, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
4098 mov ss, ax
4099 mov ax, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
4100 mov ds, ax
4101 mov ax, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
4102 mov es, ax
4103 xor si, si
4104 xor di, di
4105 cld
4106 rep
4107 movsw ;; move CX words from DS:SI to ES:DI
4108
4109 ;; make sure DS and ES limits are 64KB
4110 mov ax, #0x28
4111 mov ds, ax
4112 mov es, ax
4113
4114 ;; reset PG bit in CR0 ???
4115 mov eax, cr0
4116 and al, #0xFE
4117 mov cr0, eax
4118
4119 ;; far jump to flush CPU queue after transition to real mode
4120 JMP_AP(0xf000, real_mode)
4121
4122real_mode:
4123 ;; restore IDT to normal real-mode defaults
4124 SEG CS
4125 lidt [rmode_IDT_info]
4126
4127 // restore SS:SP from the BDA
4128 xor ax, ax
4129 mov ds, ax
4130 mov ss, 0x0469
4131 mov sp, 0x0467
4132 pop eax
4133ASM_END
4134
4135 set_enable_a20(prev_a20_enable);
4136
4137 // turn back on interrupts
4138ASM_START
4139 sti
4140ASM_END
4141
4142 regs.u.r8.ah = 0;
4143 CLEAR_CF();
4144 break;
4145
4146
4147 case 0x88:
4148 // Get the amount of extended memory (above 1M)
4149#if BX_CPU < 2
4150 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4151 SET_CF();
4152#else
4153 regs.u.r8.al = inb_cmos(0x30);
4154 regs.u.r8.ah = inb_cmos(0x31);
4155
4156 // According to Ralf Brown's interrupt the limit should be 15M,
4157 // but real machines mostly return max. 63M.
4158 if(regs.u.r16.ax > 0xffc0)
4159 regs.u.r16.ax = 0xffc0;
4160
4161 CLEAR_CF();
4162#endif
4163 break;
4164
4165#ifdef VBOX
4166 case 0x89:
4167 // Switch to Protected Mode.
4168 // ES:DI points to user-supplied GDT
4169 // BH/BL contains starting interrupt numbers for PIC0/PIC1
4170 // This subfunction does not return!
4171
4172// turn off interrupts
4173ASM_START
4174 cli
4175ASM_END
4176
4177 set_enable_a20(1); // enable A20 line; we're supposed to fail if that fails
4178
4179 // Initialize CS descriptor for BIOS
4180 write_word(ES, regs.u.r16.si+0x38+0, 0xffff);// limit 15:00 = normal 64K limit
4181 write_word(ES, regs.u.r16.si+0x38+2, 0x0000);// base 15:00
4182 write_byte(ES, regs.u.r16.si+0x38+4, 0x000f);// base 23:16 (hardcoded to f000:0000)
4183 write_byte(ES, regs.u.r16.si+0x38+5, 0x9b); // access
4184 write_word(ES, regs.u.r16.si+0x38+6, 0x0000);// base 31:24/reserved/limit 19:16
4185
4186 BX = regs.u.r16.bx;
4187ASM_START
4188 // Compiler generates locals offset info relative to SP.
4189 // Get BX (PIC offsets) from stack.
4190 mov bx, sp
4191 SEG SS
4192 mov bx, _int15_function.BX [bx]
4193
4194 // Program PICs
4195 mov al, #0x11 ; send initialisation commands
4196 out 0x20, al
4197 out 0xa0, al
4198 mov al, bh
4199 out 0x21, al
4200 mov al, bl
4201 out 0xa1, al
4202 mov al, #0x04
4203 out 0x21, al
4204 mov al, #0x02
4205 out 0xa1, al
4206 mov al, #0x01
4207 out 0x21, al
4208 out 0xa1, al
4209 mov al, #0xff ; mask all IRQs, user must re-enable
4210 out 0x21, al
4211 out 0xa1, al
4212
4213 // Load GDT and IDT from supplied data
4214 SEG ES
4215 lgdt [si + 0x08]
4216 SEG ES
4217 lidt [si + 0x10]
4218
4219 // set PE bit in CR0
4220 mov eax, cr0
4221 or al, #0x01
4222 mov cr0, eax
4223 // far jump to flush CPU queue after transition to protected mode
4224 JMP_AP(0x0038, protmode_switch)
4225
4226protmode_switch:
4227 ;; GDT points to valid descriptor table, now load SS, DS, ES
4228 mov ax, #0x28
4229 mov ss, ax
4230 mov ax, #0x18
4231 mov ds, ax
4232 mov ax, #0x20
4233 mov es, ax
4234
4235 // unwind the stack - this will break if calling sequence changes!
4236 mov sp,bp
4237 add sp,#4 ; skip return address
4238 popa ; restore regs
4239 pop ax ; skip saved es
4240 pop ax ; skip saved ds
4241 pop ax ; skip saved flags
4242
4243 // return to caller - note that we do not use IRET because
4244 // we cannot enable interrupts
4245 pop cx ; get return offset
4246 pop ax ; skip return segment
4247 pop ax ; skip flags
4248 mov ax, #0x30 ; ah must be 0 on successful exit
4249 push ax
4250 push cx ; re-create modified ret address on stack
4251 retf
4252
4253ASM_END
4254
4255 break;
4256#endif /* VBOX */
4257
4258 case 0x90:
4259 /* Device busy interrupt. Called by Int 16h when no key available */
4260 break;
4261
4262 case 0x91:
4263 /* Interrupt complete. Called by Int 16h when key becomes available */
4264 break;
4265
4266 case 0xbf:
4267 BX_INFO("*** int 15h function AH=bf not yet supported!\n");
4268 SET_CF();
4269 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4270 break;
4271
4272 case 0xC0:
4273#if 0
4274 SET_CF();
4275 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4276 break;
4277#endif
4278 CLEAR_CF();
4279 regs.u.r8.ah = 0;
4280 regs.u.r16.bx = BIOS_CONFIG_TABLE;
4281 ES = 0xF000;
4282 break;
4283
4284 case 0xc1:
4285 ES = ebda_seg;
4286 CLEAR_CF();
4287 break;
4288
4289 case 0xd8:
4290 bios_printf(BIOS_PRINTF_DEBUG, "EISA BIOS not present\n");
4291 SET_CF();
4292 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4293 break;
4294
4295#ifdef VBOX
4296 /* Make the BIOS warning for pretty much every Linux kernel start
4297 * disappear - it calls with ax=0xe980 to figure out SMI info. */
4298 case 0xe9: /* SMI functions (SpeedStep and similar things) */
4299 SET_CF();
4300 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4301 break;
4302undecoded:
4303#endif /* VBOX */
4304 default:
4305 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4306 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4307 SET_CF();
4308 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4309 break;
4310 }
4311}
4312
4313#if BX_USE_PS2_MOUSE
4314 void
4315int15_function_mouse(regs, ES, DS, FLAGS)
4316 pusha_regs_t regs; // REGS pushed via pusha
4317 Bit16u ES, DS, FLAGS;
4318{
4319 Bit16u ebda_seg=read_word(0x0040,0x000E);
4320 Bit8u mouse_flags_1, mouse_flags_2;
4321 Bit16u mouse_driver_seg;
4322 Bit16u mouse_driver_offset;
4323 Bit8u mouse_cmd;
4324 Bit8u ret, mouse_data1, mouse_data2, mouse_data3;
4325
4326BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4327
4328 switch (regs.u.r8.ah) {
4329 case 0xC2:
4330 // Return Codes status in AH
4331 // =========================
4332 // 00: success
4333 // 01: invalid subfunction (AL > 7)
4334 // 02: invalid input value (out of allowable range)
4335 // 03: interface error
4336 // 04: resend command received from mouse controller,
4337 // device driver should attempt command again
4338 // 05: cannot enable mouse, since no far call has been installed
4339 // 80/86: mouse service not implemented
4340
4341 if (regs.u.r8.al > 7) {
4342BX_DEBUG_INT15("unsupported subfn\n");
4343 // invalid function
4344 SET_CF();
4345 regs.u.r8.ah = 1;
4346 break;
4347 }
4348
4349 // Valid subfn; disable AUX input and IRQ12, assume no error
4350 set_kbd_command_byte(0x65);
4351 CLEAR_CF();
4352 regs.u.r8.ah = 0;
4353
4354 switch (regs.u.r8.al) {
4355 case 0: // Disable/Enable Mouse
4356BX_DEBUG_INT15("case 0: ");
4357 if (regs.u.r8.bh > 1) {
4358 BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs.u.r8.bh);
4359 // invalid subfunction
4360 SET_CF();
4361 regs.u.r8.ah = 1;
4362 break;
4363 }
4364 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4365 if ( (mouse_flags_2 & 0x80) == 0 ) {
4366 BX_DEBUG_INT15("INT 15h C2 Enable/Disable Mouse, no far call handler\n");
4367 SET_CF();
4368 regs.u.r8.ah = 5; // no far call installed
4369 break;
4370 }
4371 if (regs.u.r8.bh == 0) {
4372BX_DEBUG_INT15("Disable Mouse\n");
4373 mouse_cmd = 0xF5; // disable mouse command
4374 } else {
4375BX_DEBUG_INT15("Enable Mouse\n");
4376 mouse_cmd = 0xF4; // enable mouse command
4377 }
4378
4379 ret = send_to_mouse_ctrl(mouse_cmd); // disable mouse command
4380 if (ret == 0) {
4381 ret = get_mouse_data(&mouse_data1);
4382 if ( (ret == 0) || (mouse_data1 == 0xFA) ) {
4383 // success
4384 break;
4385 }
4386 }
4387
4388 // interface error
4389 SET_CF();
4390 regs.u.r8.ah = 3;
4391 break;
4392
4393 case 5: // Initialize Mouse
4394 // Valid package sizes are 1 to 8
4395 if ( (regs.u.r8.bh < 1) || (regs.u.r8.bh > 8) ) {
4396 SET_CF();
4397 regs.u.r8.ah = 2; // invalid input
4398 break;
4399 }
4400 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4401 mouse_flags_2 = (mouse_flags_2 & 0xf8) | (regs.u.r8.bh - 1);
4402 write_byte(ebda_seg, 0x0027, mouse_flags_2);
4403 // fall through!
4404
4405 case 1: // Reset Mouse
4406BX_DEBUG_INT15("case 1 or 5:\n");
4407 // clear current package byte index
4408 mouse_flags_1 = read_byte(ebda_seg, 0x0026);
4409 mouse_flags_1 = mouse_flags_1 & 0xf8;
4410 write_byte(ebda_seg, 0x0026, mouse_flags_1);
4411 ret = send_to_mouse_ctrl(0xFF); // reset mouse command
4412 if (ret == 0) {
4413 ret = get_mouse_data(&mouse_data3);
4414 // if no mouse attached, it will return RESEND
4415 if (mouse_data3 == 0xfe) {
4416 SET_CF();
4417 regs.u.r8.ah = 4; // resend
4418 break;
4419 }
4420 if (mouse_data3 != 0xfa)
4421 BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3);
4422 if ( ret == 0 ) {
4423 ret = get_mouse_data(&mouse_data1);
4424 if ( ret == 0 ) {
4425 ret = get_mouse_data(&mouse_data2);
4426 if ( ret == 0 ) {
4427 // success
4428 regs.u.r8.bl = mouse_data1;
4429 regs.u.r8.bh = mouse_data2;
4430 break;
4431 }
4432 }
4433 }
4434 }
4435
4436 // interface error
4437 SET_CF();
4438 regs.u.r8.ah = 3;
4439 break;
4440
4441 case 2: // Set Sample Rate
4442BX_DEBUG_INT15("case 2:\n");
4443 switch (regs.u.r8.bh) {
4444 case 0: mouse_data1 = 10; break; // 10 reports/sec
4445 case 1: mouse_data1 = 20; break; // 20 reports/sec
4446 case 2: mouse_data1 = 40; break; // 40 reports/sec
4447 case 3: mouse_data1 = 60; break; // 60 reports/sec
4448 case 4: mouse_data1 = 80; break; // 80 reports/sec
4449 case 5: mouse_data1 = 100; break; // 100 reports/sec (default)
4450 case 6: mouse_data1 = 200; break; // 200 reports/sec
4451 default: mouse_data1 = 0;
4452 }
4453 if (mouse_data1 > 0) {
4454 ret = send_to_mouse_ctrl(0xF3); // set sample rate command
4455 if (ret == 0) {
4456 ret = get_mouse_data(&mouse_data2);
4457 ret = send_to_mouse_ctrl(mouse_data1);
4458 ret = get_mouse_data(&mouse_data2);
4459 // success
4460 } else {
4461 // interface error
4462 SET_CF();
4463 regs.u.r8.ah = 3;
4464 }
4465 } else {
4466 // invalid input
4467 SET_CF();
4468 regs.u.r8.ah = 2;
4469 }
4470 break;
4471
4472 case 3: // Set Resolution
4473BX_DEBUG_INT15("case 3:\n");
4474 // BX:
4475 // 0 = 25 dpi, 1 count per millimeter
4476 // 1 = 50 dpi, 2 counts per millimeter
4477 // 2 = 100 dpi, 4 counts per millimeter
4478 // 3 = 200 dpi, 8 counts per millimeter
4479 if (regs.u.r8.bh < 4) {
4480 ret = send_to_mouse_ctrl(0xE8); // set resolution command
4481 if (ret == 0) {
4482 ret = get_mouse_data(&mouse_data1);
4483 if (mouse_data1 != 0xfa)
4484 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4485 ret = send_to_mouse_ctrl(regs.u.r8.bh);
4486 ret = get_mouse_data(&mouse_data1);
4487 if (mouse_data1 != 0xfa)
4488 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4489 // success
4490 } else {
4491 // interface error
4492 SET_CF();
4493 regs.u.r8.ah = 3;
4494 }
4495 } else {
4496 // invalid input
4497 SET_CF();
4498 regs.u.r8.ah = 2;
4499 }
4500 break;
4501
4502 case 4: // Get Device ID
4503BX_DEBUG_INT15("case 4:\n");
4504 ret = send_to_mouse_ctrl(0xF2); // get mouse ID command
4505 if (ret == 0) {
4506 ret = get_mouse_data(&mouse_data1);
4507 ret = get_mouse_data(&mouse_data2);
4508 regs.u.r8.bh = mouse_data2;
4509 // success
4510 } else {
4511 // interface error
4512 SET_CF();
4513 regs.u.r8.ah = 3;
4514 }
4515 break;
4516
4517 case 6: // Return Status & Set Scaling Factor...
4518BX_DEBUG_INT15("case 6:\n");
4519 switch (regs.u.r8.bh) {
4520 case 0: // Return Status
4521 ret = send_to_mouse_ctrl(0xE9); // get mouse info command
4522 if (ret == 0) {
4523 ret = get_mouse_data(&mouse_data1);
4524 if (mouse_data1 != 0xfa)
4525 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4526 if (ret == 0) {
4527 ret = get_mouse_data(&mouse_data1);
4528 if ( ret == 0 ) {
4529 ret = get_mouse_data(&mouse_data2);
4530 if ( ret == 0 ) {
4531 ret = get_mouse_data(&mouse_data3);
4532 if ( ret == 0 ) {
4533 regs.u.r8.bl = mouse_data1;
4534 regs.u.r8.cl = mouse_data2;
4535 regs.u.r8.dl = mouse_data3;
4536 // success
4537 break;
4538 }
4539 }
4540 }
4541 }
4542 }
4543
4544 // interface error
4545 SET_CF();
4546 regs.u.r8.ah = 3;
4547 break;
4548
4549 case 1: // Set Scaling Factor to 1:1
4550 case 2: // Set Scaling Factor to 2:1
4551 if (regs.u.r8.bh == 1) {
4552 ret = send_to_mouse_ctrl(0xE6);
4553 } else {
4554 ret = send_to_mouse_ctrl(0xE7);
4555 }
4556 if (ret == 0) {
4557 get_mouse_data(&mouse_data1);
4558 ret = (mouse_data1 != 0xFA);
4559 }
4560 if (ret != 0) {
4561 // interface error
4562 SET_CF();
4563 regs.u.r8.ah = 3;
4564 }
4565 break;
4566
4567 default:
4568 BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs.u.r8.bh);
4569 // invalid subfunction
4570 SET_CF();
4571 regs.u.r8.ah = 1;
4572 }
4573 break;
4574
4575 case 7: // Set Mouse Handler Address
4576BX_DEBUG_INT15("case 7:\n");
4577 mouse_driver_seg = ES;
4578 mouse_driver_offset = regs.u.r16.bx;
4579 write_word(ebda_seg, 0x0022, mouse_driver_offset);
4580 write_word(ebda_seg, 0x0024, mouse_driver_seg);
4581 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4582 if (mouse_driver_offset == 0 && mouse_driver_seg == 0) {
4583 /* remove handler */
4584 if ( (mouse_flags_2 & 0x80) != 0 ) {
4585 mouse_flags_2 &= ~0x80;
4586 }
4587 }
4588 else {
4589 /* install handler */
4590 mouse_flags_2 |= 0x80;
4591 }
4592 write_byte(ebda_seg, 0x0027, mouse_flags_2);
4593 break;
4594
4595 default:
4596 BX_PANIC("INT 15h C2 default case entered\n");
4597 // invalid subfunction
4598 SET_CF();
4599 regs.u.r8.ah = 1;
4600 }
4601BX_DEBUG_INT15("returning cf = %u, ah = %02x\n", (unsigned)GET_CF(), (unsigned)regs.u.r8.ah);
4602 // Re-enable AUX input and IRQ12
4603 set_kbd_command_byte(0x47);
4604 break;
4605
4606 default:
4607 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4608 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4609 SET_CF();
4610 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4611 break;
4612 }
4613}
4614#endif // BX_USE_PS2_MOUSE
4615
4616
4617void set_e820_range(ES, DI, start, end, extra_start, extra_end, type)
4618 Bit16u ES;
4619 Bit16u DI;
4620 Bit32u start;
4621 Bit32u end;
4622 Bit8u extra_start;
4623 Bit8u extra_end;
4624 Bit16u type;
4625{
4626 write_word(ES, DI, start);
4627 write_word(ES, DI+2, start >> 16);
4628 write_word(ES, DI+4, extra_start);
4629 write_word(ES, DI+6, 0x00);
4630
4631 end -= start;
4632 extra_end -= extra_start;
4633 write_word(ES, DI+8, end);
4634 write_word(ES, DI+10, end >> 16);
4635 write_word(ES, DI+12, extra_end);
4636 write_word(ES, DI+14, 0x0000);
4637
4638 write_word(ES, DI+16, type);
4639 write_word(ES, DI+18, 0x0);
4640}
4641
4642 void
4643int15_function32(regs, ES, DS, FLAGS)
4644 pushad_regs_t regs; // REGS pushed via pushad
4645 Bit16u ES, DS, FLAGS;
4646{
4647 Bit32u extended_memory_size=0; // 64bits long
4648 Bit32u extra_lowbits_memory_size=0;
4649 Bit16u CX,DX;
4650 Bit8u extra_highbits_memory_size=0;
4651
4652BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4653
4654 switch (regs.u.r8.ah) {
4655 case 0x86:
4656 // Wait for CX:DX microseconds. currently using the
4657 // refresh request port 0x61 bit4, toggling every 15usec
4658
4659 CX = regs.u.r16.cx;
4660 DX = regs.u.r16.dx;
4661
4662ASM_START
4663 sti
4664
4665 ;; Get the count in eax
4666 ;; VBOX: corrected _int15_function -> _int15_function32 here.
4667 mov bx, sp
4668 SEG SS
4669 mov ax, _int15_function32.CX [bx]
4670 shl eax, #16
4671 SEG SS
4672 mov ax, _int15_function32.DX [bx]
4673
4674 ;; convert to numbers of 15usec ticks
4675 mov ebx, #15
4676 xor edx, edx
4677 div eax, ebx
4678 mov ecx, eax
4679
4680 ;; wait for ecx number of refresh requests
4681 in al, #0x61
4682 and al,#0x10
4683 mov ah, al
4684
4685 or ecx, ecx
4686 je int1586_tick_end
4687int1586_tick:
4688 in al, #0x61
4689 and al,#0x10
4690 cmp al, ah
4691 je int1586_tick
4692 mov ah, al
4693 dec ecx
4694 jnz int1586_tick
4695int1586_tick_end:
4696ASM_END
4697
4698 break;
4699
4700 case 0xe8:
4701 switch(regs.u.r8.al)
4702 {
4703 case 0x20: // coded by osmaker aka K.J.
4704 if(regs.u.r32.edx == 0x534D4150)
4705 {
4706 extended_memory_size = inb_cmos(0x35);
4707 extended_memory_size <<= 8;
4708 extended_memory_size |= inb_cmos(0x34);
4709 extended_memory_size *= 64;
4710#ifndef VBOX /* The following excludes 0xf0000000 thru 0xffffffff. Trust DevPcBios.cpp to get this right. */
4711 // greater than EFF00000???
4712 if(extended_memory_size > 0x3bc000) {
4713 extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4714 }
4715#endif /* !VBOX */
4716 extended_memory_size *= 1024;
4717 extended_memory_size += (16L * 1024 * 1024);
4718
4719 if(extended_memory_size <= (16L * 1024 * 1024)) {
4720 extended_memory_size = inb_cmos(0x31);
4721 extended_memory_size <<= 8;
4722 extended_memory_size |= inb_cmos(0x30);
4723 extended_memory_size *= 1024;
4724 extended_memory_size += (1L * 1024 * 1024);
4725 }
4726
4727#ifdef VBOX /* We've already used the CMOS entries for SATA.
4728 BTW. This is the amount of memory above 4GB measured in 64KB units. */
4729 extra_lowbits_memory_size = inb_cmos(0x62);
4730 extra_lowbits_memory_size <<= 8;
4731 extra_lowbits_memory_size |= inb_cmos(0x61);
4732 extra_lowbits_memory_size <<= 16;
4733 extra_highbits_memory_size = inb_cmos(0x63);
4734 /* 0x64 and 0x65 can be used if we need to dig 1 TB or more at a later point. */
4735#else
4736 extra_lowbits_memory_size = inb_cmos(0x5c);
4737 extra_lowbits_memory_size <<= 8;
4738 extra_lowbits_memory_size |= inb_cmos(0x5b);
4739 extra_lowbits_memory_size *= 64;
4740 extra_lowbits_memory_size *= 1024;
4741 extra_highbits_memory_size = inb_cmos(0x5d);
4742#endif /* !VBOX */
4743
4744 switch(regs.u.r16.bx)
4745 {
4746 case 0:
4747 set_e820_range(ES, regs.u.r16.di,
4748#ifndef VBOX /** @todo Upstream sugggests the following, needs checking. (see next as well) */
4749 0x0000000L, 0x0009f000L, 0, 0, 1);
4750#else
4751 0x0000000L, 0x0009fc00L, 0, 0, 1);
4752#endif
4753 regs.u.r32.ebx = 1;
4754 break;
4755 case 1:
4756 set_e820_range(ES, regs.u.r16.di,
4757#ifndef VBOX /** @todo Upstream sugggests the following, needs checking. (see next as well) */
4758 0x0009f000L, 0x000a0000L, 0, 0, 2);
4759#else
4760 0x0009fc00L, 0x000a0000L, 0, 0, 2);
4761#endif
4762 regs.u.r32.ebx = 2;
4763 break;
4764 case 2:
4765#ifdef VBOX
4766 /* Mark the BIOS as reserved. VBox doesn't currently
4767 * use the 0xe0000-0xeffff area. It does use the
4768 * 0xd0000-0xdffff area for the BIOS logo, but it's
4769 * not worth marking it as reserved. Note that various
4770 * Windows versions don't accept (read: in debug builds
4771 * they trigger the "Too many similar traps" assertion)
4772 * a single reserved range from 0xd0000 to 0xffffff.
4773 * A 128K area starting from 0xd0000 works. */
4774 set_e820_range(ES, regs.u.r16.di,
4775 0x000f0000L, 0x00100000L, 0, 0, 2);
4776#else /* !VBOX */
4777 set_e820_range(ES, regs.u.r16.di,
4778 0x000e8000L, 0x00100000L, 0, 0, 2);
4779#endif /* !VBOX */
4780 regs.u.r32.ebx = 3;
4781 break;
4782 case 3:
4783#if BX_ROMBIOS32 || defined(VBOX)
4784 set_e820_range(ES, regs.u.r16.di,
4785 0x00100000L,
4786 extended_memory_size - ACPI_DATA_SIZE, 0, 0, 1);
4787 regs.u.r32.ebx = 4;
4788#else
4789 set_e820_range(ES, regs.u.r16.di,
4790 0x00100000L,
4791 extended_memory_size, 1);
4792 regs.u.r32.ebx = 5;
4793#endif
4794 break;
4795 case 4:
4796 set_e820_range(ES, regs.u.r16.di,
4797 extended_memory_size - ACPI_DATA_SIZE,
4798 extended_memory_size, 0, 0, 3); // ACPI RAM
4799 regs.u.r32.ebx = 5;
4800 break;
4801 case 5:
4802 /* 256KB BIOS area at the end of 4 GB */
4803#ifdef VBOX
4804 /* We don't set the end to 1GB here and rely on the 32-bit
4805 unsigned wrap around effect (0-0xfffc0000L). */
4806#endif
4807 set_e820_range(ES, regs.u.r16.di,
4808 0xfffc0000L, 0x00000000L, 0, 0, 2);
4809 if (extra_highbits_memory_size || extra_lowbits_memory_size)
4810 regs.u.r32.ebx = 6;
4811 else
4812 regs.u.r32.ebx = 0;
4813 break;
4814 case 6:
4815#ifdef VBOX /* Don't succeeded if no memory above 4 GB. */
4816 /* Mapping of memory above 4 GB if present.
4817 Note: set_e820_range needs do no borrowing in the
4818 subtraction because of the nice numbers. */
4819 if (extra_highbits_memory_size || extra_lowbits_memory_size)
4820 {
4821 set_e820_range(ES, regs.u.r16.di,
4822 0x00000000L, extra_lowbits_memory_size,
4823 1 /*GB*/, extra_highbits_memory_size + 1 /*GB*/, 1);
4824 regs.u.r32.ebx = 0;
4825 break;
4826 }
4827 /* fall thru */
4828#else /* !VBOX */
4829 /* Maping of memory above 4 GB */
4830 set_e820_range(ES, regs.u.r16.di, 0x00000000L,
4831 extra_lowbits_memory_size, 1, extra_highbits_memory_size
4832 + 1, 1);
4833 regs.u.r32.ebx = 0;
4834 break;
4835#endif /* !VBOX */
4836 default: /* AX=E820, DX=534D4150, BX unrecognized */
4837 goto int15_unimplemented;
4838 break;
4839 }
4840 regs.u.r32.eax = 0x534D4150;
4841 regs.u.r32.ecx = 0x14;
4842 CLEAR_CF();
4843 } else {
4844 // if DX != 0x534D4150)
4845 goto int15_unimplemented;
4846 }
4847 break;
4848
4849 case 0x01:
4850 // do we have any reason to fail here ?
4851 CLEAR_CF();
4852
4853 // my real system sets ax and bx to 0
4854 // this is confirmed by Ralph Brown list
4855 // but syslinux v1.48 is known to behave
4856 // strangely if ax is set to 0
4857 // regs.u.r16.ax = 0;
4858 // regs.u.r16.bx = 0;
4859
4860 // Get the amount of extended memory (above 1M)
4861 regs.u.r8.cl = inb_cmos(0x30);
4862 regs.u.r8.ch = inb_cmos(0x31);
4863
4864 // limit to 15M
4865 if(regs.u.r16.cx > 0x3c00)
4866 {
4867 regs.u.r16.cx = 0x3c00;
4868 }
4869
4870 // Get the amount of extended memory above 16M in 64k blocs
4871 regs.u.r8.dl = inb_cmos(0x34);
4872 regs.u.r8.dh = inb_cmos(0x35);
4873
4874 // Set configured memory equal to extended memory
4875 regs.u.r16.ax = regs.u.r16.cx;
4876 regs.u.r16.bx = regs.u.r16.dx;
4877 break;
4878 default: /* AH=0xE8?? but not implemented */
4879 goto int15_unimplemented;
4880 }
4881 break;
4882 int15_unimplemented:
4883 // fall into the default
4884 default:
4885 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4886 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4887 SET_CF();
4888 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4889 break;
4890 }
4891}
4892
4893 void
4894int16_function(DI, SI, BP, SP, BX, DX, CX, AX, FLAGS)
4895 Bit16u DI, SI, BP, SP, BX, DX, CX, AX, FLAGS;
4896{
4897 Bit8u scan_code, ascii_code, shift_flags, led_flags, count;
4898 Bit16u kbd_code, max;
4899
4900 BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX, BX, CX, DX);
4901
4902 shift_flags = read_byte(0x0040, 0x17);
4903 led_flags = read_byte(0x0040, 0x97);
4904 if ((((shift_flags >> 4) & 0x07) ^ (led_flags & 0x07)) != 0) {
4905ASM_START
4906 cli
4907ASM_END
4908 outb(0x60, 0xed);
4909 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
4910 if ((inb(0x60) == 0xfa)) {
4911 led_flags &= 0xf8;
4912 led_flags |= ((shift_flags >> 4) & 0x07);
4913 outb(0x60, led_flags & 0x07);
4914 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
4915 inb(0x60);
4916 write_byte(0x0040, 0x97, led_flags);
4917 }
4918ASM_START
4919 sti
4920ASM_END
4921 }
4922
4923 switch (GET_AH()) {
4924 case 0x00: /* read keyboard input */
4925
4926 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4927 BX_PANIC("KBD: int16h: out of keyboard input\n");
4928 }
4929 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4930 else if (ascii_code == 0xE0) ascii_code = 0;
4931 AX = (scan_code << 8) | ascii_code;
4932 break;
4933
4934 case 0x01: /* check keyboard status */
4935 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4936 SET_ZF();
4937 return;
4938 }
4939 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4940 else if (ascii_code == 0xE0) ascii_code = 0;
4941 AX = (scan_code << 8) | ascii_code;
4942 CLEAR_ZF();
4943 break;
4944
4945 case 0x02: /* get shift flag status */
4946 shift_flags = read_byte(0x0040, 0x17);
4947 SET_AL(shift_flags);
4948 break;
4949
4950 case 0x05: /* store key-stroke into buffer */
4951 if ( !enqueue_key(GET_CH(), GET_CL()) ) {
4952 SET_AL(1);
4953 }
4954 else {
4955 SET_AL(0);
4956 }
4957 break;
4958
4959 case 0x09: /* GET KEYBOARD FUNCTIONALITY */
4960 // bit Bochs Description
4961 // 7 0 reserved
4962 // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
4963 // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
4964 // 4 1 INT 16/AH=0Ah supported
4965 // 3 0 INT 16/AX=0306h supported
4966 // 2 0 INT 16/AX=0305h supported
4967 // 1 0 INT 16/AX=0304h supported
4968 // 0 0 INT 16/AX=0300h supported
4969 //
4970 SET_AL(0x30);
4971 break;
4972
4973 case 0x0A: /* GET KEYBOARD ID */
4974 count = 2;
4975 kbd_code = 0x0;
4976 outb(0x60, 0xf2);
4977 /* Wait for data */
4978 max=0xffff;
4979 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4980 if (max>0x0) {
4981 if ((inb(0x60) == 0xfa)) {
4982 do {
4983 max=0xffff;
4984 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4985 if (max>0x0) {
4986 kbd_code >>= 8;
4987 kbd_code |= (inb(0x60) << 8);
4988 }
4989 } while (--count>0);
4990 }
4991 }
4992 BX=kbd_code;
4993 break;
4994
4995 case 0x10: /* read MF-II keyboard input */
4996
4997 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4998 BX_PANIC("KBD: int16h: out of keyboard input\n");
4999 }
5000 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
5001 AX = (scan_code << 8) | ascii_code;
5002 break;
5003
5004 case 0x11: /* check MF-II keyboard status */
5005 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
5006 SET_ZF();
5007 return;
5008 }
5009 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
5010 AX = (scan_code << 8) | ascii_code;
5011 CLEAR_ZF();
5012 break;
5013
5014 case 0x12: /* get extended keyboard status */
5015 shift_flags = read_byte(0x0040, 0x17);
5016 SET_AL(shift_flags);
5017 shift_flags = read_byte(0x0040, 0x18) & 0x73;
5018 shift_flags |= read_byte(0x0040, 0x96) & 0x0c;
5019 SET_AH(shift_flags);
5020 BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX);
5021 break;
5022
5023 case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
5024 SET_AH(0x80); // function int16 ah=0x10-0x12 supported
5025 break;
5026
5027 case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
5028 // don't change AH : function int16 ah=0x20-0x22 NOT supported
5029 break;
5030
5031 case 0x6F:
5032 if (GET_AL() == 0x08)
5033 SET_AH(0x02); // unsupported, aka normal keyboard
5034
5035 default:
5036 BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
5037 }
5038}
5039
5040 unsigned int
5041dequeue_key(scan_code, ascii_code, incr)
5042 Bit8u *scan_code;
5043 Bit8u *ascii_code;
5044 unsigned int incr;
5045{
5046 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail;
5047 Bit16u ss;
5048 Bit8u acode, scode;
5049
5050#if BX_CPU < 2
5051 buffer_start = 0x001E;
5052 buffer_end = 0x003E;
5053#else
5054 buffer_start = read_word(0x0040, 0x0080);
5055 buffer_end = read_word(0x0040, 0x0082);
5056#endif
5057
5058 buffer_head = read_word(0x0040, 0x001a);
5059 buffer_tail = read_word(0x0040, 0x001c);
5060
5061 if (buffer_head != buffer_tail) {
5062 ss = get_SS();
5063 acode = read_byte(0x0040, buffer_head);
5064 scode = read_byte(0x0040, buffer_head+1);
5065 write_byte(ss, ascii_code, acode);
5066 write_byte(ss, scan_code, scode);
5067
5068 if (incr) {
5069 buffer_head += 2;
5070 if (buffer_head >= buffer_end)
5071 buffer_head = buffer_start;
5072 write_word(0x0040, 0x001a, buffer_head);
5073 }
5074 return(1);
5075 }
5076 else {
5077 return(0);
5078 }
5079}
5080
5081static char panic_msg_keyb_buffer_full[] = "%s: keyboard input buffer full\n";
5082
5083 Bit8u
5084send_to_mouse_ctrl(sendbyte)
5085 Bit8u sendbyte;
5086{
5087 Bit8u response;
5088
5089 // wait for chance to write to ctrl
5090 if ( inb(0x64) & 0x02 )
5091 BX_PANIC(panic_msg_keyb_buffer_full,"sendmouse");
5092 outb(0x64, 0xD4);
5093 outb(0x60, sendbyte);
5094 return(0);
5095}
5096
5097
5098 Bit8u
5099get_mouse_data(data)
5100 Bit8u *data;
5101{
5102 Bit8u response;
5103 Bit16u ss;
5104
5105 while ( (inb(0x64) & 0x21) != 0x21 ) {
5106 }
5107
5108 response = inb(0x60);
5109
5110 ss = get_SS();
5111 write_byte(ss, data, response);
5112 return(0);
5113}
5114
5115 void
5116set_kbd_command_byte(command_byte)
5117 Bit8u command_byte;
5118{
5119 if ( inb(0x64) & 0x02 )
5120 BX_PANIC(panic_msg_keyb_buffer_full,"setkbdcomm");
5121
5122 outb(0x64, 0x60); // write command byte
5123 outb(0x60, command_byte);
5124}
5125
5126 void
5127int09_function(DI, SI, BP, SP, BX, DX, CX, AX)
5128 Bit16u DI, SI, BP, SP, BX, DX, CX, AX;
5129{
5130 Bit8u scancode, asciicode, shift_flags;
5131 Bit8u mf2_flags, mf2_state;
5132
5133 //
5134 // DS has been set to F000 before call
5135 //
5136
5137
5138 scancode = GET_AL();
5139
5140 if (scancode == 0) {
5141 BX_INFO("KBD: int09 handler: AL=0\n");
5142 return;
5143 }
5144
5145
5146 shift_flags = read_byte(0x0040, 0x17);
5147 mf2_flags = read_byte(0x0040, 0x18);
5148 mf2_state = read_byte(0x0040, 0x96);
5149 asciicode = 0;
5150
5151 switch (scancode) {
5152 case 0x3a: /* Caps Lock press */
5153 shift_flags ^= 0x40;
5154 write_byte(0x0040, 0x17, shift_flags);
5155 mf2_flags |= 0x40;
5156 write_byte(0x0040, 0x18, mf2_flags);
5157 break;
5158 case 0xba: /* Caps Lock release */
5159 mf2_flags &= ~0x40;
5160 write_byte(0x0040, 0x18, mf2_flags);
5161 break;
5162
5163 case 0x2a: /* L Shift press */
5164 shift_flags |= 0x02;
5165 write_byte(0x0040, 0x17, shift_flags);
5166 break;
5167 case 0xaa: /* L Shift release */
5168 shift_flags &= ~0x02;
5169 write_byte(0x0040, 0x17, shift_flags);
5170 break;
5171
5172 case 0x36: /* R Shift press */
5173 shift_flags |= 0x01;
5174 write_byte(0x0040, 0x17, shift_flags);
5175 break;
5176 case 0xb6: /* R Shift release */
5177 shift_flags &= ~0x01;
5178 write_byte(0x0040, 0x17, shift_flags);
5179 break;
5180
5181 case 0x1d: /* Ctrl press */
5182 if ((mf2_state & 0x01) == 0) {
5183 shift_flags |= 0x04;
5184 write_byte(0x0040, 0x17, shift_flags);
5185 if (mf2_state & 0x02) {
5186 mf2_state |= 0x04;
5187 write_byte(0x0040, 0x96, mf2_state);
5188 } else {
5189 mf2_flags |= 0x01;
5190 write_byte(0x0040, 0x18, mf2_flags);
5191 }
5192 }
5193 break;
5194 case 0x9d: /* Ctrl release */
5195 if ((mf2_state & 0x01) == 0) {
5196 shift_flags &= ~0x04;
5197 write_byte(0x0040, 0x17, shift_flags);
5198 if (mf2_state & 0x02) {
5199 mf2_state &= ~0x04;
5200 write_byte(0x0040, 0x96, mf2_state);
5201 } else {
5202 mf2_flags &= ~0x01;
5203 write_byte(0x0040, 0x18, mf2_flags);
5204 }
5205 }
5206 break;
5207
5208 case 0x38: /* Alt press */
5209 shift_flags |= 0x08;
5210 write_byte(0x0040, 0x17, shift_flags);
5211 if (mf2_state & 0x02) {
5212 mf2_state |= 0x08;
5213 write_byte(0x0040, 0x96, mf2_state);
5214 } else {
5215 mf2_flags |= 0x02;
5216 write_byte(0x0040, 0x18, mf2_flags);
5217 }
5218 break;
5219 case 0xb8: /* Alt release */
5220 shift_flags &= ~0x08;
5221 write_byte(0x0040, 0x17, shift_flags);
5222 if (mf2_state & 0x02) {
5223 mf2_state &= ~0x08;
5224 write_byte(0x0040, 0x96, mf2_state);
5225 } else {
5226 mf2_flags &= ~0x02;
5227 write_byte(0x0040, 0x18, mf2_flags);
5228 }
5229 break;
5230
5231 case 0x45: /* Num Lock press */
5232 if ((mf2_state & 0x03) == 0) {
5233 mf2_flags |= 0x20;
5234 write_byte(0x0040, 0x18, mf2_flags);
5235 shift_flags ^= 0x20;
5236 write_byte(0x0040, 0x17, shift_flags);
5237 }
5238 break;
5239 case 0xc5: /* Num Lock release */
5240 if ((mf2_state & 0x03) == 0) {
5241 mf2_flags &= ~0x20;
5242 write_byte(0x0040, 0x18, mf2_flags);
5243 }
5244 break;
5245
5246 case 0x46: /* Scroll Lock press */
5247 mf2_flags |= 0x10;
5248 write_byte(0x0040, 0x18, mf2_flags);
5249 shift_flags ^= 0x10;
5250 write_byte(0x0040, 0x17, shift_flags);
5251 break;
5252
5253 case 0xc6: /* Scroll Lock release */
5254 mf2_flags &= ~0x10;
5255 write_byte(0x0040, 0x18, mf2_flags);
5256 break;
5257
5258#ifdef VBOX
5259 case 0x53: /* Del press */
5260 if ((shift_flags & 0x0f) == 0x0c)
5261 {
5262ASM_START
5263 /* Ctrl+Alt+Del => Reboot */
5264 jmp 0xf000:post
5265ASM_END
5266 }
5267 /* fall through */
5268#endif
5269
5270 default:
5271 if (scancode & 0x80) {
5272 break; /* toss key releases ... */
5273 }
5274 if (scancode > MAX_SCAN_CODE) {
5275 BX_INFO("KBD: int09h_handler(): unknown scancode read: 0x%02x!\n", scancode);
5276 return;
5277 }
5278 if (shift_flags & 0x08) { /* ALT */
5279 asciicode = scan_to_scanascii[scancode].alt;
5280 scancode = scan_to_scanascii[scancode].alt >> 8;
5281 } else if (shift_flags & 0x04) { /* CONTROL */
5282 asciicode = scan_to_scanascii[scancode].control;
5283 scancode = scan_to_scanascii[scancode].control >> 8;
5284 } else if (((mf2_state & 0x02) > 0) && ((scancode >= 0x47) && (scancode <= 0x53))) {
5285 /* extended keys handling */
5286 asciicode = 0xe0;
5287 scancode = scan_to_scanascii[scancode].normal >> 8;
5288 } else if (shift_flags & 0x03) { /* LSHIFT + RSHIFT */
5289 /* check if lock state should be ignored
5290 * because a SHIFT key are pressed */
5291
5292 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
5293 asciicode = scan_to_scanascii[scancode].normal;
5294 scancode = scan_to_scanascii[scancode].normal >> 8;
5295 } else {
5296 asciicode = scan_to_scanascii[scancode].shift;
5297 scancode = scan_to_scanascii[scancode].shift >> 8;
5298 }
5299 } else {
5300 /* check if lock is on */
5301 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
5302 asciicode = scan_to_scanascii[scancode].shift;
5303 scancode = scan_to_scanascii[scancode].shift >> 8;
5304 } else {
5305 asciicode = scan_to_scanascii[scancode].normal;
5306 scancode = scan_to_scanascii[scancode].normal >> 8;
5307 }
5308 }
5309 if (scancode==0 && asciicode==0) {
5310 BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
5311 }
5312 enqueue_key(scancode, asciicode);
5313 break;
5314 }
5315 if ((scancode & 0x7f) != 0x1d) {
5316 mf2_state &= ~0x01;
5317 }
5318 mf2_state &= ~0x02;
5319 write_byte(0x0040, 0x96, mf2_state);
5320}
5321
5322 unsigned int
5323enqueue_key(scan_code, ascii_code)
5324 Bit8u scan_code, ascii_code;
5325{
5326 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail, temp_tail;
5327
5328#if BX_CPU < 2
5329 buffer_start = 0x001E;
5330 buffer_end = 0x003E;
5331#else
5332 buffer_start = read_word(0x0040, 0x0080);
5333 buffer_end = read_word(0x0040, 0x0082);
5334#endif
5335
5336 buffer_head = read_word(0x0040, 0x001A);
5337 buffer_tail = read_word(0x0040, 0x001C);
5338
5339 temp_tail = buffer_tail;
5340 buffer_tail += 2;
5341 if (buffer_tail >= buffer_end)
5342 buffer_tail = buffer_start;
5343
5344 if (buffer_tail == buffer_head) {
5345 return(0);
5346 }
5347
5348 write_byte(0x0040, temp_tail, ascii_code);
5349 write_byte(0x0040, temp_tail+1, scan_code);
5350 write_word(0x0040, 0x001C, buffer_tail);
5351 return(1);
5352}
5353
5354
5355 void
5356int74_function(make_farcall, Z, Y, X, status)
5357 Bit16u make_farcall, Z, Y, X, status;
5358{
5359 Bit16u ebda_seg=read_word(0x0040,0x000E);
5360 Bit8u in_byte, index, package_count;
5361 Bit8u mouse_flags_1, mouse_flags_2;
5362
5363BX_DEBUG_INT74("entering int74_function\n");
5364 make_farcall = 0;
5365
5366 in_byte = inb(0x64);
5367 if ( (in_byte & 0x21) != 0x21 ) {
5368 return;
5369 }
5370 in_byte = inb(0x60);
5371BX_DEBUG_INT74("int74: read byte %02x\n", in_byte);
5372
5373 mouse_flags_1 = read_byte(ebda_seg, 0x0026);
5374 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
5375
5376 if ( (mouse_flags_2 & 0x80) != 0x80 ) {
5377 return;
5378 }
5379
5380 package_count = mouse_flags_2 & 0x07;
5381 index = mouse_flags_1 & 0x07;
5382 write_byte(ebda_seg, 0x28 + index, in_byte);
5383
5384 if ( index >= package_count ) {
5385BX_DEBUG_INT74("int74_function: make_farcall=1\n");
5386 status = read_byte(ebda_seg, 0x0028 + 0);
5387 X = read_byte(ebda_seg, 0x0028 + 1);
5388 Y = read_byte(ebda_seg, 0x0028 + 2);
5389 Z = 0;
5390 mouse_flags_1 = 0;
5391 // check if far call handler installed
5392 if (mouse_flags_2 & 0x80)
5393 make_farcall = 1;
5394 }
5395 else {
5396 mouse_flags_1++;
5397 }
5398 write_byte(ebda_seg, 0x0026, mouse_flags_1);
5399}
5400
5401#define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
5402
5403#if BX_USE_ATADRV
5404
5405 void
5406int13_harddisk(EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5407 Bit16u EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5408{
5409 Bit32u lba;
5410 Bit16u ebda_seg=read_word(0x0040,0x000E);
5411 Bit16u cylinder, head, sector;
5412 Bit16u segment, offset;
5413 Bit16u npc, nph, npspt, nlc, nlh, nlspt;
5414 Bit16u size, count;
5415 Bit8u device, status;
5416
5417 BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5418
5419 write_byte(0x0040, 0x008e, 0); // clear completion flag
5420
5421#ifdef VBOX_WITH_SCSI
5422 // basic check : device has to be defined
5423 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_STORAGE_DEVICES) ) {
5424 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5425 goto int13_fail;
5426 }
5427#else
5428 // basic check : device has to be defined
5429 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES) ) {
5430 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5431 goto int13_fail;
5432 }
5433#endif
5434
5435 // Get the ata channel
5436 device=read_byte(ebda_seg,&EbdaData->ata.hdidmap[GET_ELDL()-0x80]);
5437
5438#ifdef VBOX_WITH_SCSI
5439 // basic check : device has to be valid
5440 if (device >= BX_MAX_STORAGE_DEVICES) {
5441 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5442 goto int13_fail;
5443 }
5444#else
5445 // basic check : device has to be valid
5446 if (device >= BX_MAX_ATA_DEVICES) {
5447 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5448 goto int13_fail;
5449 }
5450#endif
5451
5452 switch (GET_AH()) {
5453
5454 case 0x00: /* disk controller reset */
5455#ifdef VBOX_WITH_SCSI
5456 /* SCSI controller does not need a reset. */
5457 if (!VBOX_IS_SCSI_DEVICE(device))
5458#endif
5459 ata_reset (device);
5460 goto int13_success;
5461 break;
5462
5463 case 0x01: /* read disk status */
5464 status = read_byte(0x0040, 0x0074);
5465 SET_AH(status);
5466 SET_DISK_RET_STATUS(0);
5467 /* set CF if error status read */
5468 if (status) goto int13_fail_nostatus;
5469 else goto int13_success_noah;
5470 break;
5471
5472 case 0x02: // read disk sectors
5473 case 0x03: // write disk sectors
5474 case 0x04: // verify disk sectors
5475
5476 count = GET_AL();
5477 cylinder = GET_CH();
5478 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
5479 sector = (GET_CL() & 0x3f);
5480 head = GET_DH();
5481
5482 segment = ES;
5483 offset = BX;
5484
5485 if ( (count > 128) || (count == 0) ) {
5486 BX_INFO("int13_harddisk: function %02x, count out of range!\n",GET_AH());
5487 goto int13_fail;
5488 }
5489
5490#ifdef VBOX_WITH_SCSI
5491 if (!VBOX_IS_SCSI_DEVICE(device))
5492#endif
5493 {
5494 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
5495 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
5496 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
5497 }
5498#ifdef VBOX_WITH_SCSI
5499 else
5500 {
5501 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5502
5503 nlc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.cylinders);
5504 nlh = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.heads);
5505 nlspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.spt);
5506 }
5507#endif
5508
5509 // sanity check on cyl heads, sec
5510 if( (cylinder >= nlc) || (head >= nlh) || (sector > nlspt )) {
5511 BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder, head, sector);
5512 goto int13_fail;
5513 }
5514
5515 // FIXME verify
5516 if ( GET_AH() == 0x04 ) goto int13_success;
5517
5518#ifdef VBOX_WITH_SCSI
5519 if (!VBOX_IS_SCSI_DEVICE(device))
5520#endif
5521 {
5522 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5523 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5524 }
5525#ifdef VBOX_WITH_SCSI
5526 else
5527 {
5528 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5529 nph = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.heads);
5530 npspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.spt);
5531 }
5532#endif
5533
5534 // if needed, translate lchs to lba, and execute command
5535#ifdef VBOX_WITH_SCSI
5536 if (( (nph != nlh) || (npspt != nlspt)) || VBOX_IS_SCSI_DEVICE(device)) {
5537 lba = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
5538 sector = 0; // this forces the command to be lba
5539 }
5540#else
5541 if (( (nph != nlh) || (npspt != nlspt)) ) {
5542 lba = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
5543 sector = 0; // this forces the command to be lba
5544 }
5545#endif
5546
5547 if ( GET_AH() == 0x02 )
5548 {
5549#ifdef VBOX_WITH_SCSI
5550 if (VBOX_IS_SCSI_DEVICE(device))
5551 status=scsi_read_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5552 else
5553#endif
5554 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, cylinder, head, sector, lba, segment, offset);
5555 }
5556 else
5557 {
5558#ifdef VBOX_WITH_SCSI
5559 if (VBOX_IS_SCSI_DEVICE(device))
5560 status=scsi_write_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5561 else
5562#endif
5563 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, cylinder, head, sector, lba, segment, offset);
5564 }
5565
5566 // Set nb of sector transferred
5567 SET_AL(read_word(ebda_seg, &EbdaData->ata.trsfsectors));
5568
5569 if (status != 0) {
5570 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5571 SET_AH(0x0c);
5572 goto int13_fail_noah;
5573 }
5574
5575 goto int13_success;
5576 break;
5577
5578 case 0x05: /* format disk track */
5579 BX_INFO("format disk track called\n");
5580 goto int13_success;
5581 return;
5582 break;
5583
5584 case 0x08: /* read disk drive parameters */
5585
5586 // Get logical geometry from table
5587#ifdef VBOX_WITH_SCSI
5588 if (!VBOX_IS_SCSI_DEVICE(device))
5589#endif
5590 {
5591 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
5592 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
5593 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
5594 }
5595#ifdef VBOX_WITH_SCSI
5596 else
5597 {
5598 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5599 nlc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.cylinders);
5600 nlh = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.heads);
5601 nlspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.spt);
5602 }
5603#endif
5604
5605 count = read_byte(ebda_seg, &EbdaData->ata.hdcount);
5606#ifndef VBOX
5607 nlc = nlc - 2; /* 0 based , last sector not used */
5608#else /* VBOX */
5609 /* Maximum cylinder number is just one less than the number of cylinders. */
5610 nlc = nlc - 1; /* 0 based , last sector not used */
5611#endif /* VBOX */
5612 SET_AL(0);
5613 SET_CH(nlc & 0xff);
5614 SET_CL(((nlc >> 2) & 0xc0) | (nlspt & 0x3f));
5615 SET_DH(nlh - 1);
5616 SET_DL(count); /* FIXME returns 0, 1, or n hard drives */
5617
5618 // FIXME should set ES & DI
5619
5620 goto int13_success;
5621 break;
5622
5623 case 0x10: /* check drive ready */
5624 // should look at 40:8E also???
5625
5626 // Read the status from controller
5627 status = inb(read_word(ebda_seg, &EbdaData->ata.channels[device/2].iobase1) + ATA_CB_STAT);
5628 if ( (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY ) {
5629 goto int13_success;
5630 }
5631 else {
5632 SET_AH(0xAA);
5633 goto int13_fail_noah;
5634 }
5635 break;
5636
5637 case 0x15: /* read disk drive size */
5638
5639 // Get physical geometry from table
5640#ifdef VBOX_WITH_SCSI
5641 if (!VBOX_IS_SCSI_DEVICE(device))
5642#endif
5643 {
5644 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5645 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5646 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5647 }
5648#ifdef VBOX_WITH_SCSI
5649 else
5650 {
5651 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5652 npc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.cylinders);
5653 nph = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.heads);
5654 npspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.spt);
5655 }
5656#endif
5657
5658 // Compute sector count seen by int13
5659#ifndef VBOX
5660 lba = (Bit32u)(npc - 1) * (Bit32u)nph * (Bit32u)npspt;
5661#else /* VBOX */
5662 /* Is it so hard to multiply a couple of counts (without introducing
5663 * arbitrary off by one errors)? */
5664 lba = (Bit32u)npc * (Bit32u)nph * (Bit32u)npspt;
5665#endif /* VBOX */
5666 CX = lba >> 16;
5667 DX = lba & 0xffff;
5668
5669 SET_AH(3); // hard disk accessible
5670 goto int13_success_noah;
5671 break;
5672
5673 case 0x41: // IBM/MS installation check
5674 BX=0xaa55; // install check
5675 SET_AH(0x30); // EDD 3.0
5676 CX=0x0007; // ext disk access and edd, removable supported
5677 goto int13_success_noah;
5678 break;
5679
5680 case 0x42: // IBM/MS extended read
5681 case 0x43: // IBM/MS extended write
5682 case 0x44: // IBM/MS verify
5683 case 0x47: // IBM/MS extended seek
5684
5685 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5686 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5687 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5688
5689 // Can't use 64 bits lba
5690 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5691 if (lba != 0L) {
5692 BX_PANIC("int13_harddisk: function %02x. Can't use 64bits lba\n",GET_AH());
5693 goto int13_fail;
5694 }
5695
5696 // Get 32 bits lba and check
5697 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5698
5699#ifdef VBOX_WITH_SCSI
5700 if (VBOX_IS_SCSI_DEVICE(device))
5701 {
5702 if (lba >= read_dword(ebda_seg, &EbdaData->scsi.devices[VBOX_GET_SCSI_DEVICE(device)].device_info.sectors) ) {
5703 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5704 goto int13_fail;
5705 }
5706 }
5707 else
5708#endif
5709 if (lba >= read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors) ) {
5710 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5711 goto int13_fail;
5712 }
5713
5714
5715 // If verify or seek
5716 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5717 goto int13_success;
5718
5719 // Execute the command
5720 if ( GET_AH() == 0x42 )
5721#ifdef VBOX
5722 {
5723#ifdef VBOX_WITH_SCSI
5724 if (VBOX_IS_SCSI_DEVICE(device))
5725 status=scsi_read_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5726 else
5727#endif
5728 {
5729 if (count >= 256 || lba + count >= 268435456)
5730 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS_EXT, count, 0, 0, 0, lba, segment, offset);
5731 else
5732 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba, segment, offset);
5733 }
5734 }
5735#else /* !VBOX */
5736 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba, segment, offset);
5737#endif /* VBOX */
5738 else
5739#ifdef VBOX
5740 {
5741#ifdef VBOX_WITH_SCSI
5742 if (VBOX_IS_SCSI_DEVICE(device))
5743 status=scsi_write_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5744 else
5745#endif
5746 {
5747 if (count >= 256 || lba + count >= 268435456)
5748 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS_EXT, count, 0, 0, 0, lba, segment, offset);
5749 else
5750 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
5751 }
5752 }
5753#else /* !VBOX */
5754 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
5755#endif /* VBOX */
5756
5757 count=read_word(ebda_seg, &EbdaData->ata.trsfsectors);
5758 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5759
5760 if (status != 0) {
5761 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5762 SET_AH(0x0c);
5763 goto int13_fail_noah;
5764 }
5765
5766 goto int13_success;
5767 break;
5768
5769 case 0x45: // IBM/MS lock/unlock drive
5770 case 0x49: // IBM/MS extended media change
5771 goto int13_success; // Always success for HD
5772 break;
5773
5774 case 0x46: // IBM/MS eject media
5775 SET_AH(0xb2); // Volume Not Removable
5776 goto int13_fail_noah; // Always fail for HD
5777 break;
5778
5779 case 0x48: // IBM/MS get drive parameters
5780 size=read_word(DS,SI+(Bit16u)&Int13DPT->size);
5781
5782 // Buffer is too small
5783 if(size < 0x1a)
5784 goto int13_fail;
5785
5786 // EDD 1.x
5787 if(size >= 0x1a) {
5788 Bit16u blksize;
5789
5790#ifdef VBOX_WITH_SCSI
5791 if (!VBOX_IS_SCSI_DEVICE(device))
5792#endif
5793 {
5794 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5795 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5796 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5797 lba = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors);
5798 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5799 }
5800#ifdef VBOX_WITH_SCSI
5801 else
5802 {
5803 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5804 npc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.cylinders);
5805 nph = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.heads);
5806 npspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.spt);
5807 lba = read_dword(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.sectors);
5808 blksize = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.blksize);
5809 }
5810#endif
5811
5812 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5813 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x02); // geometry is valid
5814 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, (Bit32u)npc);
5815 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, (Bit32u)nph);
5816 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, (Bit32u)npspt);
5817 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, lba); // FIXME should be Bit64
5818 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0L);
5819 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5820 }
5821
5822 // EDD 2.x
5823 if(size >= 0x1e) {
5824 Bit8u channel, dev, irq, mode, checksum, i, translation;
5825 Bit16u iobase1, iobase2, options;
5826
5827 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5828
5829 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5830 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5831
5832 // Fill in dpte
5833 channel = device / 2;
5834 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5835 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5836 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5837 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5838 translation = read_byte(ebda_seg, &EbdaData->ata.devices[device].translation);
5839
5840 options = (translation==ATA_TRANSLATION_NONE?0:1<<3); // chs translation
5841 options |= (1<<4); // lba translation
5842 options |= (mode==ATA_MODE_PIO32?1:0<<7);
5843 options |= (translation==ATA_TRANSLATION_LBA?1:0<<9);
5844 options |= (translation==ATA_TRANSLATION_RECHS?3:0<<9);
5845
5846 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5847 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5848 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5849 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5850 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5851 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5852 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5853 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5854 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5855 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5856 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5857
5858 checksum=0;
5859 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5860 checksum = ~checksum;
5861 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5862 }
5863
5864 // EDD 3.x
5865 if(size >= 0x42) {
5866 Bit8u channel, iface, checksum, i;
5867 Bit16u iobase1;
5868
5869 channel = device / 2;
5870 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5871 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5872
5873 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5874 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5875 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5876 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5877 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5878
5879 if (iface==ATA_IFACE_ISA) {
5880 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5881 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5882 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5883 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5884 }
5885 else {
5886 // FIXME PCI
5887 }
5888 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5889 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5890 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5891 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5892
5893 if (iface==ATA_IFACE_ISA) {
5894 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5895 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5896 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5897 }
5898 else {
5899 // FIXME PCI
5900 }
5901 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5902 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5903 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5904 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5905
5906 checksum=0;
5907 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5908 checksum = ~checksum;
5909 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5910 }
5911
5912 goto int13_success;
5913 break;
5914
5915 case 0x4e: // // IBM/MS set hardware configuration
5916 // DMA, prefetch, PIO maximum not supported
5917 switch (GET_AL()) {
5918 case 0x01:
5919 case 0x03:
5920 case 0x04:
5921 case 0x06:
5922 goto int13_success;
5923 break;
5924 default :
5925 goto int13_fail;
5926 }
5927 break;
5928
5929 case 0x09: /* initialize drive parameters */
5930 case 0x0c: /* seek to specified cylinder */
5931 case 0x0d: /* alternate disk reset */
5932 case 0x11: /* recalibrate */
5933 case 0x14: /* controller internal diagnostic */
5934 BX_INFO("int13_harddisk: function %02xh unimplemented, returns success\n", GET_AH());
5935 goto int13_success;
5936 break;
5937
5938 case 0x0a: /* read disk sectors with ECC */
5939 case 0x0b: /* write disk sectors with ECC */
5940 case 0x18: // set media type for format
5941 case 0x50: // IBM/MS send packet command
5942 default:
5943 BX_INFO("int13_harddisk: function %02xh unsupported, returns fail\n", GET_AH());
5944 goto int13_fail;
5945 break;
5946 }
5947
5948int13_fail:
5949 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5950int13_fail_noah:
5951 SET_DISK_RET_STATUS(GET_AH());
5952int13_fail_nostatus:
5953 SET_CF(); // error occurred
5954 return;
5955
5956int13_success:
5957 SET_AH(0x00); // no error
5958int13_success_noah:
5959 SET_DISK_RET_STATUS(0x00);
5960 CLEAR_CF(); // no error
5961 return;
5962}
5963
5964// ---------------------------------------------------------------------------
5965// Start of int13 for cdrom
5966// ---------------------------------------------------------------------------
5967
5968 void
5969int13_cdrom(EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5970 Bit16u EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5971{
5972 Bit16u ebda_seg=read_word(0x0040,0x000E);
5973 Bit8u device, status, locks;
5974 Bit8u atacmd[12];
5975 Bit32u lba;
5976 Bit16u count, segment, offset, i, size;
5977
5978 BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5979
5980 SET_DISK_RET_STATUS(0x00);
5981
5982 /* basic check : device should be 0xE0+ */
5983 if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES) ) {
5984 BX_INFO("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5985 goto int13_fail;
5986 }
5987
5988 // Get the ata channel
5989 device=read_byte(ebda_seg,&EbdaData->ata.cdidmap[GET_ELDL()-0xE0]);
5990
5991 /* basic check : device has to be valid */
5992 if (device >= BX_MAX_ATA_DEVICES) {
5993 BX_INFO("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5994 goto int13_fail;
5995 }
5996
5997 switch (GET_AH()) {
5998
5999 // all those functions return SUCCESS
6000 case 0x00: /* disk controller reset */
6001 case 0x09: /* initialize drive parameters */
6002 case 0x0c: /* seek to specified cylinder */
6003 case 0x0d: /* alternate disk reset */
6004 case 0x10: /* check drive ready */
6005 case 0x11: /* recalibrate */
6006 case 0x14: /* controller internal diagnostic */
6007 case 0x16: /* detect disk change */
6008 goto int13_success;
6009 break;
6010
6011 // all those functions return disk write-protected
6012 case 0x03: /* write disk sectors */
6013 case 0x05: /* format disk track */
6014 case 0x43: // IBM/MS extended write
6015 SET_AH(0x03);
6016 goto int13_fail_noah;
6017 break;
6018
6019 case 0x01: /* read disk status */
6020 status = read_byte(0x0040, 0x0074);
6021 SET_AH(status);
6022 SET_DISK_RET_STATUS(0);
6023
6024 /* set CF if error status read */
6025 if (status) goto int13_fail_nostatus;
6026 else goto int13_success_noah;
6027 break;
6028
6029 case 0x15: /* read disk drive size */
6030 SET_AH(0x02);
6031 goto int13_fail_noah;
6032 break;
6033
6034 case 0x41: // IBM/MS installation check
6035 BX=0xaa55; // install check
6036 SET_AH(0x30); // EDD 2.1
6037 CX=0x0007; // ext disk access, removable and edd
6038 goto int13_success_noah;
6039 break;
6040
6041 case 0x42: // IBM/MS extended read
6042 case 0x44: // IBM/MS verify sectors
6043 case 0x47: // IBM/MS extended seek
6044
6045 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
6046 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
6047 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
6048
6049 // Can't use 64 bits lba
6050 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
6051 if (lba != 0L) {
6052 BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
6053 goto int13_fail;
6054 }
6055
6056 // Get 32 bits lba
6057 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
6058
6059 // If verify or seek
6060 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
6061 goto int13_success;
6062
6063 memsetb(get_SS(),atacmd,0,12);
6064 atacmd[0]=0x28; // READ command
6065 atacmd[7]=(count & 0xff00) >> 8; // Sectors
6066 atacmd[8]=(count & 0x00ff); // Sectors
6067 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
6068 atacmd[3]=(lba & 0x00ff0000) >> 16;
6069 atacmd[4]=(lba & 0x0000ff00) >> 8;
6070 atacmd[5]=(lba & 0x000000ff);
6071 status = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, count*2048L, ATA_DATA_IN, segment,offset);
6072
6073 count = (Bit16u)(read_dword(ebda_seg, &EbdaData->ata.trsfbytes) >> 11);
6074 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
6075
6076 if (status != 0) {
6077 BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status);
6078 SET_AH(0x0c);
6079 goto int13_fail_noah;
6080 }
6081
6082 goto int13_success;
6083 break;
6084
6085 case 0x45: // IBM/MS lock/unlock drive
6086 if (GET_AL() > 2) goto int13_fail;
6087
6088 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
6089
6090 switch (GET_AL()) {
6091 case 0 : // lock
6092 if (locks == 0xff) {
6093 SET_AH(0xb4);
6094 SET_AL(1);
6095 goto int13_fail_noah;
6096 }
6097 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, ++locks);
6098 SET_AL(1);
6099 break;
6100 case 1 : // unlock
6101 if (locks == 0x00) {
6102 SET_AH(0xb0);
6103 SET_AL(0);
6104 goto int13_fail_noah;
6105 }
6106 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, --locks);
6107 SET_AL(locks==0?0:1);
6108 break;
6109 case 2 : // status
6110 SET_AL(locks==0?0:1);
6111 break;
6112 }
6113 goto int13_success;
6114 break;
6115
6116 case 0x46: // IBM/MS eject media
6117 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
6118
6119 if (locks != 0) {
6120 SET_AH(0xb1); // media locked
6121 goto int13_fail_noah;
6122 }
6123 // FIXME should handle 0x31 no media in device
6124 // FIXME should handle 0xb5 valid request failed
6125
6126 // Call removable media eject
6127 ASM_START
6128 push bp
6129 mov bp, sp
6130
6131 mov ah, #0x52
6132 int #0x15
6133 mov _int13_cdrom.status + 2[bp], ah
6134 jnc int13_cdrom_rme_end
6135 mov _int13_cdrom.status, #1
6136int13_cdrom_rme_end:
6137 pop bp
6138 ASM_END
6139
6140 if (status != 0) {
6141 SET_AH(0xb1); // media locked
6142 goto int13_fail_noah;
6143 }
6144
6145 goto int13_success;
6146 break;
6147
6148 case 0x48: // IBM/MS get drive parameters
6149 size = read_word(DS,SI+(Bit16u)&Int13Ext->size);
6150
6151 // Buffer is too small
6152 if(size < 0x1a)
6153 goto int13_fail;
6154
6155 // EDD 1.x
6156 if(size >= 0x1a) {
6157 Bit16u cylinders, heads, spt, blksize;
6158
6159 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
6160
6161 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
6162 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x74); // removable, media change, lockable, max values
6163 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, 0xffffffff);
6164 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, 0xffffffff);
6165 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, 0xffffffff);
6166 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, 0xffffffff); // FIXME should be Bit64
6167 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0xffffffff);
6168 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
6169 }
6170
6171 // EDD 2.x
6172 if(size >= 0x1e) {
6173 Bit8u channel, dev, irq, mode, checksum, i;
6174 Bit16u iobase1, iobase2, options;
6175
6176 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
6177
6178 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
6179 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
6180
6181 // Fill in dpte
6182 channel = device / 2;
6183 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
6184 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
6185 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
6186 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
6187
6188 // FIXME atapi device
6189 options = (1<<4); // lba translation
6190 options |= (1<<5); // removable device
6191 options |= (1<<6); // atapi device
6192 options |= (mode==ATA_MODE_PIO32?1:0<<7);
6193
6194 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
6195 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
6196 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
6197 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
6198 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
6199 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
6200 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
6201 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
6202 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
6203 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
6204 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
6205
6206 checksum=0;
6207 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
6208 checksum = ~checksum;
6209 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
6210 }
6211
6212 // EDD 3.x
6213 if(size >= 0x42) {
6214 Bit8u channel, iface, checksum, i;
6215 Bit16u iobase1;
6216
6217 channel = device / 2;
6218 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
6219 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
6220
6221 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
6222 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
6223 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
6224 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
6225 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
6226
6227 if (iface==ATA_IFACE_ISA) {
6228 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
6229 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
6230 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
6231 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
6232 }
6233 else {
6234 // FIXME PCI
6235 }
6236 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
6237 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
6238 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
6239 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
6240
6241 if (iface==ATA_IFACE_ISA) {
6242 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
6243 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
6244 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
6245 }
6246 else {
6247 // FIXME PCI
6248 }
6249 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
6250 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
6251 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
6252 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
6253
6254 checksum=0;
6255 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
6256 checksum = ~checksum;
6257 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
6258 }
6259
6260 goto int13_success;
6261 break;
6262
6263 case 0x49: // IBM/MS extended media change
6264 // always send changed ??
6265 SET_AH(06);
6266 goto int13_fail_nostatus;
6267 break;
6268
6269 case 0x4e: // // IBM/MS set hardware configuration
6270 // DMA, prefetch, PIO maximum not supported
6271 switch (GET_AL()) {
6272 case 0x01:
6273 case 0x03:
6274 case 0x04:
6275 case 0x06:
6276 goto int13_success;
6277 break;
6278 default :
6279 goto int13_fail;
6280 }
6281 break;
6282
6283 // all those functions return unimplemented
6284 case 0x02: /* read sectors */
6285 case 0x04: /* verify sectors */
6286 case 0x08: /* read disk drive parameters */
6287 case 0x0a: /* read disk sectors with ECC */
6288 case 0x0b: /* write disk sectors with ECC */
6289 case 0x18: /* set media type for format */
6290 case 0x50: // ? - send packet command
6291 default:
6292 BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
6293 goto int13_fail;
6294 break;
6295 }
6296
6297int13_fail:
6298 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6299int13_fail_noah:
6300 SET_DISK_RET_STATUS(GET_AH());
6301int13_fail_nostatus:
6302 SET_CF(); // error occurred
6303 return;
6304
6305int13_success:
6306 SET_AH(0x00); // no error
6307int13_success_noah:
6308 SET_DISK_RET_STATUS(0x00);
6309 CLEAR_CF(); // no error
6310 return;
6311}
6312
6313// ---------------------------------------------------------------------------
6314// End of int13 for cdrom
6315// ---------------------------------------------------------------------------
6316
6317#if BX_ELTORITO_BOOT
6318// ---------------------------------------------------------------------------
6319// Start of int13 for eltorito functions
6320// ---------------------------------------------------------------------------
6321
6322 void
6323int13_eltorito(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
6324 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
6325{
6326 Bit16u ebda_seg=read_word(0x0040,0x000E);
6327
6328 BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6329 // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
6330
6331 switch (GET_AH()) {
6332
6333 // FIXME ElTorito Various. Should be implemented
6334 case 0x4a: // ElTorito - Initiate disk emu
6335 case 0x4c: // ElTorito - Initiate disk emu and boot
6336 case 0x4d: // ElTorito - Return Boot catalog
6337 BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX);
6338 goto int13_fail;
6339 break;
6340
6341 case 0x4b: // ElTorito - Terminate disk emu
6342 // FIXME ElTorito Hardcoded
6343 write_byte(DS,SI+0x00,0x13);
6344 write_byte(DS,SI+0x01,read_byte(ebda_seg,&EbdaData->cdemu.media));
6345 write_byte(DS,SI+0x02,read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
6346 write_byte(DS,SI+0x03,read_byte(ebda_seg,&EbdaData->cdemu.controller_index));
6347 write_dword(DS,SI+0x04,read_dword(ebda_seg,&EbdaData->cdemu.ilba));
6348 write_word(DS,SI+0x08,read_word(ebda_seg,&EbdaData->cdemu.device_spec));
6349 write_word(DS,SI+0x0a,read_word(ebda_seg,&EbdaData->cdemu.buffer_segment));
6350 write_word(DS,SI+0x0c,read_word(ebda_seg,&EbdaData->cdemu.load_segment));
6351 write_word(DS,SI+0x0e,read_word(ebda_seg,&EbdaData->cdemu.sector_count));
6352 write_byte(DS,SI+0x10,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.cylinders));
6353 write_byte(DS,SI+0x11,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.spt));
6354 write_byte(DS,SI+0x12,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.heads));
6355
6356 // If we have to terminate emulation
6357 if(GET_AL() == 0x00) {
6358 // FIXME ElTorito Various. Should be handled accordingly to spec
6359 write_byte(ebda_seg,&EbdaData->cdemu.active, 0x00); // bye bye
6360 }
6361
6362 goto int13_success;
6363 break;
6364
6365 default:
6366 BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
6367 goto int13_fail;
6368 break;
6369 }
6370
6371int13_fail:
6372 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6373 SET_DISK_RET_STATUS(GET_AH());
6374 SET_CF(); // error occurred
6375 return;
6376
6377int13_success:
6378 SET_AH(0x00); // no error
6379 SET_DISK_RET_STATUS(0x00);
6380 CLEAR_CF(); // no error
6381 return;
6382}
6383
6384// ---------------------------------------------------------------------------
6385// End of int13 for eltorito functions
6386// ---------------------------------------------------------------------------
6387
6388// ---------------------------------------------------------------------------
6389// Start of int13 when emulating a device from the cd
6390// ---------------------------------------------------------------------------
6391
6392 void
6393int13_cdemu(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
6394 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
6395{
6396 Bit16u ebda_seg=read_word(0x0040,0x000E);
6397 Bit8u device, status;
6398 Bit16u vheads, vspt, vcylinders;
6399 Bit16u head, sector, cylinder, nbsectors;
6400 Bit32u vlba, ilba, slba, elba;
6401 Bit16u before, segment, offset;
6402 Bit8u atacmd[12];
6403
6404 BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6405
6406 /* at this point, we are emulating a floppy/harddisk */
6407
6408 // Recompute the device number
6409 device = read_byte(ebda_seg,&EbdaData->cdemu.controller_index) * 2;
6410 device += read_byte(ebda_seg,&EbdaData->cdemu.device_spec);
6411
6412 SET_DISK_RET_STATUS(0x00);
6413
6414 /* basic checks : emulation should be active, dl should equal the emulated drive */
6415 if( (read_byte(ebda_seg,&EbdaData->cdemu.active) ==0 )
6416 || (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive ) != GET_DL())) {
6417 BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
6418 goto int13_fail;
6419 }
6420
6421 switch (GET_AH()) {
6422
6423 // all those functions return SUCCESS
6424 case 0x00: /* disk controller reset */
6425 case 0x09: /* initialize drive parameters */
6426 case 0x0c: /* seek to specified cylinder */
6427 case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
6428 case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
6429 case 0x11: /* recalibrate */
6430 case 0x14: /* controller internal diagnostic */
6431 case 0x16: /* detect disk change */
6432 goto int13_success;
6433 break;
6434
6435 // all those functions return disk write-protected
6436 case 0x03: /* write disk sectors */
6437 case 0x05: /* format disk track */
6438 SET_AH(0x03);
6439 goto int13_fail_noah;
6440 break;
6441
6442 case 0x01: /* read disk status */
6443 status=read_byte(0x0040, 0x0074);
6444 SET_AH(status);
6445 SET_DISK_RET_STATUS(0);
6446
6447 /* set CF if error status read */
6448 if (status) goto int13_fail_nostatus;
6449 else goto int13_success_noah;
6450 break;
6451
6452 case 0x02: // read disk sectors
6453 case 0x04: // verify disk sectors
6454 vspt = read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
6455 vcylinders = read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders);
6456 vheads = read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads);
6457
6458 ilba = read_dword(ebda_seg,&EbdaData->cdemu.ilba);
6459
6460 sector = GET_CL() & 0x003f;
6461 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
6462 head = GET_DH();
6463 nbsectors = GET_AL();
6464 segment = ES;
6465 offset = BX;
6466
6467 // no sector to read ?
6468 if(nbsectors==0) goto int13_success;
6469
6470 // sanity checks sco openserver needs this!
6471 if ((sector > vspt)
6472 || (cylinder >= vcylinders)
6473 || (head >= vheads)) {
6474 goto int13_fail;
6475 }
6476
6477 // After controls, verify do nothing
6478 if (GET_AH() == 0x04) goto int13_success;
6479
6480 segment = ES+(BX / 16);
6481 offset = BX % 16;
6482
6483 // calculate the virtual lba inside the image
6484 vlba=((((Bit32u)cylinder*(Bit32u)vheads)+(Bit32u)head)*(Bit32u)vspt)+((Bit32u)(sector-1));
6485
6486 // In advance so we don't loose the count
6487 SET_AL(nbsectors);
6488
6489 // start lba on cd
6490 slba = (Bit32u)vlba/4;
6491 before= (Bit16u)vlba%4;
6492
6493 // end lba on cd
6494 elba = (Bit32u)(vlba+nbsectors-1)/4;
6495
6496 memsetb(get_SS(),atacmd,0,12);
6497 atacmd[0]=0x28; // READ command
6498 atacmd[7]=((Bit16u)(elba-slba+1) & 0xff00) >> 8; // Sectors
6499 atacmd[8]=((Bit16u)(elba-slba+1) & 0x00ff); // Sectors
6500 atacmd[2]=(ilba+slba & 0xff000000) >> 24; // LBA
6501 atacmd[3]=(ilba+slba & 0x00ff0000) >> 16;
6502 atacmd[4]=(ilba+slba & 0x0000ff00) >> 8;
6503 atacmd[5]=(ilba+slba & 0x000000ff);
6504 if((status = ata_cmd_packet(device, 12, get_SS(), atacmd, before*512, nbsectors*512L, ATA_DATA_IN, segment,offset)) != 0) {
6505 BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status);
6506 SET_AH(0x02);
6507 SET_AL(0);
6508 goto int13_fail_noah;
6509 }
6510
6511 goto int13_success;
6512 break;
6513
6514 case 0x08: /* read disk drive parameters */
6515 vspt=read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
6516 vcylinders=read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders) - 1;
6517 vheads=read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads) - 1;
6518
6519 SET_AL( 0x00 );
6520 SET_BL( 0x00 );
6521 SET_CH( vcylinders & 0xff );
6522 SET_CL((( vcylinders >> 2) & 0xc0) | ( vspt & 0x3f ));
6523 SET_DH( vheads );
6524 SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2
6525 // FIXME ElTorito Harddisk. should send the HD count
6526
6527 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
6528 case 0x01: SET_BL( 0x02 ); break;
6529 case 0x02: SET_BL( 0x04 ); break;
6530 case 0x03: SET_BL( 0x06 ); break;
6531 }
6532
6533ASM_START
6534 push bp
6535 mov bp, sp
6536 mov ax, #diskette_param_table2
6537 mov _int13_cdemu.DI+2[bp], ax
6538 mov _int13_cdemu.ES+2[bp], cs
6539 pop bp
6540ASM_END
6541 goto int13_success;
6542 break;
6543
6544 case 0x15: /* read disk drive size */
6545 // FIXME ElTorito Harddisk. What geometry to send ?
6546 SET_AH(0x03);
6547 goto int13_success_noah;
6548 break;
6549
6550 // all those functions return unimplemented
6551 case 0x0a: /* read disk sectors with ECC */
6552 case 0x0b: /* write disk sectors with ECC */
6553 case 0x18: /* set media type for format */
6554 case 0x41: // IBM/MS installation check
6555 // FIXME ElTorito Harddisk. Darwin would like to use EDD
6556 case 0x42: // IBM/MS extended read
6557 case 0x43: // IBM/MS extended write
6558 case 0x44: // IBM/MS verify sectors
6559 case 0x45: // IBM/MS lock/unlock drive
6560 case 0x46: // IBM/MS eject media
6561 case 0x47: // IBM/MS extended seek
6562 case 0x48: // IBM/MS get drive parameters
6563 case 0x49: // IBM/MS extended media change
6564 case 0x4e: // ? - set hardware configuration
6565 case 0x50: // ? - send packet command
6566 default:
6567 BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
6568 goto int13_fail;
6569 break;
6570 }
6571
6572int13_fail:
6573 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6574int13_fail_noah:
6575 SET_DISK_RET_STATUS(GET_AH());
6576int13_fail_nostatus:
6577 SET_CF(); // error occurred
6578 return;
6579
6580int13_success:
6581 SET_AH(0x00); // no error
6582int13_success_noah:
6583 SET_DISK_RET_STATUS(0x00);
6584 CLEAR_CF(); // no error
6585 return;
6586}
6587
6588// ---------------------------------------------------------------------------
6589// End of int13 when emulating a device from the cd
6590// ---------------------------------------------------------------------------
6591
6592#endif // BX_ELTORITO_BOOT
6593
6594#else //BX_USE_ATADRV
6595
6596 void
6597outLBA(cylinder,hd_heads,head,hd_sectors,sector,dl)
6598 Bit16u cylinder;
6599 Bit16u hd_heads;
6600 Bit16u head;
6601 Bit16u hd_sectors;
6602 Bit16u sector;
6603 Bit16u dl;
6604{
6605ASM_START
6606 push bp
6607 mov bp, sp
6608 push eax
6609 push ebx
6610 push edx
6611 xor eax,eax
6612 mov ax,4[bp] // cylinder
6613 xor ebx,ebx
6614 mov bl,6[bp] // hd_heads
6615 imul ebx
6616
6617 mov bl,8[bp] // head
6618 add eax,ebx
6619 mov bl,10[bp] // hd_sectors
6620 imul ebx
6621 mov bl,12[bp] // sector
6622 add eax,ebx
6623
6624 dec eax
6625 mov dx,#0x1f3
6626 out dx,al
6627 mov dx,#0x1f4
6628 mov al,ah
6629 out dx,al
6630 shr eax,#16
6631 mov dx,#0x1f5
6632 out dx,al
6633 and ah,#0xf
6634 mov bl,14[bp] // dl
6635 and bl,#1
6636 shl bl,#4
6637 or ah,bl
6638 or ah,#0xe0
6639 mov al,ah
6640 mov dx,#0x01f6
6641 out dx,al
6642 pop edx
6643 pop ebx
6644 pop eax
6645 pop bp
6646ASM_END
6647}
6648
6649 void
6650int13_harddisk(EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
6651 Bit16u EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
6652{
6653 Bit8u drive, num_sectors, sector, head, status, mod;
6654 Bit8u drive_map;
6655 Bit8u n_drives;
6656 Bit16u cyl_mod, ax;
6657 Bit16u max_cylinder, cylinder, total_sectors;
6658 Bit16u hd_cylinders;
6659 Bit8u hd_heads, hd_sectors;
6660 Bit16u val16;
6661 Bit8u sector_count;
6662 unsigned int i;
6663 Bit16u tempbx;
6664 Bit16u dpsize;
6665
6666 Bit16u count, segment, offset;
6667 Bit32u lba;
6668 Bit16u error;
6669
6670 BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6671
6672 write_byte(0x0040, 0x008e, 0); // clear completion flag
6673
6674 /* at this point, DL is >= 0x80 to be passed from the floppy int13h
6675 handler code */
6676 /* check how many disks first (cmos reg 0x12), return an error if
6677 drive not present */
6678 drive_map = inb_cmos(0x12);
6679 drive_map = (((drive_map & 0xf0)==0) ? 0 : 1) |
6680 (((drive_map & 0x0f)==0) ? 0 : 2);
6681 n_drives = (drive_map==0) ? 0 :
6682 ((drive_map==3) ? 2 : 1);
6683
6684 if (!(drive_map & (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
6685 SET_AH(0x01);
6686 SET_DISK_RET_STATUS(0x01);
6687 SET_CF(); /* error occurred */
6688 return;
6689 }
6690
6691 switch (GET_AH()) {
6692
6693 case 0x00: /* disk controller reset */
6694BX_DEBUG_INT13_HD("int13_f00\n");
6695
6696 SET_AH(0);
6697 SET_DISK_RET_STATUS(0);
6698 set_diskette_ret_status(0);
6699 set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
6700 set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
6701 CLEAR_CF(); /* successful */
6702 return;
6703 break;
6704
6705 case 0x01: /* read disk status */
6706BX_DEBUG_INT13_HD("int13_f01\n");
6707 status = read_byte(0x0040, 0x0074);
6708 SET_AH(status);
6709 SET_DISK_RET_STATUS(0);
6710 /* set CF if error status read */
6711 if (status) SET_CF();
6712 else CLEAR_CF();
6713 return;
6714 break;
6715
6716 case 0x04: // verify disk sectors
6717 case 0x02: // read disk sectors
6718 drive = GET_ELDL();
6719 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6720
6721 num_sectors = GET_AL();
6722 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
6723 sector = (GET_CL() & 0x3f);
6724 head = GET_DH();
6725
6726
6727 if (hd_cylinders > 1024) {
6728 if (hd_cylinders <= 2048) {
6729 cylinder <<= 1;
6730 }
6731 else if (hd_cylinders <= 4096) {
6732 cylinder <<= 2;
6733 }
6734 else if (hd_cylinders <= 8192) {
6735 cylinder <<= 3;
6736 }
6737 else { // hd_cylinders <= 16384
6738 cylinder <<= 4;
6739 }
6740
6741 ax = head / hd_heads;
6742 cyl_mod = ax & 0xff;
6743 head = ax >> 8;
6744 cylinder |= cyl_mod;
6745 }
6746
6747 if ( (cylinder >= hd_cylinders) ||
6748 (sector > hd_sectors) ||
6749 (head >= hd_heads) ) {
6750 SET_AH(1);
6751 SET_DISK_RET_STATUS(1);
6752 SET_CF(); /* error occurred */
6753 return;
6754 }
6755
6756 if ( (num_sectors > 128) || (num_sectors == 0) )
6757 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6758
6759 if (head > 15)
6760 BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
6761
6762 if ( GET_AH() == 0x04 ) {
6763 SET_AH(0);
6764 SET_DISK_RET_STATUS(0);
6765 CLEAR_CF();
6766 return;
6767 }
6768
6769 status = inb(0x1f7);
6770 if (status & 0x80) {
6771 BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
6772 }
6773 outb(0x01f2, num_sectors);
6774 /* activate LBA? (tomv) */
6775 if (hd_heads > 16) {
6776BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder, head, sector);
6777 outLBA(cylinder,hd_heads,head,hd_sectors,sector,drive);
6778 }
6779 else {
6780 outb(0x01f3, sector);
6781 outb(0x01f4, cylinder & 0x00ff);
6782 outb(0x01f5, cylinder >> 8);
6783 outb(0x01f6, 0xa0 | ((drive & 0x01)<<4) | (head & 0x0f));
6784 }
6785 outb(0x01f7, 0x20);
6786
6787 while (1) {
6788 status = inb(0x1f7);
6789 if ( !(status & 0x80) ) break;
6790 }
6791
6792 if (status & 0x01) {
6793 BX_PANIC("hard drive BIOS:(read/verify) read error\n");
6794 } else if ( !(status & 0x08) ) {
6795 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6796 BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
6797 }
6798
6799 sector_count = 0;
6800 tempbx = BX;
6801
6802ASM_START
6803 sti ;; enable higher priority interrupts
6804ASM_END
6805
6806 while (1) {
6807ASM_START
6808 ;; store temp bx in real DI register
6809 push bp
6810 mov bp, sp
6811 mov di, _int13_harddisk.tempbx + 2 [bp]
6812 pop bp
6813
6814 ;; adjust if there will be an overrun
6815 cmp di, #0xfe00
6816 jbe i13_f02_no_adjust
6817i13_f02_adjust:
6818 sub di, #0x0200 ; sub 512 bytes from offset
6819 mov ax, es
6820 add ax, #0x0020 ; add 512 to segment
6821 mov es, ax
6822
6823i13_f02_no_adjust:
6824 mov cx, #0x0100 ;; counter (256 words = 512b)
6825 mov dx, #0x01f0 ;; AT data read port
6826
6827 rep
6828 insw ;; CX words transfered from port(DX) to ES:[DI]
6829
6830i13_f02_done:
6831 ;; store real DI register back to temp bx
6832 push bp
6833 mov bp, sp
6834 mov _int13_harddisk.tempbx + 2 [bp], di
6835 pop bp
6836ASM_END
6837
6838 sector_count++;
6839 num_sectors--;
6840 if (num_sectors == 0) {
6841 status = inb(0x1f7);
6842 if ( (status & 0xc9) != 0x40 )
6843 BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status);
6844 break;
6845 }
6846 else {
6847 status = inb(0x1f7);
6848 if ( (status & 0xc9) != 0x48 )
6849 BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status);
6850 continue;
6851 }
6852 }
6853
6854 SET_AH(0);
6855 SET_DISK_RET_STATUS(0);
6856 SET_AL(sector_count);
6857 CLEAR_CF(); /* successful */
6858 return;
6859 break;
6860
6861
6862 case 0x03: /* write disk sectors */
6863BX_DEBUG_INT13_HD("int13_f03\n");
6864 drive = GET_ELDL ();
6865 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6866
6867 num_sectors = GET_AL();
6868 cylinder = GET_CH();
6869 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
6870 sector = (GET_CL() & 0x3f);
6871 head = GET_DH();
6872
6873 if (hd_cylinders > 1024) {
6874 if (hd_cylinders <= 2048) {
6875 cylinder <<= 1;
6876 }
6877 else if (hd_cylinders <= 4096) {
6878 cylinder <<= 2;
6879 }
6880 else if (hd_cylinders <= 8192) {
6881 cylinder <<= 3;
6882 }
6883 else { // hd_cylinders <= 16384
6884 cylinder <<= 4;
6885 }
6886
6887 ax = head / hd_heads;
6888 cyl_mod = ax & 0xff;
6889 head = ax >> 8;
6890 cylinder |= cyl_mod;
6891 }
6892
6893 if ( (cylinder >= hd_cylinders) ||
6894 (sector > hd_sectors) ||
6895 (head >= hd_heads) ) {
6896 SET_AH( 1);
6897 SET_DISK_RET_STATUS(1);
6898 SET_CF(); /* error occurred */
6899 return;
6900 }
6901
6902 if ( (num_sectors > 128) || (num_sectors == 0) )
6903 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6904
6905 if (head > 15)
6906 BX_PANIC("hard drive BIOS:(read) head > 15\n");
6907
6908 status = inb(0x1f7);
6909 if (status & 0x80) {
6910 BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
6911 }
6912// should check for Drive Ready Bit also in status reg
6913 outb(0x01f2, num_sectors);
6914
6915 /* activate LBA? (tomv) */
6916 if (hd_heads > 16) {
6917BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder, head, sector);
6918 outLBA(cylinder,hd_heads,head,hd_sectors,sector,GET_ELDL());
6919 }
6920 else {
6921 outb(0x01f3, sector);
6922 outb(0x01f4, cylinder & 0x00ff);
6923 outb(0x01f5, cylinder >> 8);
6924 outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head & 0x0f));
6925 }
6926 outb(0x01f7, 0x30);
6927
6928 // wait for busy bit to turn off after seeking
6929 while (1) {
6930 status = inb(0x1f7);
6931 if ( !(status & 0x80) ) break;
6932 }
6933
6934 if ( !(status & 0x08) ) {
6935 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6936 BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
6937 }
6938
6939 sector_count = 0;
6940 tempbx = BX;
6941
6942ASM_START
6943 sti ;; enable higher priority interrupts
6944ASM_END
6945
6946 while (1) {
6947ASM_START
6948 ;; store temp bx in real SI register
6949 push bp
6950 mov bp, sp
6951 mov si, _int13_harddisk.tempbx + 2 [bp]
6952 pop bp
6953
6954 ;; adjust if there will be an overrun
6955 cmp si, #0xfe00
6956 jbe i13_f03_no_adjust
6957i13_f03_adjust:
6958 sub si, #0x0200 ; sub 512 bytes from offset
6959 mov ax, es
6960 add ax, #0x0020 ; add 512 to segment
6961 mov es, ax
6962
6963i13_f03_no_adjust:
6964 mov cx, #0x0100 ;; counter (256 words = 512b)
6965 mov dx, #0x01f0 ;; AT data read port
6966
6967 seg ES
6968 rep
6969 outsw ;; CX words tranfered from ES:[SI] to port(DX)
6970
6971 ;; store real SI register back to temp bx
6972 push bp
6973 mov bp, sp
6974 mov _int13_harddisk.tempbx + 2 [bp], si
6975 pop bp
6976ASM_END
6977
6978 sector_count++;
6979 num_sectors--;
6980 if (num_sectors == 0) {
6981 status = inb(0x1f7);
6982 if ( (status & 0xe9) != 0x40 )
6983 BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status);
6984 break;
6985 }
6986 else {
6987 status = inb(0x1f7);
6988 if ( (status & 0xc9) != 0x48 )
6989 BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status);
6990 continue;
6991 }
6992 }
6993
6994 SET_AH(0);
6995 SET_DISK_RET_STATUS(0);
6996 SET_AL(sector_count);
6997 CLEAR_CF(); /* successful */
6998 return;
6999 break;
7000
7001 case 0x05: /* format disk track */
7002BX_DEBUG_INT13_HD("int13_f05\n");
7003 BX_PANIC("format disk track called\n");
7004 /* nop */
7005 SET_AH(0);
7006 SET_DISK_RET_STATUS(0);
7007 CLEAR_CF(); /* successful */
7008 return;
7009 break;
7010
7011 case 0x08: /* read disk drive parameters */
7012BX_DEBUG_INT13_HD("int13_f08\n");
7013
7014 drive = GET_ELDL ();
7015 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
7016
7017 // translate CHS
7018 //
7019 if (hd_cylinders <= 1024) {
7020 // hd_cylinders >>= 0;
7021 // hd_heads <<= 0;
7022 }
7023 else if (hd_cylinders <= 2048) {
7024 hd_cylinders >>= 1;
7025 hd_heads <<= 1;
7026 }
7027 else if (hd_cylinders <= 4096) {
7028 hd_cylinders >>= 2;
7029 hd_heads <<= 2;
7030 }
7031 else if (hd_cylinders <= 8192) {
7032 hd_cylinders >>= 3;
7033 hd_heads <<= 3;
7034 }
7035 else { // hd_cylinders <= 16384
7036 hd_cylinders >>= 4;
7037 hd_heads <<= 4;
7038 }
7039
7040 max_cylinder = hd_cylinders - 2; /* 0 based */
7041 SET_AL(0);
7042 SET_CH(max_cylinder & 0xff);
7043 SET_CL(((max_cylinder >> 2) & 0xc0) | (hd_sectors & 0x3f));
7044 SET_DH(hd_heads - 1);
7045 SET_DL(n_drives); /* returns 0, 1, or 2 hard drives */
7046 SET_AH(0);
7047 SET_DISK_RET_STATUS(0);
7048 CLEAR_CF(); /* successful */
7049
7050 return;
7051 break;
7052
7053 case 0x09: /* initialize drive parameters */
7054BX_DEBUG_INT13_HD("int13_f09\n");
7055 SET_AH(0);
7056 SET_DISK_RET_STATUS(0);
7057 CLEAR_CF(); /* successful */
7058 return;
7059 break;
7060
7061 case 0x0a: /* read disk sectors with ECC */
7062BX_DEBUG_INT13_HD("int13_f0a\n");
7063 case 0x0b: /* write disk sectors with ECC */
7064BX_DEBUG_INT13_HD("int13_f0b\n");
7065 BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
7066 return;
7067 break;
7068
7069 case 0x0c: /* seek to specified cylinder */
7070BX_DEBUG_INT13_HD("int13_f0c\n");
7071 BX_INFO("int13h function 0ch (seek) not implemented!\n");
7072 SET_AH(0);
7073 SET_DISK_RET_STATUS(0);
7074 CLEAR_CF(); /* successful */
7075 return;
7076 break;
7077
7078 case 0x0d: /* alternate disk reset */
7079BX_DEBUG_INT13_HD("int13_f0d\n");
7080 SET_AH(0);
7081 SET_DISK_RET_STATUS(0);
7082 CLEAR_CF(); /* successful */
7083 return;
7084 break;
7085
7086 case 0x10: /* check drive ready */
7087BX_DEBUG_INT13_HD("int13_f10\n");
7088 //SET_AH(0);
7089 //SET_DISK_RET_STATUS(0);
7090 //CLEAR_CF(); /* successful */
7091 //return;
7092 //break;
7093
7094 // should look at 40:8E also???
7095 status = inb(0x01f7);
7096 if ( (status & 0xc0) == 0x40 ) {
7097 SET_AH(0);
7098 SET_DISK_RET_STATUS(0);
7099 CLEAR_CF(); // drive ready
7100 return;
7101 }
7102 else {
7103 SET_AH(0xAA);
7104 SET_DISK_RET_STATUS(0xAA);
7105 SET_CF(); // not ready
7106 return;
7107 }
7108 break;
7109
7110 case 0x11: /* recalibrate */
7111BX_DEBUG_INT13_HD("int13_f11\n");
7112 SET_AH(0);
7113 SET_DISK_RET_STATUS(0);
7114 CLEAR_CF(); /* successful */
7115 return;
7116 break;
7117
7118 case 0x14: /* controller internal diagnostic */
7119BX_DEBUG_INT13_HD("int13_f14\n");
7120 SET_AH(0);
7121 SET_DISK_RET_STATUS(0);
7122 CLEAR_CF(); /* successful */
7123 SET_AL(0);
7124 return;
7125 break;
7126
7127 case 0x15: /* read disk drive size */
7128 drive = GET_ELDL();
7129 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
7130ASM_START
7131 push bp
7132 mov bp, sp
7133 mov al, _int13_harddisk.hd_heads + 2 [bp]
7134 mov ah, _int13_harddisk.hd_sectors + 2 [bp]
7135 mul al, ah ;; ax = heads * sectors
7136 mov bx, _int13_harddisk.hd_cylinders + 2 [bp]
7137 dec bx ;; use (cylinders - 1) ???
7138 mul ax, bx ;; dx:ax = (cylinders -1) * (heads * sectors)
7139 ;; now we need to move the 32bit result dx:ax to what the
7140 ;; BIOS wants which is cx:dx.
7141 ;; and then into CX:DX on the stack
7142 mov _int13_harddisk.CX + 2 [bp], dx
7143 mov _int13_harddisk.DX + 2 [bp], ax
7144 pop bp
7145ASM_END
7146 SET_AH(3); // hard disk accessible
7147 SET_DISK_RET_STATUS(0); // ??? should this be 0
7148 CLEAR_CF(); // successful
7149 return;
7150 break;
7151
7152 case 0x18: // set media type for format
7153 case 0x41: // IBM/MS
7154 case 0x42: // IBM/MS
7155 case 0x43: // IBM/MS
7156 case 0x44: // IBM/MS
7157 case 0x45: // IBM/MS lock/unlock drive
7158 case 0x46: // IBM/MS eject media
7159 case 0x47: // IBM/MS extended seek
7160 case 0x49: // IBM/MS extended media change
7161 case 0x50: // IBM/MS send packet command
7162 default:
7163 BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
7164
7165 SET_AH(1); // code=invalid function in AH or invalid parameter
7166 SET_DISK_RET_STATUS(1);
7167 SET_CF(); /* unsuccessful */
7168 return;
7169 break;
7170 }
7171}
7172
7173static char panic_msg_reg12h[] = "HD%d cmos reg 12h not type F\n";
7174static char panic_msg_reg19h[] = "HD%d cmos reg %02xh not user definable type 47\n";
7175
7176 void
7177get_hd_geometry(drive, hd_cylinders, hd_heads, hd_sectors)
7178 Bit8u drive;
7179 Bit16u *hd_cylinders;
7180 Bit8u *hd_heads;
7181 Bit8u *hd_sectors;
7182{
7183 Bit8u hd_type;
7184 Bit16u ss;
7185 Bit16u cylinders;
7186 Bit8u iobase;
7187
7188 ss = get_SS();
7189 if (drive == 0x80) {
7190 hd_type = inb_cmos(0x12) & 0xf0;
7191 if (hd_type != 0xf0)
7192 BX_INFO(panic_msg_reg12h,0);
7193 hd_type = inb_cmos(0x19); // HD0: extended type
7194 if (hd_type != 47)
7195 BX_INFO(panic_msg_reg19h,0,0x19);
7196 iobase = 0x1b;
7197 } else {
7198 hd_type = inb_cmos(0x12) & 0x0f;
7199 if (hd_type != 0x0f)
7200 BX_INFO(panic_msg_reg12h,1);
7201 hd_type = inb_cmos(0x1a); // HD1: extended type
7202 if (hd_type != 47)
7203 BX_INFO(panic_msg_reg19h,0,0x1a);
7204 iobase = 0x24;
7205 }
7206
7207 // cylinders
7208 cylinders = inb_cmos(iobase) | (inb_cmos(iobase+1) << 8);
7209 write_word(ss, hd_cylinders, cylinders);
7210
7211 // heads
7212 write_byte(ss, hd_heads, inb_cmos(iobase+2));
7213
7214 // sectors per track
7215 write_byte(ss, hd_sectors, inb_cmos(iobase+8));
7216}
7217
7218#endif //else BX_USE_ATADRV
7219
7220#if BX_SUPPORT_FLOPPY
7221
7222//////////////////////
7223// FLOPPY functions //
7224//////////////////////
7225
7226void floppy_reset_controller()
7227{
7228 Bit8u val8;
7229
7230 // Reset controller
7231 val8 = inb(0x03f2);
7232 outb(0x03f2, val8 & ~0x04);
7233 outb(0x03f2, val8 | 0x04);
7234
7235 // Wait for controller to come out of reset
7236 do {
7237 val8 = inb(0x3f4);
7238 } while ( (val8 & 0xc0) != 0x80 );
7239}
7240
7241void floppy_prepare_controller(drive)
7242 Bit16u drive;
7243{
7244 Bit8u val8, dor, prev_reset;
7245
7246 // set 40:3e bit 7 to 0
7247 val8 = read_byte(0x0040, 0x003e);
7248 val8 &= 0x7f;
7249 write_byte(0x0040, 0x003e, val8);
7250
7251 // turn on motor of selected drive, DMA & int enabled, normal operation
7252 prev_reset = inb(0x03f2) & 0x04;
7253 if (drive)
7254 dor = 0x20;
7255 else
7256 dor = 0x10;
7257 dor |= 0x0c;
7258 dor |= drive;
7259 outb(0x03f2, dor);
7260
7261 // reset the disk motor timeout value of INT 08
7262 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
7263
7264#ifdef VBOX
7265 // program data rate
7266 val8 = read_byte(0x0040, 0x008b);
7267 val8 >>= 6;
7268 outb(0x03f7, val8);
7269#endif
7270
7271 // wait for drive readiness
7272 do {
7273 val8 = inb(0x3f4);
7274 } while ( (val8 & 0xc0) != 0x80 );
7275
7276 if (prev_reset == 0) {
7277 // turn on interrupts
7278ASM_START
7279 sti
7280ASM_END
7281 // wait on 40:3e bit 7 to become 1
7282 do {
7283 val8 = read_byte(0x0040, 0x003e);
7284 } while ( (val8 & 0x80) == 0 );
7285 val8 &= 0x7f;
7286ASM_START
7287 cli
7288ASM_END
7289 write_byte(0x0040, 0x003e, val8);
7290 }
7291}
7292
7293 bx_bool
7294floppy_media_known(drive)
7295 Bit16u drive;
7296{
7297 Bit8u val8;
7298 Bit16u media_state_offset;
7299
7300 val8 = read_byte(0x0040, 0x003e); // diskette recal status
7301 if (drive)
7302 val8 >>= 1;
7303 val8 &= 0x01;
7304 if (val8 == 0)
7305 return(0);
7306
7307 media_state_offset = 0x0090;
7308 if (drive)
7309 media_state_offset += 1;
7310
7311 val8 = read_byte(0x0040, media_state_offset);
7312 val8 = (val8 >> 4) & 0x01;
7313 if (val8 == 0)
7314 return(0);
7315
7316 // check pass, return KNOWN
7317 return(1);
7318}
7319
7320 bx_bool
7321floppy_media_sense(drive)
7322 Bit16u drive;
7323{
7324 bx_bool retval;
7325 Bit16u media_state_offset;
7326 Bit8u drive_type, config_data, media_state;
7327
7328 if (floppy_drive_recal(drive) == 0) {
7329 return(0);
7330 }
7331
7332 // for now cheat and get drive type from CMOS,
7333 // assume media is same as drive type
7334
7335 // ** config_data **
7336 // Bitfields for diskette media control:
7337 // Bit(s) Description (Table M0028)
7338 // 7-6 last data rate set by controller
7339 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
7340 // 5-4 last diskette drive step rate selected
7341 // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
7342 // 3-2 {data rate at start of operation}
7343 // 1-0 reserved
7344
7345 // ** media_state **
7346 // Bitfields for diskette drive media state:
7347 // Bit(s) Description (Table M0030)
7348 // 7-6 data rate
7349 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
7350 // 5 double stepping required (e.g. 360kB in 1.2MB)
7351 // 4 media type established
7352 // 3 drive capable of supporting 4MB media
7353 // 2-0 on exit from BIOS, contains
7354 // 000 trying 360kB in 360kB
7355 // 001 trying 360kB in 1.2MB
7356 // 010 trying 1.2MB in 1.2MB
7357 // 011 360kB in 360kB established
7358 // 100 360kB in 1.2MB established
7359 // 101 1.2MB in 1.2MB established
7360 // 110 reserved
7361 // 111 all other formats/drives
7362
7363 drive_type = inb_cmos(0x10);
7364 if (drive == 0)
7365 drive_type >>= 4;
7366 else
7367 drive_type &= 0x0f;
7368 if ( drive_type == 1 ) {
7369 // 360K 5.25" drive
7370 config_data = 0x00; // 0000 0000
7371 media_state = 0x25; // 0010 0101
7372 retval = 1;
7373 }
7374 else if ( drive_type == 2 ) {
7375 // 1.2 MB 5.25" drive
7376 config_data = 0x00; // 0000 0000
7377 media_state = 0x25; // 0010 0101 // need double stepping??? (bit 5)
7378 retval = 1;
7379 }
7380 else if ( drive_type == 3 ) {
7381 // 720K 3.5" drive
7382 config_data = 0x00; // 0000 0000 ???
7383 media_state = 0x17; // 0001 0111
7384 retval = 1;
7385 }
7386 else if ( drive_type == 4 ) {
7387 // 1.44 MB 3.5" drive
7388 config_data = 0x00; // 0000 0000
7389 media_state = 0x17; // 0001 0111
7390 retval = 1;
7391 }
7392 else if ( drive_type == 5 ) {
7393 // 2.88 MB 3.5" drive
7394 config_data = 0xCC; // 1100 1100
7395 media_state = 0xD7; // 1101 0111
7396 retval = 1;
7397 }
7398 //
7399 // Extended floppy size uses special cmos setting
7400 else if ( drive_type == 6 ) {
7401 // 160k 5.25" drive
7402 config_data = 0x00; // 0000 0000
7403 media_state = 0x27; // 0010 0111
7404 retval = 1;
7405 }
7406 else if ( drive_type == 7 ) {
7407 // 180k 5.25" drive
7408 config_data = 0x00; // 0000 0000
7409 media_state = 0x27; // 0010 0111
7410 retval = 1;
7411 }
7412 else if ( drive_type == 8 ) {
7413 // 320k 5.25" drive
7414 config_data = 0x00; // 0000 0000
7415 media_state = 0x27; // 0010 0111
7416 retval = 1;
7417 }
7418
7419 else {
7420 // not recognized
7421 config_data = 0x00; // 0000 0000
7422 media_state = 0x00; // 0000 0000
7423 retval = 0;
7424 }
7425
7426 if (drive == 0)
7427 media_state_offset = 0x90;
7428 else
7429 media_state_offset = 0x91;
7430 write_byte(0x0040, 0x008B, config_data);
7431 write_byte(0x0040, media_state_offset, media_state);
7432
7433 return(retval);
7434}
7435
7436 bx_bool
7437floppy_drive_recal(drive)
7438 Bit16u drive;
7439{
7440 Bit8u val8;
7441 Bit16u curr_cyl_offset;
7442
7443 floppy_prepare_controller(drive);
7444
7445 // send Recalibrate command (2 bytes) to controller
7446 outb(0x03f5, 0x07); // 07: Recalibrate
7447 outb(0x03f5, drive); // 0=drive0, 1=drive1
7448
7449 // turn on interrupts
7450ASM_START
7451 sti
7452ASM_END
7453
7454 // wait on 40:3e bit 7 to become 1
7455 do {
7456 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7457 } while ( val8 == 0 );
7458
7459 val8 = 0; // separate asm from while() loop
7460 // turn off interrupts
7461ASM_START
7462 cli
7463ASM_END
7464
7465 // set 40:3e bit 7 to 0, and calibrated bit
7466 val8 = read_byte(0x0040, 0x003e);
7467 val8 &= 0x7f;
7468 if (drive) {
7469 val8 |= 0x02; // Drive 1 calibrated
7470 curr_cyl_offset = 0x0095;
7471 } else {
7472 val8 |= 0x01; // Drive 0 calibrated
7473 curr_cyl_offset = 0x0094;
7474 }
7475 write_byte(0x0040, 0x003e, val8);
7476 write_byte(0x0040, curr_cyl_offset, 0); // current cylinder is 0
7477
7478 return(1);
7479}
7480
7481
7482
7483 bx_bool
7484floppy_drive_exists(drive)
7485 Bit16u drive;
7486{
7487 Bit8u drive_type;
7488
7489 // check CMOS to see if drive exists
7490 drive_type = inb_cmos(0x10);
7491 if (drive == 0)
7492 drive_type >>= 4;
7493 else
7494 drive_type &= 0x0f;
7495 if ( drive_type == 0 )
7496 return(0);
7497 else
7498 return(1);
7499}
7500
7501 void
7502int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
7503 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
7504{
7505 Bit8u drive, num_sectors, track, sector, head, status;
7506 Bit16u base_address, base_count, base_es;
7507 Bit8u page, mode_register, val8, dor;
7508 Bit8u return_status[7];
7509 Bit8u drive_type, num_floppies, ah;
7510 Bit16u es, last_addr;
7511
7512 BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
7513
7514 ah = GET_AH();
7515
7516 switch ( ah ) {
7517 case 0x00: // diskette controller reset
7518BX_DEBUG_INT13_FL("floppy f00\n");
7519 drive = GET_ELDL();
7520 if (drive > 1) {
7521 SET_AH(1); // invalid param
7522 set_diskette_ret_status(1);
7523 SET_CF();
7524 return;
7525 }
7526 drive_type = inb_cmos(0x10);
7527
7528 if (drive == 0)
7529 drive_type >>= 4;
7530 else
7531 drive_type &= 0x0f;
7532 if (drive_type == 0) {
7533 SET_AH(0x80); // drive not responding
7534 set_diskette_ret_status(0x80);
7535 SET_CF();
7536 return;
7537 }
7538 SET_AH(0);
7539 set_diskette_ret_status(0);
7540 CLEAR_CF(); // successful
7541 set_diskette_current_cyl(drive, 0); // current cylinder
7542 return;
7543
7544 case 0x01: // Read Diskette Status
7545 CLEAR_CF();
7546 val8 = read_byte(0x0000, 0x0441);
7547 SET_AH(val8);
7548 if (val8) {
7549 SET_CF();
7550 }
7551 return;
7552
7553 case 0x02: // Read Diskette Sectors
7554 case 0x03: // Write Diskette Sectors
7555 case 0x04: // Verify Diskette Sectors
7556 num_sectors = GET_AL();
7557 track = GET_CH();
7558 sector = GET_CL();
7559 head = GET_DH();
7560 drive = GET_ELDL();
7561
7562 if ( (drive > 1) || (head > 1) ||
7563 (num_sectors == 0) || (num_sectors > 72) ) {
7564BX_INFO("floppy: drive>1 || head>1 ...\n");
7565 SET_AH(1);
7566 set_diskette_ret_status(1);
7567 SET_AL(0); // no sectors read
7568 SET_CF(); // error occurred
7569 return;
7570 }
7571
7572 // see if drive exists
7573 if (floppy_drive_exists(drive) == 0) {
7574 SET_AH(0x80); // not responding
7575 set_diskette_ret_status(0x80);
7576 SET_AL(0); // no sectors read
7577 SET_CF(); // error occurred
7578 return;
7579 }
7580
7581 // see if media in drive, and type is known
7582 if (floppy_media_known(drive) == 0) {
7583 if (floppy_media_sense(drive) == 0) {
7584 SET_AH(0x0C); // Media type not found
7585 set_diskette_ret_status(0x0C);
7586 SET_AL(0); // no sectors read
7587 SET_CF(); // error occurred
7588 return;
7589 }
7590 }
7591
7592 if (ah == 0x02) {
7593 // Read Diskette Sectors
7594
7595 //-----------------------------------
7596 // set up DMA controller for transfer
7597 //-----------------------------------
7598
7599 // es:bx = pointer to where to place information from diskette
7600 // port 04: DMA-1 base and current address, channel 2
7601 // port 05: DMA-1 base and current count, channel 2
7602 page = (ES >> 12); // upper 4 bits
7603 base_es = (ES << 4); // lower 16bits contributed by ES
7604 base_address = base_es + BX; // lower 16 bits of address
7605 // contributed by ES:BX
7606 if ( base_address < base_es ) {
7607 // in case of carry, adjust page by 1
7608 page++;
7609 }
7610 base_count = (num_sectors * 512) - 1;
7611
7612 // check for 64K boundary overrun
7613 last_addr = base_address + base_count;
7614 if (last_addr < base_address) {
7615 SET_AH(0x09);
7616 set_diskette_ret_status(0x09);
7617 SET_AL(0); // no sectors read
7618 SET_CF(); // error occurred
7619 return;
7620 }
7621
7622 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7623 outb(0x000a, 0x06);
7624
7625 BX_DEBUG_INT13_FL("clear flip-flop\n");
7626 outb(0x000c, 0x00); // clear flip-flop
7627 outb(0x0004, base_address);
7628 outb(0x0004, base_address>>8);
7629 BX_DEBUG_INT13_FL("clear flip-flop\n");
7630 outb(0x000c, 0x00); // clear flip-flop
7631 outb(0x0005, base_count);
7632 outb(0x0005, base_count>>8);
7633
7634 // port 0b: DMA-1 Mode Register
7635 mode_register = 0x46; // single mode, increment, autoinit disable,
7636 // transfer type=write, channel 2
7637 BX_DEBUG_INT13_FL("setting mode register\n");
7638 outb(0x000b, mode_register);
7639
7640 BX_DEBUG_INT13_FL("setting page register\n");
7641 // port 81: DMA-1 Page Register, channel 2
7642 outb(0x0081, page);
7643
7644 BX_DEBUG_INT13_FL("unmask chan 2\n");
7645 outb(0x000a, 0x02); // unmask channel 2
7646
7647 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7648 outb(0x000a, 0x02);
7649
7650 //--------------------------------------
7651 // set up floppy controller for transfer
7652 //--------------------------------------
7653 floppy_prepare_controller(drive);
7654
7655 // send read-normal-data command (9 bytes) to controller
7656 outb(0x03f5, 0xe6); // e6: read normal data
7657 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7658 outb(0x03f5, track);
7659 outb(0x03f5, head);
7660 outb(0x03f5, sector);
7661 outb(0x03f5, 2); // 512 byte sector size
7662 outb(0x03f5, sector + num_sectors - 1); // last sector to read on track
7663 outb(0x03f5, 0); // Gap length
7664 outb(0x03f5, 0xff); // Gap length
7665
7666 // turn on interrupts
7667 ASM_START
7668 sti
7669 ASM_END
7670
7671 // wait on 40:3e bit 7 to become 1
7672 do {
7673 val8 = read_byte(0x0040, 0x0040);
7674 if (val8 == 0) {
7675 floppy_reset_controller();
7676 SET_AH(0x80); // drive not ready (timeout)
7677 set_diskette_ret_status(0x80);
7678 SET_AL(0); // no sectors read
7679 SET_CF(); // error occurred
7680 return;
7681 }
7682 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7683 } while ( val8 == 0 );
7684
7685 val8 = 0; // separate asm from while() loop
7686 // turn off interrupts
7687 ASM_START
7688 cli
7689 ASM_END
7690
7691 // set 40:3e bit 7 to 0
7692 val8 = read_byte(0x0040, 0x003e);
7693 val8 &= 0x7f;
7694 write_byte(0x0040, 0x003e, val8);
7695
7696 // check port 3f4 for accessibility to status bytes
7697 val8 = inb(0x3f4);
7698 if ( (val8 & 0xc0) != 0xc0 )
7699 BX_PANIC("int13_diskette: ctrl not ready\n");
7700
7701 // read 7 return status bytes from controller
7702 // using loop index broken, have to unroll...
7703 return_status[0] = inb(0x3f5);
7704 return_status[1] = inb(0x3f5);
7705 return_status[2] = inb(0x3f5);
7706 return_status[3] = inb(0x3f5);
7707 return_status[4] = inb(0x3f5);
7708 return_status[5] = inb(0x3f5);
7709 return_status[6] = inb(0x3f5);
7710 // record in BIOS Data Area
7711 write_byte(0x0040, 0x0042, return_status[0]);
7712 write_byte(0x0040, 0x0043, return_status[1]);
7713 write_byte(0x0040, 0x0044, return_status[2]);
7714 write_byte(0x0040, 0x0045, return_status[3]);
7715 write_byte(0x0040, 0x0046, return_status[4]);
7716 write_byte(0x0040, 0x0047, return_status[5]);
7717 write_byte(0x0040, 0x0048, return_status[6]);
7718
7719 if ( (return_status[0] & 0xc0) != 0 ) {
7720 SET_AH(0x20);
7721 set_diskette_ret_status(0x20);
7722 SET_AL(0); // no sectors read
7723 SET_CF(); // error occurred
7724 return;
7725 }
7726
7727 // ??? should track be new val from return_status[3] ?
7728 set_diskette_current_cyl(drive, track);
7729 // AL = number of sectors read (same value as passed)
7730 SET_AH(0x00); // success
7731 CLEAR_CF(); // success
7732 return;
7733 } else if (ah == 0x03) {
7734 // Write Diskette Sectors
7735
7736 //-----------------------------------
7737 // set up DMA controller for transfer
7738 //-----------------------------------
7739
7740 // es:bx = pointer to where to place information from diskette
7741 // port 04: DMA-1 base and current address, channel 2
7742 // port 05: DMA-1 base and current count, channel 2
7743 page = (ES >> 12); // upper 4 bits
7744 base_es = (ES << 4); // lower 16bits contributed by ES
7745 base_address = base_es + BX; // lower 16 bits of address
7746 // contributed by ES:BX
7747 if ( base_address < base_es ) {
7748 // in case of carry, adjust page by 1
7749 page++;
7750 }
7751 base_count = (num_sectors * 512) - 1;
7752
7753 // check for 64K boundary overrun
7754 last_addr = base_address + base_count;
7755 if (last_addr < base_address) {
7756 SET_AH(0x09);
7757 set_diskette_ret_status(0x09);
7758 SET_AL(0); // no sectors read
7759 SET_CF(); // error occurred
7760 return;
7761 }
7762
7763 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7764 outb(0x000a, 0x06);
7765
7766 outb(0x000c, 0x00); // clear flip-flop
7767 outb(0x0004, base_address);
7768 outb(0x0004, base_address>>8);
7769 outb(0x000c, 0x00); // clear flip-flop
7770 outb(0x0005, base_count);
7771 outb(0x0005, base_count>>8);
7772
7773 // port 0b: DMA-1 Mode Register
7774 mode_register = 0x4a; // single mode, increment, autoinit disable,
7775 // transfer type=read, channel 2
7776 outb(0x000b, mode_register);
7777
7778 // port 81: DMA-1 Page Register, channel 2
7779 outb(0x0081, page);
7780
7781 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7782 outb(0x000a, 0x02);
7783
7784 //--------------------------------------
7785 // set up floppy controller for transfer
7786 //--------------------------------------
7787 floppy_prepare_controller(drive);
7788
7789 // send write-normal-data command (9 bytes) to controller
7790 outb(0x03f5, 0xc5); // c5: write normal data
7791 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7792 outb(0x03f5, track);
7793 outb(0x03f5, head);
7794 outb(0x03f5, sector);
7795 outb(0x03f5, 2); // 512 byte sector size
7796 outb(0x03f5, sector + num_sectors - 1); // last sector to write on track
7797 outb(0x03f5, 0); // Gap length
7798 outb(0x03f5, 0xff); // Gap length
7799
7800 // turn on interrupts
7801 ASM_START
7802 sti
7803 ASM_END
7804
7805 // wait on 40:3e bit 7 to become 1
7806 do {
7807 val8 = read_byte(0x0040, 0x0040);
7808 if (val8 == 0) {
7809 floppy_reset_controller();
7810 SET_AH(0x80); // drive not ready (timeout)
7811 set_diskette_ret_status(0x80);
7812 SET_AL(0); // no sectors written
7813 SET_CF(); // error occurred
7814 return;
7815 }
7816 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7817 } while ( val8 == 0 );
7818
7819 val8 = 0; // separate asm from while() loop
7820 // turn off interrupts
7821 ASM_START
7822 cli
7823 ASM_END
7824
7825 // set 40:3e bit 7 to 0
7826 val8 = read_byte(0x0040, 0x003e);
7827 val8 &= 0x7f;
7828 write_byte(0x0040, 0x003e, val8);
7829
7830 // check port 3f4 for accessibility to status bytes
7831 val8 = inb(0x3f4);
7832 if ( (val8 & 0xc0) != 0xc0 )
7833 BX_PANIC("int13_diskette: ctrl not ready\n");
7834
7835 // read 7 return status bytes from controller
7836 // using loop index broken, have to unroll...
7837 return_status[0] = inb(0x3f5);
7838 return_status[1] = inb(0x3f5);
7839 return_status[2] = inb(0x3f5);
7840 return_status[3] = inb(0x3f5);
7841 return_status[4] = inb(0x3f5);
7842 return_status[5] = inb(0x3f5);
7843 return_status[6] = inb(0x3f5);
7844 // record in BIOS Data Area
7845 write_byte(0x0040, 0x0042, return_status[0]);
7846 write_byte(0x0040, 0x0043, return_status[1]);
7847 write_byte(0x0040, 0x0044, return_status[2]);
7848 write_byte(0x0040, 0x0045, return_status[3]);
7849 write_byte(0x0040, 0x0046, return_status[4]);
7850 write_byte(0x0040, 0x0047, return_status[5]);
7851 write_byte(0x0040, 0x0048, return_status[6]);
7852
7853 if ( (return_status[0] & 0xc0) != 0 ) {
7854 if ( (return_status[1] & 0x02) != 0 ) {
7855 // diskette not writable.
7856 // AH=status code=0x03 (tried to write on write-protected disk)
7857 // AL=number of sectors written=0
7858 AX = 0x0300;
7859 SET_CF();
7860 return;
7861 } else {
7862 BX_PANIC("int13_diskette_function: read error\n");
7863 }
7864 }
7865
7866 // ??? should track be new val from return_status[3] ?
7867 set_diskette_current_cyl(drive, track);
7868 // AL = number of sectors read (same value as passed)
7869 SET_AH(0x00); // success
7870 CLEAR_CF(); // success
7871 return;
7872 } else { // if (ah == 0x04)
7873 // Verify Diskette Sectors
7874
7875 // ??? should track be new val from return_status[3] ?
7876 set_diskette_current_cyl(drive, track);
7877 // AL = number of sectors verified (same value as passed)
7878 CLEAR_CF(); // success
7879 SET_AH(0x00); // success
7880 return;
7881 }
7882 break;
7883
7884 case 0x05: // format diskette track
7885BX_DEBUG_INT13_FL("floppy f05\n");
7886
7887 num_sectors = GET_AL();
7888 track = GET_CH();
7889 head = GET_DH();
7890 drive = GET_ELDL();
7891
7892 if ((drive > 1) || (head > 1) || (track > 79) ||
7893 (num_sectors == 0) || (num_sectors > 18)) {
7894 SET_AH(1);
7895 set_diskette_ret_status(1);
7896 SET_CF(); // error occurred
7897 }
7898
7899 // see if drive exists
7900 if (floppy_drive_exists(drive) == 0) {
7901 SET_AH(0x80); // drive not responding
7902 set_diskette_ret_status(0x80);
7903 SET_CF(); // error occurred
7904 return;
7905 }
7906
7907 // see if media in drive, and type is known
7908 if (floppy_media_known(drive) == 0) {
7909 if (floppy_media_sense(drive) == 0) {
7910 SET_AH(0x0C); // Media type not found
7911 set_diskette_ret_status(0x0C);
7912 SET_AL(0); // no sectors read
7913 SET_CF(); // error occurred
7914 return;
7915 }
7916 }
7917
7918 // set up DMA controller for transfer
7919 page = (ES >> 12); // upper 4 bits
7920 base_es = (ES << 4); // lower 16bits contributed by ES
7921 base_address = base_es + BX; // lower 16 bits of address
7922 // contributed by ES:BX
7923 if ( base_address < base_es ) {
7924 // in case of carry, adjust page by 1
7925 page++;
7926 }
7927 base_count = (num_sectors * 4) - 1;
7928
7929 // check for 64K boundary overrun
7930 last_addr = base_address + base_count;
7931 if (last_addr < base_address) {
7932 SET_AH(0x09);
7933 set_diskette_ret_status(0x09);
7934 SET_AL(0); // no sectors read
7935 SET_CF(); // error occurred
7936 return;
7937 }
7938
7939 outb(0x000a, 0x06);
7940 outb(0x000c, 0x00); // clear flip-flop
7941 outb(0x0004, base_address);
7942 outb(0x0004, base_address>>8);
7943 outb(0x000c, 0x00); // clear flip-flop
7944 outb(0x0005, base_count);
7945 outb(0x0005, base_count>>8);
7946 mode_register = 0x4a; // single mode, increment, autoinit disable,
7947 // transfer type=read, channel 2
7948 outb(0x000b, mode_register);
7949 // port 81: DMA-1 Page Register, channel 2
7950 outb(0x0081, page);
7951 outb(0x000a, 0x02);
7952
7953 // set up floppy controller for transfer
7954 floppy_prepare_controller(drive);
7955
7956 // send format-track command (6 bytes) to controller
7957 outb(0x03f5, 0x4d); // 4d: format track
7958 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7959 outb(0x03f5, 2); // 512 byte sector size
7960 outb(0x03f5, num_sectors); // number of sectors per track
7961 outb(0x03f5, 0); // Gap length
7962 outb(0x03f5, 0xf6); // Fill byte
7963 // turn on interrupts
7964 ASM_START
7965 sti
7966 ASM_END
7967
7968 // wait on 40:3e bit 7 to become 1
7969 do {
7970 val8 = read_byte(0x0040, 0x0040);
7971 if (val8 == 0) {
7972 floppy_reset_controller();
7973 SET_AH(0x80); // drive not ready (timeout)
7974 set_diskette_ret_status(0x80);
7975 SET_CF(); // error occurred
7976 return;
7977 }
7978 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7979 } while ( val8 == 0 );
7980
7981 val8 = 0; // separate asm from while() loop
7982 // turn off interrupts
7983 ASM_START
7984 cli
7985 ASM_END
7986 // set 40:3e bit 7 to 0
7987 val8 = read_byte(0x0040, 0x003e);
7988 val8 &= 0x7f;
7989 write_byte(0x0040, 0x003e, val8);
7990 // check port 3f4 for accessibility to status bytes
7991 val8 = inb(0x3f4);
7992 if ( (val8 & 0xc0) != 0xc0 )
7993 BX_PANIC("int13_diskette: ctrl not ready\n");
7994
7995 // read 7 return status bytes from controller
7996 // using loop index broken, have to unroll...
7997 return_status[0] = inb(0x3f5);
7998 return_status[1] = inb(0x3f5);
7999 return_status[2] = inb(0x3f5);
8000 return_status[3] = inb(0x3f5);
8001 return_status[4] = inb(0x3f5);
8002 return_status[5] = inb(0x3f5);
8003 return_status[6] = inb(0x3f5);
8004 // record in BIOS Data Area
8005 write_byte(0x0040, 0x0042, return_status[0]);
8006 write_byte(0x0040, 0x0043, return_status[1]);
8007 write_byte(0x0040, 0x0044, return_status[2]);
8008 write_byte(0x0040, 0x0045, return_status[3]);
8009 write_byte(0x0040, 0x0046, return_status[4]);
8010 write_byte(0x0040, 0x0047, return_status[5]);
8011 write_byte(0x0040, 0x0048, return_status[6]);
8012
8013 if ( (return_status[0] & 0xc0) != 0 ) {
8014 if ( (return_status[1] & 0x02) != 0 ) {
8015 // diskette not writable.
8016 // AH=status code=0x03 (tried to write on write-protected disk)
8017 // AL=number of sectors written=0
8018 AX = 0x0300;
8019 SET_CF();
8020 return;
8021 } else {
8022 BX_PANIC("int13_diskette_function: write error\n");
8023 }
8024 }
8025
8026 SET_AH(0);
8027 set_diskette_ret_status(0);
8028 set_diskette_current_cyl(drive, 0);
8029 CLEAR_CF(); // successful
8030 return;
8031
8032
8033 case 0x08: // read diskette drive parameters
8034BX_DEBUG_INT13_FL("floppy f08\n");
8035 drive = GET_ELDL();
8036
8037 if (drive > 1) {
8038 AX = 0;
8039 BX = 0;
8040 CX = 0;
8041 DX = 0;
8042 ES = 0;
8043 DI = 0;
8044 SET_DL(num_floppies);
8045 SET_CF();
8046 return;
8047 }
8048
8049 drive_type = inb_cmos(0x10);
8050 num_floppies = 0;
8051 if (drive_type & 0xf0)
8052 num_floppies++;
8053 if (drive_type & 0x0f)
8054 num_floppies++;
8055
8056 if (drive == 0)
8057 drive_type >>= 4;
8058 else
8059 drive_type &= 0x0f;
8060
8061 SET_BH(0);
8062 SET_BL(drive_type);
8063 SET_AH(0);
8064 SET_AL(0);
8065 SET_DL(num_floppies);
8066
8067 switch (drive_type) {
8068 case 0: // none
8069 CX = 0;
8070 SET_DH(0); // max head #
8071 break;
8072
8073 case 1: // 360KB, 5.25"
8074 CX = 0x2709; // 40 tracks, 9 sectors
8075 SET_DH(1); // max head #
8076 break;
8077
8078 case 2: // 1.2MB, 5.25"
8079 CX = 0x4f0f; // 80 tracks, 15 sectors
8080 SET_DH(1); // max head #
8081 break;
8082
8083 case 3: // 720KB, 3.5"
8084 CX = 0x4f09; // 80 tracks, 9 sectors
8085 SET_DH(1); // max head #
8086 break;
8087
8088 case 4: // 1.44MB, 3.5"
8089 CX = 0x4f12; // 80 tracks, 18 sectors
8090 SET_DH(1); // max head #
8091 break;
8092
8093 case 5: // 2.88MB, 3.5"
8094 CX = 0x4f24; // 80 tracks, 36 sectors
8095 SET_DH(1); // max head #
8096 break;
8097
8098 case 6: // 160k, 5.25"
8099 CX = 0x2708; // 40 tracks, 8 sectors
8100 SET_DH(0); // max head #
8101 break;
8102
8103 case 7: // 180k, 5.25"
8104 CX = 0x2709; // 40 tracks, 9 sectors
8105 SET_DH(0); // max head #
8106 break;
8107
8108 case 8: // 320k, 5.25"
8109 CX = 0x2708; // 40 tracks, 8 sectors
8110 SET_DH(1); // max head #
8111 break;
8112
8113 default: // ?
8114 BX_PANIC("floppy: int13: bad floppy type\n");
8115 }
8116
8117 /* set es & di to point to 11 byte diskette param table in ROM */
8118ASM_START
8119 push bp
8120 mov bp, sp
8121 mov ax, #diskette_param_table2
8122 mov _int13_diskette_function.DI+2[bp], ax
8123 mov _int13_diskette_function.ES+2[bp], cs
8124 pop bp
8125ASM_END
8126 CLEAR_CF(); // success
8127 /* disk status not changed upon success */
8128 return;
8129
8130
8131 case 0x15: // read diskette drive type
8132BX_DEBUG_INT13_FL("floppy f15\n");
8133 drive = GET_ELDL();
8134 if (drive > 1) {
8135 SET_AH(0); // only 2 drives supported
8136 // set_diskette_ret_status here ???
8137 SET_CF();
8138 return;
8139 }
8140 drive_type = inb_cmos(0x10);
8141
8142 if (drive == 0)
8143 drive_type >>= 4;
8144 else
8145 drive_type &= 0x0f;
8146 CLEAR_CF(); // successful, not present
8147 if (drive_type==0) {
8148 SET_AH(0); // drive not present
8149 }
8150 else {
8151 SET_AH(1); // drive present, does not support change line
8152 }
8153
8154 return;
8155
8156 case 0x16: // get diskette change line status
8157BX_DEBUG_INT13_FL("floppy f16\n");
8158 drive = GET_ELDL();
8159 if (drive > 1) {
8160 SET_AH(0x01); // invalid drive
8161 set_diskette_ret_status(0x01);
8162 SET_CF();
8163 return;
8164 }
8165
8166 SET_AH(0x06); // change line not supported
8167 set_diskette_ret_status(0x06);
8168 SET_CF();
8169 return;
8170
8171 case 0x17: // set diskette type for format(old)
8172BX_DEBUG_INT13_FL("floppy f17\n");
8173 /* not used for 1.44M floppies */
8174 SET_AH(0x01); // not supported
8175 set_diskette_ret_status(1); /* not supported */
8176 SET_CF();
8177 return;
8178
8179 case 0x18: // set diskette type for format(new)
8180BX_DEBUG_INT13_FL("floppy f18\n");
8181 SET_AH(0x01); // do later
8182 set_diskette_ret_status(1);
8183 SET_CF();
8184 return;
8185
8186 default:
8187 BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
8188
8189 // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
8190 SET_AH(0x01); // ???
8191 set_diskette_ret_status(1);
8192 SET_CF();
8193 return;
8194 // }
8195 }
8196}
8197#else // #if BX_SUPPORT_FLOPPY
8198 void
8199int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
8200 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
8201{
8202 Bit8u val8;
8203
8204 switch ( GET_AH() ) {
8205
8206 case 0x01: // Read Diskette Status
8207 CLEAR_CF();
8208 val8 = read_byte(0x0000, 0x0441);
8209 SET_AH(val8);
8210 if (val8) {
8211 SET_CF();
8212 }
8213 return;
8214
8215 default:
8216 SET_CF();
8217 write_byte(0x0000, 0x0441, 0x01);
8218 SET_AH(0x01);
8219 }
8220}
8221#endif // #if BX_SUPPORT_FLOPPY
8222
8223 void
8224set_diskette_ret_status(value)
8225 Bit8u value;
8226{
8227 write_byte(0x0040, 0x0041, value);
8228}
8229
8230 void
8231set_diskette_current_cyl(drive, cyl)
8232 Bit8u drive;
8233 Bit8u cyl;
8234{
8235 if (drive > 1)
8236 BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
8237 write_byte(0x0040, 0x0094+drive, cyl);
8238}
8239
8240 void
8241determine_floppy_media(drive)
8242 Bit16u drive;
8243{
8244#if 0
8245 Bit8u val8, DOR, ctrl_info;
8246
8247 ctrl_info = read_byte(0x0040, 0x008F);
8248 if (drive==1)
8249 ctrl_info >>= 4;
8250 else
8251 ctrl_info &= 0x0f;
8252
8253#if 0
8254 if (drive == 0) {
8255 DOR = 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
8256 }
8257 else {
8258 DOR = 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
8259 }
8260#endif
8261
8262 if ( (ctrl_info & 0x04) != 0x04 ) {
8263 // Drive not determined means no drive exists, done.
8264 return;
8265 }
8266
8267#if 0
8268 // check Main Status Register for readiness
8269 val8 = inb(0x03f4) & 0x80; // Main Status Register
8270 if (val8 != 0x80)
8271 BX_PANIC("d_f_m: MRQ bit not set\n");
8272
8273 // change line
8274
8275 // existing BDA values
8276
8277 // turn on drive motor
8278 outb(0x03f2, DOR); // Digital Output Register
8279 //
8280#endif
8281 BX_PANIC("d_f_m: OK so far\n");
8282#endif
8283}
8284
8285 void
8286int17_function(regs, ds, iret_addr)
8287 pusha_regs_t regs; // regs pushed from PUSHA instruction
8288 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8289 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8290{
8291 Bit16u addr,timeout;
8292 Bit8u val8;
8293
8294 ASM_START
8295 sti
8296 ASM_END
8297
8298 addr = read_word(0x0040, (regs.u.r16.dx << 1) + 8);
8299 if ((regs.u.r8.ah < 3) && (regs.u.r16.dx < 3) && (addr > 0)) {
8300 timeout = read_byte(0x0040, 0x0078 + regs.u.r16.dx) << 8;
8301 if (regs.u.r8.ah == 0) {
8302 outb(addr, regs.u.r8.al);
8303 val8 = inb(addr+2);
8304 outb(addr+2, val8 | 0x01); // send strobe
8305 ASM_START
8306 nop
8307 ASM_END
8308 outb(addr+2, val8 & ~0x01);
8309 while (((inb(addr+1) & 0x40) == 0x40) && (timeout)) {
8310 timeout--;
8311 }
8312 }
8313 if (regs.u.r8.ah == 1) {
8314 val8 = inb(addr+2);
8315 outb(addr+2, val8 & ~0x04); // send init
8316 ASM_START
8317 nop
8318 ASM_END
8319 outb(addr+2, val8 | 0x04);
8320 }
8321 val8 = inb(addr+1);
8322 regs.u.r8.ah = (val8 ^ 0x48);
8323 if (!timeout) regs.u.r8.ah |= 0x01;
8324 ClearCF(iret_addr.flags);
8325 } else {
8326 SetCF(iret_addr.flags); // Unsupported
8327 }
8328}
8329
8330// returns bootsegment in ax, drive in bl
8331 Bit32u
8332int19_function(bseqnr)
8333Bit8u bseqnr;
8334{
8335 Bit16u ebda_seg=read_word(0x0040,0x000E);
8336 Bit16u bootseq;
8337 Bit8u bootdrv;
8338 Bit8u bootcd;
8339#ifdef VBOX
8340 Bit8u bootlan;
8341#endif /* VBOX */
8342 Bit8u bootchk;
8343 Bit16u bootseg;
8344 Bit16u status;
8345 Bit8u lastdrive=0;
8346
8347 // if BX_ELTORITO_BOOT is not defined, old behavior
8348 // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
8349 // in preparation for the intial INT 13h (0=floppy A:, 0x80=C:)
8350 // 0: system boot sequence, first drive C: then A:
8351 // 1: system boot sequence, first drive A: then C:
8352 // else BX_ELTORITO_BOOT is defined
8353 // CMOS regs 0x3D and 0x38 contain the boot sequence:
8354 // CMOS reg 0x3D & 0x0f : 1st boot device
8355 // CMOS reg 0x3D & 0xf0 : 2nd boot device
8356 // CMOS reg 0x38 & 0xf0 : 3rd boot device
8357#ifdef VBOX
8358 // CMOS reg 0x3C & 0x0f : 4th boot device
8359#endif /* VBOX */
8360 // boot device codes:
8361 // 0x00 : not defined
8362 // 0x01 : first floppy
8363 // 0x02 : first harddrive
8364 // 0x03 : first cdrom
8365#ifdef VBOX
8366 // 0x04 : local area network
8367#endif /* VBOX */
8368 // else : boot failure
8369
8370 // Get the boot sequence
8371#if BX_ELTORITO_BOOT
8372 bootseq=inb_cmos(0x3d);
8373 bootseq|=((inb_cmos(0x38) & 0xf0) << 4);
8374#ifdef VBOX
8375 bootseq|=((inb_cmos(0x3c) & 0x0f) << 12);
8376 if (read_byte(ebda_seg, &EbdaData->uForceBootDevice))
8377 bootseq = read_byte(ebda_seg, &EbdaData->uForceBootDevice);
8378 /* Boot delay hack. */
8379 if (bseqnr == 1)
8380 delay_boot((inb_cmos(0x3c) & 0xf0) >> 4); /* Implemented in logo.c */
8381#endif /* VBOX */
8382
8383 if (bseqnr==2) bootseq >>= 4;
8384 if (bseqnr==3) bootseq >>= 8;
8385#ifdef VBOX
8386 if (bseqnr==4) bootseq >>= 12;
8387#endif /* VBOX */
8388 if (bootseq<0x10) lastdrive = 1;
8389 bootdrv=0x00; bootcd=0;
8390#ifdef VBOX
8391 bootlan=0;
8392#endif /* VBOX */
8393
8394 switch(bootseq & 0x0f) {
8395 case 0x01:
8396 bootdrv=0x00;
8397 bootcd=0;
8398 break;
8399 case 0x02:
8400 {
8401 // Get the Boot drive.
8402 Bit8u boot_drive = read_byte(ebda_seg, &EbdaData->uForceBootDrive);
8403
8404 bootdrv = boot_drive + 0x80;
8405 bootcd=0;
8406 break;
8407 }
8408 case 0x03:
8409 bootdrv=0x00;
8410 bootcd=1;
8411 break;
8412#ifdef VBOX
8413 case 0x04: bootlan=1; break;
8414#endif /* VBOX */
8415 default: return 0x00000000;
8416 }
8417#else
8418 bootseq=inb_cmos(0x2d);
8419
8420 if (bseqnr==2) {
8421 bootseq ^= 0x20;
8422 lastdrive = 1;
8423 }
8424 bootdrv=0x00; bootcd=0;
8425 if((bootseq&0x20)==0) bootdrv=0x80;
8426#endif // BX_ELTORITO_BOOT
8427
8428#if BX_ELTORITO_BOOT
8429 // We have to boot from cd
8430 if (bootcd != 0) {
8431 status = cdrom_boot();
8432
8433 // If failure
8434 if ( (status & 0x00ff) !=0 ) {
8435 print_cdromboot_failure(status);
8436#ifdef VBOX
8437 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
8438#else /* !VBOX */
8439 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
8440#endif /* !VBOX */
8441 return 0x00000000;
8442 }
8443
8444 bootseg = read_word(ebda_seg,&EbdaData->cdemu.load_segment);
8445 bootdrv = (Bit8u)(status>>8);
8446 }
8447
8448#endif // BX_ELTORITO_BOOT
8449
8450#ifdef VBOX
8451 // Check for boot from LAN first
8452 if (bootlan == 1) {
8453 if (read_word(VBOX_LANBOOT_SEG,0) == 0xaa55) {
8454 Bit16u pnpoff;
8455 Bit32u manuf;
8456 // This is NOT a generic PnP implementation, but an Etherboot-specific hack.
8457 pnpoff = read_word(VBOX_LANBOOT_SEG,0x1a);
8458 if (read_dword(VBOX_LANBOOT_SEG,pnpoff) == 0x506e5024) {
8459 // Found PnP signature
8460 manuf = read_dword(VBOX_LANBOOT_SEG,read_word(VBOX_LANBOOT_SEG,pnpoff+0xe));
8461 if (manuf == 0x65687445) {
8462 // Found Etherboot ROM
8463 print_boot_device(bootcd, bootlan, bootdrv);
8464ASM_START
8465 push ds
8466 push es
8467 pusha
8468 calli 0x0006,VBOX_LANBOOT_SEG
8469 popa
8470 pop es
8471 pop ds
8472ASM_END
8473 } else if (manuf == 0x65746E49) {
8474 // Found Intel PXE ROM
8475 print_boot_device(bootcd, bootlan, bootdrv);
8476ASM_START
8477 push ds
8478 push es
8479 pusha
8480 sti ; Why are interrupts disabled now? Because we were called through an INT!
8481 push #VBOX_LANBOOT_SEG
8482 pop ds
8483 mov bx,#0x1a ; PnP header offset
8484 mov bx,[bx]
8485 add bx,#0x1a ; BEV offset in PnP header
8486 mov ax,[bx]
8487 test ax,ax
8488 jz no_rom
8489bev_jump:
8490 push cs
8491 push #no_rom
8492 push #VBOX_LANBOOT_SEG
8493 push ax
8494 retf ; call Boot Entry Vector
8495no_rom:
8496 popa
8497 pop es
8498 pop ds
8499ASM_END
8500 }
8501 }
8502 }
8503
8504 // boot from LAN will not return if successful.
8505 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
8506 return 0x00000000;
8507 }
8508#endif /* VBOX */
8509 // We have to boot from harddisk or floppy
8510#ifdef VBOX
8511 if (bootcd == 0 && bootlan == 0) {
8512#else /* !VBOX */
8513 if (bootcd == 0) {
8514#endif /* !VBOX */
8515 bootseg=0x07c0;
8516
8517ASM_START
8518 push bp
8519 mov bp, sp
8520
8521 xor ax, ax
8522 mov _int19_function.status + 2[bp], ax
8523 mov dl, _int19_function.bootdrv + 2[bp]
8524 mov ax, _int19_function.bootseg + 2[bp]
8525 mov es, ax ;; segment
8526 xor bx, bx ;; offset
8527 mov ah, #0x02 ;; function 2, read diskette sector
8528 mov al, #0x01 ;; read 1 sector
8529 mov ch, #0x00 ;; track 0
8530 mov cl, #0x01 ;; sector 1
8531 mov dh, #0x00 ;; head 0
8532 int #0x13 ;; read sector
8533 jnc int19_load_done
8534 mov ax, #0x0001
8535 mov _int19_function.status + 2[bp], ax
8536
8537int19_load_done:
8538 pop bp
8539ASM_END
8540
8541 if (status != 0) {
8542#ifdef VBOX
8543 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
8544#else /* !VBOX */
8545 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
8546#endif /* !VBOX */
8547 return 0x00000000;
8548 }
8549 }
8550
8551#ifdef VBOX
8552 // Don't check boot sectors on floppies and don't read CMOS - byte
8553 // 0x38 in CMOS always has the low bit clear.
8554 // There is *no* requirement whatsoever for a valid boot sector to
8555 // have a 55AAh signature. UNIX boot floppies typically have no such
8556 // signature. In general, it is impossible to tell a valid bootsector
8557 // from an invalid one.
8558 // NB: It is somewhat common for failed OS installs to have the
8559 // 0x55AA signature and a valid partition table but zeros in the
8560 // rest of the boot sector. We do a quick check by comparing the first
8561 // two words of boot sector; if identical, the boot sector is
8562 // extremely unlikely to be valid.
8563#endif
8564 // check signature if instructed by cmos reg 0x38, only for floppy
8565 // bootchk = 1 : signature check disabled
8566 // bootchk = 0 : signature check enabled
8567 if (bootdrv != 0) bootchk = 0;
8568#ifdef VBOX
8569 else bootchk = 1; /* disable 0x55AA signature check on drive A: */
8570#else
8571 else bootchk = inb_cmos(0x38) & 0x01;
8572#endif
8573
8574#if BX_ELTORITO_BOOT
8575 // if boot from cd, no signature check
8576 if (bootcd != 0)
8577 bootchk = 1;
8578#endif // BX_ELTORITO_BOOT
8579
8580 if (bootchk == 0) {
8581 if (read_word(bootseg,0x1fe) != 0xaa55 ||
8582 read_word(bootseg,0) == read_word(bootseg,2)) {
8583#ifdef VBOX
8584 print_boot_failure(bootcd, bootlan, bootdrv, 0, lastdrive);
8585#else /* !VBOX */
8586 print_boot_failure(bootcd, bootdrv, 0, lastdrive);
8587#endif /* VBOX */
8588 return 0x00000000;
8589 }
8590 }
8591
8592#if BX_ELTORITO_BOOT
8593 // Print out the boot string
8594#ifdef VBOX
8595 print_boot_device(bootcd, bootlan, bootdrv);
8596#else /* !VBOX */
8597 print_boot_device(bootcd, bootdrv);
8598#endif /* !VBOX */
8599#else // BX_ELTORITO_BOOT
8600#ifdef VBOX
8601 print_boot_device(0, bootlan, bootdrv);
8602#else /* !VBOX */
8603 print_boot_device(0, bootdrv);
8604#endif /* !VBOX */
8605#endif // BX_ELTORITO_BOOT
8606
8607 // return the boot segment
8608 return (((Bit32u)bootdrv) << 16) + bootseg;
8609}
8610
8611 void
8612int1a_function(regs, ds, iret_addr)
8613 pusha_regs_t regs; // regs pushed from PUSHA instruction
8614 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8615 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8616{
8617 Bit8u val8;
8618
8619 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);
8620
8621 ASM_START
8622 sti
8623 ASM_END
8624
8625 switch (regs.u.r8.ah) {
8626 case 0: // get current clock count
8627 ASM_START
8628 cli
8629 ASM_END
8630 regs.u.r16.cx = BiosData->ticks_high;
8631 regs.u.r16.dx = BiosData->ticks_low;
8632 regs.u.r8.al = BiosData->midnight_flag;
8633 BiosData->midnight_flag = 0; // reset flag
8634 ASM_START
8635 sti
8636 ASM_END
8637 // AH already 0
8638 ClearCF(iret_addr.flags); // OK
8639 break;
8640
8641 case 1: // Set Current Clock Count
8642 ASM_START
8643 cli
8644 ASM_END
8645 BiosData->ticks_high = regs.u.r16.cx;
8646 BiosData->ticks_low = regs.u.r16.dx;
8647 BiosData->midnight_flag = 0; // reset flag
8648 ASM_START
8649 sti
8650 ASM_END
8651 regs.u.r8.ah = 0;
8652 ClearCF(iret_addr.flags); // OK
8653 break;
8654
8655
8656 case 2: // Read CMOS Time
8657 if (rtc_updating()) {
8658 SetCF(iret_addr.flags);
8659 break;
8660 }
8661
8662 regs.u.r8.dh = inb_cmos(0x00); // Seconds
8663 regs.u.r8.cl = inb_cmos(0x02); // Minutes
8664 regs.u.r8.ch = inb_cmos(0x04); // Hours
8665 regs.u.r8.dl = inb_cmos(0x0b) & 0x01; // Stat Reg B
8666 regs.u.r8.ah = 0;
8667 regs.u.r8.al = regs.u.r8.ch;
8668 ClearCF(iret_addr.flags); // OK
8669 break;
8670
8671 case 3: // Set CMOS Time
8672 // Using a debugger, I notice the following masking/setting
8673 // of bits in Status Register B, by setting Reg B to
8674 // a few values and getting its value after INT 1A was called.
8675 //
8676 // try#1 try#2 try#3
8677 // before 1111 1101 0111 1101 0000 0000
8678 // after 0110 0010 0110 0010 0000 0010
8679 //
8680 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8681 // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
8682 if (rtc_updating()) {
8683 init_rtc();
8684 // fall through as if an update were not in progress
8685 }
8686 outb_cmos(0x00, regs.u.r8.dh); // Seconds
8687 outb_cmos(0x02, regs.u.r8.cl); // Minutes
8688 outb_cmos(0x04, regs.u.r8.ch); // Hours
8689 // Set Daylight Savings time enabled bit to requested value
8690 val8 = (inb_cmos(0x0b) & 0x60) | 0x02 | (regs.u.r8.dl & 0x01);
8691 // (reg B already selected)
8692 outb_cmos(0x0b, val8);
8693 regs.u.r8.ah = 0;
8694 regs.u.r8.al = val8; // val last written to Reg B
8695 ClearCF(iret_addr.flags); // OK
8696 break;
8697
8698 case 4: // Read CMOS Date
8699 regs.u.r8.ah = 0;
8700 if (rtc_updating()) {
8701 SetCF(iret_addr.flags);
8702 break;
8703 }
8704 regs.u.r8.cl = inb_cmos(0x09); // Year
8705 regs.u.r8.dh = inb_cmos(0x08); // Month
8706 regs.u.r8.dl = inb_cmos(0x07); // Day of Month
8707 regs.u.r8.ch = inb_cmos(0x32); // Century
8708 regs.u.r8.al = regs.u.r8.ch;
8709 ClearCF(iret_addr.flags); // OK
8710 break;
8711
8712 case 5: // Set CMOS Date
8713 // Using a debugger, I notice the following masking/setting
8714 // of bits in Status Register B, by setting Reg B to
8715 // a few values and getting its value after INT 1A was called.
8716 //
8717 // try#1 try#2 try#3 try#4
8718 // before 1111 1101 0111 1101 0000 0010 0000 0000
8719 // after 0110 1101 0111 1101 0000 0010 0000 0000
8720 //
8721 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8722 // My assumption: RegB = (RegB & 01111111b)
8723 if (rtc_updating()) {
8724 init_rtc();
8725 SetCF(iret_addr.flags);
8726 break;
8727 }
8728 outb_cmos(0x09, regs.u.r8.cl); // Year
8729 outb_cmos(0x08, regs.u.r8.dh); // Month
8730 outb_cmos(0x07, regs.u.r8.dl); // Day of Month
8731 outb_cmos(0x32, regs.u.r8.ch); // Century
8732 val8 = inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
8733 outb_cmos(0x0b, val8);
8734 regs.u.r8.ah = 0;
8735 regs.u.r8.al = val8; // AL = val last written to Reg B
8736 ClearCF(iret_addr.flags); // OK
8737 break;
8738
8739 case 6: // Set Alarm Time in CMOS
8740 // Using a debugger, I notice the following masking/setting
8741 // of bits in Status Register B, by setting Reg B to
8742 // a few values and getting its value after INT 1A was called.
8743 //
8744 // try#1 try#2 try#3
8745 // before 1101 1111 0101 1111 0000 0000
8746 // after 0110 1111 0111 1111 0010 0000
8747 //
8748 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8749 // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
8750 val8 = inb_cmos(0x0b); // Get Status Reg B
8751 regs.u.r16.ax = 0;
8752 if (val8 & 0x20) {
8753 // Alarm interrupt enabled already
8754 SetCF(iret_addr.flags); // Error: alarm in use
8755 break;
8756 }
8757 if (rtc_updating()) {
8758 init_rtc();
8759 // fall through as if an update were not in progress
8760 }
8761 outb_cmos(0x01, regs.u.r8.dh); // Seconds alarm
8762 outb_cmos(0x03, regs.u.r8.cl); // Minutes alarm
8763 outb_cmos(0x05, regs.u.r8.ch); // Hours alarm
8764 outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
8765 // enable Status Reg B alarm bit, clear halt clock bit
8766 outb_cmos(0x0b, (val8 & 0x7f) | 0x20);
8767 ClearCF(iret_addr.flags); // OK
8768 break;
8769
8770 case 7: // Turn off Alarm
8771 // Using a debugger, I notice the following masking/setting
8772 // of bits in Status Register B, by setting Reg B to
8773 // a few values and getting its value after INT 1A was called.
8774 //
8775 // try#1 try#2 try#3 try#4
8776 // before 1111 1101 0111 1101 0010 0000 0010 0010
8777 // after 0100 0101 0101 0101 0000 0000 0000 0010
8778 //
8779 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8780 // My assumption: RegB = (RegB & 01010111b)
8781 val8 = inb_cmos(0x0b); // Get Status Reg B
8782 // clear clock-halt bit, disable alarm bit
8783 outb_cmos(0x0b, val8 & 0x57); // disable alarm bit
8784 regs.u.r8.ah = 0;
8785 regs.u.r8.al = val8; // val last written to Reg B
8786 ClearCF(iret_addr.flags); // OK
8787 break;
8788#if BX_PCIBIOS
8789 case 0xb1:
8790 // real mode PCI BIOS functions now handled in assembler code
8791 // this C code handles the error code for information only
8792 if (regs.u.r8.bl == 0xff) {
8793 BX_INFO("PCI BIOS: PCI not present\n");
8794 } else if (regs.u.r8.bl == 0x81) {
8795 BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs.u.r8.al);
8796 } else if (regs.u.r8.bl == 0x83) {
8797 BX_INFO("bad PCI vendor ID %04x\n", regs.u.r16.dx);
8798 } else if (regs.u.r8.bl == 0x86) {
8799 if (regs.u.r8.al == 0x02) {
8800 BX_INFO("PCI device %04x:%04x not found at index %d\n", regs.u.r16.dx, regs.u.r16.cx, regs.u.r16.si);
8801 } else {
8802 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);
8803 }
8804 }
8805 regs.u.r8.ah = regs.u.r8.bl;
8806 SetCF(iret_addr.flags);
8807 break;
8808#endif
8809
8810 default:
8811 SetCF(iret_addr.flags); // Unsupported
8812 }
8813}
8814
8815 void
8816int70_function(regs, ds, iret_addr)
8817 pusha_regs_t regs; // regs pushed from PUSHA instruction
8818 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8819 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8820{
8821 // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
8822 Bit8u registerB = 0, registerC = 0;
8823
8824 // Check which modes are enabled and have occurred.
8825 registerB = inb_cmos( 0xB );
8826 registerC = inb_cmos( 0xC );
8827
8828 if( ( registerB & 0x60 ) != 0 ) {
8829 if( ( registerC & 0x20 ) != 0 ) {
8830 // Handle Alarm Interrupt.
8831ASM_START
8832 sti
8833 int #0x4a
8834 cli
8835ASM_END
8836 }
8837 if( ( registerC & 0x40 ) != 0 ) {
8838 // Handle Periodic Interrupt.
8839
8840 if( read_byte( 0x40, 0xA0 ) != 0 ) {
8841 // Wait Interval (Int 15, AH=83) active.
8842 Bit32u time, toggle;
8843
8844 time = read_dword( 0x40, 0x9C ); // Time left in microseconds.
8845 if( time < 0x3D1 ) {
8846 // Done waiting.
8847 Bit16u segment, offset;
8848
8849 segment = read_word( 0x40, 0x98 );
8850 offset = read_word( 0x40, 0x9A );
8851 write_byte( 0x40, 0xA0, 0 ); // Turn of status byte.
8852 outb_cmos( 0xB, registerB & 0x37 ); // Clear the Periodic Interrupt.
8853 write_byte(segment, offset, read_byte(segment, offset) | 0x80 ); // Write to specified flag byte.
8854 } else {
8855 // Continue waiting.
8856 time -= 0x3D1;
8857 write_dword( 0x40, 0x9C, time );
8858 }
8859 }
8860 }
8861 }
8862
8863ASM_START
8864 call eoi_both_pics
8865ASM_END
8866}
8867
8868 void
8869dummy_isr_function(regs, ds, iret_addr)
8870 pusha_regs_t regs; // regs pushed from PUSHA instruction
8871 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8872 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8873{
8874 // Interrupt handler for unexpected hardware interrupts. We have to clear
8875 // the PIC because if we don't, the next EOI will clear the wrong interrupt
8876 // and all hell will break loose! This routine also masks the unexpected
8877 // interrupt so it will generally be called only once for each unexpected
8878 // interrupt level.
8879 Bit8u isrA, isrB, imr, last_int = 0xFF;
8880
8881 outb( 0x20, 0x0B );
8882 isrA = inb( 0x20 );
8883 if (isrA) {
8884 outb( 0xA0, 0x0B );
8885 isrB = inb( 0xA0 );
8886 if (isrB) {
8887 imr = inb( 0xA1 );
8888 outb( 0xA1, imr | isrB ); // Mask this interrupt
8889 outb( 0xA0, 0x20 ); // Send EOI on slave PIC
8890 } else {
8891 imr = inb( 0x21 );
8892 isrA &= 0xFB; // Never mask the cascade interrupt
8893 outb( 0x21, imr | isrA); // Mask this interrupt
8894 }
8895 outb( 0x20, 0x20 ); // Send EOI on master PIC
8896 last_int = isrA;
8897 }
8898 write_byte( 0x40, 0x6B, last_int ); // Write INTR_FLAG
8899}
8900
8901ASM_START
8902;------------------------------------------
8903;- INT74h : PS/2 mouse hardware interrupt -
8904;------------------------------------------
8905int74_handler:
8906 sti
8907 pusha
8908 push ds ;; save DS
8909 push #0x00 ;; placeholder for status
8910 push #0x00 ;; placeholder for X
8911 push #0x00 ;; placeholder for Y
8912 push #0x00 ;; placeholder for Z
8913 push #0x00 ;; placeholder for make_far_call boolean
8914 call _int74_function
8915 pop cx ;; remove make_far_call from stack
8916 jcxz int74_done
8917
8918 ;; make far call to EBDA:0022
8919 push #0x00
8920 pop ds
8921 push 0x040E ;; push 0000:040E (opcodes 0xff, 0x36, 0x0E, 0x04)
8922 pop ds
8923 //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
8924 call far ptr[0x22]
8925int74_done:
8926 cli
8927 call eoi_both_pics
8928 add sp, #8 ;; pop status, x, y, z
8929
8930 pop ds ;; restore DS
8931 popa
8932 iret
8933
8934
8935;; This will perform an IRET, but will retain value of current CF
8936;; by altering flags on stack. Better than RETF #02.
8937iret_modify_cf:
8938 jc carry_set
8939 push bp
8940 mov bp, sp
8941 and BYTE [bp + 0x06], #0xfe
8942 pop bp
8943 iret
8944carry_set:
8945 push bp
8946 mov bp, sp
8947 or BYTE [bp + 0x06], #0x01
8948 pop bp
8949 iret
8950
8951
8952;----------------------
8953;- INT13h (relocated) -
8954;----------------------
8955;
8956; int13_relocated is a little bit messed up since I played with it
8957; I have to rewrite it:
8958; - call a function that detect which function to call
8959; - make all called C function get the same parameters list
8960;
8961int13_relocated:
8962
8963#if BX_ELTORITO_BOOT
8964 ;; check for an eltorito function
8965 cmp ah,#0x4a
8966 jb int13_not_eltorito
8967 cmp ah,#0x4d
8968 ja int13_not_eltorito
8969
8970 pusha
8971 push es
8972 push ds
8973 push ss
8974 pop ds
8975
8976 push #int13_out
8977 jmp _int13_eltorito ;; ELDX not used
8978
8979int13_not_eltorito:
8980 push ax
8981 push bx
8982 push cx
8983 push dx
8984
8985 ;; check if emulation active
8986 call _cdemu_isactive
8987 cmp al,#0x00
8988 je int13_cdemu_inactive
8989
8990 ;; check if access to the emulated drive
8991 call _cdemu_emulated_drive
8992 pop dx
8993 push dx
8994 cmp al,dl ;; int13 on emulated drive
8995 jne int13_nocdemu
8996
8997 pop dx
8998 pop cx
8999 pop bx
9000 pop ax
9001
9002 pusha
9003 push es
9004 push ds
9005 push ss
9006 pop ds
9007
9008 push #int13_out
9009 jmp _int13_cdemu ;; ELDX not used
9010
9011int13_nocdemu:
9012 and dl,#0xE0 ;; mask to get device class, including cdroms
9013 cmp al,dl ;; al is 0x00 or 0x80
9014 jne int13_cdemu_inactive ;; inactive for device class
9015
9016 pop dx
9017 pop cx
9018 pop bx
9019 pop ax
9020
9021 push ax
9022 push cx
9023 push dx
9024 push bx
9025
9026 dec dl ;; real drive is dl - 1
9027 jmp int13_legacy
9028
9029int13_cdemu_inactive:
9030 pop dx
9031 pop cx
9032 pop bx
9033 pop ax
9034
9035#endif // BX_ELTORITO_BOOT
9036
9037int13_noeltorito:
9038
9039 push ax
9040 push cx
9041 push dx
9042 push bx
9043
9044int13_legacy:
9045
9046 push dx ;; push eltorito value of dx instead of sp
9047
9048 push bp
9049 push si
9050 push di
9051
9052 push es
9053 push ds
9054 push ss
9055 pop ds
9056
9057 ;; now the 16-bit registers can be restored with:
9058 ;; pop ds; pop es; popa; iret
9059 ;; arguments passed to functions should be
9060 ;; DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS
9061
9062 test dl, #0x80
9063 jnz int13_notfloppy
9064
9065 push #int13_out
9066 jmp _int13_diskette_function
9067
9068int13_notfloppy:
9069
9070#if BX_USE_ATADRV
9071
9072 cmp dl, #0xE0
9073 jb int13_notcdrom
9074
9075 // ebx is modified: BSD 5.2.1 boot loader problem
9076 // someone should figure out which 32 bit register that actually are used
9077
9078 shr ebx, #16
9079 push bx
9080
9081 call _int13_cdrom
9082
9083 pop bx
9084 shl ebx, #16
9085
9086 jmp int13_out
9087
9088int13_notcdrom:
9089
9090#endif
9091
9092int13_disk:
9093 ;; int13_harddisk modifies high word of EAX
9094 shr eax, #16
9095 push ax
9096 call _int13_harddisk
9097 pop ax
9098 shl eax, #16
9099
9100int13_out:
9101 pop ds
9102 pop es
9103 popa
9104 iret
9105
9106;----------
9107;- INT18h -
9108;----------
9109int18_handler: ;; Boot Failure routing
9110 call _int18_panic_msg
9111 hlt
9112 iret
9113
9114;----------
9115;- INT19h -
9116;----------
9117int19_relocated: ;; Boot function, relocated
9118
9119#ifdef VBOX
9120 // If an already booted OS calls int 0x19 to reboot, it is not sufficient
9121 // just to try booting from the configured drives. All BIOS variables and
9122 // interrupt vectors need to be reset, otherwise strange things may happen.
9123 // The approach used is faking a warm reboot (which just skips showing the
9124 // logo), which is a bit more than what we need, but hey, it's fast.
9125 mov bp, sp
9126 mov ax, 2[bp]
9127 cmp ax, #0xf000
9128 jz bios_initiated_boot
9129 xor ax, ax
9130 mov ds, ax
9131 mov ax, #0x1234
9132 mov 0x472, ax
9133 jmp post
9134bios_initiated_boot:
9135#endif /* VBOX */
9136
9137 ;; int19 was beginning to be really complex, so now it
9138 ;; just calls a C function that does the work
9139 ;; it returns in BL the boot drive, and in AX the boot segment
9140 ;; the boot segment will be 0x0000 if something has failed
9141
9142 push bp
9143 mov bp, sp
9144
9145 ;; drop ds
9146 xor ax, ax
9147 mov ds, ax
9148
9149 ;; 1st boot device
9150 mov ax, #0x0001
9151 push ax
9152 call _int19_function
9153 inc sp
9154 inc sp
9155 ;; bl contains the boot drive
9156 ;; ax contains the boot segment or 0 if failure
9157
9158 test ax, ax ;; if ax is 0 try next boot device
9159 jnz boot_setup
9160
9161 ;; 2nd boot device
9162 mov ax, #0x0002
9163 push ax
9164 call _int19_function
9165 inc sp
9166 inc sp
9167 test ax, ax ;; if ax is 0 try next boot device
9168 jnz boot_setup
9169
9170 ;; 3rd boot device
9171 mov ax, #0x0003
9172 push ax
9173 call _int19_function
9174 inc sp
9175 inc sp
9176#ifdef VBOX
9177 test ax, ax ;; if ax is 0 try next boot device
9178 jnz boot_setup
9179
9180 ;; 4th boot device
9181 mov ax, #0x0004
9182 push ax
9183 call _int19_function
9184 inc sp
9185 inc sp
9186#endif /* VBOX */
9187 test ax, ax ;; if ax is 0 call int18
9188 jz int18_handler
9189
9190boot_setup:
9191 mov dl, bl ;; set drive so guest os find it
9192 shl eax, #0x04 ;; convert seg to ip
9193 mov 2[bp], ax ;; set ip
9194
9195 shr eax, #0x04 ;; get cs back
9196 and ax, #0xF000 ;; remove what went in ip
9197 mov 4[bp], ax ;; set cs
9198 xor ax, ax
9199 mov es, ax ;; set es to zero fixes [ 549815 ]
9200 mov [bp], ax ;; set bp to zero
9201 mov ax, #0xaa55 ;; set ok flag
9202
9203 pop bp
9204 iret ;; Beam me up Scotty
9205
9206;----------
9207;- INT1Ch -
9208;----------
9209int1c_handler: ;; User Timer Tick
9210 iret
9211
9212
9213;----------------------
9214;- POST: Floppy Drive -
9215;----------------------
9216floppy_drive_post:
9217 xor ax, ax
9218 mov ds, ax
9219
9220 mov al, #0x00
9221 mov 0x043e, al ;; drive 0 & 1 uncalibrated, no interrupt has occurred
9222
9223 mov 0x043f, al ;; diskette motor status: read op, drive0, motors off
9224
9225 mov 0x0440, al ;; diskette motor timeout counter: not active
9226 mov 0x0441, al ;; diskette controller status return code
9227
9228 mov 0x0442, al ;; disk & diskette controller status register 0
9229 mov 0x0443, al ;; diskette controller status register 1
9230 mov 0x0444, al ;; diskette controller status register 2
9231 mov 0x0445, al ;; diskette controller cylinder number
9232 mov 0x0446, al ;; diskette controller head number
9233 mov 0x0447, al ;; diskette controller sector number
9234 mov 0x0448, al ;; diskette controller bytes written
9235
9236 mov 0x048b, al ;; diskette configuration data
9237
9238 ;; -----------------------------------------------------------------
9239 ;; (048F) diskette controller information
9240 ;;
9241 mov al, #0x10 ;; get CMOS diskette drive type
9242 out 0x70, AL
9243 in AL, 0x71
9244 mov ah, al ;; save byte to AH
9245
9246look_drive0:
9247 shr al, #4 ;; look at top 4 bits for drive 0
9248 jz f0_missing ;; jump if no drive0
9249 mov bl, #0x07 ;; drive0 determined, multi-rate, has changed line
9250 jmp look_drive1
9251f0_missing:
9252 mov bl, #0x00 ;; no drive0
9253
9254look_drive1:
9255 mov al, ah ;; restore from AH
9256 and al, #0x0f ;; look at bottom 4 bits for drive 1
9257 jz f1_missing ;; jump if no drive1
9258 or bl, #0x70 ;; drive1 determined, multi-rate, has changed line
9259f1_missing:
9260 ;; leave high bits in BL zerod
9261 mov 0x048f, bl ;; put new val in BDA (diskette controller information)
9262 ;; -----------------------------------------------------------------
9263
9264 mov al, #0x00
9265 mov 0x0490, al ;; diskette 0 media state
9266 mov 0x0491, al ;; diskette 1 media state
9267
9268 ;; diskette 0,1 operational starting state
9269 ;; drive type has not been determined,
9270 ;; has no changed detection line
9271 mov 0x0492, al
9272 mov 0x0493, al
9273
9274 mov 0x0494, al ;; diskette 0 current cylinder
9275 mov 0x0495, al ;; diskette 1 current cylinder
9276
9277 mov al, #0x02
9278 out #0x0a, al ;; clear DMA-1 channel 2 mask bit
9279
9280 SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
9281 SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
9282 SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
9283
9284 ret
9285
9286
9287;--------------------
9288;- POST: HARD DRIVE -
9289;--------------------
9290; relocated here because the primary POST area isnt big enough.
9291hard_drive_post:
9292 // IRQ 14 = INT 76h
9293 // INT 76h calls INT 15h function ax=9100
9294
9295 mov al, #0x0a ; 0000 1010 = reserved, disable IRQ 14
9296 mov dx, #0x03f6
9297 out dx, al
9298
9299 xor ax, ax
9300 mov ds, ax
9301 mov 0x0474, al /* hard disk status of last operation */
9302 mov 0x0477, al /* hard disk port offset (XT only ???) */
9303 mov 0x048c, al /* hard disk status register */
9304 mov 0x048d, al /* hard disk error register */
9305 mov 0x048e, al /* hard disk task complete flag */
9306 mov al, #0x01
9307 mov 0x0475, al /* hard disk number attached */
9308 mov al, #0xc0
9309 mov 0x0476, al /* hard disk control byte */
9310 SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
9311 SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
9312 ;; INT 41h: hard disk 0 configuration pointer
9313 ;; INT 46h: hard disk 1 configuration pointer
9314 SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D)
9315 SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D)
9316
9317#ifndef VBOX /* This is done later (and the CMOS format is now different). */
9318 ;; move disk geometry data from CMOS to EBDA disk parameter table(s)
9319 mov al, #0x12
9320 out #0x70, al
9321 in al, #0x71
9322 and al, #0xf0
9323 cmp al, #0xf0
9324 je post_d0_extended
9325 jmp check_for_hd1
9326post_d0_extended:
9327 mov al, #0x19
9328 out #0x70, al
9329 in al, #0x71
9330 cmp al, #47 ;; decimal 47 - user definable
9331 je post_d0_type47
9332 HALT(__LINE__)
9333post_d0_type47:
9334 ;; CMOS purpose param table offset
9335 ;; 1b cylinders low 0
9336 ;; 1c cylinders high 1
9337 ;; 1d heads 2
9338 ;; 1e write pre-comp low 5
9339 ;; 1f write pre-comp high 6
9340 ;; 20 retries/bad map/heads>8 8
9341 ;; 21 landing zone low C
9342 ;; 22 landing zone high D
9343 ;; 23 sectors/track E
9344
9345 mov ax, #EBDA_SEG
9346 mov ds, ax
9347
9348 ;;; Filling EBDA table for hard disk 0.
9349 mov al, #0x1f
9350 out #0x70, al
9351 in al, #0x71
9352 mov ah, al
9353 mov al, #0x1e
9354 out #0x70, al
9355 in al, #0x71
9356 mov (0x003d + 0x05), ax ;; write precomp word
9357
9358 mov al, #0x20
9359 out #0x70, al
9360 in al, #0x71
9361 mov (0x003d + 0x08), al ;; drive control byte
9362
9363 mov al, #0x22
9364 out #0x70, al
9365 in al, #0x71
9366 mov ah, al
9367 mov al, #0x21
9368 out #0x70, al
9369 in al, #0x71
9370 mov (0x003d + 0x0C), ax ;; landing zone word
9371
9372 mov al, #0x1c ;; get cylinders word in AX
9373 out #0x70, al
9374 in al, #0x71 ;; high byte
9375 mov ah, al
9376 mov al, #0x1b
9377 out #0x70, al
9378 in al, #0x71 ;; low byte
9379 mov bx, ax ;; BX = cylinders
9380
9381 mov al, #0x1d
9382 out #0x70, al
9383 in al, #0x71
9384 mov cl, al ;; CL = heads
9385
9386 mov al, #0x23
9387 out #0x70, al
9388 in al, #0x71
9389 mov dl, al ;; DL = sectors
9390
9391 cmp bx, #1024
9392 jnbe hd0_post_logical_chs ;; if cylinders > 1024, use translated style CHS
9393
9394hd0_post_physical_chs:
9395 ;; no logical CHS mapping used, just physical CHS
9396 ;; use Standard Fixed Disk Parameter Table (FDPT)
9397 mov (0x003d + 0x00), bx ;; number of physical cylinders
9398 mov (0x003d + 0x02), cl ;; number of physical heads
9399 mov (0x003d + 0x0E), dl ;; number of physical sectors
9400 jmp check_for_hd1
9401
9402hd0_post_logical_chs:
9403 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
9404 mov (0x003d + 0x09), bx ;; number of physical cylinders
9405 mov (0x003d + 0x0b), cl ;; number of physical heads
9406 mov (0x003d + 0x04), dl ;; number of physical sectors
9407 mov (0x003d + 0x0e), dl ;; number of logical sectors (same)
9408 mov al, #0xa0
9409 mov (0x003d + 0x03), al ;; A0h signature, indicates translated table
9410
9411 cmp bx, #2048
9412 jnbe hd0_post_above_2048
9413 ;; 1024 < c <= 2048 cylinders
9414 shr bx, #0x01
9415 shl cl, #0x01
9416 jmp hd0_post_store_logical
9417
9418hd0_post_above_2048:
9419 cmp bx, #4096
9420 jnbe hd0_post_above_4096
9421 ;; 2048 < c <= 4096 cylinders
9422 shr bx, #0x02
9423 shl cl, #0x02
9424 jmp hd0_post_store_logical
9425
9426hd0_post_above_4096:
9427 cmp bx, #8192
9428 jnbe hd0_post_above_8192
9429 ;; 4096 < c <= 8192 cylinders
9430 shr bx, #0x03
9431 shl cl, #0x03
9432 jmp hd0_post_store_logical
9433
9434hd0_post_above_8192:
9435 ;; 8192 < c <= 16384 cylinders
9436 shr bx, #0x04
9437 shl cl, #0x04
9438
9439hd0_post_store_logical:
9440 mov (0x003d + 0x00), bx ;; number of physical cylinders
9441 mov (0x003d + 0x02), cl ;; number of physical heads
9442 ;; checksum
9443 mov cl, #0x0f ;; repeat count
9444 mov si, #0x003d ;; offset to disk0 FDPT
9445 mov al, #0x00 ;; sum
9446hd0_post_checksum_loop:
9447 add al, [si]
9448 inc si
9449 dec cl
9450 jnz hd0_post_checksum_loop
9451 not al ;; now take 2s complement
9452 inc al
9453 mov [si], al
9454;;; Done filling EBDA table for hard disk 0.
9455
9456
9457check_for_hd1:
9458 ;; is there really a second hard disk? if not, return now
9459 mov al, #0x12
9460 out #0x70, al
9461 in al, #0x71
9462 and al, #0x0f
9463 jnz post_d1_exists
9464 ret
9465post_d1_exists:
9466 ;; check that the hd type is really 0x0f.
9467 cmp al, #0x0f
9468 jz post_d1_extended
9469 HALT(__LINE__)
9470post_d1_extended:
9471 ;; check that the extended type is 47 - user definable
9472 mov al, #0x1a
9473 out #0x70, al
9474 in al, #0x71
9475 cmp al, #47 ;; decimal 47 - user definable
9476 je post_d1_type47
9477 HALT(__LINE__)
9478post_d1_type47:
9479 ;; Table for disk1.
9480 ;; CMOS purpose param table offset
9481 ;; 0x24 cylinders low 0
9482 ;; 0x25 cylinders high 1
9483 ;; 0x26 heads 2
9484 ;; 0x27 write pre-comp low 5
9485 ;; 0x28 write pre-comp high 6
9486 ;; 0x29 heads>8 8
9487 ;; 0x2a landing zone low C
9488 ;; 0x2b landing zone high D
9489 ;; 0x2c sectors/track E
9490;;; Fill EBDA table for hard disk 1.
9491 mov ax, #EBDA_SEG
9492 mov ds, ax
9493 mov al, #0x28
9494 out #0x70, al
9495 in al, #0x71
9496 mov ah, al
9497 mov al, #0x27
9498 out #0x70, al
9499 in al, #0x71
9500 mov (0x004d + 0x05), ax ;; write precomp word
9501
9502 mov al, #0x29
9503 out #0x70, al
9504 in al, #0x71
9505 mov (0x004d + 0x08), al ;; drive control byte
9506
9507 mov al, #0x2b
9508 out #0x70, al
9509 in al, #0x71
9510 mov ah, al
9511 mov al, #0x2a
9512 out #0x70, al
9513 in al, #0x71
9514 mov (0x004d + 0x0C), ax ;; landing zone word
9515
9516 mov al, #0x25 ;; get cylinders word in AX
9517 out #0x70, al
9518 in al, #0x71 ;; high byte
9519 mov ah, al
9520 mov al, #0x24
9521 out #0x70, al
9522 in al, #0x71 ;; low byte
9523 mov bx, ax ;; BX = cylinders
9524
9525 mov al, #0x26
9526 out #0x70, al
9527 in al, #0x71
9528 mov cl, al ;; CL = heads
9529
9530 mov al, #0x2c
9531 out #0x70, al
9532 in al, #0x71
9533 mov dl, al ;; DL = sectors
9534
9535 cmp bx, #1024
9536 jnbe hd1_post_logical_chs ;; if cylinders > 1024, use translated style CHS
9537
9538hd1_post_physical_chs:
9539 ;; no logical CHS mapping used, just physical CHS
9540 ;; use Standard Fixed Disk Parameter Table (FDPT)
9541 mov (0x004d + 0x00), bx ;; number of physical cylinders
9542 mov (0x004d + 0x02), cl ;; number of physical heads
9543 mov (0x004d + 0x0E), dl ;; number of physical sectors
9544 ret
9545
9546hd1_post_logical_chs:
9547 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
9548 mov (0x004d + 0x09), bx ;; number of physical cylinders
9549 mov (0x004d + 0x0b), cl ;; number of physical heads
9550 mov (0x004d + 0x04), dl ;; number of physical sectors
9551 mov (0x004d + 0x0e), dl ;; number of logical sectors (same)
9552 mov al, #0xa0
9553 mov (0x004d + 0x03), al ;; A0h signature, indicates translated table
9554
9555 cmp bx, #2048
9556 jnbe hd1_post_above_2048
9557 ;; 1024 < c <= 2048 cylinders
9558 shr bx, #0x01
9559 shl cl, #0x01
9560 jmp hd1_post_store_logical
9561
9562hd1_post_above_2048:
9563 cmp bx, #4096
9564 jnbe hd1_post_above_4096
9565 ;; 2048 < c <= 4096 cylinders
9566 shr bx, #0x02
9567 shl cl, #0x02
9568 jmp hd1_post_store_logical
9569
9570hd1_post_above_4096:
9571 cmp bx, #8192
9572 jnbe hd1_post_above_8192
9573 ;; 4096 < c <= 8192 cylinders
9574 shr bx, #0x03
9575 shl cl, #0x03
9576 jmp hd1_post_store_logical
9577
9578hd1_post_above_8192:
9579 ;; 8192 < c <= 16384 cylinders
9580 shr bx, #0x04
9581 shl cl, #0x04
9582
9583hd1_post_store_logical:
9584 mov (0x004d + 0x00), bx ;; number of physical cylinders
9585 mov (0x004d + 0x02), cl ;; number of physical heads
9586 ;; checksum
9587 mov cl, #0x0f ;; repeat count
9588 mov si, #0x004d ;; offset to disk0 FDPT
9589 mov al, #0x00 ;; sum
9590hd1_post_checksum_loop:
9591 add al, [si]
9592 inc si
9593 dec cl
9594 jnz hd1_post_checksum_loop
9595 not al ;; now take 2s complement
9596 inc al
9597 mov [si], al
9598;;; Done filling EBDA table for hard disk 1.
9599#endif /* !VBOX */
9600
9601 ret
9602
9603;--------------------
9604;- POST: EBDA segment
9605;--------------------
9606; relocated here because the primary POST area isnt big enough.
9607; the SET_INT_VECTORs have nothing to do with EBDA but do not
9608; fit into the primary POST area either
9609ebda_post:
9610 SET_INT_VECTOR(0x0D, #0xF000, #dummy_isr); IRQ 5
9611 SET_INT_VECTOR(0x0F, #0xF000, #dummy_isr); IRQ 7
9612 SET_INT_VECTOR(0x72, #0xF000, #dummy_isr); IRQ 11
9613 SET_INT_VECTOR(0x77, #0xF000, #dummy_isr); IRQ 15
9614
9615#if BX_USE_EBDA
9616 mov ax, #EBDA_SEG
9617 mov ds, ax
9618 mov byte ptr [0x0], #EBDA_SIZE
9619#endif
9620 xor ax, ax ; mov EBDA seg into 40E
9621 mov ds, ax
9622 mov word ptr [0x40E], #EBDA_SEG
9623 ret;;
9624
9625;--------------------
9626;- POST: EOI + jmp via [0x40:67)
9627;--------------------
9628; relocated here because the primary POST area isnt big enough.
9629eoi_jmp_post:
9630 call eoi_both_pics
9631
9632 xor ax, ax
9633 mov ds, ax
9634
9635 jmp far ptr [0x467]
9636
9637
9638;--------------------
9639eoi_both_pics:
9640 mov al, #0x20
9641 out #0xA0, al ;; slave PIC EOI
9642eoi_master_pic:
9643 mov al, #0x20
9644 out #0x20, al ;; master PIC EOI
9645 ret
9646
9647;--------------------
9648BcdToBin:
9649 ;; in: AL in BCD format
9650 ;; out: AL in binary format, AH will always be 0
9651 ;; trashes BX
9652 mov bl, al
9653 and bl, #0x0f ;; bl has low digit
9654 shr al, #4 ;; al has high digit
9655 mov bh, #10
9656 mul al, bh ;; multiply high digit by 10 (result in AX)
9657 add al, bl ;; then add low digit
9658 ret
9659
9660;--------------------
9661timer_tick_post:
9662 ;; Setup the Timer Ticks Count (0x46C:dword) and
9663 ;; Timer Ticks Roller Flag (0x470:byte)
9664 ;; The Timer Ticks Count needs to be set according to
9665 ;; the current CMOS time, as if ticks have been occurring
9666 ;; at 18.2hz since midnight up to this point. Calculating
9667 ;; this is a little complicated. Here are the factors I gather
9668 ;; regarding this. 14,318,180 hz was the original clock speed,
9669 ;; chosen so it could be divided by either 3 to drive the 5Mhz CPU
9670 ;; at the time, or 4 to drive the CGA video adapter. The div3
9671 ;; source was divided again by 4 to feed a 1.193Mhz signal to
9672 ;; the timer. With a maximum 16bit timer count, this is again
9673 ;; divided down by 65536 to 18.2hz.
9674 ;;
9675 ;; 14,318,180 Hz clock
9676 ;; /3 = 4,772,726 Hz fed to orginal 5Mhz CPU
9677 ;; /4 = 1,193,181 Hz fed to timer
9678 ;; /65536 (maximum timer count) = 18.20650736 ticks/second
9679 ;; 1 second = 18.20650736 ticks
9680 ;; 1 minute = 1092.390442 ticks
9681 ;; 1 hour = 65543.42651 ticks
9682 ;;
9683 ;; Given the values in the CMOS clock, one could calculate
9684 ;; the number of ticks by the following:
9685 ;; ticks = (BcdToBin(seconds) * 18.206507) +
9686 ;; (BcdToBin(minutes) * 1092.3904)
9687 ;; (BcdToBin(hours) * 65543.427)
9688 ;; To get a little more accuracy, since Im using integer
9689 ;; arithmatic, I use:
9690 ;; ticks = (BcdToBin(seconds) * 18206507) / 1000000 +
9691 ;; (BcdToBin(minutes) * 10923904) / 10000 +
9692 ;; (BcdToBin(hours) * 65543427) / 1000
9693
9694 ;; assuming DS=0000
9695
9696 ;; get CMOS seconds
9697 xor eax, eax ;; clear EAX
9698 mov al, #0x00
9699 out #0x70, al
9700 in al, #0x71 ;; AL has CMOS seconds in BCD
9701 call BcdToBin ;; EAX now has seconds in binary
9702 mov edx, #18206507
9703 mul eax, edx
9704 mov ebx, #1000000
9705 xor edx, edx
9706 div eax, ebx
9707 mov ecx, eax ;; ECX will accumulate total ticks
9708
9709 ;; get CMOS minutes
9710 xor eax, eax ;; clear EAX
9711 mov al, #0x02
9712 out #0x70, al
9713 in al, #0x71 ;; AL has CMOS minutes in BCD
9714 call BcdToBin ;; EAX now has minutes in binary
9715 mov edx, #10923904
9716 mul eax, edx
9717 mov ebx, #10000
9718 xor edx, edx
9719 div eax, ebx
9720 add ecx, eax ;; add to total ticks
9721
9722 ;; get CMOS hours
9723 xor eax, eax ;; clear EAX
9724 mov al, #0x04
9725 out #0x70, al
9726 in al, #0x71 ;; AL has CMOS hours in BCD
9727 call BcdToBin ;; EAX now has hours in binary
9728 mov edx, #65543427
9729 mul eax, edx
9730 mov ebx, #1000
9731 xor edx, edx
9732 div eax, ebx
9733 add ecx, eax ;; add to total ticks
9734
9735 mov 0x46C, ecx ;; Timer Ticks Count
9736 xor al, al
9737 mov 0x470, al ;; Timer Ticks Rollover Flag
9738 ret
9739
9740;--------------------
9741int76_handler:
9742 ;; record completion in BIOS task complete flag
9743 push ax
9744 push ds
9745 mov ax, #0x0040
9746 mov ds, ax
9747 mov 0x008E, #0xff
9748 call eoi_both_pics
9749 pop ds
9750 pop ax
9751 iret
9752
9753
9754;--------------------
9755#ifdef VBOX
9756init_pic:
9757 ;; init PIC
9758 mov al, #0x11 ; send initialisation commands
9759 out 0x20, al
9760 out 0xa0, al
9761 mov al, #0x08
9762 out 0x21, al
9763 mov al, #0x70
9764 out 0xa1, al
9765 mov al, #0x04
9766 out 0x21, al
9767 mov al, #0x02
9768 out 0xa1, al
9769 mov al, #0x01
9770 out 0x21, al
9771 out 0xa1, al
9772 mov al, #0xb8
9773 out 0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6
9774#if BX_USE_PS2_MOUSE
9775 mov al, #0x8f
9776#else
9777 mov al, #0x9f
9778#endif
9779 out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14
9780 ret
9781#endif /* VBOX */
9782
9783;--------------------
9784#if BX_APM
9785
9786use32 386
9787#define APM_PROT32
9788#include "apmbios.S"
9789
9790use16 386
9791#define APM_PROT16
9792#include "apmbios.S"
9793
9794#define APM_REAL
9795#include "apmbios.S"
9796
9797#endif
9798
9799;--------------------
9800#if BX_PCIBIOS
9801use32 386
9802.align 16
9803bios32_structure:
9804 db 0x5f, 0x33, 0x32, 0x5f ;; "_32_" signature
9805 dw bios32_entry_point, 0xf ;; 32 bit physical address
9806 db 0 ;; revision level
9807 ;; length in paragraphs and checksum stored in a word to prevent errors
9808 dw (~(((bios32_entry_point >> 8) + (bios32_entry_point & 0xff) + 0x32) \
9809 & 0xff) << 8) + 0x01
9810 db 0,0,0,0,0 ;; reserved
9811
9812.align 16
9813bios32_entry_point:
9814 pushfd
9815 cmp eax, #0x49435024 ;; "$PCI"
9816 jne unknown_service
9817 mov eax, #0x80000000
9818 mov dx, #0x0cf8
9819 out dx, eax
9820 mov dx, #0x0cfc
9821 in eax, dx
9822#ifdef PCI_FIXED_HOST_BRIDGE
9823 cmp eax, #PCI_FIXED_HOST_BRIDGE
9824 jne unknown_service
9825#else
9826 ;; say ok if a device is present
9827 cmp eax, #0xffffffff
9828 je unknown_service
9829#endif
9830 mov ebx, #0x000f0000
9831 mov ecx, #0
9832 mov edx, #pcibios_protected
9833 xor al, al
9834 jmp bios32_end
9835unknown_service:
9836 mov al, #0x80
9837bios32_end:
9838#ifdef BX_QEMU
9839 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
9840#endif
9841 popfd
9842 retf
9843
9844.align 16
9845pcibios_protected:
9846 pushfd
9847 cli
9848 push esi
9849 push edi
9850 cmp al, #0x01 ;; installation check
9851 jne pci_pro_f02
9852 mov bx, #0x0210
9853 mov cx, #0
9854 mov edx, #0x20494350 ;; "PCI "
9855 mov al, #0x01
9856 jmp pci_pro_ok
9857pci_pro_f02: ;; find pci device
9858 cmp al, #0x02
9859 jne pci_pro_f03
9860 shl ecx, #16
9861 mov cx, dx
9862 xor ebx, ebx
9863 mov di, #0x00
9864pci_pro_devloop:
9865 call pci_pro_select_reg
9866 mov dx, #0x0cfc
9867 in eax, dx
9868 cmp eax, ecx
9869 jne pci_pro_nextdev
9870 cmp si, #0
9871 je pci_pro_ok
9872 dec si
9873pci_pro_nextdev:
9874 inc ebx
9875 cmp ebx, #0x10000
9876 jne pci_pro_devloop
9877 mov ah, #0x86
9878 jmp pci_pro_fail
9879pci_pro_f03: ;; find class code
9880 cmp al, #0x03
9881 jne pci_pro_f08
9882 xor ebx, ebx
9883 mov di, #0x08
9884pci_pro_devloop2:
9885 call pci_pro_select_reg
9886 mov dx, #0x0cfc
9887 in eax, dx
9888 shr eax, #8
9889 cmp eax, ecx
9890 jne pci_pro_nextdev2
9891 cmp si, #0
9892 je pci_pro_ok
9893 dec si
9894pci_pro_nextdev2:
9895 inc ebx
9896 cmp ebx, #0x10000
9897 jne pci_pro_devloop2
9898 mov ah, #0x86
9899 jmp pci_pro_fail
9900pci_pro_f08: ;; read configuration byte
9901 cmp al, #0x08
9902 jne pci_pro_f09
9903 call pci_pro_select_reg
9904 push edx
9905 mov dx, di
9906 and dx, #0x03
9907 add dx, #0x0cfc
9908 in al, dx
9909 pop edx
9910 mov cl, al
9911 jmp pci_pro_ok
9912pci_pro_f09: ;; read configuration word
9913 cmp al, #0x09
9914 jne pci_pro_f0a
9915 call pci_pro_select_reg
9916 push edx
9917 mov dx, di
9918 and dx, #0x02
9919 add dx, #0x0cfc
9920 in ax, dx
9921 pop edx
9922 mov cx, ax
9923 jmp pci_pro_ok
9924pci_pro_f0a: ;; read configuration dword
9925 cmp al, #0x0a
9926 jne pci_pro_f0b
9927 call pci_pro_select_reg
9928 push edx
9929 mov dx, #0x0cfc
9930 in eax, dx
9931 pop edx
9932 mov ecx, eax
9933 jmp pci_pro_ok
9934pci_pro_f0b: ;; write configuration byte
9935 cmp al, #0x0b
9936 jne pci_pro_f0c
9937 call pci_pro_select_reg
9938 push edx
9939 mov dx, di
9940 and dx, #0x03
9941 add dx, #0x0cfc
9942 mov al, cl
9943 out dx, al
9944 pop edx
9945 jmp pci_pro_ok
9946pci_pro_f0c: ;; write configuration word
9947 cmp al, #0x0c
9948 jne pci_pro_f0d
9949 call pci_pro_select_reg
9950 push edx
9951 mov dx, di
9952 and dx, #0x02
9953 add dx, #0x0cfc
9954 mov ax, cx
9955 out dx, ax
9956 pop edx
9957 jmp pci_pro_ok
9958pci_pro_f0d: ;; write configuration dword
9959 cmp al, #0x0d
9960 jne pci_pro_unknown
9961 call pci_pro_select_reg
9962 push edx
9963 mov dx, #0x0cfc
9964 mov eax, ecx
9965 out dx, eax
9966 pop edx
9967 jmp pci_pro_ok
9968pci_pro_unknown:
9969 mov ah, #0x81
9970pci_pro_fail:
9971 pop edi
9972 pop esi
9973#ifdef BX_QEMU
9974 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
9975#endif
9976 popfd
9977 stc
9978 retf
9979pci_pro_ok:
9980 xor ah, ah
9981 pop edi
9982 pop esi
9983#ifdef BX_QEMU
9984 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
9985#endif
9986 popfd
9987 clc
9988 retf
9989
9990pci_pro_select_reg:
9991 push edx
9992 mov eax, #0x800000
9993 mov ax, bx
9994 shl eax, #8
9995 and di, #0xff
9996 or ax, di
9997 and al, #0xfc
9998 mov dx, #0x0cf8
9999 out dx, eax
10000 pop edx
10001 ret
10002
10003use16 386
10004
10005pcibios_real:
10006 push eax
10007 push dx
10008 mov eax, #0x80000000
10009 mov dx, #0x0cf8
10010 out dx, eax
10011 mov dx, #0x0cfc
10012 in eax, dx
10013#ifdef PCI_FIXED_HOST_BRIDGE
10014 cmp eax, #PCI_FIXED_HOST_BRIDGE
10015 je pci_present
10016#else
10017 ;; say ok if a device is present
10018 cmp eax, #0xffffffff
10019 jne pci_present
10020#endif
10021 pop dx
10022 pop eax
10023 mov ah, #0xff
10024 stc
10025 ret
10026pci_present:
10027 pop dx
10028 pop eax
10029 cmp al, #0x01 ;; installation check
10030 jne pci_real_f02
10031 mov ax, #0x0001
10032 mov bx, #0x0210
10033 mov cx, #0
10034 mov edx, #0x20494350 ;; "PCI "
10035 mov edi, #0xf0000
10036 mov di, #pcibios_protected
10037 clc
10038 ret
10039pci_real_f02: ;; find pci device
10040 push esi
10041 push edi
10042 push edx
10043 cmp al, #0x02
10044 jne pci_real_f03
10045 shl ecx, #16
10046 mov cx, dx
10047 xor ebx, ebx
10048 mov di, #0x00
10049pci_real_devloop:
10050 call pci_real_select_reg
10051 mov dx, #0x0cfc
10052 in eax, dx
10053 cmp eax, ecx
10054 jne pci_real_nextdev
10055 cmp si, #0
10056 je pci_real_ok
10057 dec si
10058pci_real_nextdev:
10059 inc ebx
10060 cmp ebx, #0x10000
10061 jne pci_real_devloop
10062 mov dx, cx
10063 shr ecx, #16
10064 mov ax, #0x8602
10065 jmp pci_real_fail
10066pci_real_f03: ;; find class code
10067 cmp al, #0x03
10068 jne pci_real_f08
10069 xor ebx, ebx
10070 mov di, #0x08
10071pci_real_devloop2:
10072 call pci_real_select_reg
10073 mov dx, #0x0cfc
10074 in eax, dx
10075 shr eax, #8
10076 cmp eax, ecx
10077 jne pci_real_nextdev2
10078 cmp si, #0
10079 je pci_real_ok
10080 dec si
10081pci_real_nextdev2:
10082 inc ebx
10083 cmp ebx, #0x10000
10084 jne pci_real_devloop2
10085 mov ax, #0x8603
10086 jmp pci_real_fail
10087pci_real_f08: ;; read configuration byte
10088 cmp al, #0x08
10089 jne pci_real_f09
10090 call pci_real_select_reg
10091 push dx
10092 mov dx, di
10093 and dx, #0x03
10094 add dx, #0x0cfc
10095 in al, dx
10096 pop dx
10097 mov cl, al
10098 jmp pci_real_ok
10099pci_real_f09: ;; read configuration word
10100 cmp al, #0x09
10101 jne pci_real_f0a
10102 call pci_real_select_reg
10103 push dx
10104 mov dx, di
10105 and dx, #0x02
10106 add dx, #0x0cfc
10107 in ax, dx
10108 pop dx
10109 mov cx, ax
10110 jmp pci_real_ok
10111pci_real_f0a: ;; read configuration dword
10112 cmp al, #0x0a
10113 jne pci_real_f0b
10114 call pci_real_select_reg
10115 push dx
10116 mov dx, #0x0cfc
10117 in eax, dx
10118 pop dx
10119 mov ecx, eax
10120 jmp pci_real_ok
10121pci_real_f0b: ;; write configuration byte
10122 cmp al, #0x0b
10123 jne pci_real_f0c
10124 call pci_real_select_reg
10125 push dx
10126 mov dx, di
10127 and dx, #0x03
10128 add dx, #0x0cfc
10129 mov al, cl
10130 out dx, al
10131 pop dx
10132 jmp pci_real_ok
10133pci_real_f0c: ;; write configuration word
10134 cmp al, #0x0c
10135 jne pci_real_f0d
10136 call pci_real_select_reg
10137 push dx
10138 mov dx, di
10139 and dx, #0x02
10140 add dx, #0x0cfc
10141 mov ax, cx
10142 out dx, ax
10143 pop dx
10144 jmp pci_real_ok
10145pci_real_f0d: ;; write configuration dword
10146 cmp al, #0x0d
10147 jne pci_real_f0e
10148 call pci_real_select_reg
10149 push dx
10150 mov dx, #0x0cfc
10151 mov eax, ecx
10152 out dx, eax
10153 pop dx
10154 jmp pci_real_ok
10155pci_real_f0e: ;; get irq routing options
10156 cmp al, #0x0e
10157 jne pci_real_unknown
10158 SEG ES
10159 cmp word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
10160 jb pci_real_too_small
10161 SEG ES
10162 mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
10163 pushf
10164 push ds
10165 push es
10166 push cx
10167 push si
10168 push di
10169 cld
10170 mov si, #pci_routing_table_structure_start
10171 push cs
10172 pop ds
10173 SEG ES
10174 mov cx, [di+2]
10175 SEG ES
10176 mov es, [di+4]
10177 mov di, cx
10178 mov cx, #pci_routing_table_structure_end - pci_routing_table_structure_start
10179 rep
10180 movsb
10181 pop di
10182 pop si
10183 pop cx
10184 pop es
10185 pop ds
10186 popf
10187 mov bx, #(1 << 9) | (1 << 11) ;; irq 9 and 11 are used
10188 jmp pci_real_ok
10189pci_real_too_small:
10190 SEG ES
10191 mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
10192 mov ah, #0x89
10193 jmp pci_real_fail
10194
10195pci_real_unknown:
10196 mov ah, #0x81
10197pci_real_fail:
10198 pop edx
10199 pop edi
10200 pop esi
10201 stc
10202 ret
10203pci_real_ok:
10204 xor ah, ah
10205 pop edx
10206 pop edi
10207 pop esi
10208 clc
10209 ret
10210
10211;; prepare from reading the PCI config space; on input:
10212;; bx = bus/dev/fn
10213;; di = offset into config space header
10214;; destroys eax and may modify di
10215pci_real_select_reg:
10216 push dx
10217 mov eax, #0x800000
10218 mov ax, bx
10219 shl eax, #8
10220 and di, #0xff
10221 or ax, di
10222 and al, #0xfc
10223 mov dx, #0x0cf8
10224 out dx, eax
10225 pop dx
10226 ret
10227
10228.align 16
10229pci_routing_table_structure:
10230 db 0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature
10231 db 0, 1 ;; version
10232#ifdef VBOX
10233#if 0
10234 dw 32 + (30 * 16) ;; table size
10235#else
10236 dw 32 + (10 * 16) ;; table size
10237#endif
10238#else /* !VBOX */
10239 dw 32 + (6 * 16) ;; table size
10240#endif /* !VBOX */
10241 db 0 ;; PCI interrupt router bus
10242 db 0x08 ;; PCI interrupt router DevFunc
10243 dw 0x0000 ;; PCI exclusive IRQs
10244 dw 0x8086 ;; compatible PCI interrupt router vendor ID
10245 dw 0x7000 ;; compatible PCI interrupt router device ID
10246 dw 0,0 ;; Miniport data
10247 db 0,0,0,0,0,0,0,0,0,0,0 ;; reserved
10248#ifdef VBOX
10249 db 0x00 ;; checksum (set by biossums)
10250#else /* !VBOX */
10251 db 0x07 ;; checksum
10252#endif /* !VBOX */
10253pci_routing_table_structure_start:
10254 ;; first slot entry PCI-to-ISA (embedded)
10255 db 0 ;; pci bus number
10256 db 0x08 ;; pci device number (bit 7-3)
10257 db 0x60 ;; link value INTA#: pointer into PCI2ISA config space
10258 dw 0xdef8 ;; IRQ bitmap INTA#
10259 db 0x61 ;; link value INTB#
10260 dw 0xdef8 ;; IRQ bitmap INTB#
10261 db 0x62 ;; link value INTC#
10262 dw 0xdef8 ;; IRQ bitmap INTC#
10263 db 0x63 ;; link value INTD#
10264 dw 0xdef8 ;; IRQ bitmap INTD#
10265 db 0 ;; physical slot (0 = embedded)
10266 db 0 ;; reserved
10267 ;; second slot entry: 1st PCI slot
10268 db 0 ;; pci bus number
10269 db 0x10 ;; pci device number (bit 7-3)
10270 db 0x61 ;; link value INTA#
10271 dw 0xdef8 ;; IRQ bitmap INTA#
10272 db 0x62 ;; link value INTB#
10273 dw 0xdef8 ;; IRQ bitmap INTB#
10274 db 0x63 ;; link value INTC#
10275 dw 0xdef8 ;; IRQ bitmap INTC#
10276 db 0x60 ;; link value INTD#
10277 dw 0xdef8 ;; IRQ bitmap INTD#
10278 db 1 ;; physical slot (0 = embedded)
10279 db 0 ;; reserved
10280 ;; third slot entry: 2nd PCI slot
10281 db 0 ;; pci bus number
10282 db 0x18 ;; pci device number (bit 7-3)
10283 db 0x62 ;; link value INTA#
10284 dw 0xdef8 ;; IRQ bitmap INTA#
10285 db 0x63 ;; link value INTB#
10286 dw 0xdef8 ;; IRQ bitmap INTB#
10287 db 0x60 ;; link value INTC#
10288 dw 0xdef8 ;; IRQ bitmap INTC#
10289 db 0x61 ;; link value INTD#
10290 dw 0xdef8 ;; IRQ bitmap INTD#
10291 db 2 ;; physical slot (0 = embedded)
10292 db 0 ;; reserved
10293 ;; 4th slot entry: 3rd PCI slot
10294 db 0 ;; pci bus number
10295 db 0x20 ;; pci device number (bit 7-3)
10296 db 0x63 ;; link value INTA#
10297 dw 0xdef8 ;; IRQ bitmap INTA#
10298 db 0x60 ;; link value INTB#
10299 dw 0xdef8 ;; IRQ bitmap INTB#
10300 db 0x61 ;; link value INTC#
10301 dw 0xdef8 ;; IRQ bitmap INTC#
10302 db 0x62 ;; link value INTD#
10303 dw 0xdef8 ;; IRQ bitmap INTD#
10304 db 3 ;; physical slot (0 = embedded)
10305 db 0 ;; reserved
10306 ;; 5th slot entry: 4rd PCI slot
10307 db 0 ;; pci bus number
10308 db 0x28 ;; pci device number (bit 7-3)
10309 db 0x60 ;; link value INTA#
10310 dw 0xdef8 ;; IRQ bitmap INTA#
10311 db 0x61 ;; link value INTB#
10312 dw 0xdef8 ;; IRQ bitmap INTB#
10313 db 0x62 ;; link value INTC#
10314 dw 0xdef8 ;; IRQ bitmap INTC#
10315 db 0x63 ;; link value INTD#
10316 dw 0xdef8 ;; IRQ bitmap INTD#
10317 db 4 ;; physical slot (0 = embedded)
10318 db 0 ;; reserved
10319 ;; 6th slot entry: 5rd PCI slot
10320 db 0 ;; pci bus number
10321 db 0x30 ;; pci device number (bit 7-3)
10322 db 0x61 ;; link value INTA#
10323 dw 0xdef8 ;; IRQ bitmap INTA#
10324 db 0x62 ;; link value INTB#
10325 dw 0xdef8 ;; IRQ bitmap INTB#
10326 db 0x63 ;; link value INTC#
10327 dw 0xdef8 ;; IRQ bitmap INTC#
10328 db 0x60 ;; link value INTD#
10329 dw 0xdef8 ;; IRQ bitmap INTD#
10330 db 5 ;; physical slot (0 = embedded)
10331 db 0 ;; reserved
10332#ifdef VBOX
10333 ;; 7th slot entry: 6th PCI slot
10334 db 0 ;; pci bus number
10335 db 0x38 ;; pci device number (bit 7-3)
10336 db 0x62 ;; link value INTA#
10337 dw 0xdef8 ;; IRQ bitmap INTA#
10338 db 0x63 ;; link value INTB#
10339 dw 0xdef8 ;; IRQ bitmap INTB#
10340 db 0x60 ;; link value INTC#
10341 dw 0xdef8 ;; IRQ bitmap INTC#
10342 db 0x61 ;; link value INTD#
10343 dw 0xdef8 ;; IRQ bitmap INTD#
10344 db 6 ;; physical slot (0 = embedded)
10345 db 0 ;; reserved
10346 ;; 8th slot entry: 7th PCI slot
10347 db 0 ;; pci bus number
10348 db 0x40 ;; pci device number (bit 7-3)
10349 db 0x63 ;; link value INTA#
10350 dw 0xdef8 ;; IRQ bitmap INTA#
10351 db 0x60 ;; link value INTB#
10352 dw 0xdef8 ;; IRQ bitmap INTB#
10353 db 0x61 ;; link value INTC#
10354 dw 0xdef8 ;; IRQ bitmap INTC#
10355 db 0x62 ;; link value INTD#
10356 dw 0xdef8 ;; IRQ bitmap INTD#
10357 db 7 ;; physical slot (0 = embedded)
10358 db 0 ;; reserved
10359 ;; 9th slot entry: 8th PCI slot
10360 db 0 ;; pci bus number
10361 db 0x48 ;; pci device number (bit 7-3)
10362 db 0x60 ;; link value INTA#
10363 dw 0xdef8 ;; IRQ bitmap INTA#
10364 db 0x61 ;; link value INTB#
10365 dw 0xdef8 ;; IRQ bitmap INTB#
10366 db 0x62 ;; link value INTC#
10367 dw 0xdef8 ;; IRQ bitmap INTC#
10368 db 0x63 ;; link value INTD#
10369 dw 0xdef8 ;; IRQ bitmap INTD#
10370 db 8 ;; physical slot (0 = embedded)
10371 db 0 ;; reserved
10372 ;; 10th slot entry: 9th PCI slot
10373 db 0 ;; pci bus number
10374 db 0x50 ;; pci device number (bit 7-3)
10375 db 0x61 ;; link value INTA#
10376 dw 0xdef8 ;; IRQ bitmap INTA#
10377 db 0x62 ;; link value INTB#
10378 dw 0xdef8 ;; IRQ bitmap INTB#
10379 db 0x63 ;; link value INTC#
10380 dw 0xdef8 ;; IRQ bitmap INTC#
10381 db 0x60 ;; link value INTD#
10382 dw 0xdef8 ;; IRQ bitmap INTD#
10383 db 9 ;; physical slot (0 = embedded)
10384 db 0 ;; reserved
10385 ;; 11th slot entry: 10th PCI slot
10386 db 0 ;; pci bus number
10387 db 0x58 ;; pci device number (bit 7-3)
10388 db 0x61 ;; link value INTA#
10389 dw 0xdef8 ;; IRQ bitmap INTA#
10390 db 0x62 ;; link value INTB#
10391 dw 0xdef8 ;; IRQ bitmap INTB#
10392 db 0x63 ;; link value INTC#
10393 dw 0xdef8 ;; IRQ bitmap INTC#
10394 db 0x60 ;; link value INTD#
10395 dw 0xdef8 ;; IRQ bitmap INTD#
10396 db 10 ;; physical slot (0 = embedded)
10397 db 0 ;; reserved
10398 ;; 12th slot entry: 11th PCI slot
10399 db 0 ;; pci bus number
10400 db 0x60 ;; pci device number (bit 7-3)
10401 db 0x61 ;; link value INTA#
10402 dw 0xdef8 ;; IRQ bitmap INTA#
10403 db 0x62 ;; link value INTB#
10404 dw 0xdef8 ;; IRQ bitmap INTB#
10405 db 0x63 ;; link value INTC#
10406 dw 0xdef8 ;; IRQ bitmap INTC#
10407 db 0x60 ;; link value INTD#
10408 dw 0xdef8 ;; IRQ bitmap INTD#
10409 db 11 ;; physical slot (0 = embedded)
10410 db 0 ;; reserved
10411 ;; 13th slot entry: 12th PCI slot
10412 db 0 ;; pci bus number
10413 db 0x68 ;; pci device number (bit 7-3)
10414 db 0x61 ;; link value INTA#
10415 dw 0xdef8 ;; IRQ bitmap INTA#
10416 db 0x62 ;; link value INTB#
10417 dw 0xdef8 ;; IRQ bitmap INTB#
10418 db 0x63 ;; link value INTC#
10419 dw 0xdef8 ;; IRQ bitmap INTC#
10420 db 0x60 ;; link value INTD#
10421 dw 0xdef8 ;; IRQ bitmap INTD#
10422 db 12 ;; physical slot (0 = embedded)
10423 db 0 ;; reserved
10424 ;; 14th slot entry: 13th PCI slot
10425 db 0 ;; pci bus number
10426 db 0x70 ;; pci device number (bit 7-3)
10427 db 0x61 ;; link value INTA#
10428 dw 0xdef8 ;; IRQ bitmap INTA#
10429 db 0x62 ;; link value INTB#
10430 dw 0xdef8 ;; IRQ bitmap INTB#
10431 db 0x63 ;; link value INTC#
10432 dw 0xdef8 ;; IRQ bitmap INTC#
10433 db 0x60 ;; link value INTD#
10434 dw 0xdef8 ;; IRQ bitmap INTD#
10435 db 13 ;; physical slot (0 = embedded)
10436 db 0 ;; reserved
10437 ;; 15th slot entry: 14th PCI slot
10438 db 0 ;; pci bus number
10439 db 0x78 ;; pci device number (bit 7-3)
10440 db 0x61 ;; link value INTA#
10441 dw 0xdef8 ;; IRQ bitmap INTA#
10442 db 0x62 ;; link value INTB#
10443 dw 0xdef8 ;; IRQ bitmap INTB#
10444 db 0x63 ;; link value INTC#
10445 dw 0xdef8 ;; IRQ bitmap INTC#
10446 db 0x60 ;; link value INTD#
10447 dw 0xdef8 ;; IRQ bitmap INTD#
10448 db 14 ;; physical slot (0 = embedded)
10449 db 0 ;; reserved
10450 ;; 16th slot entry: 15th PCI slot
10451 db 0 ;; pci bus number
10452 db 0x80 ;; pci device number (bit 7-3)
10453 db 0x61 ;; link value INTA#
10454 dw 0xdef8 ;; IRQ bitmap INTA#
10455 db 0x62 ;; link value INTB#
10456 dw 0xdef8 ;; IRQ bitmap INTB#
10457 db 0x63 ;; link value INTC#
10458 dw 0xdef8 ;; IRQ bitmap INTC#
10459 db 0x60 ;; link value INTD#
10460 dw 0xdef8 ;; IRQ bitmap INTD#
10461 db 15 ;; physical slot (0 = embedded)
10462 db 0 ;; reserved
10463 ;; 17th slot entry: 16th PCI slot
10464 db 0 ;; pci bus number
10465 db 0x88 ;; pci device number (bit 7-3)
10466 db 0x61 ;; link value INTA#
10467 dw 0xdef8 ;; IRQ bitmap INTA#
10468 db 0x62 ;; link value INTB#
10469 dw 0xdef8 ;; IRQ bitmap INTB#
10470 db 0x63 ;; link value INTC#
10471 dw 0xdef8 ;; IRQ bitmap INTC#
10472 db 0x60 ;; link value INTD#
10473 dw 0xdef8 ;; IRQ bitmap INTD#
10474 db 16 ;; physical slot (0 = embedded)
10475 db 0 ;; reserved
10476 ;; 18th slot entry: 17th PCI slot
10477 db 0 ;; pci bus number
10478 db 0x90 ;; pci device number (bit 7-3)
10479 db 0x61 ;; link value INTA#
10480 dw 0xdef8 ;; IRQ bitmap INTA#
10481 db 0x62 ;; link value INTB#
10482 dw 0xdef8 ;; IRQ bitmap INTB#
10483 db 0x63 ;; link value INTC#
10484 dw 0xdef8 ;; IRQ bitmap INTC#
10485 db 0x60 ;; link value INTD#
10486 dw 0xdef8 ;; IRQ bitmap INTD#
10487 db 17 ;; physical slot (0 = embedded)
10488 db 0 ;; reserved
10489 ;; 19th slot entry: 18th PCI slot
10490 db 0 ;; pci bus number
10491 db 0x98 ;; pci device number (bit 7-3)
10492 db 0x61 ;; link value INTA#
10493 dw 0xdef8 ;; IRQ bitmap INTA#
10494 db 0x62 ;; link value INTB#
10495 dw 0xdef8 ;; IRQ bitmap INTB#
10496 db 0x63 ;; link value INTC#
10497 dw 0xdef8 ;; IRQ bitmap INTC#
10498 db 0x60 ;; link value INTD#
10499 dw 0xdef8 ;; IRQ bitmap INTD#
10500 db 18 ;; physical slot (0 = embedded)
10501 db 0 ;; reserved
10502 ;; 20th slot entry: 19th PCI slot
10503 db 0 ;; pci bus number
10504 db 0xa0 ;; pci device number (bit 7-3)
10505 db 0x61 ;; link value INTA#
10506 dw 0xdef8 ;; IRQ bitmap INTA#
10507 db 0x62 ;; link value INTB#
10508 dw 0xdef8 ;; IRQ bitmap INTB#
10509 db 0x63 ;; link value INTC#
10510 dw 0xdef8 ;; IRQ bitmap INTC#
10511 db 0x60 ;; link value INTD#
10512 dw 0xdef8 ;; IRQ bitmap INTD#
10513 db 19 ;; physical slot (0 = embedded)
10514 db 0 ;; reserved
10515 ;; 21th slot entry: 20th PCI slot
10516 db 0 ;; pci bus number
10517 db 0xa8 ;; pci device number (bit 7-3)
10518 db 0x61 ;; link value INTA#
10519 dw 0xdef8 ;; IRQ bitmap INTA#
10520 db 0x62 ;; link value INTB#
10521 dw 0xdef8 ;; IRQ bitmap INTB#
10522 db 0x63 ;; link value INTC#
10523 dw 0xdef8 ;; IRQ bitmap INTC#
10524 db 0x60 ;; link value INTD#
10525 dw 0xdef8 ;; IRQ bitmap INTD#
10526 db 20 ;; physical slot (0 = embedded)
10527 db 0 ;; reserved
10528 ;; 21th slot entry: 20th PCI slot
10529 db 0 ;; pci bus number
10530 db 0xb0 ;; pci device number (bit 7-3)
10531 db 0x61 ;; link value INTA#
10532 dw 0xdef8 ;; IRQ bitmap INTA#
10533 db 0x62 ;; link value INTB#
10534 dw 0xdef8 ;; IRQ bitmap INTB#
10535 db 0x63 ;; link value INTC#
10536 dw 0xdef8 ;; IRQ bitmap INTC#
10537 db 0x60 ;; link value INTD#
10538 dw 0xdef8 ;; IRQ bitmap INTD#
10539 db 20 ;; physical slot (0 = embedded)
10540 db 0 ;; reserved
10541 ;; 22th slot entry: 21th PCI slot
10542 db 0 ;; pci bus number
10543 db 0xb8 ;; pci device number (bit 7-3)
10544 db 0x61 ;; link value INTA#
10545 dw 0xdef8 ;; IRQ bitmap INTA#
10546 db 0x62 ;; link value INTB#
10547 dw 0xdef8 ;; IRQ bitmap INTB#
10548 db 0x63 ;; link value INTC#
10549 dw 0xdef8 ;; IRQ bitmap INTC#
10550 db 0x60 ;; link value INTD#
10551 dw 0xdef8 ;; IRQ bitmap INTD#
10552 db 21 ;; physical slot (0 = embedded)
10553 db 0 ;; reserved
10554 ;; 23th slot entry: 22th PCI slot
10555 db 0 ;; pci bus number
10556 db 0xc0 ;; pci device number (bit 7-3)
10557 db 0x61 ;; link value INTA#
10558 dw 0xdef8 ;; IRQ bitmap INTA#
10559 db 0x62 ;; link value INTB#
10560 dw 0xdef8 ;; IRQ bitmap INTB#
10561 db 0x63 ;; link value INTC#
10562 dw 0xdef8 ;; IRQ bitmap INTC#
10563 db 0x60 ;; link value INTD#
10564 dw 0xdef8 ;; IRQ bitmap INTD#
10565 db 22 ;; physical slot (0 = embedded)
10566 db 0 ;; reserved
10567 ;; 24th slot entry: 23th PCI slot
10568 db 0 ;; pci bus number
10569 db 0xc8 ;; pci device number (bit 7-3)
10570 db 0x61 ;; link value INTA#
10571 dw 0xdef8 ;; IRQ bitmap INTA#
10572 db 0x62 ;; link value INTB#
10573 dw 0xdef8 ;; IRQ bitmap INTB#
10574 db 0x63 ;; link value INTC#
10575 dw 0xdef8 ;; IRQ bitmap INTC#
10576 db 0x60 ;; link value INTD#
10577 dw 0xdef8 ;; IRQ bitmap INTD#
10578 db 23 ;; physical slot (0 = embedded)
10579 db 0 ;; reserved
10580 ;; 25th slot entry: 24th PCI slot
10581 db 0 ;; pci bus number
10582 db 0xd0 ;; pci device number (bit 7-3)
10583 db 0x61 ;; link value INTA#
10584 dw 0xdef8 ;; IRQ bitmap INTA#
10585 db 0x62 ;; link value INTB#
10586 dw 0xdef8 ;; IRQ bitmap INTB#
10587 db 0x63 ;; link value INTC#
10588 dw 0xdef8 ;; IRQ bitmap INTC#
10589 db 0x60 ;; link value INTD#
10590 dw 0xdef8 ;; IRQ bitmap INTD#
10591 db 24 ;; physical slot (0 = embedded)
10592 db 0 ;; reserved
10593 ;; 26th slot entry: 25th PCI slot
10594 db 0 ;; pci bus number
10595 db 0xd8 ;; pci device number (bit 7-3)
10596 db 0x61 ;; link value INTA#
10597 dw 0xdef8 ;; IRQ bitmap INTA#
10598 db 0x62 ;; link value INTB#
10599 dw 0xdef8 ;; IRQ bitmap INTB#
10600 db 0x63 ;; link value INTC#
10601 dw 0xdef8 ;; IRQ bitmap INTC#
10602 db 0x60 ;; link value INTD#
10603 dw 0xdef8 ;; IRQ bitmap INTD#
10604 db 25 ;; physical slot (0 = embedded)
10605 db 0 ;; reserved
10606 ;; 27th slot entry: 26th PCI slot
10607 db 0 ;; pci bus number
10608 db 0xe0 ;; pci device number (bit 7-3)
10609 db 0x61 ;; link value INTA#
10610 dw 0xdef8 ;; IRQ bitmap INTA#
10611 db 0x62 ;; link value INTB#
10612 dw 0xdef8 ;; IRQ bitmap INTB#
10613 db 0x63 ;; link value INTC#
10614 dw 0xdef8 ;; IRQ bitmap INTC#
10615 db 0x60 ;; link value INTD#
10616 dw 0xdef8 ;; IRQ bitmap INTD#
10617 db 26 ;; physical slot (0 = embedded)
10618 db 0 ;; reserved
10619 ;; 28th slot entry: 27th PCI slot
10620 db 0 ;; pci bus number
10621 db 0xe8 ;; pci device number (bit 7-3)
10622 db 0x61 ;; link value INTA#
10623 dw 0xdef8 ;; IRQ bitmap INTA#
10624 db 0x62 ;; link value INTB#
10625 dw 0xdef8 ;; IRQ bitmap INTB#
10626 db 0x63 ;; link value INTC#
10627 dw 0xdef8 ;; IRQ bitmap INTC#
10628 db 0x60 ;; link value INTD#
10629 dw 0xdef8 ;; IRQ bitmap INTD#
10630 db 27 ;; physical slot (0 = embedded)
10631 db 0 ;; reserved
10632 ;; 29th slot entry: 28th PCI slot
10633 db 0 ;; pci bus number
10634 db 0xf0 ;; pci device number (bit 7-3)
10635 db 0x61 ;; link value INTA#
10636 dw 0xdef8 ;; IRQ bitmap INTA#
10637 db 0x62 ;; link value INTB#
10638 dw 0xdef8 ;; IRQ bitmap INTB#
10639 db 0x63 ;; link value INTC#
10640 dw 0xdef8 ;; IRQ bitmap INTC#
10641 db 0x60 ;; link value INTD#
10642 dw 0xdef8 ;; IRQ bitmap INTD#
10643 db 28 ;; physical slot (0 = embedded)
10644 db 0 ;; reserved
10645 ;; 30th slot entry: 29th PCI slot
10646 db 0 ;; pci bus number
10647 db 0xf8 ;; pci device number (bit 7-3)
10648 db 0x61 ;; link value INTA#
10649 dw 0xdef8 ;; IRQ bitmap INTA#
10650 db 0x62 ;; link value INTB#
10651 dw 0xdef8 ;; IRQ bitmap INTB#
10652 db 0x63 ;; link value INTC#
10653 dw 0xdef8 ;; IRQ bitmap INTC#
10654 db 0x60 ;; link value INTD#
10655 dw 0xdef8 ;; IRQ bitmap INTD#
10656 db 29 ;; physical slot (0 = embedded)
10657 db 0 ;; reserved
10658#endif /* VBOX */
10659pci_routing_table_structure_end:
10660
10661#if !BX_ROMBIOS32
10662pci_irq_list:
10663 db 11, 10, 9, 5;
10664
10665pcibios_init_sel_reg:
10666 push eax
10667 mov eax, #0x800000
10668 mov ax, bx
10669 shl eax, #8
10670 and dl, #0xfc
10671 or al, dl
10672 mov dx, #0x0cf8
10673 out dx, eax
10674 pop eax
10675 ret
10676
10677pcibios_init_iomem_bases:
10678 push bp
10679 mov bp, sp
10680 mov eax, #0xe0000000 ;; base for memory init
10681 push eax
10682 mov ax, #0xc000 ;; base for i/o init
10683 push ax
10684 mov ax, #0x0010 ;; start at base address #0
10685 push ax
10686 mov bx, #0x0008
10687pci_init_io_loop1:
10688 mov dl, #0x00
10689 call pcibios_init_sel_reg
10690 mov dx, #0x0cfc
10691 in ax, dx
10692 cmp ax, #0xffff
10693 jz next_pci_dev
10694#ifndef VBOX /* This currently breaks restoring a previously saved state. */
10695 mov dl, #0x04 ;; disable i/o and memory space access
10696 call pcibios_init_sel_reg
10697 mov dx, #0x0cfc
10698 in al, dx
10699 and al, #0xfc
10700 out dx, al
10701pci_init_io_loop2:
10702 mov dl, [bp-8]
10703 call pcibios_init_sel_reg
10704 mov dx, #0x0cfc
10705 in eax, dx
10706 test al, #0x01
10707 jnz init_io_base
10708 mov ecx, eax
10709 mov eax, #0xffffffff
10710 out dx, eax
10711 in eax, dx
10712 cmp eax, ecx
10713 je next_pci_base
10714 xor eax, #0xffffffff
10715 mov ecx, eax
10716 mov eax, [bp-4]
10717 out dx, eax
10718 add eax, ecx ;; calculate next free mem base
10719 add eax, #0x01000000
10720 and eax, #0xff000000
10721 mov [bp-4], eax
10722 jmp next_pci_base
10723init_io_base:
10724 mov cx, ax
10725 mov ax, #0xffff
10726 out dx, ax
10727 in ax, dx
10728 cmp ax, cx
10729 je next_pci_base
10730 xor ax, #0xfffe
10731 mov cx, ax
10732 mov ax, [bp-6]
10733 out dx, ax
10734 add ax, cx ;; calculate next free i/o base
10735 add ax, #0x0100
10736 and ax, #0xff00
10737 mov [bp-6], ax
10738next_pci_base:
10739 mov al, [bp-8]
10740 add al, #0x04
10741 cmp al, #0x28
10742 je enable_iomem_space
10743 mov byte ptr[bp-8], al
10744 jmp pci_init_io_loop2
10745#endif /* !VBOX */
10746enable_iomem_space:
10747 mov dl, #0x04 ;; enable i/o and memory space access if available
10748 call pcibios_init_sel_reg
10749 mov dx, #0x0cfc
10750 in al, dx
10751 or al, #0x07
10752 out dx, al
10753#ifdef VBOX
10754 mov dl, #0x00 ;; check if PCI device is AMD PCNet
10755 call pcibios_init_sel_reg
10756 mov dx, #0x0cfc
10757 in eax, dx
10758 cmp eax, #0x20001022
10759 jne next_pci_dev
10760 mov dl, #0x10 ;; get I/O address
10761 call pcibios_init_sel_reg
10762 mov dx, #0x0cfc
10763 in ax, dx
10764 and ax, #0xfffc
10765 mov cx, ax
10766 mov dx, cx
10767 add dx, #0x14 ;; reset register if PCNet is in word I/O mode
10768 in ax, dx ;; reset is performed by reading the reset register
10769 mov dx, cx
10770 add dx, #0x18 ;; reset register if PCNet is in word I/O mode
10771 in eax, dx ;; reset is performed by reading the reset register
10772#endif /* VBOX */
10773next_pci_dev:
10774 mov byte ptr[bp-8], #0x10
10775 inc bx
10776 cmp bx, #0x0100
10777 jne pci_init_io_loop1
10778 mov sp, bp
10779 pop bp
10780 ret
10781
10782pcibios_init_set_elcr:
10783 push ax
10784 push cx
10785 mov dx, #0x04d0
10786 test al, #0x08
10787 jz is_master_pic
10788 inc dx
10789 and al, #0x07
10790is_master_pic:
10791 mov cl, al
10792 mov bl, #0x01
10793 shl bl, cl
10794 in al, dx
10795 or al, bl
10796 out dx, al
10797 pop cx
10798 pop ax
10799 ret
10800
10801pcibios_init_irqs:
10802 push ds
10803 push bp
10804 mov ax, #0xf000
10805 mov ds, ax
10806 mov dx, #0x04d0 ;; reset ELCR1 + ELCR2
10807 mov al, #0x00
10808 out dx, al
10809 inc dx
10810 out dx, al
10811 mov si, #pci_routing_table_structure
10812 mov bh, [si+8]
10813 mov bl, [si+9]
10814 mov dl, #0x00
10815 call pcibios_init_sel_reg
10816 mov dx, #0x0cfc
10817 in eax, dx
10818 cmp eax, [si+12] ;; check irq router
10819 jne pci_init_end
10820 mov dl, [si+34]
10821 call pcibios_init_sel_reg
10822 push bx ;; save irq router bus + devfunc
10823 mov dx, #0x0cfc
10824 mov ax, #0x8080
10825 out dx, ax ;; reset PIRQ route control
10826 add dx, #2
10827 out dx, ax
10828 mov ax, [si+6]
10829 sub ax, #0x20
10830 shr ax, #4
10831 mov cx, ax
10832 add si, #0x20 ;; set pointer to 1st entry
10833 mov bp, sp
10834 mov ax, #pci_irq_list
10835 push ax
10836 xor ax, ax
10837 push ax
10838pci_init_irq_loop1:
10839 mov bh, [si]
10840 mov bl, [si+1]
10841pci_init_irq_loop2:
10842 mov dl, #0x00
10843 call pcibios_init_sel_reg
10844 mov dx, #0x0cfc
10845 in ax, dx
10846 cmp ax, #0xffff
10847 jnz pci_test_int_pin
10848 test bl, #0x07
10849 jz next_pir_entry
10850 jmp next_pci_func
10851pci_test_int_pin:
10852 mov dl, #0x3c
10853 call pcibios_init_sel_reg
10854 mov dx, #0x0cfd
10855 in al, dx
10856 and al, #0x07
10857 jz next_pci_func
10858 dec al ;; determine pirq reg
10859 mov dl, #0x03
10860 mul al, dl
10861 add al, #0x02
10862 xor ah, ah
10863 mov bx, ax
10864 mov al, [si+bx]
10865 mov dl, al
10866 mov bx, [bp]
10867 call pcibios_init_sel_reg
10868 mov dx, #0x0cfc
10869 and al, #0x03
10870 add dl, al
10871 in al, dx
10872 cmp al, #0x80
10873 jb pirq_found
10874 mov bx, [bp-2] ;; pci irq list pointer
10875 mov al, [bx]
10876 out dx, al
10877 inc bx
10878 mov [bp-2], bx
10879 call pcibios_init_set_elcr
10880pirq_found:
10881 mov bh, [si]
10882 mov bl, [si+1]
10883 add bl, [bp-3] ;; pci function number
10884 mov dl, #0x3c
10885 call pcibios_init_sel_reg
10886 mov dx, #0x0cfc
10887 out dx, al
10888next_pci_func:
10889 inc byte ptr[bp-3]
10890 inc bl
10891 test bl, #0x07
10892 jnz pci_init_irq_loop2
10893next_pir_entry:
10894 add si, #0x10
10895 mov byte ptr[bp-3], #0x00
10896 loop pci_init_irq_loop1
10897 mov sp, bp
10898 pop bx
10899pci_init_end:
10900 pop bp
10901 pop ds
10902 ret
10903#endif // !BX_ROMBIOS32
10904#endif // BX_PCIBIOS
10905
10906#if BX_ROMBIOS32
10907rombios32_init:
10908 ;; save a20 and enable it
10909 in al, 0x92
10910 push ax
10911 or al, #0x02
10912 out 0x92, al
10913
10914 ;; save SS:SP to the BDA
10915 xor ax, ax
10916 mov ds, ax
10917 mov 0x0469, ss
10918 mov 0x0467, sp
10919
10920 SEG CS
10921 lidt [pmode_IDT_info]
10922 SEG CS
10923 lgdt [rombios32_gdt_48]
10924 ;; set PE bit in CR0
10925 mov eax, cr0
10926 or al, #0x01
10927 mov cr0, eax
10928 ;; start protected mode code: ljmpl 0x10:rombios32_init1
10929 db 0x66, 0xea
10930 dw rombios32_05
10931 dw 0x000f ;; high 16 bit address
10932 dw 0x0010
10933
10934use32 386
10935rombios32_05:
10936 ;; init data segments
10937 mov eax, #0x18
10938 mov ds, ax
10939 mov es, ax
10940 mov ss, ax
10941 xor eax, eax
10942 mov fs, ax
10943 mov gs, ax
10944 cld
10945
10946 ;; copy rombios32 code to ram (ram offset = 1MB)
10947 mov esi, #0xfffe0000
10948 mov edi, #0x00040000
10949 mov ecx, #0x10000 / 4
10950 rep
10951 movsd
10952
10953 ;; init the stack pointer
10954 mov esp, #0x00080000
10955
10956 ;; call rombios32 code
10957 mov eax, #0x00040000
10958 call eax
10959
10960 ;; return to 16 bit protected mode first
10961 db 0xea
10962 dd rombios32_10
10963 dw 0x20
10964
10965use16 386
10966rombios32_10:
10967 ;; restore data segment limits to 0xffff
10968 mov ax, #0x28
10969 mov ds, ax
10970 mov es, ax
10971 mov ss, ax
10972 mov fs, ax
10973 mov gs, ax
10974
10975 ;; reset PE bit in CR0
10976 mov eax, cr0
10977 and al, #0xFE
10978 mov cr0, eax
10979
10980 ;; far jump to flush CPU queue after transition to real mode
10981 JMP_AP(0xf000, rombios32_real_mode)
10982
10983rombios32_real_mode:
10984 ;; restore IDT to normal real-mode defaults
10985 SEG CS
10986 lidt [rmode_IDT_info]
10987
10988 xor ax, ax
10989 mov ds, ax
10990 mov es, ax
10991 mov fs, ax
10992 mov gs, ax
10993
10994 ;; restore SS:SP from the BDA
10995 mov ss, 0x0469
10996 xor esp, esp
10997 mov sp, 0x0467
10998 ;; restore a20
10999 pop ax
11000 out 0x92, al
11001 ret
11002
11003rombios32_gdt_48:
11004 dw 0x30
11005 dw rombios32_gdt
11006 dw 0x000f
11007
11008rombios32_gdt:
11009 dw 0, 0, 0, 0
11010 dw 0, 0, 0, 0
11011 dw 0xffff, 0, 0x9b00, 0x00cf ; 32 bit flat code segment (0x10)
11012 dw 0xffff, 0, 0x9300, 0x00cf ; 32 bit flat data segment (0x18)
11013 dw 0xffff, 0, 0x9b0f, 0x0000 ; 16 bit code segment base=0xf0000 limit=0xffff
11014 dw 0xffff, 0, 0x9300, 0x0000 ; 16 bit data segment base=0x0 limit=0xffff
11015#endif // BX_ROMBIOS32
11016
11017
11018; parallel port detection: base address in DX, index in BX, timeout in CL
11019detect_parport:
11020 push dx
11021 add dx, #2
11022 in al, dx
11023 and al, #0xdf ; clear input mode
11024 out dx, al
11025 pop dx
11026 mov al, #0xaa
11027 out dx, al
11028 in al, dx
11029 cmp al, #0xaa
11030 jne no_parport
11031 push bx
11032 shl bx, #1
11033 mov [bx+0x408], dx ; Parallel I/O address
11034 pop bx
11035 mov [bx+0x478], cl ; Parallel printer timeout
11036 inc bx
11037no_parport:
11038 ret
11039
11040; serial port detection: base address in DX, index in BX, timeout in CL
11041detect_serial:
11042 push dx
11043 inc dx
11044 mov al, #0x02
11045 out dx, al
11046 in al, dx
11047 cmp al, #0x02
11048 jne no_serial
11049 inc dx
11050 in al, dx
11051 cmp al, #0x02
11052 jne no_serial
11053 dec dx
11054 xor al, al
11055 out dx, al
11056 pop dx
11057 push bx
11058 shl bx, #1
11059 mov [bx+0x400], dx ; Serial I/O address
11060 pop bx
11061 mov [bx+0x47c], cl ; Serial timeout
11062 inc bx
11063 ret
11064no_serial:
11065 pop dx
11066 ret
11067
11068rom_checksum:
11069 push ax
11070 push bx
11071 push cx
11072 xor ax, ax
11073 xor bx, bx
11074 xor cx, cx
11075 mov ch, [2]
11076 shl cx, #1
11077checksum_loop:
11078 add al, [bx]
11079 inc bx
11080 loop checksum_loop
11081 and al, #0xff
11082 pop cx
11083 pop bx
11084 pop ax
11085 ret
11086
11087rom_scan:
11088 ;; Scan for existence of valid expansion ROMS.
11089 ;; Video ROM: from 0xC0000..0xC7FFF in 2k increments
11090 ;; General ROM: from 0xC8000..0xDFFFF in 2k increments
11091 ;; System ROM: only 0xE0000
11092 ;;
11093 ;; Header:
11094 ;; Offset Value
11095 ;; 0 0x55
11096 ;; 1 0xAA
11097 ;; 2 ROM length in 512-byte blocks
11098 ;; 3 ROM initialization entry point (FAR CALL)
11099
11100 mov cx, #0xc000
11101rom_scan_loop:
11102 mov ds, cx
11103 mov ax, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
11104 cmp [0], #0xAA55 ;; look for signature
11105 jne rom_scan_increment
11106 call rom_checksum
11107 jnz rom_scan_increment
11108 mov al, [2] ;; change increment to ROM length in 512-byte blocks
11109
11110 ;; We want our increment in 512-byte quantities, rounded to
11111 ;; the nearest 2k quantity, since we only scan at 2k intervals.
11112 test al, #0x03
11113 jz block_count_rounded
11114 and al, #0xfc ;; needs rounding up
11115 add al, #0x04
11116block_count_rounded:
11117
11118 xor bx, bx ;; Restore DS back to 0000:
11119 mov ds, bx
11120 push ax ;; Save AX
11121 ;; Push addr of ROM entry point
11122 push cx ;; Push seg
11123 push #0x0003 ;; Push offset
11124 mov bp, sp ;; Call ROM init routine using seg:off on stack
11125 db 0xff ;; call_far ss:[bp+0]
11126 db 0x5e
11127 db 0
11128 cli ;; In case expansion ROM BIOS turns IF on
11129 add sp, #2 ;; Pop offset value
11130 pop cx ;; Pop seg value (restore CX)
11131 pop ax ;; Restore AX
11132rom_scan_increment:
11133 shl ax, #5 ;; convert 512-bytes blocks to 16-byte increments
11134 ;; because the segment selector is shifted left 4 bits.
11135 add cx, ax
11136 cmp cx, #0xe800 ;; Must encompass VBOX_LANBOOT_SEG!
11137 jbe rom_scan_loop
11138
11139 xor ax, ax ;; Restore DS back to 0000:
11140 mov ds, ax
11141 ret
11142
11143#define LVT0 0xFEE00350
11144#define LVT1 0xFEE00360
11145
11146;; Program LVT0/LVT1 entries in the local APIC. Some Linux kernels (e.g., RHEL4
11147;; SMP 32-bit) expect the entries to be unmasked in virtual wire mode.
11148
11149setup_lapic:
11150 pushf
11151 cli ;; Interrupts would kill us!
11152 call pmode_enter
11153 mov esi, #LVT0 ;; Program LVT0 to ExtINT and unmask
11154 mov eax, [esi]
11155 and eax, #0xfffe00ff
11156 or ah, #0x07
11157 mov [esi], eax
11158 mov esi, #LVT1 ;; Program LVT1 to NMI and unmask
11159 mov eax, [esi]
11160 and eax, #0xfffe00ff
11161 or ah, #0x04
11162 mov [esi], eax
11163 call pmode_exit
11164 popf
11165 ret
11166
11167;; Enter and exit minimal protected-mode environment. May only be called from
11168;; the F000 segment (16-bit). Does not switch stacks. Must be run with disabled
11169;; interrupts(!). On return from pmode_enter, DS contains a selector which can
11170;; address the entire 4GB address space.
11171
11172pmode_enter:
11173 push cs
11174 pop ds
11175 lgdt [pmbios_gdt_desc]
11176 mov eax, cr0
11177 or al, #0x1
11178 mov cr0, eax
11179 JMP_AP(0x20, really_enter_pm)
11180really_enter_pm:
11181 mov ax, #0x18
11182 mov ds, ax
11183 ret
11184
11185pmode_exit:
11186 mov eax, cr0
11187 and al, #0xfe
11188 mov cr0, eax
11189 JMP_AP(0xF000, really_exit_pm)
11190really_exit_pm:
11191 ret
11192
11193pmbios_gdt_desc:
11194 dw 0x30
11195 dw pmbios_gdt
11196 dw 0x000f
11197
11198pmbios_gdt:
11199 dw 0, 0, 0, 0
11200 dw 0, 0, 0, 0
11201 dw 0xffff, 0, 0x9b00, 0x00cf ; 32 bit flat code segment (0x10)
11202 dw 0xffff, 0, 0x9300, 0x00cf ; 32 bit flat data segment (0x18)
11203 dw 0xffff, 0, 0x9b0f, 0x0000 ; 16 bit code segment base=0xf0000 limit=0xffff
11204 dw 0xffff, 0, 0x9300, 0x0000 ; 16 bit data segment base=0x0 limit=0xffff
11205
11206;; for 'C' strings and other data, insert them here with
11207;; a the following hack:
11208;; DATA_SEG_DEFS_HERE
11209
11210
11211;; the following area can be used to write dynamically generated tables
11212 .align 16
11213bios_table_area_start:
11214 dd 0xaafb4442
11215 dd bios_table_area_end - bios_table_area_start - 8;
11216
11217;--------
11218;- POST -
11219;--------
11220.org 0xe05b ; POST Entry Point
11221bios_table_area_end:
11222post:
11223
11224 xor ax, ax
11225
11226 ;; first reset the DMA controllers
11227 out 0x0d,al
11228 out 0xda,al
11229
11230 ;; then initialize the DMA controllers
11231 mov al, #0xC0
11232 out 0xD6, al ; cascade mode of channel 4 enabled
11233 mov al, #0x00
11234 out 0xD4, al ; unmask channel 4
11235
11236 ;; Examine CMOS shutdown status.
11237 mov AL, #0x0f
11238 out 0x70, AL
11239 in AL, 0x71
11240
11241 ;; backup status
11242 mov bl, al
11243
11244 ;; Reset CMOS shutdown status.
11245 mov AL, #0x0f
11246 out 0x70, AL ; select CMOS register Fh
11247 mov AL, #0x00
11248 out 0x71, AL ; set shutdown action to normal
11249
11250 ;; Examine CMOS shutdown status.
11251 mov al, bl
11252
11253 ;; 0x00, 0x09, 0x0D+ = normal startup
11254 cmp AL, #0x00
11255 jz normal_post
11256 cmp AL, #0x0d
11257 jae normal_post
11258 cmp AL, #0x09
11259 je normal_post
11260
11261 ;; 0x05 = eoi + jmp via [0x40:0x67] jump
11262 cmp al, #0x05
11263 je eoi_jmp_post
11264
11265#ifdef VBOX
11266 ;; just ignore all other CMOS shutdown status values (OpenSolaris sets it to 0xA for some reason in certain cases)
11267 ;; (shutdown_status_panic just crashes the VM as it calls int 0x10 before the IDT table has been initialized)
11268 jmp normal_post
11269#else
11270 ;; Examine CMOS shutdown status.
11271 ;; 0x01,0x02,0x03,0x04,0x06,0x07,0x08, 0x0a, 0x0b, 0x0c = Unimplemented shutdown status.
11272 push bx
11273 call _shutdown_status_panic
11274#endif
11275
11276#if 0
11277 HALT(__LINE__)
11278 ;
11279 ;#if 0
11280 ; 0xb0, 0x20, /* mov al, #0x20 */
11281 ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */
11282 ;#endif
11283 ;
11284 pop es
11285 pop ds
11286 popa
11287 iret
11288#endif
11289
11290normal_post:
11291 ; case 0: normal startup
11292
11293 cli
11294 mov ax, #0xfffe
11295 mov sp, ax
11296 xor ax, ax
11297 mov ds, ax
11298 mov ss, ax
11299
11300#ifndef VBOX
11301 ;; zero out BIOS data area (40:00..40:ff)
11302 mov es, ax
11303 mov cx, #0x0080 ;; 128 words
11304 mov di, #0x0400
11305 cld
11306 rep
11307 stosw
11308#else /* VBOX */
11309 ;; zero out segment 0 (includes BIOS data area) except word at 40:72
11310 mov es, ax
11311 xor di, di
11312 cld
11313 mov cx, #0x0239 ;; 569 words
11314 rep
11315 stosw
11316 inc di
11317 inc di
11318 mov cx, #0x7dc6 ;; 32198 words
11319 rep
11320 stosw
11321 ;; zero out remaining base memory except the last 16 bytes of the EBDA
11322 ;; because we store the MP table there
11323 xor eax, eax
11324 xor bx, bx
11325memory_zero_loop:
11326 add bx, #0x1000
11327 cmp bx, #0x9000
11328 jae memory_cleared
11329 mov es, bx
11330 xor di, di
11331 mov cx, #0x4000
11332 rep
11333 stosd
11334 jmp memory_zero_loop
11335memory_cleared:
11336 mov es, bx
11337 xor di, di
11338 mov cx, #0x3f00
11339 rep
11340 stosd
11341 xor bx, bx
11342#endif
11343
11344 call _log_bios_start
11345
11346 ;; set all interrupts to default handler
11347 xor bx, bx ;; offset index
11348 mov cx, #0x0100 ;; counter (256 interrupts)
11349 mov ax, #dummy_iret_handler
11350 mov dx, #0xF000
11351
11352post_default_ints:
11353 mov [bx], ax
11354 add bx, #2
11355 mov [bx], dx
11356 add bx, #2
11357 loop post_default_ints
11358
11359 ;; set vector 0x79 to zero
11360 ;; this is used by 'gardian angel' protection system
11361 SET_INT_VECTOR(0x79, #0, #0)
11362
11363 ;; base memory in K 40:13 (word)
11364 mov ax, #BASE_MEM_IN_K
11365 mov 0x0413, ax
11366
11367
11368 ;; Manufacturing Test 40:12
11369 ;; zerod out above
11370
11371#ifndef VBOX
11372 ;; Warm Boot Flag 0040:0072
11373 ;; value of 1234h = skip memory checks
11374 ;; zerod out above
11375#endif /* !VBOX */
11376
11377
11378 ;; Printer Services vector
11379 SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
11380
11381 ;; Bootstrap failure vector
11382 SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
11383
11384 ;; Bootstrap Loader vector
11385 SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
11386
11387 ;; User Timer Tick vector
11388 SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
11389
11390 ;; Memory Size Check vector
11391 SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
11392
11393 ;; Equipment Configuration Check vector
11394 SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
11395
11396 ;; System Services
11397 SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
11398
11399 ;; EBDA setup
11400 call ebda_post
11401
11402 ;; PIT setup
11403 SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
11404 ;; int 1C already points at dummy_iret_handler (above)
11405 mov al, #0x34 ; timer0: binary count, 16bit count, mode 2
11406 out 0x43, al
11407 mov al, #0x00 ; maximum count of 0000H = 18.2Hz
11408 out 0x40, al
11409 out 0x40, al
11410
11411 ;; Keyboard
11412 SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
11413 SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
11414
11415 xor ax, ax
11416 mov ds, ax
11417 mov 0x0417, al /* keyboard shift flags, set 1 */
11418 mov 0x0418, al /* keyboard shift flags, set 2 */
11419 mov 0x0419, al /* keyboard alt-numpad work area */
11420 mov 0x0471, al /* keyboard ctrl-break flag */
11421 mov 0x0497, al /* keyboard status flags 4 */
11422 mov al, #0x10
11423 mov 0x0496, al /* keyboard status flags 3 */
11424
11425
11426 /* keyboard head of buffer pointer */
11427 mov bx, #0x001E
11428 mov 0x041A, bx
11429
11430 /* keyboard end of buffer pointer */
11431 mov 0x041C, bx
11432
11433 /* keyboard pointer to start of buffer */
11434 mov bx, #0x001E
11435 mov 0x0480, bx
11436
11437 /* keyboard pointer to end of buffer */
11438 mov bx, #0x003E
11439 mov 0x0482, bx
11440
11441 /* init the keyboard */
11442 call _keyboard_init
11443
11444 ;; mov CMOS Equipment Byte to BDA Equipment Word
11445 mov ax, 0x0410
11446 mov al, #0x14
11447 out 0x70, al
11448 in al, 0x71
11449 mov 0x0410, ax
11450
11451
11452 ;; Parallel setup
11453 SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
11454 xor ax, ax
11455 mov ds, ax
11456 xor bx, bx
11457 mov cl, #0x14 ; timeout value
11458 mov dx, #0x378 ; Parallel I/O address, port 1
11459 call detect_parport
11460 mov dx, #0x278 ; Parallel I/O address, port 2
11461 call detect_parport
11462 shl bx, #0x0e
11463 mov ax, 0x410 ; Equipment word bits 14..15 determing # parallel ports
11464 and ax, #0x3fff
11465 or ax, bx ; set number of parallel ports
11466 mov 0x410, ax
11467
11468 ;; Serial setup
11469 SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
11470 SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
11471 xor bx, bx
11472 mov cl, #0x0a ; timeout value
11473 mov dx, #0x03f8 ; Serial I/O address, port 1
11474 call detect_serial
11475 mov dx, #0x02f8 ; Serial I/O address, port 2
11476 call detect_serial
11477 mov dx, #0x03e8 ; Serial I/O address, port 3
11478 call detect_serial
11479 mov dx, #0x02e8 ; Serial I/O address, port 4
11480 call detect_serial
11481 shl bx, #0x09
11482 mov ax, 0x410 ; Equipment word bits 9..11 determing # serial ports
11483 and ax, #0xf1ff
11484 or ax, bx ; set number of serial port
11485 mov 0x410, ax
11486
11487 ;; CMOS RTC
11488 SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
11489 SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
11490 SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
11491 ;; BIOS DATA AREA 0x4CE ???
11492 call timer_tick_post
11493
11494 ;; PS/2 mouse setup
11495 SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
11496
11497 ;; IRQ13 (FPU exception) setup
11498 SET_INT_VECTOR(0x75, #0xF000, #int75_handler)
11499
11500 ;; Video setup
11501 SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
11502
11503#ifdef VBOX
11504 ;; moved the PIC initialization to another place as we need
11505 ;; some space for additions init calls. Otherwise this code
11506 ;; overlaps with the NMI handler at 0xe2c3 (fixed BIOS entry)
11507 call init_pic
11508#else /* !VBOX */
11509 ;; PIC
11510 mov al, #0x11 ; send initialisation commands
11511 out 0x20, al
11512 out 0xa0, al
11513 mov al, #0x08
11514 out 0x21, al
11515 mov al, #0x70
11516 out 0xa1, al
11517 mov al, #0x04
11518 out 0x21, al
11519 mov al, #0x02
11520 out 0xa1, al
11521 mov al, #0x01
11522 out 0x21, al
11523 out 0xa1, al
11524 mov al, #0xb8
11525 out 0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6
11526#if BX_USE_PS2_MOUSE
11527 mov al, #0x8f
11528#else
11529 mov al, #0x9f
11530#endif
11531 out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14
11532#endif /* !VBOX */
11533
11534#if BX_ROMBIOS32
11535 call rombios32_init
11536#else
11537 call pcibios_init_iomem_bases
11538 call pcibios_init_irqs
11539#endif
11540 call setup_lapic
11541 call rom_scan
11542
11543#if BX_USE_ATADRV
11544 ;;
11545 ;; ATA/ATAPI driver setup
11546 ;;
11547 call _ata_init
11548 call _ata_detect
11549 ;;
11550#endif
11551
11552#ifdef VBOX_WITH_SCSI
11553 ;;
11554 ;; SCSI driver setup
11555 ;;
11556 call _scsi_init
11557 ;;
11558#endif
11559
11560 call _print_bios_banner
11561
11562 ;;
11563 ;; Floppy setup
11564 ;;
11565 call floppy_drive_post
11566
11567 ;;
11568 ;; Hard Drive setup
11569 ;;
11570 call hard_drive_post
11571
11572#if BX_ELTORITO_BOOT
11573 ;;
11574 ;; eltorito floppy/harddisk emulation from cd
11575 ;;
11576 call _cdemu_init
11577 ;;
11578#endif // BX_ELTORITO_BOOT
11579
11580 sti ;; enable interrupts
11581 int #0x19
11582
11583.org 0xe2c3 ; NMI Handler Entry Point
11584nmi:
11585 ;; FIXME the NMI handler should not panic
11586 ;; but iret when called from int75 (fpu exception)
11587 call _nmi_handler_msg
11588 iret
11589
11590int75_handler:
11591 out 0xf0, al // clear irq13
11592 call eoi_both_pics // clear interrupt
11593 int 2 // legacy nmi call
11594 iret
11595
11596;-------------------------------------------
11597;- INT 13h Fixed Disk Services Entry Point -
11598;-------------------------------------------
11599.org 0xe3fe ; INT 13h Fixed Disk Services Entry Point
11600int13_handler:
11601 //JMPL(int13_relocated)
11602 jmp int13_relocated
11603
11604.org 0xe401 ; Fixed Disk Parameter Table
11605
11606;----------
11607;- INT19h -
11608;----------
11609.org 0xe6f2 ; INT 19h Boot Load Service Entry Point
11610int19_handler:
11611
11612 jmp int19_relocated
11613;-------------------------------------------
11614;- System BIOS Configuration Data Table
11615;-------------------------------------------
11616.org BIOS_CONFIG_TABLE
11617db 0x08 ; Table size (bytes) -Lo
11618db 0x00 ; Table size (bytes) -Hi
11619db SYS_MODEL_ID
11620db SYS_SUBMODEL_ID
11621db BIOS_REVISION
11622; Feature byte 1
11623; b7: 1=DMA channel 3 used by hard disk
11624; b6: 1=2 interrupt controllers present
11625; b5: 1=RTC present
11626; b4: 1=BIOS calls int 15h/4Fh every key
11627; b3: 1=wait for extern event supported (Int 15h/41h)
11628; b2: 1=extended BIOS data area used
11629; b1: 0=AT or ESDI bus, 1=MicroChannel
11630; b0: 1=Dual bus (MicroChannel + ISA)
11631db (0 << 7) | \
11632 (1 << 6) | \
11633 (1 << 5) | \
11634 (BX_CALL_INT15_4F << 4) | \
11635 (0 << 3) | \
11636 (BX_USE_EBDA << 2) | \
11637 (0 << 1) | \
11638 (0 << 0)
11639; Feature byte 2
11640; b7: 1=32-bit DMA supported
11641; b6: 1=int16h, function 9 supported
11642; b5: 1=int15h/C6h (get POS data) supported
11643; b4: 1=int15h/C7h (get mem map info) supported
11644; b3: 1=int15h/C8h (en/dis CPU) supported
11645; b2: 1=non-8042 kb controller
11646; b1: 1=data streaming supported
11647; b0: reserved
11648db (0 << 7) | \
11649 (1 << 6) | \
11650 (0 << 5) | \
11651 (0 << 4) | \
11652 (0 << 3) | \
11653 (0 << 2) | \
11654 (0 << 1) | \
11655 (0 << 0)
11656; Feature byte 3
11657; b7: not used
11658; b6: reserved
11659; b5: reserved
11660; b4: POST supports ROM-to-RAM enable/disable
11661; b3: SCSI on system board
11662; b2: info panel installed
11663; b1: Initial Machine Load (IML) system - BIOS on disk
11664; b0: SCSI supported in IML
11665db 0x00
11666; Feature byte 4
11667; b7: IBM private
11668; b6: EEPROM present
11669; b5-3: ABIOS presence (011 = not supported)
11670; b2: private
11671; b1: memory split above 16Mb supported
11672; b0: POSTEXT directly supported by POST
11673db 0x00
11674; Feature byte 5 (IBM)
11675; b1: enhanced mouse
11676; b0: flash EPROM
11677db 0x00
11678
11679
11680
11681.org 0xe729 ; Baud Rate Generator Table
11682
11683;----------
11684;- INT14h -
11685;----------
11686.org 0xe739 ; INT 14h Serial Communications Service Entry Point
11687int14_handler:
11688 push ds
11689 pusha
11690 xor ax, ax
11691 mov ds, ax
11692 call _int14_function
11693 popa
11694 pop ds
11695 iret
11696
11697
11698;----------------------------------------
11699;- INT 16h Keyboard Service Entry Point -
11700;----------------------------------------
11701.org 0xe82e
11702int16_handler:
11703
11704 sti
11705 push ds
11706 pushf
11707 pusha
11708
11709 cmp ah, #0x00
11710 je int16_F00
11711 cmp ah, #0x10
11712 je int16_F00
11713
11714 mov bx, #0xf000
11715 mov ds, bx
11716 call _int16_function
11717 popa
11718 popf
11719 pop ds
11720 jz int16_zero_set
11721
11722int16_zero_clear:
11723 push bp
11724 mov bp, sp
11725 //SEG SS
11726 and BYTE [bp + 0x06], #0xbf
11727 pop bp
11728 iret
11729
11730int16_zero_set:
11731 push bp
11732 mov bp, sp
11733 //SEG SS
11734 or BYTE [bp + 0x06], #0x40
11735 pop bp
11736 iret
11737
11738int16_F00:
11739 mov bx, #0x0040
11740 mov ds, bx
11741
11742int16_wait_for_key:
11743 cli
11744 mov bx, 0x001a
11745 cmp bx, 0x001c
11746 jne int16_key_found
11747 sti
11748 nop
11749#if 0
11750 /* no key yet, call int 15h, function AX=9002 */
11751 0x50, /* push AX */
11752 0xb8, 0x02, 0x90, /* mov AX, #0x9002 */
11753 0xcd, 0x15, /* int 15h */
11754 0x58, /* pop AX */
11755 0xeb, 0xea, /* jmp WAIT_FOR_KEY */
11756#endif
11757 jmp int16_wait_for_key
11758
11759int16_key_found:
11760 mov bx, #0xf000
11761 mov ds, bx
11762 call _int16_function
11763 popa
11764 popf
11765 pop ds
11766#if 0
11767 /* notify int16 complete w/ int 15h, function AX=9102 */
11768 0x50, /* push AX */
11769 0xb8, 0x02, 0x91, /* mov AX, #0x9102 */
11770 0xcd, 0x15, /* int 15h */
11771 0x58, /* pop AX */
11772#endif
11773 iret
11774
11775
11776
11777;-------------------------------------------------
11778;- INT09h : Keyboard Hardware Service Entry Point -
11779;-------------------------------------------------
11780.org 0xe987
11781int09_handler:
11782 cli
11783 push ax
11784
11785 mov al, #0xAD ;;disable keyboard
11786 out #0x64, al
11787
11788 mov al, #0x0B
11789 out #0x20, al
11790 in al, #0x20
11791 and al, #0x02
11792 jz int09_finish
11793
11794 in al, #0x60 ;;read key from keyboard controller
11795 sti
11796 push ds
11797 pusha
11798#ifdef BX_CALL_INT15_4F
11799 mov ah, #0x4f ;; allow for keyboard intercept
11800 stc
11801 int #0x15
11802 jnc int09_done
11803#endif
11804
11805 ;; check for extended key
11806 cmp al, #0xe0
11807 jne int09_check_pause
11808 xor ax, ax
11809 mov ds, ax
11810 mov al, BYTE [0x496] ;; mf2_state |= 0x02
11811 or al, #0x02
11812 mov BYTE [0x496], al
11813 jmp int09_done
11814
11815int09_check_pause: ;; check for pause key
11816 cmp al, #0xe1
11817 jne int09_process_key
11818 xor ax, ax
11819 mov ds, ax
11820 mov al, BYTE [0x496] ;; mf2_state |= 0x01
11821 or al, #0x01
11822 mov BYTE [0x496], al
11823 jmp int09_done
11824
11825int09_process_key:
11826 mov bx, #0xf000
11827 mov ds, bx
11828 call _int09_function
11829
11830int09_done:
11831 popa
11832 pop ds
11833 cli
11834 call eoi_master_pic
11835
11836int09_finish:
11837 mov al, #0xAE ;;enable keyboard
11838 out #0x64, al
11839 pop ax
11840 iret
11841
11842
11843;----------------------------------------
11844;- INT 13h Diskette Service Entry Point -
11845;----------------------------------------
11846.org 0xec59
11847int13_diskette:
11848 jmp int13_noeltorito
11849
11850;---------------------------------------------
11851;- INT 0Eh Diskette Hardware ISR Entry Point -
11852;---------------------------------------------
11853.org 0xef57 ; INT 0Eh Diskette Hardware ISR Entry Point
11854int0e_handler:
11855 push ax
11856 push dx
11857 mov dx, #0x03f4
11858 in al, dx
11859 and al, #0xc0
11860 cmp al, #0xc0
11861 je int0e_normal
11862 mov dx, #0x03f5
11863 mov al, #0x08 ; sense interrupt status
11864 out dx, al
11865int0e_loop1:
11866 mov dx, #0x03f4
11867 in al, dx
11868 and al, #0xc0
11869 cmp al, #0xc0
11870 jne int0e_loop1
11871int0e_loop2:
11872 mov dx, #0x03f5
11873 in al, dx
11874 mov dx, #0x03f4
11875 in al, dx
11876 and al, #0xc0
11877 cmp al, #0xc0
11878 je int0e_loop2
11879int0e_normal:
11880 push ds
11881 xor ax, ax ;; segment 0000
11882 mov ds, ax
11883 call eoi_master_pic
11884 mov al, 0x043e
11885 or al, #0x80 ;; diskette interrupt has occurred
11886 mov 0x043e, al
11887 pop ds
11888 pop dx
11889 pop ax
11890 iret
11891
11892
11893.org 0xefc7 ; Diskette Controller Parameter Table
11894diskette_param_table:
11895;; Since no provisions are made for multiple drive types, most
11896;; values in this table are ignored. I set parameters for 1.44M
11897;; floppy here
11898db 0xAF
11899db 0x02 ;; head load time 0000001, DMA used
11900db 0x25
11901db 0x02
11902db 18
11903db 0x1B
11904db 0xFF
11905db 0x6C
11906db 0xF6
11907db 0x0F
11908db 0x08
11909
11910
11911;----------------------------------------
11912;- INT17h : Printer Service Entry Point -
11913;----------------------------------------
11914.org 0xefd2
11915int17_handler:
11916 push ds
11917 pusha
11918 xor ax, ax
11919 mov ds, ax
11920 call _int17_function
11921 popa
11922 pop ds
11923 iret
11924
11925diskette_param_table2:
11926;; New diskette parameter table adding 3 parameters from IBM
11927;; Since no provisions are made for multiple drive types, most
11928;; values in this table are ignored. I set parameters for 1.44M
11929;; floppy here
11930db 0xAF
11931db 0x02 ;; head load time 0000001, DMA used
11932db 0x25
11933db 0x02
11934db 18
11935db 0x1B
11936db 0xFF
11937db 0x6C
11938db 0xF6
11939db 0x0F
11940db 0x08
11941db 79 ;; maximum track
11942db 0 ;; data transfer rate
11943db 4 ;; drive type in cmos
11944
11945.org 0xf045 ; INT 10 Functions 0-Fh Entry Point
11946 HALT(__LINE__)
11947 iret
11948
11949;----------
11950;- INT10h -
11951;----------
11952.org 0xf065 ; INT 10h Video Support Service Entry Point
11953int10_handler:
11954 ;; dont do anything, since the VGA BIOS handles int10h requests
11955 iret
11956
11957.org 0xf0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
11958
11959;----------
11960;- INT12h -
11961;----------
11962.org 0xf841 ; INT 12h Memory Size Service Entry Point
11963; ??? different for Pentium (machine check)?
11964int12_handler:
11965 push ds
11966 mov ax, #0x0040
11967 mov ds, ax
11968 mov ax, 0x0013
11969 pop ds
11970 iret
11971
11972;----------
11973;- INT11h -
11974;----------
11975.org 0xf84d ; INT 11h Equipment List Service Entry Point
11976int11_handler:
11977 push ds
11978 mov ax, #0x0040
11979 mov ds, ax
11980 mov ax, 0x0010
11981 pop ds
11982 iret
11983
11984;----------
11985;- INT15h -
11986;----------
11987.org 0xf859 ; INT 15h System Services Entry Point
11988int15_handler:
11989 pushf
11990#if BX_APM
11991 cmp ah, #0x53
11992 je apm_call
11993#endif
11994 push ds
11995 push es
11996 cmp ah, #0x86
11997 je int15_handler32
11998 cmp ah, #0xE8
11999 je int15_handler32
12000 pusha
12001#if BX_USE_PS2_MOUSE
12002 cmp ah, #0xC2
12003 je int15_handler_mouse
12004#endif
12005 call _int15_function
12006int15_handler_mouse_ret:
12007 popa
12008int15_handler32_ret:
12009 pop es
12010 pop ds
12011 popf
12012 jmp iret_modify_cf
12013#if BX_APM
12014apm_call:
12015 jmp _apmreal_entry
12016#endif
12017
12018#if BX_USE_PS2_MOUSE
12019int15_handler_mouse:
12020 call _int15_function_mouse
12021 jmp int15_handler_mouse_ret
12022#endif
12023
12024int15_handler32:
12025 pushad
12026 call _int15_function32
12027 popad
12028 jmp int15_handler32_ret
12029
12030;; Protected mode IDT descriptor
12031;;
12032;; I just make the limit 0, so the machine will shutdown
12033;; if an exception occurs during protected mode memory
12034;; transfers.
12035;;
12036;; Set base to f0000 to correspond to beginning of BIOS,
12037;; in case I actually define an IDT later
12038;; Set limit to 0
12039
12040pmode_IDT_info:
12041dw 0x0000 ;; limit 15:00
12042dw 0x0000 ;; base 15:00
12043db 0x0f ;; base 23:16
12044
12045;; Real mode IDT descriptor
12046;;
12047;; Set to typical real-mode values.
12048;; base = 000000
12049;; limit = 03ff
12050
12051rmode_IDT_info:
12052dw 0x03ff ;; limit 15:00
12053dw 0x0000 ;; base 15:00
12054db 0x00 ;; base 23:16
12055
12056;;
12057;; Handler for unexpected hardware interrupts
12058;;
12059dummy_isr:
12060 push ds
12061 pushad
12062 xor ax, ax
12063 mov ds, ax
12064 call _dummy_isr_function
12065 popad
12066 pop ds
12067 iret
12068
12069;----------
12070;- INT1Ah -
12071;----------
12072.org 0xfe6e ; INT 1Ah Time-of-day Service Entry Point
12073int1a_handler:
12074#if BX_PCIBIOS
12075 cmp ah, #0xb1
12076 jne int1a_normal
12077 call pcibios_real
12078 jc pcibios_error
12079 retf 2
12080pcibios_error:
12081 mov bl, ah
12082 mov ah, #0xb1
12083 push ds
12084 pusha
12085 mov ax, ss ; set readable descriptor to ds, for calling pcibios
12086 mov ds, ax ; on 16bit protected mode.
12087 jmp int1a_callfunction
12088int1a_normal:
12089#endif
12090 push ds
12091 pusha
12092 xor ax, ax
12093 mov ds, ax
12094int1a_callfunction:
12095 call _int1a_function
12096 popa
12097 pop ds
12098 iret
12099
12100;;
12101;; int70h: IRQ8 - CMOS RTC
12102;;
12103int70_handler:
12104 push ds
12105 pushad
12106 xor ax, ax
12107 mov ds, ax
12108 call _int70_function
12109 popad
12110 pop ds
12111 iret
12112
12113;---------
12114;- INT08 -
12115;---------
12116.org 0xfea5 ; INT 08h System Timer ISR Entry Point
12117int08_handler:
12118 sti
12119 push eax
12120 push ds
12121 xor ax, ax
12122 mov ds, ax
12123
12124 ;; time to turn off drive(s)?
12125 mov al,0x0440
12126 or al,al
12127 jz int08_floppy_off
12128 dec al
12129 mov 0x0440,al
12130 jnz int08_floppy_off
12131 ;; turn motor(s) off
12132 push dx
12133 mov dx,#0x03f2
12134 in al,dx
12135 and al,#0xcf
12136 out dx,al
12137 pop dx
12138int08_floppy_off:
12139
12140 mov eax, 0x046c ;; get ticks dword
12141 inc eax
12142
12143 ;; compare eax to one days worth of timer ticks at 18.2 hz
12144 cmp eax, #0x001800B0
12145 jb int08_store_ticks
12146 ;; there has been a midnight rollover at this point
12147 xor eax, eax ;; zero out counter
12148 inc BYTE 0x0470 ;; increment rollover flag
12149
12150int08_store_ticks:
12151 mov 0x046c, eax ;; store new ticks dword
12152 ;; chain to user timer tick INT #0x1c
12153 //pushf
12154 //;; call_ep [ds:loc]
12155 //CALL_EP( 0x1c << 2 )
12156 int #0x1c
12157 cli
12158 call eoi_master_pic
12159 pop ds
12160 pop eax
12161 iret
12162
12163.org 0xfef3 ; Initial Interrupt Vector Offsets Loaded by POST
12164
12165
12166.org 0xff00
12167.ascii BIOS_COPYRIGHT_STRING
12168
12169#ifdef VBOX
12170// The SMBIOS header
12171.org 0xff30
12172.align 16
12173 db 0x5f, 0x53, 0x4d, 0x5f ; "_SM_" signature
12174 db 0x00 ; checksum (set by biossums)
12175 db 0x1f ; EPS length, defined by standard
12176 db VBOX_SMBIOS_MAJOR_VER ; SMBIOS major version
12177 db VBOX_SMBIOS_MINOR_VER ; SMBIOS minor version
12178 dw VBOX_SMBIOS_MAXSS ; Maximum structure size
12179 db 0x00 ; Entry point revision
12180 db 0x00, 0x00, 0x00, 0x00, 0x00
12181
12182// The DMI header
12183 db 0x5f, 0x44, 0x4d, 0x49, 0x5f ; "_DMI_" signature
12184 db 0x00 ; checksum (set by biossums)
12185 dw VBOX_DMI_TABLE_SIZE ; DMI tables length
12186 dd VBOX_DMI_TABLE_BASE ; DMI tables base
12187 dw VBOX_DMI_TABLE_ENTR ; DMI tables entries
12188 db VBOX_DMI_TABLE_VER ; DMI version
12189 db 0x00 ; Just for alignment
12190#endif
12191
12192;------------------------------------------------
12193;- IRET Instruction for Dummy Interrupt Handler -
12194;------------------------------------------------
12195.org 0xff53 ; IRET Instruction for Dummy Interrupt Handler
12196dummy_iret_handler:
12197 iret
12198
12199.org 0xff54 ; INT 05h Print Screen Service Entry Point
12200 HALT(__LINE__)
12201 iret
12202
12203.org 0xfff0 ; Power-up Entry Point
12204 jmp 0xf000:post
12205
12206.org 0xfff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
12207.ascii BIOS_BUILD_DATE
12208
12209.org 0xfffe ; System Model ID
12210db SYS_MODEL_ID
12211db 0x00 ; filler
12212
12213.org 0xfa6e ;; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
12214ASM_END
12215/*
12216 * This font comes from the fntcol16.zip package (c) by Joseph Gil
12217 * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
12218 * This font is public domain
12219 */
12220static Bit8u vgafont8[128*8]=
12221{
12222 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
12223 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
12224 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
12225 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
12226 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
12227 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
12228 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
12229 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
12230 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
12231 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
12232 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
12233 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
12234 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
12235 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
12236 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
12237 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
12238 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
12239 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
12240 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
12241 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
12242 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
12243 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
12244 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
12245 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
12246 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
12247 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
12248 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
12249 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
12250 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
12251 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
12252 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
12253 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
12254 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
12255 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
12256 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
12257 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
12258 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
12259 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
12260 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
12261 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
12262 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
12263 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
12264 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
12265 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
12266 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
12267 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
12268 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
12269 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
12270 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
12271 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
12272 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
12273 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
12274 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
12275 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
12276 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
12277 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
12278 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
12279 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
12280 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
12281 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
12282 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
12283 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
12284 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
12285 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
12286 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
12287 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
12288 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
12289 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
12290 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
12291 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
12292 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
12293 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
12294 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
12295 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
12296 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
12297 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
12298 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
12299 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
12300 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
12301 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
12302 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
12303 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
12304 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
12305 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
12306 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
12307 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
12308 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
12309 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
12310 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
12311 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
12312 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
12313 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
12314 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
12315 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
12316 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
12317 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
12318 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
12319 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
12320 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
12321 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
12322 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
12323 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
12324 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
12325 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
12326 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
12327 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
12328 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
12329 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
12330 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
12331 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
12332 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
12333 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
12334 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
12335 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
12336 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
12337 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
12338 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
12339 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
12340 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
12341 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
12342 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
12343 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
12344 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
12345 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
12346 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
12347 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
12348 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
12349 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
12350};
12351
12352ASM_START
12353.org 0xcc00
12354// bcc-generated data will be placed here
12355ASM_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