VirtualBox

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

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

DevVGA.cpp,rombios.c: Disable the logo from DevVGA instead of rombios.c in debug builds. Only disable it when default settings are used so one can easily force it to appear in all kinds of builds.

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