VirtualBox

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

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

burn fix

  • Property svn:eol-style set to native
File size: 335.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 compatibility 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 ([email protected])
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 ([email protected])
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 segment.
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_1 0x12378086 ;; i440FX PCI bridge
248#define PCI_FIXED_HOST_BRIDGE_2 0x244e8086 ;; ICH9 PCI bridge
249
250// #20 is dec 20
251// #$20 is hex 20 = 32
252// #0x20 is hex 20 = 32
253// LDA #$20
254// JSR $E820
255// LDD .i,S
256// JSR $C682
257// mov al, #$20
258
259// all hex literals should be prefixed with '0x'
260// grep "#[0-9a-fA-F][0-9a-fA-F]" rombios.c
261// no mov SEG-REG, #value, must mov register into seg-reg
262// grep -i "mov[ ]*.s" rombios.c
263
264// This is for compiling with gcc2 and gcc3
265#define ASM_START #asm
266#define ASM_END #endasm
267
268ASM_START
269.rom
270
271.org 0x0000
272
273#if BX_CPU >= 3
274use16 386
275#else
276use16 286
277#endif
278
279MACRO HALT
280 ;; the HALT macro is called with the line number of the HALT call.
281 ;; The line number is then sent to the PANIC_PORT, causing Bochs/Plex
282 ;; to print a BX_PANIC message. This will normally halt the simulation
283 ;; with a message such as "BIOS panic at rombios.c, line 4091".
284 ;; However, users can choose to make panics non-fatal and continue.
285#if BX_VIRTUAL_PORTS
286 mov dx,#PANIC_PORT
287 mov ax,#?1
288 out dx,ax
289#else
290 mov dx,#0x80
291 mov ax,#?1
292 out dx,al
293#endif
294MEND
295
296MACRO JMP_AP
297 db 0xea
298 dw ?2
299 dw ?1
300MEND
301
302MACRO SET_INT_VECTOR
303 mov ax, ?3
304 mov ?1*4, ax
305 mov ax, ?2
306 mov ?1*4+2, ax
307MEND
308
309ASM_END
310
311typedef unsigned char Bit8u;
312typedef unsigned short Bit16u;
313typedef unsigned short bx_bool;
314typedef unsigned long Bit32u;
315
316#if BX_USE_ATADRV
317
318 void memsetb(seg,offset,value,count);
319 void memcpyb(dseg,doffset,sseg,soffset,count);
320 void memcpyd(dseg,doffset,sseg,soffset,count);
321
322 // memset of count bytes
323 void
324 memsetb(seg,offset,value,count)
325 Bit16u seg;
326 Bit16u offset;
327 Bit16u value;
328 Bit16u count;
329 {
330 ASM_START
331 push bp
332 mov bp, sp
333
334 push ax
335 push cx
336 push es
337 push di
338
339 mov cx, 10[bp] ; count
340 test cx, cx
341 je memsetb_end
342 mov ax, 4[bp] ; segment
343 mov es, ax
344 mov ax, 6[bp] ; offset
345 mov di, ax
346 mov al, 8[bp] ; value
347 cld
348 rep
349 stosb
350
351 memsetb_end:
352 pop di
353 pop es
354 pop cx
355 pop ax
356
357 pop bp
358 ASM_END
359 }
360
361#if 0
362 // memcpy of count bytes
363 void
364 memcpyb(dseg,doffset,sseg,soffset,count)
365 Bit16u dseg;
366 Bit16u doffset;
367 Bit16u sseg;
368 Bit16u soffset;
369 Bit16u count;
370 {
371 ASM_START
372 push bp
373 mov bp, sp
374
375 push ax
376 push cx
377 push es
378 push di
379 push ds
380 push si
381
382 mov cx, 12[bp] ; count
383 cmp cx, #0x0000
384 je memcpyb_end
385 mov ax, 4[bp] ; dsegment
386 mov es, ax
387 mov ax, 6[bp] ; doffset
388 mov di, ax
389 mov ax, 8[bp] ; ssegment
390 mov ds, ax
391 mov ax, 10[bp] ; soffset
392 mov si, ax
393 cld
394 rep
395 movsb
396
397 memcpyb_end:
398 pop si
399 pop ds
400 pop di
401 pop es
402 pop cx
403 pop ax
404
405 pop bp
406 ASM_END
407 }
408
409 // memcpy of count dword
410 void
411 memcpyd(dseg,doffset,sseg,soffset,count)
412 Bit16u dseg;
413 Bit16u doffset;
414 Bit16u sseg;
415 Bit16u soffset;
416 Bit16u count;
417 {
418 ASM_START
419 push bp
420 mov bp, sp
421
422 push ax
423 push cx
424 push es
425 push di
426 push ds
427 push si
428
429 mov cx, 12[bp] ; count
430 test cx, cx
431 je memcpyd_end
432 mov ax, 4[bp] ; dsegment
433 mov es, ax
434 mov ax, 6[bp] ; doffset
435 mov di, ax
436 mov ax, 8[bp] ; ssegment
437 mov ds, ax
438 mov ax, 10[bp] ; soffset
439 mov si, ax
440 cld
441 rep
442 movsd
443
444 memcpyd_end:
445 pop si
446 pop ds
447 pop di
448 pop es
449 pop cx
450 pop ax
451
452 pop bp
453 ASM_END
454 }
455#endif
456#endif //BX_USE_ATADRV
457
458 // read_dword and write_dword functions
459 static Bit32u read_dword();
460 static void write_dword();
461
462 Bit32u
463 read_dword(seg, offset)
464 Bit16u seg;
465 Bit16u offset;
466 {
467 ASM_START
468 push bp
469 mov bp, sp
470
471 push bx
472 push ds
473 mov ax, 4[bp] ; segment
474 mov ds, ax
475 mov bx, 6[bp] ; offset
476 mov ax, [bx]
477 add bx, #2
478 mov dx, [bx]
479 ;; ax = return value (word)
480 ;; dx = return value (word)
481 pop ds
482 pop bx
483
484 pop bp
485 ASM_END
486 }
487
488 void
489 write_dword(seg, offset, data)
490 Bit16u seg;
491 Bit16u offset;
492 Bit32u data;
493 {
494 ASM_START
495 push bp
496 mov bp, sp
497
498 push ax
499 push bx
500 push ds
501 mov ax, 4[bp] ; segment
502 mov ds, ax
503 mov bx, 6[bp] ; offset
504 mov ax, 8[bp] ; data word
505 mov [bx], ax ; write data word
506 add bx, #2
507 mov ax, 10[bp] ; data word
508 mov [bx], ax ; write data word
509 pop ds
510 pop bx
511 pop ax
512
513 pop bp
514 ASM_END
515 }
516
517 // Bit32u (unsigned long) and long helper functions
518 ASM_START
519
520 ;; and function
521 landl:
522 landul:
523 SEG SS
524 and ax,[di]
525 SEG SS
526 and bx,2[di]
527 ret
528
529 ;; add function
530 laddl:
531 laddul:
532 SEG SS
533 add ax,[di]
534 SEG SS
535 adc bx,2[di]
536 ret
537
538 ;; cmp function
539 lcmpl:
540 lcmpul:
541 and eax, #0x0000FFFF
542 shl ebx, #16
543 or eax, ebx
544 shr ebx, #16
545 SEG SS
546 cmp eax, dword ptr [di]
547 ret
548
549 ;; sub function
550 lsubl:
551 lsubul:
552 SEG SS
553 sub ax,[di]
554 SEG SS
555 sbb bx,2[di]
556 ret
557
558 ;; mul function
559 lmull:
560 lmulul:
561 and eax, #0x0000FFFF
562 shl ebx, #16
563 or eax, ebx
564 SEG SS
565 mul eax, dword ptr [di]
566 mov ebx, eax
567 shr ebx, #16
568 ret
569
570 ;; dec function
571 ldecl:
572 ldecul:
573 SEG SS
574 dec dword ptr [bx]
575 ret
576
577 ;; or function
578 lorl:
579 lorul:
580 SEG SS
581 or ax,[di]
582 SEG SS
583 or bx,2[di]
584 ret
585
586 ;; inc function
587 lincl:
588 lincul:
589 SEG SS
590 inc dword ptr [bx]
591 ret
592
593 ;; tst function
594 ltstl:
595 ltstul:
596 and eax, #0x0000FFFF
597 shl ebx, #16
598 or eax, ebx
599 shr ebx, #16
600 test eax, eax
601 ret
602
603 ;; sr function
604 lsrul:
605 mov cx,di
606 jcxz lsr_exit
607 and eax, #0x0000FFFF
608 shl ebx, #16
609 or eax, ebx
610 lsr_loop:
611 shr eax, #1
612 loop lsr_loop
613 mov ebx, eax
614 shr ebx, #16
615 lsr_exit:
616 ret
617
618 ;; sl function
619 lsll:
620 lslul:
621 mov cx,di
622 jcxz lsl_exit
623 and eax, #0x0000FFFF
624 shl ebx, #16
625 or eax, ebx
626 lsl_loop:
627 shl eax, #1
628 loop lsl_loop
629 mov ebx, eax
630 shr ebx, #16
631 lsl_exit:
632 ret
633
634 idiv_:
635 cwd
636 idiv bx
637 ret
638
639 idiv_u:
640 xor dx,dx
641 div bx
642 ret
643
644 ldivul:
645 and eax, #0x0000FFFF
646 shl ebx, #16
647 or eax, ebx
648 xor edx, edx
649 SEG SS
650 mov bx, 2[di]
651 shl ebx, #16
652 SEG SS
653 mov bx, [di]
654 div ebx
655 mov ebx, eax
656 shr ebx, #16
657 ret
658
659 ASM_END
660
661// for access to RAM area which is used by interrupt vectors
662// and BIOS Data Area
663
664typedef struct {
665 unsigned char filler1[0x400];
666 unsigned char filler2[0x6c];
667 Bit16u ticks_low;
668 Bit16u ticks_high;
669 Bit8u midnight_flag;
670 } bios_data_t;
671
672#define BiosData ((bios_data_t *) 0)
673
674#if BX_USE_ATADRV
675 typedef struct {
676 Bit16u heads; // # heads
677 Bit16u cylinders; // # cylinders
678 Bit16u spt; // # sectors / track
679 } chs_t;
680
681 // DPTE definition
682 typedef struct {
683 Bit16u iobase1;
684 Bit16u iobase2;
685 Bit8u prefix;
686 Bit8u unused;
687 Bit8u irq;
688 Bit8u blkcount;
689 Bit8u dma;
690 Bit8u pio;
691 Bit16u options;
692 Bit16u reserved;
693 Bit8u revision;
694 Bit8u checksum;
695 } dpte_t;
696
697 typedef struct {
698 Bit8u iface; // ISA or PCI
699 Bit16u iobase1; // IO Base 1
700 Bit16u iobase2; // IO Base 2
701 Bit8u irq; // IRQ
702 } ata_channel_t;
703
704 typedef struct {
705 Bit8u type; // Detected type of ata (ata/atapi/none/unknown/scsi)
706 Bit8u device; // Detected type of attached devices (hd/cd/none)
707 Bit8u removable; // Removable device flag
708 Bit8u lock; // Locks for removable devices
709 Bit8u mode; // transfer mode : PIO 16/32 bits - IRQ - ISADMA - PCIDMA
710 Bit16u blksize; // block size
711
712 Bit8u translation; // type of translation
713 chs_t lchs; // Logical CHS
714 chs_t pchs; // Physical CHS
715
716 Bit32u sectors; // Total sectors count
717 } ata_device_t;
718
719 typedef struct {
720 // ATA channels info
721 ata_channel_t channels[BX_MAX_ATA_INTERFACES];
722
723 // ATA devices info
724 ata_device_t devices[BX_MAX_ATA_DEVICES];
725 //
726 // map between (bios hd id - 0x80) and ata channels and scsi disks.
727#ifdef VBOX_WITH_SCSI
728 Bit8u hdcount, hdidmap[BX_MAX_ATA_DEVICES+BX_MAX_SCSI_DEVICES];
729#else
730 Bit8u hdcount, hdidmap[BX_MAX_ATA_DEVICES];
731#endif
732
733 // map between (bios cd id - 0xE0) and ata channels
734 Bit8u cdcount, cdidmap[BX_MAX_ATA_DEVICES];
735
736 // Buffer for DPTE table
737 dpte_t dpte;
738
739 // Count of transferred sectors and bytes
740 Bit16u trsfsectors;
741 Bit32u trsfbytes;
742
743 } ata_t;
744
745#if BX_ELTORITO_BOOT
746 // ElTorito Device Emulation data
747 typedef struct {
748 Bit8u active;
749 Bit8u media;
750 Bit8u emulated_drive;
751 Bit8u controller_index;
752 Bit16u device_spec;
753 Bit32u ilba;
754 Bit16u buffer_segment;
755 Bit16u load_segment;
756 Bit16u sector_count;
757
758 // Virtual device
759 chs_t vdevice;
760 } cdemu_t;
761#endif // BX_ELTORITO_BOOT
762
763#ifdef VBOX_WITH_SCSI
764 typedef struct {
765 // I/O port this device is attached to.
766 Bit16u io_base;
767 // Target Id.
768 Bit8u target_id;
769 // SCSI devices info
770 ata_device_t device_info;
771 } scsi_device_t;
772
773 typedef struct {
774 // SCSi device info
775 scsi_device_t devices[BX_MAX_SCSI_DEVICES];
776 // Number of scsi disks.
777 Bit8u hdcount;
778 } scsi_t;
779#endif
780
781 // for access to EBDA area
782 // The EBDA structure should conform to
783 // http://www.frontiernet.net/~fys/rombios.htm document
784 // I made the ata and cdemu structs begin at 0x121 in the EBDA seg
785 typedef struct {
786 unsigned char filler1[0x3D];
787
788 // FDPT - Can be split into data members if needed
789 unsigned char fdpt0[0x10];
790 unsigned char fdpt1[0x10];
791
792 unsigned char filler2[0xC4];
793
794 // ATA Driver data
795 ata_t ata;
796
797#if BX_ELTORITO_BOOT
798 // El Torito Emulation data
799 cdemu_t cdemu;
800#endif // BX_ELTORITO_BOOT
801
802#ifdef VBOX
803
804#ifdef VBOX_WITH_SCSI
805 // SCSI Driver data
806 scsi_t scsi;
807# endif
808
809 unsigned char uForceBootDrive;
810 unsigned char uForceBootDevice;
811#endif /* VBOX */
812
813 } ebda_data_t;
814
815#ifdef VBOX
816 // the last 16 bytes of the EBDA segment are used for the MPS floating
817 // pointer structure (only if an IOAPIC is present)
818#endif
819
820 #define EbdaData ((ebda_data_t *) 0)
821
822 // for access to the int13ext structure
823 typedef struct {
824 Bit8u size;
825 Bit8u reserved;
826 Bit16u count;
827 Bit16u offset;
828 Bit16u segment;
829 Bit32u lba1;
830 Bit32u lba2;
831 } int13ext_t;
832
833 #define Int13Ext ((int13ext_t *) 0)
834
835 // Disk Physical Table definition
836 typedef struct {
837 Bit16u size;
838 Bit16u infos;
839 Bit32u cylinders;
840 Bit32u heads;
841 Bit32u spt;
842 Bit32u sector_count1;
843 Bit32u sector_count2;
844 Bit16u blksize;
845 Bit16u dpte_offset;
846 Bit16u dpte_segment;
847 Bit16u key;
848 Bit8u dpi_length;
849 Bit8u reserved1;
850 Bit16u reserved2;
851 Bit8u host_bus[4];
852 Bit8u iface_type[8];
853 Bit8u iface_path[8];
854 Bit8u device_path[8];
855 Bit8u reserved3;
856 Bit8u checksum;
857 } dpt_t;
858
859 #define Int13DPT ((dpt_t *) 0)
860
861#endif // BX_USE_ATADRV
862
863typedef struct {
864 union {
865 struct {
866 Bit16u di, si, bp, sp;
867 Bit16u bx, dx, cx, ax;
868 } r16;
869 struct {
870 Bit16u filler[4];
871 Bit8u bl, bh, dl, dh, cl, ch, al, ah;
872 } r8;
873 } u;
874 } pusha_regs_t;
875
876typedef struct {
877 union {
878 struct {
879 Bit32u edi, esi, ebp, esp;
880 Bit32u ebx, edx, ecx, eax;
881 } r32;
882 struct {
883 Bit16u di, filler1, si, filler2, bp, filler3, sp, filler4;
884 Bit16u bx, filler5, dx, filler6, cx, filler7, ax, filler8;
885 } r16;
886 struct {
887 Bit32u filler[4];
888 Bit8u bl, bh;
889 Bit16u filler1;
890 Bit8u dl, dh;
891 Bit16u filler2;
892 Bit8u cl, ch;
893 Bit16u filler3;
894 Bit8u al, ah;
895 Bit16u filler4;
896 } r8;
897 } u;
898} pushad_regs_t;
899
900typedef struct {
901 union {
902 struct {
903 Bit16u flags;
904 } r16;
905 struct {
906 Bit8u flagsl;
907 Bit8u flagsh;
908 } r8;
909 } u;
910 } flags_t;
911
912#define SetCF(x) x.u.r8.flagsl |= 0x01
913#define SetZF(x) x.u.r8.flagsl |= 0x40
914#define ClearCF(x) x.u.r8.flagsl &= 0xfe
915#define ClearZF(x) x.u.r8.flagsl &= 0xbf
916#define GetCF(x) (x.u.r8.flagsl & 0x01)
917
918typedef struct {
919 Bit16u ip;
920 Bit16u cs;
921 flags_t flags;
922 } iret_addr_t;
923
924
925
926static Bit8u inb();
927static Bit8u inb_cmos();
928static void outb();
929static void outb_cmos();
930static Bit16u inw();
931static void outw();
932static void init_rtc();
933static bx_bool rtc_updating();
934
935static Bit8u read_byte();
936static Bit16u read_word();
937static void write_byte();
938static void write_word();
939static void bios_printf();
940
941static Bit8u send_to_mouse_ctrl();
942static Bit8u get_mouse_data();
943static void set_kbd_command_byte();
944
945static void int09_function();
946static void int13_harddisk();
947static void int13_cdrom();
948static void int13_cdemu();
949static void int13_eltorito();
950static void int13_diskette_function();
951static void int14_function();
952static void int15_function();
953static void int16_function();
954static void int17_function();
955static Bit32u int19_function();
956static void int1a_function();
957static void int70_function();
958static void int74_function();
959static void dummy_isr_function();
960static Bit16u get_CS();
961static Bit16u get_SS();
962static unsigned int enqueue_key();
963static unsigned int dequeue_key();
964static void get_hd_geometry();
965static void set_diskette_ret_status();
966static void set_diskette_current_cyl();
967static void determine_floppy_media();
968static bx_bool floppy_drive_exists();
969static bx_bool floppy_drive_recal();
970static bx_bool floppy_media_known();
971static bx_bool floppy_media_sense();
972static bx_bool set_enable_a20();
973static void debugger_on();
974static void debugger_off();
975static void keyboard_init();
976static void keyboard_panic();
977static void shutdown_status_panic();
978static void nmi_handler_msg();
979
980static void print_bios_banner();
981static void print_boot_device();
982static void print_boot_failure();
983static void print_cdromboot_failure();
984
985# if BX_USE_ATADRV
986
987// ATA / ATAPI driver
988void ata_init();
989void ata_detect();
990void ata_reset();
991
992Bit16u ata_cmd_non_data();
993Bit16u ata_cmd_data_in();
994Bit16u ata_cmd_data_out();
995Bit16u ata_cmd_packet();
996
997Bit16u atapi_get_sense();
998Bit16u atapi_is_ready();
999Bit16u atapi_is_cdrom();
1000
1001#endif // BX_USE_ATADRV
1002
1003#if BX_ELTORITO_BOOT
1004
1005void cdemu_init();
1006Bit8u cdemu_isactive();
1007Bit8u cdemu_emulated_drive();
1008
1009Bit16u cdrom_boot();
1010
1011#endif // BX_ELTORITO_BOOT
1012
1013#ifdef VBOX
1014static char bios_prefix_string[] = "BIOS: ";
1015/* Do not use build timestamps in this string. Otherwise even rebuilding the
1016 * very same code will lead to compare errors when restoring saved state. */
1017static char bios_cvs_version_string[] = "VirtualBox " VBOX_VERSION_STRING;
1018#define BIOS_COPYRIGHT_STRING "Oracle VM VirtualBox BIOS"
1019#else /* !VBOX */
1020static char bios_cvs_version_string[] = "$Revision: 1.176 $ $Date: 2006/12/30 17:13:17 $";
1021
1022#define BIOS_COPYRIGHT_STRING "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team."
1023#endif /* !VBOX */
1024
1025#define BIOS_PRINTF_HALT 1
1026#define BIOS_PRINTF_SCREEN 2
1027#define BIOS_PRINTF_INFO 4
1028#define BIOS_PRINTF_DEBUG 8
1029#define BIOS_PRINTF_ALL (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO)
1030#define BIOS_PRINTF_DEBHALT (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO | BIOS_PRINTF_HALT)
1031
1032#define printf(format, p...) bios_printf(BIOS_PRINTF_SCREEN, format, ##p)
1033
1034// Defines the output macros.
1035// BX_DEBUG goes to INFO port until we can easily choose debug info on a
1036// per-device basis. Debug info are sent only in debug mode
1037#if DEBUG_ROMBIOS
1038# define BX_DEBUG(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
1039#else
1040# define BX_DEBUG(format, p...)
1041#endif
1042#ifdef VBOX
1043#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)
1044#else /* !VBOX */
1045#define BX_INFO(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
1046#endif /* !VBOX */
1047#define BX_PANIC(format, p...) bios_printf(BIOS_PRINTF_DEBHALT, format, ##p)
1048
1049#if DEBUG_ATA
1050# define BX_DEBUG_ATA(a...) BX_DEBUG(a)
1051#else
1052# define BX_DEBUG_ATA(a...)
1053#endif
1054#if DEBUG_INT13_HD
1055# define BX_DEBUG_INT13_HD(a...) BX_DEBUG(a)
1056#else
1057# define BX_DEBUG_INT13_HD(a...)
1058#endif
1059#if DEBUG_INT13_CD
1060# define BX_DEBUG_INT13_CD(a...) BX_DEBUG(a)
1061#else
1062# define BX_DEBUG_INT13_CD(a...)
1063#endif
1064#if DEBUG_INT13_ET
1065# define BX_DEBUG_INT13_ET(a...) BX_DEBUG(a)
1066#else
1067# define BX_DEBUG_INT13_ET(a...)
1068#endif
1069#if DEBUG_INT13_FL
1070# define BX_DEBUG_INT13_FL(a...) BX_DEBUG(a)
1071#else
1072# define BX_DEBUG_INT13_FL(a...)
1073#endif
1074#if DEBUG_INT15
1075# define BX_DEBUG_INT15(a...) BX_DEBUG(a)
1076#else
1077# define BX_DEBUG_INT15(a...)
1078#endif
1079#if DEBUG_INT16
1080# define BX_DEBUG_INT16(a...) BX_DEBUG(a)
1081#else
1082# define BX_DEBUG_INT16(a...)
1083#endif
1084#if DEBUG_INT1A
1085# define BX_DEBUG_INT1A(a...) BX_DEBUG(a)
1086#else
1087# define BX_DEBUG_INT1A(a...)
1088#endif
1089#if DEBUG_INT74
1090# define BX_DEBUG_INT74(a...) BX_DEBUG(a)
1091#else
1092# define BX_DEBUG_INT74(a...)
1093#endif
1094
1095#define SET_AL(val8) AX = ((AX & 0xff00) | (val8))
1096#define SET_BL(val8) BX = ((BX & 0xff00) | (val8))
1097#define SET_CL(val8) CX = ((CX & 0xff00) | (val8))
1098#define SET_DL(val8) DX = ((DX & 0xff00) | (val8))
1099#define SET_AH(val8) AX = ((AX & 0x00ff) | ((val8) << 8))
1100#define SET_BH(val8) BX = ((BX & 0x00ff) | ((val8) << 8))
1101#define SET_CH(val8) CX = ((CX & 0x00ff) | ((val8) << 8))
1102#define SET_DH(val8) DX = ((DX & 0x00ff) | ((val8) << 8))
1103
1104#define GET_AL() ( AX & 0x00ff )
1105#define GET_BL() ( BX & 0x00ff )
1106#define GET_CL() ( CX & 0x00ff )
1107#define GET_DL() ( DX & 0x00ff )
1108#define GET_AH() ( AX >> 8 )
1109#define GET_BH() ( BX >> 8 )
1110#define GET_CH() ( CX >> 8 )
1111#define GET_DH() ( DX >> 8 )
1112
1113#define GET_ELDL() ( ELDX & 0x00ff )
1114#define GET_ELDH() ( ELDX >> 8 )
1115
1116#define SET_CF() FLAGS |= 0x0001
1117#define CLEAR_CF() FLAGS &= 0xfffe
1118#define GET_CF() (FLAGS & 0x0001)
1119
1120#define SET_ZF() FLAGS |= 0x0040
1121#define CLEAR_ZF() FLAGS &= 0xffbf
1122#define GET_ZF() (FLAGS & 0x0040)
1123
1124#define UNSUPPORTED_FUNCTION 0x86
1125
1126#define none 0
1127#define MAX_SCAN_CODE 0x58
1128
1129static struct {
1130 Bit16u normal;
1131 Bit16u shift;
1132 Bit16u control;
1133 Bit16u alt;
1134 Bit8u lock_flags;
1135 } scan_to_scanascii[MAX_SCAN_CODE + 1] = {
1136 { none, none, none, none, none },
1137 { 0x011b, 0x011b, 0x011b, 0x0100, none }, /* escape */
1138 { 0x0231, 0x0221, none, 0x7800, none }, /* 1! */
1139 { 0x0332, 0x0340, 0x0300, 0x7900, none }, /* 2@ */
1140 { 0x0433, 0x0423, none, 0x7a00, none }, /* 3# */
1141 { 0x0534, 0x0524, none, 0x7b00, none }, /* 4$ */
1142 { 0x0635, 0x0625, none, 0x7c00, none }, /* 5% */
1143 { 0x0736, 0x075e, 0x071e, 0x7d00, none }, /* 6^ */
1144 { 0x0837, 0x0826, none, 0x7e00, none }, /* 7& */
1145 { 0x0938, 0x092a, none, 0x7f00, none }, /* 8* */
1146 { 0x0a39, 0x0a28, none, 0x8000, none }, /* 9( */
1147 { 0x0b30, 0x0b29, none, 0x8100, none }, /* 0) */
1148 { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200, none }, /* -_ */
1149 { 0x0d3d, 0x0d2b, none, 0x8300, none }, /* =+ */
1150 { 0x0e08, 0x0e08, 0x0e7f, none, none }, /* backspace */
1151 { 0x0f09, 0x0f00, none, none, none }, /* tab */
1152 { 0x1071, 0x1051, 0x1011, 0x1000, 0x40 }, /* Q */
1153 { 0x1177, 0x1157, 0x1117, 0x1100, 0x40 }, /* W */
1154 { 0x1265, 0x1245, 0x1205, 0x1200, 0x40 }, /* E */
1155 { 0x1372, 0x1352, 0x1312, 0x1300, 0x40 }, /* R */
1156 { 0x1474, 0x1454, 0x1414, 0x1400, 0x40 }, /* T */
1157 { 0x1579, 0x1559, 0x1519, 0x1500, 0x40 }, /* Y */
1158 { 0x1675, 0x1655, 0x1615, 0x1600, 0x40 }, /* U */
1159 { 0x1769, 0x1749, 0x1709, 0x1700, 0x40 }, /* I */
1160 { 0x186f, 0x184f, 0x180f, 0x1800, 0x40 }, /* O */
1161 { 0x1970, 0x1950, 0x1910, 0x1900, 0x40 }, /* P */
1162 { 0x1a5b, 0x1a7b, 0x1a1b, none, none }, /* [{ */
1163 { 0x1b5d, 0x1b7d, 0x1b1d, none, none }, /* ]} */
1164 { 0x1c0d, 0x1c0d, 0x1c0a, none, none }, /* Enter */
1165 { none, none, none, none, none }, /* L Ctrl */
1166 { 0x1e61, 0x1e41, 0x1e01, 0x1e00, 0x40 }, /* A */
1167 { 0x1f73, 0x1f53, 0x1f13, 0x1f00, 0x40 }, /* S */
1168 { 0x2064, 0x2044, 0x2004, 0x2000, 0x40 }, /* D */
1169 { 0x2166, 0x2146, 0x2106, 0x2100, 0x40 }, /* F */
1170 { 0x2267, 0x2247, 0x2207, 0x2200, 0x40 }, /* G */
1171 { 0x2368, 0x2348, 0x2308, 0x2300, 0x40 }, /* H */
1172 { 0x246a, 0x244a, 0x240a, 0x2400, 0x40 }, /* J */
1173 { 0x256b, 0x254b, 0x250b, 0x2500, 0x40 }, /* K */
1174 { 0x266c, 0x264c, 0x260c, 0x2600, 0x40 }, /* L */
1175 { 0x273b, 0x273a, none, none, none }, /* ;: */
1176 { 0x2827, 0x2822, none, none, none }, /* '" */
1177 { 0x2960, 0x297e, none, none, none }, /* `~ */
1178 { none, none, none, none, none }, /* L shift */
1179 { 0x2b5c, 0x2b7c, 0x2b1c, none, none }, /* |\ */
1180 { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, 0x40 }, /* Z */
1181 { 0x2d78, 0x2d58, 0x2d18, 0x2d00, 0x40 }, /* X */
1182 { 0x2e63, 0x2e43, 0x2e03, 0x2e00, 0x40 }, /* C */
1183 { 0x2f76, 0x2f56, 0x2f16, 0x2f00, 0x40 }, /* V */
1184 { 0x3062, 0x3042, 0x3002, 0x3000, 0x40 }, /* B */
1185 { 0x316e, 0x314e, 0x310e, 0x3100, 0x40 }, /* N */
1186 { 0x326d, 0x324d, 0x320d, 0x3200, 0x40 }, /* M */
1187 { 0x332c, 0x333c, none, none, none }, /* ,< */
1188 { 0x342e, 0x343e, none, none, none }, /* .> */
1189 { 0x352f, 0x353f, none, none, none }, /* /? */
1190 { none, none, none, none, none }, /* R Shift */
1191 { 0x372a, 0x372a, none, none, none }, /* * */
1192 { none, none, none, none, none }, /* L Alt */
1193 { 0x3920, 0x3920, 0x3920, 0x3920, none }, /* space */
1194 { none, none, none, none, none }, /* caps lock */
1195 { 0x3b00, 0x5400, 0x5e00, 0x6800, none }, /* F1 */
1196 { 0x3c00, 0x5500, 0x5f00, 0x6900, none }, /* F2 */
1197 { 0x3d00, 0x5600, 0x6000, 0x6a00, none }, /* F3 */
1198 { 0x3e00, 0x5700, 0x6100, 0x6b00, none }, /* F4 */
1199 { 0x3f00, 0x5800, 0x6200, 0x6c00, none }, /* F5 */
1200 { 0x4000, 0x5900, 0x6300, 0x6d00, none }, /* F6 */
1201 { 0x4100, 0x5a00, 0x6400, 0x6e00, none }, /* F7 */
1202 { 0x4200, 0x5b00, 0x6500, 0x6f00, none }, /* F8 */
1203 { 0x4300, 0x5c00, 0x6600, 0x7000, none }, /* F9 */
1204 { 0x4400, 0x5d00, 0x6700, 0x7100, none }, /* F10 */
1205 { none, none, none, none, none }, /* Num Lock */
1206 { none, none, none, none, none }, /* Scroll Lock */
1207 { 0x4700, 0x4737, 0x7700, none, 0x20 }, /* 7 Home */
1208 { 0x4800, 0x4838, none, none, 0x20 }, /* 8 UP */
1209 { 0x4900, 0x4939, 0x8400, none, 0x20 }, /* 9 PgUp */
1210 { 0x4a2d, 0x4a2d, none, none, none }, /* - */
1211 { 0x4b00, 0x4b34, 0x7300, none, 0x20 }, /* 4 Left */
1212 { 0x4c00, 0x4c35, none, none, 0x20 }, /* 5 */
1213 { 0x4d00, 0x4d36, 0x7400, none, 0x20 }, /* 6 Right */
1214 { 0x4e2b, 0x4e2b, none, none, none }, /* + */
1215 { 0x4f00, 0x4f31, 0x7500, none, 0x20 }, /* 1 End */
1216 { 0x5000, 0x5032, none, none, 0x20 }, /* 2 Down */
1217 { 0x5100, 0x5133, 0x7600, none, 0x20 }, /* 3 PgDn */
1218 { 0x5200, 0x5230, none, none, 0x20 }, /* 0 Ins */
1219 { 0x5300, 0x532e, none, none, 0x20 }, /* Del */
1220 { none, none, none, none, none },
1221 { none, none, none, none, none },
1222 { 0x565c, 0x567c, none, none, none }, /* \| */
1223#ifndef VBOX
1224 { 0x5700, 0x5700, none, none, none }, /* F11 */
1225 { 0x5800, 0x5800, none, none, none } /* F12 */
1226#else
1227 { 0x8500, 0x8700, 0x8900, 0x8b00, none }, /* F11 */
1228 { 0x8600, 0x8800, 0x8a00, 0x8c00, none } /* F12 */
1229#endif
1230 };
1231
1232 Bit8u
1233inb(port)
1234 Bit16u port;
1235{
1236ASM_START
1237 push bp
1238 mov bp, sp
1239
1240 push dx
1241 mov dx, 4[bp]
1242 in al, dx
1243 pop dx
1244
1245 pop bp
1246ASM_END
1247}
1248
1249#if BX_USE_ATADRV
1250 Bit16u
1251inw(port)
1252 Bit16u port;
1253{
1254ASM_START
1255 push bp
1256 mov bp, sp
1257
1258 push dx
1259 mov dx, 4[bp]
1260 in ax, dx
1261 pop dx
1262
1263 pop bp
1264ASM_END
1265}
1266#endif
1267
1268 void
1269outb(port, val)
1270 Bit16u port;
1271 Bit8u val;
1272{
1273ASM_START
1274 push bp
1275 mov bp, sp
1276
1277 push ax
1278 push dx
1279 mov dx, 4[bp]
1280 mov al, 6[bp]
1281 out dx, al
1282 pop dx
1283 pop ax
1284
1285 pop bp
1286ASM_END
1287}
1288
1289#if BX_USE_ATADRV
1290 void
1291outw(port, val)
1292 Bit16u port;
1293 Bit16u val;
1294{
1295ASM_START
1296 push bp
1297 mov bp, sp
1298
1299 push ax
1300 push dx
1301 mov dx, 4[bp]
1302 mov ax, 6[bp]
1303 out dx, ax
1304 pop dx
1305 pop ax
1306
1307 pop bp
1308ASM_END
1309}
1310#endif
1311
1312 void
1313outb_cmos(cmos_reg, val)
1314 Bit8u cmos_reg;
1315 Bit8u val;
1316{
1317ASM_START
1318 push bp
1319 mov bp, sp
1320
1321 mov al, 4[bp] ;; cmos_reg
1322 out 0x70, al
1323 mov al, 6[bp] ;; val
1324 out 0x71, al
1325
1326 pop bp
1327ASM_END
1328}
1329
1330 Bit8u
1331inb_cmos(cmos_reg)
1332 Bit8u cmos_reg;
1333{
1334ASM_START
1335 push bp
1336 mov bp, sp
1337
1338 mov al, 4[bp] ;; cmos_reg
1339 out 0x70, al
1340 in al, 0x71
1341
1342 pop bp
1343ASM_END
1344}
1345
1346 void
1347init_rtc()
1348{
1349 outb_cmos(0x0a, 0x26);
1350 outb_cmos(0x0b, 0x02);
1351 inb_cmos(0x0c);
1352 inb_cmos(0x0d);
1353}
1354
1355 bx_bool
1356rtc_updating()
1357{
1358 // This function checks to see if the update-in-progress bit
1359 // is set in CMOS Status Register A. If not, it returns 0.
1360 // If it is set, it tries to wait until there is a transition
1361 // to 0, and will return 0 if such a transition occurs. A 1
1362 // is returned only after timing out. The maximum period
1363 // that this bit should be set is constrained to 244useconds.
1364 // The count I use below guarantees coverage or more than
1365 // this time, with any reasonable IPS setting.
1366
1367 Bit16u count;
1368
1369 count = 25000;
1370 while (--count != 0) {
1371 if ( (inb_cmos(0x0a) & 0x80) == 0 )
1372 return(0);
1373 }
1374 return(1); // update-in-progress never transitioned to 0
1375}
1376
1377
1378 Bit8u
1379read_byte(seg, offset)
1380 Bit16u seg;
1381 Bit16u offset;
1382{
1383ASM_START
1384 push bp
1385 mov bp, sp
1386
1387 push bx
1388 push ds
1389 mov ax, 4[bp] ; segment
1390 mov ds, ax
1391 mov bx, 6[bp] ; offset
1392 mov al, [bx]
1393 ;; al = return value (byte)
1394 pop ds
1395 pop bx
1396
1397 pop bp
1398ASM_END
1399}
1400
1401 Bit16u
1402read_word(seg, offset)
1403 Bit16u seg;
1404 Bit16u offset;
1405{
1406ASM_START
1407 push bp
1408 mov bp, sp
1409
1410 push bx
1411 push ds
1412 mov ax, 4[bp] ; segment
1413 mov ds, ax
1414 mov bx, 6[bp] ; offset
1415 mov ax, [bx]
1416 ;; ax = return value (word)
1417 pop ds
1418 pop bx
1419
1420 pop bp
1421ASM_END
1422}
1423
1424 void
1425write_byte(seg, offset, data)
1426 Bit16u seg;
1427 Bit16u offset;
1428 Bit8u data;
1429{
1430ASM_START
1431 push bp
1432 mov bp, sp
1433
1434 push ax
1435 push bx
1436 push ds
1437 mov ax, 4[bp] ; segment
1438 mov ds, ax
1439 mov bx, 6[bp] ; offset
1440 mov al, 8[bp] ; data byte
1441 mov [bx], al ; write data byte
1442 pop ds
1443 pop bx
1444 pop ax
1445
1446 pop bp
1447ASM_END
1448}
1449
1450 void
1451write_word(seg, offset, data)
1452 Bit16u seg;
1453 Bit16u offset;
1454 Bit16u data;
1455{
1456ASM_START
1457 push bp
1458 mov bp, sp
1459
1460 push ax
1461 push bx
1462 push ds
1463 mov ax, 4[bp] ; segment
1464 mov ds, ax
1465 mov bx, 6[bp] ; offset
1466 mov ax, 8[bp] ; data word
1467 mov [bx], ax ; write data word
1468 pop ds
1469 pop bx
1470 pop ax
1471
1472 pop bp
1473ASM_END
1474}
1475
1476 Bit16u
1477get_CS()
1478{
1479ASM_START
1480 mov ax, cs
1481ASM_END
1482}
1483
1484 Bit16u
1485get_SS()
1486{
1487ASM_START
1488 mov ax, ss
1489ASM_END
1490}
1491
1492#if BX_DEBUG_SERIAL
1493/* serial debug port*/
1494#define BX_DEBUG_PORT 0x03f8
1495
1496/* data */
1497#define UART_RBR 0x00
1498#define UART_THR 0x00
1499
1500/* control */
1501#define UART_IER 0x01
1502#define UART_IIR 0x02
1503#define UART_FCR 0x02
1504#define UART_LCR 0x03
1505#define UART_MCR 0x04
1506#define UART_DLL 0x00
1507#define UART_DLM 0x01
1508
1509/* status */
1510#define UART_LSR 0x05
1511#define UART_MSR 0x06
1512#define UART_SCR 0x07
1513
1514int uart_can_tx_byte(base_port)
1515 Bit16u base_port;
1516{
1517 return inb(base_port + UART_LSR) & 0x20;
1518}
1519
1520void uart_wait_to_tx_byte(base_port)
1521 Bit16u base_port;
1522{
1523 while (!uart_can_tx_byte(base_port));
1524}
1525
1526void uart_wait_until_sent(base_port)
1527 Bit16u base_port;
1528{
1529 while (!(inb(base_port + UART_LSR) & 0x40));
1530}
1531
1532void uart_tx_byte(base_port, data)
1533 Bit16u base_port;
1534 Bit8u data;
1535{
1536 uart_wait_to_tx_byte(base_port);
1537 outb(base_port + UART_THR, data);
1538 uart_wait_until_sent(base_port);
1539}
1540#endif
1541
1542 void
1543wrch(c)
1544 Bit8u c;
1545{
1546 ASM_START
1547 push bp
1548 mov bp, sp
1549
1550 push bx
1551 mov ah, #0x0e
1552 mov al, 4[bp]
1553 xor bx,bx
1554 int #0x10
1555 pop bx
1556
1557 pop bp
1558 ASM_END
1559}
1560
1561 void
1562send(action, c)
1563 Bit16u action;
1564 Bit8u c;
1565{
1566#if BX_DEBUG_SERIAL
1567 if (c == '\n') uart_tx_byte(BX_DEBUG_PORT, '\r');
1568 uart_tx_byte(BX_DEBUG_PORT, c);
1569#endif
1570#if BX_VIRTUAL_PORTS
1571 if (action & BIOS_PRINTF_DEBUG) outb(DEBUG_PORT, c);
1572 if (action & BIOS_PRINTF_INFO) outb(INFO_PORT, c);
1573#endif
1574 if (action & BIOS_PRINTF_SCREEN) {
1575 if (c == '\n') wrch('\r');
1576 wrch(c);
1577 }
1578}
1579
1580 void
1581put_int(action, val, width, neg)
1582 Bit16u action;
1583 short val, width;
1584 bx_bool neg;
1585{
1586 short nval = val / 10;
1587 if (nval)
1588 put_int(action, nval, width - 1, neg);
1589 else {
1590 while (--width > 0) send(action, ' ');
1591 if (neg) send(action, '-');
1592 }
1593 send(action, val - (nval * 10) + '0');
1594}
1595
1596 void
1597put_uint(action, val, width, neg)
1598 Bit16u action;
1599 unsigned short val;
1600 short width;
1601 bx_bool neg;
1602{
1603 unsigned short nval = val / 10;
1604 if (nval)
1605 put_uint(action, nval, width - 1, neg);
1606 else {
1607 while (--width > 0) send(action, ' ');
1608 if (neg) send(action, '-');
1609 }
1610 send(action, val - (nval * 10) + '0');
1611}
1612
1613 void
1614put_luint(action, val, width, neg)
1615 Bit16u action;
1616 unsigned long val;
1617 short width;
1618 bx_bool neg;
1619{
1620 unsigned long nval = val / 10;
1621 if (nval)
1622 put_luint(action, nval, width - 1, neg);
1623 else {
1624 while (--width > 0) send(action, ' ');
1625 if (neg) send(action, '-');
1626 }
1627 send(action, val - (nval * 10) + '0');
1628}
1629
1630void put_str(action, segment, offset)
1631 Bit16u action;
1632 Bit16u segment;
1633 Bit16u offset;
1634{
1635 Bit8u c;
1636
1637 while (c = read_byte(segment, offset)) {
1638 send(action, c);
1639 offset++;
1640 }
1641}
1642
1643
1644//--------------------------------------------------------------------------
1645// bios_printf()
1646// A compact variable argument printf function.
1647//
1648// Supports %[format_width][length]format
1649// where format can be x,X,u,d,s,S,c
1650// and the optional length modifier is l (ell)
1651//--------------------------------------------------------------------------
1652 void
1653bios_printf(action, s)
1654 Bit16u action;
1655 Bit8u *s;
1656{
1657 Bit8u c, format_char;
1658 bx_bool in_format;
1659 short i;
1660 Bit16u *arg_ptr;
1661 Bit16u arg_seg, arg, nibble, hibyte, shift_count, format_width, hexadd;
1662
1663 arg_ptr = &s;
1664 arg_seg = get_SS();
1665
1666 in_format = 0;
1667 format_width = 0;
1668
1669 if ((action & BIOS_PRINTF_DEBHALT) == BIOS_PRINTF_DEBHALT) {
1670#if BX_VIRTUAL_PORTS
1671 outb(PANIC_PORT2, 0x00);
1672#endif
1673 bios_printf (BIOS_PRINTF_SCREEN, "FATAL: ");
1674 }
1675
1676 while (c = read_byte(get_CS(), s)) {
1677 if ( c == '%' ) {
1678 in_format = 1;
1679 format_width = 0;
1680 }
1681 else if (in_format) {
1682 if ( (c>='0') && (c<='9') ) {
1683 format_width = (format_width * 10) + (c - '0');
1684 }
1685 else {
1686 arg_ptr++; // increment to next arg
1687 arg = read_word(arg_seg, arg_ptr);
1688 if (c == 'x' || c == 'X') {
1689 if (format_width == 0)
1690 format_width = 4;
1691 if (c == 'x')
1692 hexadd = 'a';
1693 else
1694 hexadd = 'A';
1695 for (i=format_width-1; i>=0; i--) {
1696 nibble = (arg >> (4 * i)) & 0x000f;
1697 send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd));
1698 }
1699 }
1700 else if (c == 'u') {
1701 put_uint(action, arg, format_width, 0);
1702 }
1703 else if (c == 'l') {
1704 s++;
1705 c = read_byte(get_CS(), s); /* is it ld,lx,lu? */
1706 arg_ptr++; /* increment to next arg */
1707 hibyte = read_word(arg_seg, arg_ptr);
1708 if (c == 'd') {
1709 if (hibyte & 0x8000)
1710 put_luint(action, 0L-(((Bit32u) hibyte << 16) | arg), format_width-1, 1);
1711 else
1712 put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
1713 }
1714 else if (c == 'u') {
1715 put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
1716 }
1717 else if (c == 'x' || c == 'X')
1718 {
1719 if (format_width == 0)
1720 format_width = 8;
1721 if (c == 'x')
1722 hexadd = 'a';
1723 else
1724 hexadd = 'A';
1725 for (i=format_width-1; i>=0; i--) {
1726 nibble = ((((Bit32u) hibyte <<16) | arg) >> (4 * i)) & 0x000f;
1727 send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd));
1728 }
1729 }
1730 }
1731 else if (c == 'd') {
1732 if (arg & 0x8000)
1733 put_int(action, -arg, format_width - 1, 1);
1734 else
1735 put_int(action, arg, format_width, 0);
1736 }
1737 else if (c == 's') {
1738 put_str(action, get_CS(), arg);
1739 }
1740 else if (c == 'S') {
1741 hibyte = arg;
1742 arg_ptr++;
1743 arg = read_word(arg_seg, arg_ptr);
1744 put_str(action, hibyte, arg);
1745 }
1746 else if (c == 'c') {
1747 send(action, arg);
1748 }
1749 else
1750 BX_PANIC("bios_printf: unknown format\n");
1751 in_format = 0;
1752 }
1753 }
1754 else {
1755 send(action, c);
1756 }
1757 s ++;
1758 }
1759
1760 if (action & BIOS_PRINTF_HALT) {
1761 // freeze in a busy loop.
1762ASM_START
1763 cli
1764 halt2_loop:
1765 hlt
1766 jmp halt2_loop
1767ASM_END
1768 }
1769}
1770
1771//--------------------------------------------------------------------------
1772// keyboard_init
1773//--------------------------------------------------------------------------
1774// this file is based on LinuxBIOS implementation of keyboard.c
1775// could convert to #asm to gain space
1776 void
1777keyboard_init()
1778{
1779 Bit16u max;
1780
1781 /* ------------------- Flush buffers ------------------------*/
1782 /* Wait until buffer is empty */
1783 max=0xffff;
1784 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
1785
1786 /* flush incoming keys */
1787 max=0x2000;
1788 while (--max > 0) {
1789 outb(0x80, 0x00);
1790 if (inb(0x64) & 0x01) {
1791 inb(0x60);
1792 max = 0x2000;
1793 }
1794 }
1795
1796 // Due to timer issues, and if the IPS setting is > 15000000,
1797 // the incoming keys might not be flushed here. That will
1798 // cause a panic a few lines below. See sourceforge bug report :
1799 // [ 642031 ] FATAL: Keyboard RESET error:993
1800
1801 /* ------------------- controller side ----------------------*/
1802 /* send cmd = 0xAA, self test 8042 */
1803 outb(0x64, 0xaa);
1804
1805 /* Wait until buffer is empty */
1806 max=0xffff;
1807 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
1808 if (max==0x0) keyboard_panic(00);
1809
1810 /* Wait for data */
1811 max=0xffff;
1812 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x01);
1813 if (max==0x0) keyboard_panic(01);
1814
1815 /* read self-test result, 0x55 should be returned from 0x60 */
1816 if ((inb(0x60) != 0x55)){
1817 keyboard_panic(991);
1818 }
1819
1820 /* send cmd = 0xAB, keyboard interface test */
1821 outb(0x64,0xab);
1822
1823 /* Wait until buffer is empty */
1824 max=0xffff;
1825 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x10);
1826 if (max==0x0) keyboard_panic(10);
1827
1828 /* Wait for data */
1829 max=0xffff;
1830 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x11);
1831 if (max==0x0) keyboard_panic(11);
1832
1833 /* read keyboard interface test result, */
1834 /* 0x00 should be returned form 0x60 */
1835 if ((inb(0x60) != 0x00)) {
1836 keyboard_panic(992);
1837 }
1838
1839 /* Enable Keyboard clock */
1840 outb(0x64,0xae);
1841 outb(0x64,0xa8);
1842
1843 /* ------------------- keyboard side ------------------------*/
1844 /* reset keyboard and self test (keyboard side) */
1845 outb(0x60, 0xff);
1846
1847 /* Wait until buffer is empty */
1848 max=0xffff;
1849 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x20);
1850 if (max==0x0) keyboard_panic(20);
1851
1852 /* Wait for data */
1853 max=0xffff;
1854 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x21);
1855 if (max==0x0) keyboard_panic(21);
1856
1857 /* keyboard should return ACK */
1858 if ((inb(0x60) != 0xfa)) {
1859 keyboard_panic(993);
1860 }
1861
1862 /* Wait for data */
1863 max=0xffff;
1864 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x31);
1865 if (max==0x0) keyboard_panic(31);
1866
1867 if ((inb(0x60) != 0xaa)) {
1868 keyboard_panic(994);
1869 }
1870
1871 /* Disable keyboard */
1872 outb(0x60, 0xf5);
1873
1874 /* Wait until buffer is empty */
1875 max=0xffff;
1876 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x40);
1877 if (max==0x0) keyboard_panic(40);
1878
1879 /* Wait for data */
1880 max=0xffff;
1881 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x41);
1882 if (max==0x0) keyboard_panic(41);
1883
1884 /* keyboard should return ACK */
1885 if ((inb(0x60) != 0xfa)) {
1886 keyboard_panic(995);
1887 }
1888
1889 /* Write Keyboard Mode */
1890 outb(0x64, 0x60);
1891
1892 /* Wait until buffer is empty */
1893 max=0xffff;
1894 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x50);
1895 if (max==0x0) keyboard_panic(50);
1896
1897 /* send cmd: scan code convert, disable mouse, enable IRQ 1 */
1898 outb(0x60, 0x65);
1899
1900 /* Wait until buffer is empty */
1901 max=0xffff;
1902 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x60);
1903 if (max==0x0) keyboard_panic(60);
1904
1905 /* Enable keyboard */
1906 outb(0x60, 0xf4);
1907
1908 /* Wait until buffer is empty */
1909 max=0xffff;
1910 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x70);
1911 if (max==0x0) keyboard_panic(70);
1912
1913 /* Wait for data */
1914 max=0xffff;
1915 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x71);
1916 if (max==0x0) keyboard_panic(70);
1917
1918 /* keyboard should return ACK */
1919 if ((inb(0x60) != 0xfa)) {
1920 keyboard_panic(996);
1921 }
1922
1923 outb(0x80, 0x77);
1924}
1925
1926//--------------------------------------------------------------------------
1927// keyboard_panic
1928//--------------------------------------------------------------------------
1929 void
1930keyboard_panic(status)
1931 Bit16u status;
1932{
1933 // If you're getting a 993 keyboard panic here,
1934 // please see the comment in keyboard_init
1935
1936 BX_PANIC("Keyboard error:%u\n",status);
1937}
1938
1939//--------------------------------------------------------------------------
1940// shutdown_status_panic
1941// called when the shutdown status is not implemented, displays the status
1942//--------------------------------------------------------------------------
1943 void
1944shutdown_status_panic(status)
1945 Bit16u status;
1946{
1947 BX_PANIC("Unimplemented shutdown status: %02x\n",(Bit8u)status);
1948}
1949
1950#ifdef VBOX
1951#include "logo.c"
1952#endif /* VBOX */
1953
1954//--------------------------------------------------------------------------
1955// print_bios_banner
1956// displays a the bios version
1957//--------------------------------------------------------------------------
1958void
1959print_bios_banner()
1960{
1961#ifdef VBOX
1962 // Skip the logo if a warm boot is requested.
1963 Bit16u warm_boot = read_word(0x0040,0x0072);
1964 write_word(0x0040,0x0072, 0);
1965 if (warm_boot == 0x1234)
1966 return;
1967 /* show graphical logo */
1968 show_logo();
1969#else /* !VBOX */
1970 printf(BX_APPNAME" BIOS - build: %s\n%s\nOptions: ",
1971 BIOS_BUILD_DATE, bios_cvs_version_string);
1972 printf(
1973#if BX_APM
1974 "apmbios "
1975#endif
1976#if BX_PCIBIOS
1977 "pcibios "
1978#endif
1979#if BX_ELTORITO_BOOT
1980 "eltorito "
1981#endif
1982#if BX_ROMBIOS32
1983 "rombios32 "
1984#endif
1985 "\n\n");
1986#endif /* VBOX */
1987}
1988
1989//--------------------------------------------------------------------------
1990// print_boot_device
1991// displays the boot device
1992//--------------------------------------------------------------------------
1993
1994#ifdef VBOX
1995static char drivetypes[][10]={"Floppy","Hard Disk","CD-ROM","LAN"};
1996#else /* !VBOX */
1997static char drivetypes[][10]={"Floppy","Hard Disk","CD-Rom"};
1998#endif /* !VBOX */
1999
2000#ifdef VBOX
2001void
2002print_boot_device(cdboot, lanboot, drive)
2003 Bit8u cdboot; Bit8u lanboot; Bit16u drive;
2004#else /* !VBOX */
2005void
2006print_boot_device(cdboot, drive)
2007 Bit8u cdboot; Bit16u drive;
2008#endif /* !VBOX */
2009{
2010 Bit8u i;
2011
2012#ifdef VBOX
2013 // cdboot contains 0 if lan/floppy/harddisk, 1 otherwise
2014 // lanboot contains 0 if floppy/harddisk, 1 otherwise
2015#else /* !VBOX */
2016 // cdboot contains 0 if floppy/harddisk, 1 otherwise
2017#endif /* !VBOX */
2018 // drive contains real/emulated boot drive
2019
2020 if(cdboot)i=2; // CD-Rom
2021#ifdef VBOX
2022 else if(lanboot)i=3; // LAN
2023#endif /* VBOX */
2024 else if((drive&0x0080)==0x00)i=0; // Floppy
2025 else if((drive&0x0080)==0x80)i=1; // Hard drive
2026 else return;
2027
2028#ifdef VBOX
2029 BX_INFO("Booting from %s...\n",drivetypes[i]);
2030#else /* !VBOX */
2031 printf("Booting from %s...\n",drivetypes[i]);
2032#endif /* !VBOX */
2033}
2034
2035//--------------------------------------------------------------------------
2036// print_boot_failure
2037// displays the reason why boot failed
2038//--------------------------------------------------------------------------
2039#ifdef VBOX
2040 void
2041print_boot_failure(cdboot, lanboot, drive, reason, lastdrive)
2042 Bit8u cdboot; Bit8u lanboot; Bit8u drive; Bit8u reason; Bit8u lastdrive;
2043#else /* !VBOX */
2044 void
2045print_boot_failure(cdboot, drive, reason, lastdrive)
2046 Bit8u cdboot; Bit8u drive; Bit8u lastdrive;
2047#endif /* !VBOX */
2048{
2049 Bit16u drivenum = drive&0x7f;
2050
2051 // cdboot: 1 if boot from cd, 0 otherwise
2052#ifdef VBOX
2053 // lanboot: 1 if boot from lan, 0 otherwise
2054#endif /* VBOX */
2055 // drive : drive number
2056 // reason: 0 signature check failed, 1 read error
2057 // lastdrive: 1 boot drive is the last one in boot sequence
2058
2059 if (cdboot)
2060#ifndef VBOX
2061 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s failed\n",drivetypes[2]);
2062#else /* VBOX */
2063 BX_INFO("Boot from %s failed\n",drivetypes[2]);
2064 else if (lanboot)
2065 BX_INFO("Boot from %s failed\n",drivetypes[3]);
2066#endif /* VBOX */
2067 else if (drive & 0x80)
2068#ifndef VBOX
2069 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[1],drivenum);
2070#else /* VBOX */
2071 BX_INFO("Boot from %s %d failed\n", drivetypes[1],drivenum);
2072#endif /* VBOX */
2073 else
2074#ifndef VBOX
2075 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[0],drivenum);
2076#else /* VBOX */
2077 BX_INFO("Boot from %s %d failed\n", drivetypes[0],drivenum);
2078#endif /* VBOX */
2079
2080 if (lastdrive==1) {
2081 if (reason==0)
2082#ifndef VBOX
2083 BX_PANIC("Not a bootable disk\n");
2084#else /* VBOX */
2085 BX_PANIC("No bootable medium found! System halted.\n");
2086#endif /* VBOX */
2087 else
2088#ifndef VBOX
2089 BX_PANIC("Could not read the boot disk\n");
2090#else /* VBOX */
2091 BX_PANIC("Could not read from the boot medium! System halted.\n");
2092#endif /* VBOX */
2093 }
2094}
2095
2096//--------------------------------------------------------------------------
2097// print_cdromboot_failure
2098// displays the reason why boot failed
2099//--------------------------------------------------------------------------
2100 void
2101print_cdromboot_failure( code )
2102 Bit16u code;
2103{
2104#ifndef VBOX
2105 bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "CDROM boot failure code : %04x\n",code);
2106#else /* VBOX */
2107 BX_INFO("CDROM boot failure code : %04x\n",code);
2108#endif /* VBOX */
2109
2110 return;
2111}
2112
2113void
2114nmi_handler_msg()
2115{
2116 BX_PANIC("NMI Handler called\n");
2117}
2118
2119void
2120int18_panic_msg()
2121{
2122 BX_PANIC("INT18: BOOT FAILURE\n");
2123}
2124
2125void
2126log_bios_start()
2127{
2128#if BX_DEBUG_SERIAL
2129 outb(BX_DEBUG_PORT+UART_LCR, 0x03); /* setup for serial logging: 8N1 */
2130#endif
2131 BX_INFO("%s\n", bios_cvs_version_string);
2132}
2133
2134 bx_bool
2135set_enable_a20(val)
2136 bx_bool val;
2137{
2138 Bit8u oldval;
2139
2140 // Use PS2 System Control port A to set A20 enable
2141
2142 // get current setting first
2143 oldval = inb(0x92);
2144
2145 // change A20 status
2146 if (val)
2147 outb(0x92, oldval | 0x02);
2148 else
2149 outb(0x92, oldval & 0xfd);
2150
2151 return((oldval & 0x02) != 0);
2152}
2153
2154 void
2155debugger_on()
2156{
2157 outb(0xfedc, 0x01);
2158}
2159
2160 void
2161debugger_off()
2162{
2163 outb(0xfedc, 0x00);
2164}
2165
2166#if BX_USE_ATADRV
2167
2168// ---------------------------------------------------------------------------
2169// Start of ATA/ATAPI Driver
2170// ---------------------------------------------------------------------------
2171
2172// Global defines -- ATA register and register bits.
2173// command block & control block regs
2174#define ATA_CB_DATA 0 // data reg in/out pio_base_addr1+0
2175#define ATA_CB_ERR 1 // error in pio_base_addr1+1
2176#define ATA_CB_FR 1 // feature reg out pio_base_addr1+1
2177#define ATA_CB_SC 2 // sector count in/out pio_base_addr1+2
2178#define ATA_CB_SN 3 // sector number in/out pio_base_addr1+3
2179#define ATA_CB_CL 4 // cylinder low in/out pio_base_addr1+4
2180#define ATA_CB_CH 5 // cylinder high in/out pio_base_addr1+5
2181#define ATA_CB_DH 6 // device head in/out pio_base_addr1+6
2182#define ATA_CB_STAT 7 // primary status in pio_base_addr1+7
2183#define ATA_CB_CMD 7 // command out pio_base_addr1+7
2184#define ATA_CB_ASTAT 6 // alternate status in pio_base_addr2+6
2185#define ATA_CB_DC 6 // device control out pio_base_addr2+6
2186#define ATA_CB_DA 7 // device address in pio_base_addr2+7
2187
2188#define ATA_CB_ER_ICRC 0x80 // ATA Ultra DMA bad CRC
2189#define ATA_CB_ER_BBK 0x80 // ATA bad block
2190#define ATA_CB_ER_UNC 0x40 // ATA uncorrected error
2191#define ATA_CB_ER_MC 0x20 // ATA media change
2192#define ATA_CB_ER_IDNF 0x10 // ATA id not found
2193#define ATA_CB_ER_MCR 0x08 // ATA media change request
2194#define ATA_CB_ER_ABRT 0x04 // ATA command aborted
2195#define ATA_CB_ER_NTK0 0x02 // ATA track 0 not found
2196#define ATA_CB_ER_NDAM 0x01 // ATA address mark not found
2197
2198#define ATA_CB_ER_P_SNSKEY 0xf0 // ATAPI sense key (mask)
2199#define ATA_CB_ER_P_MCR 0x08 // ATAPI Media Change Request
2200#define ATA_CB_ER_P_ABRT 0x04 // ATAPI command abort
2201#define ATA_CB_ER_P_EOM 0x02 // ATAPI End of Media
2202#define ATA_CB_ER_P_ILI 0x01 // ATAPI Illegal Length Indication
2203
2204// ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC)
2205#define ATA_CB_SC_P_TAG 0xf8 // ATAPI tag (mask)
2206#define ATA_CB_SC_P_REL 0x04 // ATAPI release
2207#define ATA_CB_SC_P_IO 0x02 // ATAPI I/O
2208#define ATA_CB_SC_P_CD 0x01 // ATAPI C/D
2209
2210// bits 7-4 of the device/head (CB_DH) reg
2211#define ATA_CB_DH_DEV0 0xa0 // select device 0
2212#define ATA_CB_DH_DEV1 0xb0 // select device 1
2213
2214// status reg (CB_STAT and CB_ASTAT) bits
2215#define ATA_CB_STAT_BSY 0x80 // busy
2216#define ATA_CB_STAT_RDY 0x40 // ready
2217#define ATA_CB_STAT_DF 0x20 // device fault
2218#define ATA_CB_STAT_WFT 0x20 // write fault (old name)
2219#define ATA_CB_STAT_SKC 0x10 // seek complete
2220#define ATA_CB_STAT_SERV 0x10 // service
2221#define ATA_CB_STAT_DRQ 0x08 // data request
2222#define ATA_CB_STAT_CORR 0x04 // corrected
2223#define ATA_CB_STAT_IDX 0x02 // index
2224#define ATA_CB_STAT_ERR 0x01 // error (ATA)
2225#define ATA_CB_STAT_CHK 0x01 // check (ATAPI)
2226
2227// device control reg (CB_DC) bits
2228#define ATA_CB_DC_HD15 0x08 // bit should always be set to one
2229#define ATA_CB_DC_SRST 0x04 // soft reset
2230#define ATA_CB_DC_NIEN 0x02 // disable interrupts
2231
2232// Most mandatory and optional ATA commands (from ATA-3),
2233#define ATA_CMD_CFA_ERASE_SECTORS 0xC0
2234#define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03
2235#define ATA_CMD_CFA_TRANSLATE_SECTOR 0x87
2236#define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD
2237#define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38
2238#define ATA_CMD_CHECK_POWER_MODE1 0xE5
2239#define ATA_CMD_CHECK_POWER_MODE2 0x98
2240#define ATA_CMD_DEVICE_RESET 0x08
2241#define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90
2242#define ATA_CMD_FLUSH_CACHE 0xE7
2243#define ATA_CMD_FORMAT_TRACK 0x50
2244#define ATA_CMD_IDENTIFY_DEVICE 0xEC
2245#define ATA_CMD_IDENTIFY_DEVICE_PACKET 0xA1
2246#define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xA1
2247#define ATA_CMD_IDLE1 0xE3
2248#define ATA_CMD_IDLE2 0x97
2249#define ATA_CMD_IDLE_IMMEDIATE1 0xE1
2250#define ATA_CMD_IDLE_IMMEDIATE2 0x95
2251#define ATA_CMD_INITIALIZE_DRIVE_PARAMETERS 0x91
2252#define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
2253#define ATA_CMD_NOP 0x00
2254#define ATA_CMD_PACKET 0xA0
2255#define ATA_CMD_READ_BUFFER 0xE4
2256#define ATA_CMD_READ_DMA 0xC8
2257#define ATA_CMD_READ_DMA_QUEUED 0xC7
2258#define ATA_CMD_READ_MULTIPLE 0xC4
2259#define ATA_CMD_READ_SECTORS 0x20
2260#ifdef VBOX
2261#define ATA_CMD_READ_SECTORS_EXT 0x24
2262#endif /* VBOX */
2263#define ATA_CMD_READ_VERIFY_SECTORS 0x40
2264#define ATA_CMD_RECALIBRATE 0x10
2265#define ATA_CMD_SEEK 0x70
2266#define ATA_CMD_SET_FEATURES 0xEF
2267#define ATA_CMD_SET_MULTIPLE_MODE 0xC6
2268#define ATA_CMD_SLEEP1 0xE6
2269#define ATA_CMD_SLEEP2 0x99
2270#define ATA_CMD_STANDBY1 0xE2
2271#define ATA_CMD_STANDBY2 0x96
2272#define ATA_CMD_STANDBY_IMMEDIATE1 0xE0
2273#define ATA_CMD_STANDBY_IMMEDIATE2 0x94
2274#define ATA_CMD_WRITE_BUFFER 0xE8
2275#define ATA_CMD_WRITE_DMA 0xCA
2276#define ATA_CMD_WRITE_DMA_QUEUED 0xCC
2277#define ATA_CMD_WRITE_MULTIPLE 0xC5
2278#define ATA_CMD_WRITE_SECTORS 0x30
2279#ifdef VBOX
2280#define ATA_CMD_WRITE_SECTORS_EXT 0x34
2281#endif /* VBOX */
2282#define ATA_CMD_WRITE_VERIFY 0x3C
2283
2284#define ATA_IFACE_NONE 0x00
2285#define ATA_IFACE_ISA 0x00
2286#define ATA_IFACE_PCI 0x01
2287
2288#define ATA_TYPE_NONE 0x00
2289#define ATA_TYPE_UNKNOWN 0x01
2290#define ATA_TYPE_ATA 0x02
2291#define ATA_TYPE_ATAPI 0x03
2292#ifdef VBOX
2293#define ATA_TYPE_SCSI 0x04 // SCSI disk
2294#endif
2295
2296#define ATA_DEVICE_NONE 0x00
2297#define ATA_DEVICE_HD 0xFF
2298#define ATA_DEVICE_CDROM 0x05
2299
2300#define ATA_MODE_NONE 0x00
2301#define ATA_MODE_PIO16 0x00
2302#define ATA_MODE_PIO32 0x01
2303#define ATA_MODE_ISADMA 0x02
2304#define ATA_MODE_PCIDMA 0x03
2305#define ATA_MODE_USEIRQ 0x10
2306
2307#define ATA_TRANSLATION_NONE 0
2308#define ATA_TRANSLATION_LBA 1
2309#define ATA_TRANSLATION_LARGE 2
2310#define ATA_TRANSLATION_RECHS 3
2311
2312#define ATA_DATA_NO 0x00
2313#define ATA_DATA_IN 0x01
2314#define ATA_DATA_OUT 0x02
2315
2316// ---------------------------------------------------------------------------
2317// ATA/ATAPI driver : initialization
2318// ---------------------------------------------------------------------------
2319void ata_init( )
2320{
2321 Bit16u ebda_seg=read_word(0x0040,0x000E);
2322 Bit8u channel, device;
2323
2324 // Channels info init.
2325 for (channel=0; channel<BX_MAX_ATA_INTERFACES; channel++) {
2326 write_byte(ebda_seg,&EbdaData->ata.channels[channel].iface,ATA_IFACE_NONE);
2327 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1,0x0);
2328 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2,0x0);
2329 write_byte(ebda_seg,&EbdaData->ata.channels[channel].irq,0);
2330 }
2331
2332 // Devices info init.
2333 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2334 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
2335 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_NONE);
2336 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable,0);
2337 write_byte(ebda_seg,&EbdaData->ata.devices[device].lock,0);
2338 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode,ATA_MODE_NONE);
2339 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,0);
2340 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation,ATA_TRANSLATION_NONE);
2341 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads,0);
2342 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders,0);
2343 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt,0);
2344 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads,0);
2345 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders,0);
2346 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt,0);
2347
2348 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors,0L);
2349 }
2350
2351 // hdidmap and cdidmap init.
2352 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2353 write_byte(ebda_seg,&EbdaData->ata.hdidmap[device],BX_MAX_STORAGE_DEVICES);
2354 write_byte(ebda_seg,&EbdaData->ata.cdidmap[device],BX_MAX_STORAGE_DEVICES);
2355 }
2356
2357 write_byte(ebda_seg,&EbdaData->ata.hdcount,0);
2358 write_byte(ebda_seg,&EbdaData->ata.cdcount,0);
2359}
2360
2361// ---------------------------------------------------------------------------
2362// ATA/ATAPI driver : device detection
2363// ---------------------------------------------------------------------------
2364
2365void ata_detect( )
2366{
2367 Bit16u ebda_seg=read_word(0x0040,0x000E);
2368 Bit8u hdcount, cdcount, device, type;
2369 Bit8u buffer[0x0200];
2370
2371#if BX_MAX_ATA_INTERFACES > 0
2372 write_byte(ebda_seg,&EbdaData->ata.channels[0].iface,ATA_IFACE_ISA);
2373 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase1,0x1f0);
2374 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase2,0x3f0);
2375 write_byte(ebda_seg,&EbdaData->ata.channels[0].irq,14);
2376#endif
2377#if BX_MAX_ATA_INTERFACES > 1
2378 write_byte(ebda_seg,&EbdaData->ata.channels[1].iface,ATA_IFACE_ISA);
2379 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase1,0x170);
2380 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase2,0x370);
2381 write_byte(ebda_seg,&EbdaData->ata.channels[1].irq,15);
2382#endif
2383#if BX_MAX_ATA_INTERFACES > 2
2384 write_byte(ebda_seg,&EbdaData->ata.channels[2].iface,ATA_IFACE_ISA);
2385 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase1,0x1e8);
2386 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase2,0x3e0);
2387 write_byte(ebda_seg,&EbdaData->ata.channels[2].irq,12);
2388#endif
2389#if BX_MAX_ATA_INTERFACES > 3
2390 write_byte(ebda_seg,&EbdaData->ata.channels[3].iface,ATA_IFACE_ISA);
2391 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase1,0x168);
2392 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase2,0x360);
2393 write_byte(ebda_seg,&EbdaData->ata.channels[3].irq,11);
2394#endif
2395#if BX_MAX_ATA_INTERFACES > 4
2396#error Please fill the ATA interface informations
2397#endif
2398
2399 // Device detection
2400 hdcount=cdcount=0;
2401
2402 for(device=0; device<BX_MAX_ATA_DEVICES; device++) {
2403 Bit16u iobase1, iobase2;
2404 Bit8u channel, slave, shift;
2405 Bit8u sc, sn, cl, ch, st;
2406
2407 channel = device / 2;
2408 slave = device % 2;
2409
2410 iobase1 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1);
2411 iobase2 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2);
2412
2413 // Disable interrupts
2414 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2415
2416 // Look for device
2417 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2418 outb(iobase1+ATA_CB_SC, 0x55);
2419 outb(iobase1+ATA_CB_SN, 0xaa);
2420 outb(iobase1+ATA_CB_SC, 0xaa);
2421 outb(iobase1+ATA_CB_SN, 0x55);
2422 outb(iobase1+ATA_CB_SC, 0x55);
2423 outb(iobase1+ATA_CB_SN, 0xaa);
2424
2425 // If we found something
2426 sc = inb(iobase1+ATA_CB_SC);
2427 sn = inb(iobase1+ATA_CB_SN);
2428
2429 if ( (sc == 0x55) && (sn == 0xaa) ) {
2430 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_UNKNOWN);
2431
2432 // reset the channel
2433 ata_reset(device);
2434
2435 // check for ATA or ATAPI
2436 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2437 sc = inb(iobase1+ATA_CB_SC);
2438 sn = inb(iobase1+ATA_CB_SN);
2439 if ((sc==0x01) && (sn==0x01)) {
2440 cl = inb(iobase1+ATA_CB_CL);
2441 ch = inb(iobase1+ATA_CB_CH);
2442 st = inb(iobase1+ATA_CB_STAT);
2443
2444 if ((cl==0x14) && (ch==0xeb)) {
2445 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATAPI);
2446 } else if ((cl==0x00) && (ch==0x00) && (st!=0x00)) {
2447 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATA);
2448 } else if ((cl==0xff) && (ch==0xff)) {
2449 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
2450 }
2451 }
2452 }
2453
2454#ifdef VBOX
2455 // Enable interrupts
2456 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2457#endif /* VBOX */
2458
2459 type=read_byte(ebda_seg,&EbdaData->ata.devices[device].type);
2460
2461 // Now we send a IDENTIFY command to ATA device
2462 if(type == ATA_TYPE_ATA) {
2463 Bit32u sectors;
2464 Bit16u cylinders, heads, spt, blksize;
2465#ifdef VBOX
2466 Bit16u lcylinders, lheads, lspt;
2467 Bit8u chsgeo_base;
2468#endif /* VBOX */
2469 Bit8u translation, removable, mode;
2470
2471 //Temporary values to do the transfer
2472 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2473 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2474
2475 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE, 1, 0, 0, 0, 0L, get_SS(),buffer) !=0 )
2476 BX_PANIC("ata-detect: Failed to detect ATA device\n");
2477
2478 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2479 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2480#ifdef VBOX
2481 blksize = 512; /* There is no sector size field any more. */
2482#else /* !VBOX */
2483 blksize = read_word(get_SS(),buffer+10);
2484#endif /* !VBOX */
2485
2486 cylinders = read_word(get_SS(),buffer+(1*2)); // word 1
2487 heads = read_word(get_SS(),buffer+(3*2)); // word 3
2488 spt = read_word(get_SS(),buffer+(6*2)); // word 6
2489
2490 sectors = read_dword(get_SS(),buffer+(60*2)); // word 60 and word 61
2491#ifdef VBOX
2492 /** @todo update sectors to be a 64 bit number (also lba...). */
2493 if (sectors == 268435455)
2494 sectors = read_dword(get_SS(),buffer+(100*2)); // words 100 to 103 (someday)
2495 switch (device)
2496 {
2497 case 0:
2498 chsgeo_base = 0x1e;
2499 break;
2500 case 1:
2501 chsgeo_base = 0x26;
2502 break;
2503 case 2:
2504 chsgeo_base = 0x67;
2505 break;
2506 case 3:
2507 chsgeo_base = 0x70;
2508 break;
2509 case 4:
2510 chsgeo_base = 0x40;
2511 break;
2512 case 5:
2513 chsgeo_base = 0x48;
2514 break;
2515 case 6:
2516 chsgeo_base = 0x50;
2517 break;
2518 case 7:
2519 chsgeo_base = 0x58;
2520 break;
2521 default:
2522 chsgeo_base = 0;
2523 }
2524 if (chsgeo_base != 0)
2525 {
2526 lcylinders = inb_cmos(chsgeo_base) + (inb_cmos(chsgeo_base+1) << 8);
2527 lheads = inb_cmos(chsgeo_base+2);
2528 lspt = inb_cmos(chsgeo_base+7);
2529 }
2530 else
2531 {
2532 lcylinders = 0;
2533 lheads = 0;
2534 lspt = 0;
2535 }
2536 BX_INFO("ata%d-%d: PCHS=%u/%d/%d LCHS=%u/%u/%u\n", channel, slave, cylinders, heads, spt, lcylinders, lheads, lspt);
2537#endif /* VBOX */
2538
2539 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2540 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2541 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2542 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2543 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads, heads);
2544 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders, cylinders);
2545 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt, spt);
2546 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors, sectors);
2547#ifdef VBOX
2548 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, lheads);
2549 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, lcylinders);
2550 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, lspt);
2551 if (device < 2)
2552 {
2553 Bit8u sum, i;
2554 unsigned char *fdpt;
2555 if (device == 0)
2556 fdpt = &EbdaData->fdpt0;
2557 else
2558 fdpt = &EbdaData->fdpt1;
2559
2560 /* Update the DPT for drive 0/1 pointed to by Int41/46. This used
2561 * to be done at POST time with lots of ugly assembler code, which
2562 * isn't worth the effort of converting from AMI to Award CMOS
2563 * format. Just do it here. */
2564 write_word(ebda_seg, fdpt + 0x00, lcylinders);
2565 write_byte(ebda_seg, fdpt + 0x02, lheads);
2566 write_byte(ebda_seg, fdpt + 0x0e, lspt);
2567 write_word(ebda_seg, fdpt + 0x09, cylinders);
2568 write_byte(ebda_seg, fdpt + 0x0b, heads);
2569 write_byte(ebda_seg, fdpt + 0x04, spt);
2570 write_byte(ebda_seg, fdpt + 0x03, 0xa0);
2571 sum = 0;
2572 for (i = 0; i < 0xf; i++)
2573 sum += read_byte(ebda_seg, fdpt + i);
2574 sum = 1 - sum;
2575 write_byte(ebda_seg, fdpt + 0x0f, sum);
2576 }
2577#else /* !VBOX */
2578 BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel, slave,cylinders, heads, spt);
2579
2580 translation = inb_cmos(0x39 + channel/2);
2581 for (shift=device%4; shift>0; shift--) translation >>= 2;
2582 translation &= 0x03;
2583
2584 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation, translation);
2585
2586 switch (translation) {
2587 case ATA_TRANSLATION_NONE:
2588 BX_INFO("none");
2589 break;
2590 case ATA_TRANSLATION_LBA:
2591 BX_INFO("lba");
2592 break;
2593 case ATA_TRANSLATION_LARGE:
2594 BX_INFO("large");
2595 break;
2596 case ATA_TRANSLATION_RECHS:
2597 BX_INFO("r-echs");
2598 break;
2599 }
2600 switch (translation) {
2601 case ATA_TRANSLATION_NONE:
2602 break;
2603 case ATA_TRANSLATION_LBA:
2604 spt = 63;
2605 sectors /= 63;
2606 heads = sectors / 1024;
2607 if (heads>128) heads = 255;
2608 else if (heads>64) heads = 128;
2609 else if (heads>32) heads = 64;
2610 else if (heads>16) heads = 32;
2611 else heads=16;
2612 cylinders = sectors / heads;
2613 break;
2614 case ATA_TRANSLATION_RECHS:
2615 // Take care not to overflow
2616 if (heads==16) {
2617 if(cylinders>61439) cylinders=61439;
2618 heads=15;
2619 cylinders = (Bit16u)((Bit32u)(cylinders)*16/15);
2620 }
2621 // then go through the large bitshift process
2622 case ATA_TRANSLATION_LARGE:
2623 while(cylinders > 1024) {
2624 cylinders >>= 1;
2625 heads <<= 1;
2626
2627 // If we max out the head count
2628 if (heads > 127) break;
2629 }
2630 break;
2631 }
2632 // clip to 1024 cylinders in lchs
2633 if (cylinders > 1024) cylinders=1024;
2634 BX_INFO(" LCHS=%d/%d/%d\n", cylinders, heads, spt);
2635
2636 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, heads);
2637 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, cylinders);
2638 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, spt);
2639#endif /* VBOX */
2640
2641 // fill hdidmap
2642 write_byte(ebda_seg,&EbdaData->ata.hdidmap[hdcount], device);
2643 hdcount++;
2644 }
2645
2646 // Now we send a IDENTIFY command to ATAPI device
2647 if(type == ATA_TYPE_ATAPI) {
2648
2649 Bit8u type, removable, mode;
2650 Bit16u blksize;
2651
2652 //Temporary values to do the transfer
2653 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_CDROM);
2654 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2655
2656 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE_PACKET, 1, 0, 0, 0, 0L, get_SS(),buffer) != 0)
2657 BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
2658
2659 type = read_byte(get_SS(),buffer+1) & 0x1f;
2660 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2661 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2662 blksize = 2048;
2663
2664 write_byte(ebda_seg,&EbdaData->ata.devices[device].device, type);
2665 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2666 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2667 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2668
2669 // fill cdidmap
2670 write_byte(ebda_seg,&EbdaData->ata.cdidmap[cdcount], device);
2671 cdcount++;
2672 }
2673
2674 {
2675 Bit32u sizeinmb;
2676 Bit16u ataversion;
2677 Bit8u c, i, version, model[41];
2678
2679 switch (type) {
2680 case ATA_TYPE_ATA:
2681 sizeinmb = read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors);
2682 sizeinmb >>= 11;
2683 case ATA_TYPE_ATAPI:
2684 // Read ATA/ATAPI version
2685 ataversion=((Bit16u)(read_byte(get_SS(),buffer+161))<<8)|read_byte(get_SS(),buffer+160);
2686 for(version=15;version>0;version--) {
2687 if((ataversion&(1<<version))!=0)
2688 break;
2689 }
2690
2691 // Read model name
2692 for(i=0;i<20;i++){
2693 write_byte(get_SS(),model+(i*2),read_byte(get_SS(),buffer+(i*2)+54+1));
2694 write_byte(get_SS(),model+(i*2)+1,read_byte(get_SS(),buffer+(i*2)+54));
2695 }
2696
2697 // Reformat
2698 write_byte(get_SS(),model+40,0x00);
2699 for(i=39;i>0;i--){
2700 if(read_byte(get_SS(),model+i)==0x20)
2701 write_byte(get_SS(),model+i,0x00);
2702 else break;
2703 }
2704 break;
2705 }
2706
2707#ifdef VBOX
2708 // we don't want any noisy output for now
2709#else /* !VBOX */
2710 switch (type) {
2711 case ATA_TYPE_ATA:
2712 printf("ata%d %s: ",channel,slave?" slave":"master");
2713 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2714 printf(" ATA-%d Hard-Disk (%lu MBytes)\n", version, sizeinmb);
2715 break;
2716 case ATA_TYPE_ATAPI:
2717 printf("ata%d %s: ",channel,slave?" slave":"master");
2718 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2719 if(read_byte(ebda_seg,&EbdaData->ata.devices[device].device)==ATA_DEVICE_CDROM)
2720 printf(" ATAPI-%d CD-Rom/DVD-Rom\n",version);
2721 else
2722 printf(" ATAPI-%d Device\n",version);
2723 break;
2724 case ATA_TYPE_UNKNOWN:
2725 printf("ata%d %s: Unknown device\n",channel,slave?" slave":"master");
2726 break;
2727 }
2728#endif /* !VBOX */
2729 }
2730 }
2731
2732 // Store the devices counts
2733 write_byte(ebda_seg,&EbdaData->ata.hdcount, hdcount);
2734 write_byte(ebda_seg,&EbdaData->ata.cdcount, cdcount);
2735 write_byte(0x40,0x75, hdcount);
2736
2737#ifdef VBOX
2738 // we don't want any noisy output for now
2739#else /* !VBOX */
2740 printf("\n");
2741#endif /* !VBOX */
2742
2743 // FIXME : should use bios=cmos|auto|disable bits
2744 // FIXME : should know about translation bits
2745 // FIXME : move hard_drive_post here
2746
2747}
2748
2749// ---------------------------------------------------------------------------
2750// ATA/ATAPI driver : software reset
2751// ---------------------------------------------------------------------------
2752// ATA-3
2753// 8.2.1 Software reset - Device 0
2754
2755void ata_reset(device)
2756Bit16u device;
2757{
2758 Bit16u ebda_seg=read_word(0x0040,0x000E);
2759 Bit16u iobase1, iobase2;
2760 Bit8u channel, slave, sn, sc;
2761 Bit16u max;
2762#ifdef VBOX
2763 Bit16u pdelay;
2764#endif /* VBOX */
2765
2766 channel = device / 2;
2767 slave = device % 2;
2768
2769 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2770 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2771
2772 // Reset
2773
2774// 8.2.1 (a) -- set SRST in DC
2775 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN | ATA_CB_DC_SRST);
2776
2777// 8.2.1 (b) -- wait for BSY
2778 max=0xff;
2779 while(--max>0) {
2780 Bit8u status = inb(iobase1+ATA_CB_STAT);
2781 if ((status & ATA_CB_STAT_BSY) != 0) break;
2782 }
2783
2784// 8.2.1 (f) -- clear SRST
2785 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2786
2787 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_NONE) {
2788
2789// 8.2.1 (g) -- check for sc==sn==0x01
2790 // select device
2791 outb(iobase1+ATA_CB_DH, slave?ATA_CB_DH_DEV1:ATA_CB_DH_DEV0);
2792 sc = inb(iobase1+ATA_CB_SC);
2793 sn = inb(iobase1+ATA_CB_SN);
2794
2795 if ( (sc==0x01) && (sn==0x01) ) {
2796
2797// 8.2.1 (h) -- wait for not BSY
2798#ifdef VBOX
2799 max=0xffff; /* The ATA specification says that the drive may be busy for up to 30 seconds. */
2800#else /* !VBOX */
2801 max=0xff;
2802#endif /* !VBOX */
2803 while(--max>0) {
2804 Bit8u status = inb(iobase1+ATA_CB_STAT);
2805 if ((status & ATA_CB_STAT_BSY) == 0) break;
2806#ifdef VBOX
2807 pdelay=0xffff;
2808 while (--pdelay>0) {
2809 /* nothing */
2810 }
2811#endif /* VBOX */
2812 }
2813 }
2814 }
2815
2816// 8.2.1 (i) -- wait for DRDY
2817#ifdef VBOX
2818 max=0x10; /* Speed up for virtual drives. Disks are immediately ready, CDs never */
2819#else /* !VBOX */
2820 max=0xfff;
2821#endif /* !VBOX */
2822 while(--max>0) {
2823 Bit8u status = inb(iobase1+ATA_CB_STAT);
2824 if ((status & ATA_CB_STAT_RDY) != 0) break;
2825 }
2826
2827 // Enable interrupts
2828 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2829}
2830
2831// ---------------------------------------------------------------------------
2832// ATA/ATAPI driver : execute a non data command
2833// ---------------------------------------------------------------------------
2834
2835Bit16u ata_cmd_non_data()
2836{return 0;}
2837
2838// ---------------------------------------------------------------------------
2839// ATA/ATAPI driver : execute a data-in command
2840// ---------------------------------------------------------------------------
2841 // returns
2842 // 0 : no error
2843 // 1 : BUSY bit set
2844 // 2 : read error
2845 // 3 : expected DRQ=1
2846 // 4 : no sectors left to read/verify
2847 // 5 : more sectors to read/verify
2848 // 6 : no sectors left to write
2849 // 7 : more sectors to write
2850Bit16u ata_cmd_data_in(device, command, count, cylinder, head, sector, lba, segment, offset)
2851Bit16u device, command, count, cylinder, head, sector, segment, offset;
2852Bit32u lba;
2853{
2854 Bit16u ebda_seg=read_word(0x0040,0x000E);
2855 Bit16u iobase1, iobase2, blksize;
2856 Bit8u channel, slave;
2857 Bit8u status, current, mode;
2858
2859 channel = device / 2;
2860 slave = device % 2;
2861
2862 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2863 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2864 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2865 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2866 if (mode == ATA_MODE_PIO32) blksize>>=2;
2867 else blksize>>=1;
2868
2869#ifdef VBOX
2870 status = inb(iobase1 + ATA_CB_STAT);
2871 if (status & ATA_CB_STAT_BSY)
2872 {
2873 // Enable interrupts
2874 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2875 return 1;
2876 }
2877#endif /* VBOX */
2878
2879 // sector will be 0 only on lba access. Convert to lba-chs
2880 if (sector == 0) {
2881#ifdef VBOX
2882 if (count >= 256 || lba + count >= 268435456)
2883 {
2884 sector = (lba & 0xff000000L) >> 24;
2885 cylinder = 0; /* The parameter lba is just a 32 bit value. */
2886 outb(iobase1 + ATA_CB_SC, (count & 0xff00) >> 8);
2887 outb(iobase1 + ATA_CB_SN, sector);
2888 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2889 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2890 /* Leave the bottom 24 bits as is, they are treated correctly by the
2891 * LBA28 code path. */
2892 lba &= 0xffffff;
2893 }
2894#endif /* VBOX */
2895 sector = (Bit16u) (lba & 0x000000ffL);
2896 lba >>= 8;
2897 cylinder = (Bit16u) (lba & 0x0000ffffL);
2898 lba >>= 16;
2899 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
2900 }
2901
2902 // Reset count of transferred data
2903 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2904 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2905 current = 0;
2906
2907#ifndef VBOX
2908 status = inb(iobase1 + ATA_CB_STAT);
2909 if (status & ATA_CB_STAT_BSY) return 1;
2910#endif /* !VBOX */
2911
2912 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2913 outb(iobase1 + ATA_CB_FR, 0x00);
2914 outb(iobase1 + ATA_CB_SC, count);
2915 outb(iobase1 + ATA_CB_SN, sector);
2916 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2917 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2918 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
2919 outb(iobase1 + ATA_CB_CMD, command);
2920
2921 while (1) {
2922 status = inb(iobase1 + ATA_CB_STAT);
2923 if ( !(status & ATA_CB_STAT_BSY) ) break;
2924 }
2925
2926 if (status & ATA_CB_STAT_ERR) {
2927 BX_DEBUG_ATA("ata_cmd_data_in : read error\n");
2928#ifdef VBOX
2929 // Enable interrupts
2930 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2931#endif /* VBOX */
2932 return 2;
2933 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2934 BX_DEBUG_ATA("ata_cmd_data_in : DRQ not set (status %02x)\n", (unsigned) status);
2935#ifdef VBOX
2936 // Enable interrupts
2937 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2938#endif /* VBOX */
2939 return 3;
2940 }
2941
2942 // FIXME : move seg/off translation here
2943
2944ASM_START
2945 sti ;; enable higher priority interrupts
2946ASM_END
2947
2948 while (1) {
2949
2950ASM_START
2951 push bp
2952 mov bp, sp
2953 mov di, _ata_cmd_data_in.offset + 2[bp]
2954 mov ax, _ata_cmd_data_in.segment + 2[bp]
2955 mov cx, _ata_cmd_data_in.blksize + 2[bp]
2956
2957 ;; adjust if there will be an overrun. 2K max sector size
2958 cmp di, #0xf800 ;;
2959 jbe ata_in_no_adjust
2960
2961ata_in_adjust:
2962 sub di, #0x0800 ;; sub 2 kbytes from offset
2963 add ax, #0x0080 ;; add 2 Kbytes to segment
2964
2965ata_in_no_adjust:
2966 mov es, ax ;; segment in es
2967
2968 mov dx, _ata_cmd_data_in.iobase1 + 2[bp] ;; ATA data read port
2969
2970 mov ah, _ata_cmd_data_in.mode + 2[bp]
2971 cmp ah, #ATA_MODE_PIO32
2972 je ata_in_32
2973
2974ata_in_16:
2975 rep
2976 insw ;; CX words transferred from port(DX) to ES:[DI]
2977 jmp ata_in_done
2978
2979ata_in_32:
2980 rep
2981 insd ;; CX dwords transferred from port(DX) to ES:[DI]
2982
2983ata_in_done:
2984 mov _ata_cmd_data_in.offset + 2[bp], di
2985 mov _ata_cmd_data_in.segment + 2[bp], es
2986 pop bp
2987ASM_END
2988
2989 current++;
2990 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
2991 count--;
2992#ifdef VBOX
2993 while (1) {
2994 status = inb(iobase1 + ATA_CB_STAT);
2995 if ( !(status & ATA_CB_STAT_BSY) ) break;
2996 }
2997#else /* !VBOX */
2998 status = inb(iobase1 + ATA_CB_STAT);
2999#endif /* !VBOX */
3000 if (count == 0) {
3001 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3002 != ATA_CB_STAT_RDY ) {
3003 BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n", (unsigned) status);
3004#ifdef VBOX
3005 // Enable interrupts
3006 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3007#endif /* VBOX */
3008 return 4;
3009 }
3010 break;
3011 }
3012 else {
3013 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3014 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3015 BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n", (unsigned) status);
3016#ifdef VBOX
3017 // Enable interrupts
3018 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3019#endif /* VBOX */
3020 return 5;
3021 }
3022 continue;
3023 }
3024 }
3025 // Enable interrupts
3026 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3027 return 0;
3028}
3029
3030// ---------------------------------------------------------------------------
3031// ATA/ATAPI driver : execute a data-out command
3032// ---------------------------------------------------------------------------
3033 // returns
3034 // 0 : no error
3035 // 1 : BUSY bit set
3036 // 2 : read error
3037 // 3 : expected DRQ=1
3038 // 4 : no sectors left to read/verify
3039 // 5 : more sectors to read/verify
3040 // 6 : no sectors left to write
3041 // 7 : more sectors to write
3042Bit16u ata_cmd_data_out(device, command, count, cylinder, head, sector, lba, segment, offset)
3043Bit16u device, command, count, cylinder, head, sector, segment, offset;
3044Bit32u lba;
3045{
3046 Bit16u ebda_seg=read_word(0x0040,0x000E);
3047 Bit16u iobase1, iobase2, blksize;
3048 Bit8u channel, slave;
3049 Bit8u status, current, mode;
3050
3051 channel = device / 2;
3052 slave = device % 2;
3053
3054 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
3055 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
3056 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
3057 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
3058 if (mode == ATA_MODE_PIO32) blksize>>=2;
3059 else blksize>>=1;
3060
3061#ifdef VBOX
3062 status = inb(iobase1 + ATA_CB_STAT);
3063 if (status & ATA_CB_STAT_BSY)
3064 {
3065 // Enable interrupts
3066 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3067 return 1;
3068 }
3069#endif /* VBOX */
3070
3071 // sector will be 0 only on lba access. Convert to lba-chs
3072 if (sector == 0) {
3073#ifdef VBOX
3074 if (count >= 256 || lba + count >= 268435456)
3075 {
3076 sector = (lba & 0xff000000L) >> 24;
3077 cylinder = 0; /* The parameter lba is just a 32 bit value. */
3078 outb(iobase1 + ATA_CB_SC, (count & 0xff00) >> 8);
3079 outb(iobase1 + ATA_CB_SN, sector);
3080 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
3081 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
3082 /* Leave the bottom 24 bits as is, they are treated correctly by the
3083 * LBA28 code path. */
3084 lba &= 0xffffff;
3085 }
3086#endif /* VBOX */
3087 sector = (Bit16u) (lba & 0x000000ffL);
3088 lba >>= 8;
3089 cylinder = (Bit16u) (lba & 0x0000ffffL);
3090 lba >>= 16;
3091 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
3092 }
3093
3094 // Reset count of transferred data
3095 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
3096 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
3097 current = 0;
3098
3099#ifndef VBOX
3100 status = inb(iobase1 + ATA_CB_STAT);
3101 if (status & ATA_CB_STAT_BSY) return 1;
3102#endif /* !VBOX */
3103
3104 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
3105 outb(iobase1 + ATA_CB_FR, 0x00);
3106 outb(iobase1 + ATA_CB_SC, count);
3107 outb(iobase1 + ATA_CB_SN, sector);
3108 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
3109 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
3110 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
3111 outb(iobase1 + ATA_CB_CMD, command);
3112
3113 while (1) {
3114 status = inb(iobase1 + ATA_CB_STAT);
3115 if ( !(status & ATA_CB_STAT_BSY) ) break;
3116 }
3117
3118 if (status & ATA_CB_STAT_ERR) {
3119 BX_DEBUG_ATA("ata_cmd_data_out : read error\n");
3120#ifdef VBOX
3121 // Enable interrupts
3122 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3123#endif /* VBOX */
3124 return 2;
3125 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
3126 BX_DEBUG_ATA("ata_cmd_data_out : DRQ not set (status %02x)\n", (unsigned) status);
3127#ifdef VBOX
3128 // Enable interrupts
3129 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3130#endif /* VBOX */
3131 return 3;
3132 }
3133
3134 // FIXME : move seg/off translation here
3135
3136ASM_START
3137 sti ;; enable higher priority interrupts
3138ASM_END
3139
3140 while (1) {
3141
3142ASM_START
3143 push bp
3144 mov bp, sp
3145 mov si, _ata_cmd_data_out.offset + 2[bp]
3146 mov ax, _ata_cmd_data_out.segment + 2[bp]
3147 mov cx, _ata_cmd_data_out.blksize + 2[bp]
3148
3149 ;; adjust if there will be an overrun. 2K max sector size
3150 cmp si, #0xf800 ;;
3151 jbe ata_out_no_adjust
3152
3153ata_out_adjust:
3154 sub si, #0x0800 ;; sub 2 kbytes from offset
3155 add ax, #0x0080 ;; add 2 Kbytes to segment
3156
3157ata_out_no_adjust:
3158 mov es, ax ;; segment in es
3159
3160 mov dx, _ata_cmd_data_out.iobase1 + 2[bp] ;; ATA data write port
3161
3162 mov ah, _ata_cmd_data_out.mode + 2[bp]
3163 cmp ah, #ATA_MODE_PIO32
3164 je ata_out_32
3165
3166ata_out_16:
3167 seg ES
3168 rep
3169 outsw ;; CX words transferred from port(DX) to ES:[SI]
3170 jmp ata_out_done
3171
3172ata_out_32:
3173 seg ES
3174 rep
3175 outsd ;; CX dwords transferred from port(DX) to ES:[SI]
3176
3177ata_out_done:
3178 mov _ata_cmd_data_out.offset + 2[bp], si
3179 mov _ata_cmd_data_out.segment + 2[bp], es
3180 pop bp
3181ASM_END
3182
3183 current++;
3184 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
3185 count--;
3186#ifdef VBOX
3187 while (1) {
3188 status = inb(iobase1 + ATA_CB_STAT);
3189 if ( !(status & ATA_CB_STAT_BSY) ) break;
3190 }
3191#else /* !VBOX */
3192 status = inb(iobase1 + ATA_CB_STAT);
3193#endif /* VBOX */
3194 if (count == 0) {
3195 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3196 != ATA_CB_STAT_RDY ) {
3197 BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n", (unsigned) status);
3198#ifdef VBOX
3199 // Enable interrupts
3200 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3201#endif /* VBOX */
3202 return 6;
3203 }
3204 break;
3205 }
3206 else {
3207 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3208 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3209 BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n", (unsigned) status);
3210#ifdef VBOX
3211 // Enable interrupts
3212 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3213#endif /* VBOX */
3214 return 7;
3215 }
3216 continue;
3217 }
3218 }
3219 // Enable interrupts
3220 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3221 return 0;
3222}
3223
3224// ---------------------------------------------------------------------------
3225// ATA/ATAPI driver : execute a packet command
3226// ---------------------------------------------------------------------------
3227 // returns
3228 // 0 : no error
3229 // 1 : error in parameters
3230 // 2 : BUSY bit set
3231 // 3 : error
3232 // 4 : not ready
3233Bit16u ata_cmd_packet(device, cmdlen, cmdseg, cmdoff, header, length, inout, bufseg, bufoff)
3234Bit8u cmdlen,inout;
3235Bit16u device,cmdseg, cmdoff, bufseg, bufoff;
3236Bit16u header;
3237Bit32u length;
3238{
3239 Bit16u ebda_seg=read_word(0x0040,0x000E);
3240 Bit16u iobase1, iobase2;
3241 Bit16u lcount, lbefore, lafter, count;
3242 Bit8u channel, slave;
3243 Bit8u status, mode, lmode;
3244 Bit32u total, transfer;
3245
3246 channel = device / 2;
3247 slave = device % 2;
3248
3249 // Data out is not supported yet
3250 if (inout == ATA_DATA_OUT) {
3251 BX_INFO("ata_cmd_packet: DATA_OUT not supported yet\n");
3252 return 1;
3253 }
3254
3255 // The header length must be even
3256 if (header & 1) {
3257 BX_DEBUG_ATA("ata_cmd_packet : header must be even (%04x)\n",header);
3258 return 1;
3259 }
3260
3261 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
3262 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
3263 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
3264 transfer= 0L;
3265
3266 if (cmdlen < 12) cmdlen=12;
3267 if (cmdlen > 12) cmdlen=16;
3268 cmdlen>>=1;
3269
3270 // Reset count of transferred data
3271 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
3272 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
3273
3274 status = inb(iobase1 + ATA_CB_STAT);
3275 if (status & ATA_CB_STAT_BSY) return 2;
3276
3277 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
3278 // outb(iobase1 + ATA_CB_FR, 0x00);
3279 // outb(iobase1 + ATA_CB_SC, 0x00);
3280 // outb(iobase1 + ATA_CB_SN, 0x00);
3281 outb(iobase1 + ATA_CB_CL, 0xfff0 & 0x00ff);
3282 outb(iobase1 + ATA_CB_CH, 0xfff0 >> 8);
3283 outb(iobase1 + ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
3284 outb(iobase1 + ATA_CB_CMD, ATA_CMD_PACKET);
3285
3286 // Device should ok to receive command
3287 while (1) {
3288 status = inb(iobase1 + ATA_CB_STAT);
3289 if ( !(status & ATA_CB_STAT_BSY) ) break;
3290 }
3291
3292 if (status & ATA_CB_STAT_ERR) {
3293 BX_DEBUG_ATA("ata_cmd_packet : error, status is %02x\n",status);
3294#ifdef VBOX
3295 // Enable interrupts
3296 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3297#endif /* VBOX */
3298 return 3;
3299 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
3300 BX_DEBUG_ATA("ata_cmd_packet : DRQ not set (status %02x)\n", (unsigned) status);
3301#ifdef VBOX
3302 // Enable interrupts
3303 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3304#endif /* VBOX */
3305 return 4;
3306 }
3307
3308 // Normalize address
3309 cmdseg += (cmdoff / 16);
3310 cmdoff %= 16;
3311
3312 // Send command to device
3313ASM_START
3314 sti ;; enable higher priority interrupts
3315
3316 push bp
3317 mov bp, sp
3318
3319 mov si, _ata_cmd_packet.cmdoff + 2[bp]
3320 mov ax, _ata_cmd_packet.cmdseg + 2[bp]
3321 mov cx, _ata_cmd_packet.cmdlen + 2[bp]
3322 mov es, ax ;; segment in es
3323
3324 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data write port
3325
3326 seg ES
3327 rep
3328 outsw ;; CX words transferred from port(DX) to ES:[SI]
3329
3330 pop bp
3331ASM_END
3332
3333 if (inout == ATA_DATA_NO) {
3334 status = inb(iobase1 + ATA_CB_STAT);
3335 }
3336 else {
3337 while (1) {
3338
3339#ifdef VBOX
3340 while (1) {
3341 status = inb(iobase1 + ATA_CB_STAT);
3342 if ( !(status & ATA_CB_STAT_BSY) ) break;
3343 }
3344#else /* VBOX */
3345 status = inb(iobase1 + ATA_CB_STAT);
3346#endif /* VBOX */
3347
3348 // Check if command completed
3349 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_DRQ) ) ==0 ) break;
3350
3351 if (status & ATA_CB_STAT_ERR) {
3352 BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status);
3353#ifdef VBOX
3354 // Enable interrupts
3355 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3356#endif /* VBOX */
3357 return 3;
3358 }
3359
3360 // Device must be ready to send data
3361 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3362 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3363 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", status);
3364#ifdef VBOX
3365 // Enable interrupts
3366 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3367#endif /* VBOX */
3368 return 4;
3369 }
3370
3371 // Normalize address
3372 bufseg += (bufoff / 16);
3373 bufoff %= 16;
3374
3375 // Get the byte count
3376 lcount = ((Bit16u)(inb(iobase1 + ATA_CB_CH))<<8)+inb(iobase1 + ATA_CB_CL);
3377
3378 // adjust to read what we want
3379 if(header>lcount) {
3380 lbefore=lcount;
3381 header-=lcount;
3382 lcount=0;
3383 }
3384 else {
3385 lbefore=header;
3386 header=0;
3387 lcount-=lbefore;
3388 }
3389
3390 if(lcount>length) {
3391 lafter=lcount-length;
3392 lcount=length;
3393 length=0;
3394 }
3395 else {
3396 lafter=0;
3397 length-=lcount;
3398 }
3399
3400 // Save byte count
3401 count = lcount;
3402
3403 BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore+lcount+lafter,lbefore,lcount,lafter);
3404 BX_DEBUG_ATA("to 0x%04x:0x%04x\n",bufseg,bufoff);
3405
3406 // If counts not dividable by 4, use 16bits mode
3407 lmode = mode;
3408 if (lbefore & 0x03) lmode=ATA_MODE_PIO16;
3409 if (lcount & 0x03) lmode=ATA_MODE_PIO16;
3410 if (lafter & 0x03) lmode=ATA_MODE_PIO16;
3411
3412 // adds an extra byte if count are odd. before is always even
3413 if (lcount & 0x01) {
3414 lcount+=1;
3415 if ((lafter > 0) && (lafter & 0x01)) {
3416 lafter-=1;
3417 }
3418 }
3419
3420 if (lmode == ATA_MODE_PIO32) {
3421 lcount>>=2; lbefore>>=2; lafter>>=2;
3422 }
3423 else {
3424 lcount>>=1; lbefore>>=1; lafter>>=1;
3425 }
3426
3427 ; // FIXME bcc bug
3428
3429ASM_START
3430 push bp
3431 mov bp, sp
3432
3433 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data read port
3434
3435 mov cx, _ata_cmd_packet.lbefore + 2[bp]
3436 jcxz ata_packet_no_before
3437
3438 mov ah, _ata_cmd_packet.lmode + 2[bp]
3439 cmp ah, #ATA_MODE_PIO32
3440 je ata_packet_in_before_32
3441
3442ata_packet_in_before_16:
3443 in ax, dx
3444 loop ata_packet_in_before_16
3445 jmp ata_packet_no_before
3446
3447ata_packet_in_before_32:
3448 push eax
3449ata_packet_in_before_32_loop:
3450 in eax, dx
3451 loop ata_packet_in_before_32_loop
3452 pop eax
3453
3454ata_packet_no_before:
3455 mov cx, _ata_cmd_packet.lcount + 2[bp]
3456 jcxz ata_packet_after
3457
3458 mov di, _ata_cmd_packet.bufoff + 2[bp]
3459 mov ax, _ata_cmd_packet.bufseg + 2[bp]
3460 mov es, ax
3461
3462 mov ah, _ata_cmd_packet.lmode + 2[bp]
3463 cmp ah, #ATA_MODE_PIO32
3464 je ata_packet_in_32
3465
3466ata_packet_in_16:
3467 rep
3468 insw ;; CX words transferred tp port(DX) to ES:[DI]
3469 jmp ata_packet_after
3470
3471ata_packet_in_32:
3472 rep
3473 insd ;; CX dwords transferred to port(DX) to ES:[DI]
3474
3475ata_packet_after:
3476 mov cx, _ata_cmd_packet.lafter + 2[bp]
3477 jcxz ata_packet_done
3478
3479 mov ah, _ata_cmd_packet.lmode + 2[bp]
3480 cmp ah, #ATA_MODE_PIO32
3481 je ata_packet_in_after_32
3482
3483ata_packet_in_after_16:
3484 in ax, dx
3485 loop ata_packet_in_after_16
3486 jmp ata_packet_done
3487
3488ata_packet_in_after_32:
3489 push eax
3490ata_packet_in_after_32_loop:
3491 in eax, dx
3492 loop ata_packet_in_after_32_loop
3493 pop eax
3494
3495ata_packet_done:
3496 pop bp
3497ASM_END
3498
3499 // Compute new buffer address
3500 bufoff += count;
3501
3502 // Save transferred bytes count
3503 transfer += count;
3504 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,transfer);
3505 }
3506 }
3507
3508 // Final check, device must be ready
3509 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3510 != ATA_CB_STAT_RDY ) {
3511 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", (unsigned) status);
3512#ifdef VBOX
3513 // Enable interrupts
3514 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3515#endif /* VBOX */
3516 return 4;
3517 }
3518
3519 // Enable interrupts
3520 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3521 return 0;
3522}
3523
3524// ---------------------------------------------------------------------------
3525// End of ATA/ATAPI Driver
3526// ---------------------------------------------------------------------------
3527
3528// ---------------------------------------------------------------------------
3529// Start of ATA/ATAPI generic functions
3530// ---------------------------------------------------------------------------
3531
3532#if 0 // currently unused
3533 Bit16u
3534atapi_get_sense(device)
3535 Bit16u device;
3536{
3537 Bit8u atacmd[12];
3538 Bit8u buffer[16];
3539 Bit8u i;
3540
3541 memsetb(get_SS(),atacmd,0,12);
3542
3543 // Request SENSE
3544 atacmd[0]=0x03;
3545 atacmd[4]=0x20;
3546 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 16L, ATA_DATA_IN, get_SS(), buffer) != 0)
3547 return 0x0002;
3548
3549 if ((buffer[0] & 0x7e) == 0x70) {
3550 return (((Bit16u)buffer[2]&0x0f)*0x100)+buffer[12];
3551 }
3552
3553 return 0;
3554}
3555
3556 Bit16u
3557atapi_is_ready(device)
3558 Bit16u device;
3559{
3560 Bit8u atacmd[12];
3561 Bit8u buffer[];
3562
3563 memsetb(get_SS(),atacmd,0,12);
3564
3565 // Test Unit Ready
3566 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3567 return 0x000f;
3568
3569 if (atapi_get_sense(device) !=0 ) {
3570 memsetb(get_SS(),atacmd,0,12);
3571
3572 // try to send Test Unit Ready again
3573 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3574 return 0x000f;
3575
3576 return atapi_get_sense(device);
3577 }
3578 return 0;
3579}
3580#endif
3581
3582 Bit16u
3583atapi_is_cdrom(device)
3584 Bit8u device;
3585{
3586 Bit16u ebda_seg=read_word(0x0040,0x000E);
3587
3588 if (device >= BX_MAX_ATA_DEVICES)
3589 return 0;
3590
3591 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_ATAPI)
3592 return 0;
3593
3594 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].device) != ATA_DEVICE_CDROM)
3595 return 0;
3596
3597 return 1;
3598}
3599
3600// ---------------------------------------------------------------------------
3601// End of ATA/ATAPI generic functions
3602// ---------------------------------------------------------------------------
3603
3604#endif // BX_USE_ATADRV
3605
3606#if BX_ELTORITO_BOOT
3607
3608// ---------------------------------------------------------------------------
3609// Start of El-Torito boot functions
3610// ---------------------------------------------------------------------------
3611
3612 void
3613cdemu_init()
3614{
3615 Bit16u ebda_seg=read_word(0x0040,0x000E);
3616
3617 // the only important data is this one for now
3618 write_byte(ebda_seg,&EbdaData->cdemu.active,0x00);
3619}
3620
3621 Bit8u
3622cdemu_isactive()
3623{
3624 Bit16u ebda_seg=read_word(0x0040,0x000E);
3625
3626 return(read_byte(ebda_seg,&EbdaData->cdemu.active));
3627}
3628
3629 Bit8u
3630cdemu_emulated_drive()
3631{
3632 Bit16u ebda_seg=read_word(0x0040,0x000E);
3633
3634 return(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
3635}
3636
3637static char isotag[6]="CD001";
3638static char eltorito[24]="EL TORITO SPECIFICATION";
3639//
3640// Returns ah: emulated drive, al: error code
3641//
3642 Bit16u
3643cdrom_boot()
3644{
3645 Bit16u ebda_seg=read_word(0x0040,0x000E);
3646 Bit8u atacmd[12], buffer[2048];
3647 Bit32u lba;
3648 Bit16u boot_segment, nbsectors, i, error;
3649 Bit8u device;
3650#ifdef VBOX
3651 Bit8u read_try;
3652#endif /* VBOX */
3653
3654 // Find out the first cdrom
3655 for (device=0; device<BX_MAX_ATA_DEVICES;device++) {
3656 if (atapi_is_cdrom(device)) break;
3657 }
3658
3659 // if not found
3660 if(device >= BX_MAX_ATA_DEVICES) return 2;
3661
3662 // Read the Boot Record Volume Descriptor
3663 memsetb(get_SS(),atacmd,0,12);
3664 atacmd[0]=0x28; // READ command
3665 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3666 atacmd[8]=(0x01 & 0x00ff); // Sectors
3667 atacmd[2]=(0x11 & 0xff000000) >> 24; // LBA
3668 atacmd[3]=(0x11 & 0x00ff0000) >> 16;
3669 atacmd[4]=(0x11 & 0x0000ff00) >> 8;
3670 atacmd[5]=(0x11 & 0x000000ff);
3671#ifdef VBOX
3672 for (read_try = 0; read_try <= 4; read_try++)
3673 {
3674 error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer);
3675 if (!error)
3676 break;
3677 }
3678 if (error)
3679 return 3;
3680#else /* !VBOX */
3681 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3682 return 3;
3683#endif /* !VBOX */
3684
3685 // Validity checks
3686 if(buffer[0]!=0)return 4;
3687 for(i=0;i<5;i++){
3688 if(buffer[1+i]!=read_byte(0xf000,&isotag[i]))return 5;
3689 }
3690 for(i=0;i<23;i++)
3691 if(buffer[7+i]!=read_byte(0xf000,&eltorito[i]))return 6;
3692
3693 // ok, now we calculate the Boot catalog address
3694 lba=buffer[0x4A]*0x1000000+buffer[0x49]*0x10000+buffer[0x48]*0x100+buffer[0x47];
3695
3696 // And we read the Boot Catalog
3697 memsetb(get_SS(),atacmd,0,12);
3698 atacmd[0]=0x28; // READ command
3699 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3700 atacmd[8]=(0x01 & 0x00ff); // Sectors
3701 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3702 atacmd[3]=(lba & 0x00ff0000) >> 16;
3703 atacmd[4]=(lba & 0x0000ff00) >> 8;
3704 atacmd[5]=(lba & 0x000000ff);
3705 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3706 return 7;
3707
3708 // Validation entry
3709 if(buffer[0x00]!=0x01)return 8; // Header
3710 if(buffer[0x01]!=0x00)return 9; // Platform
3711 if(buffer[0x1E]!=0x55)return 10; // key 1
3712 if(buffer[0x1F]!=0xAA)return 10; // key 2
3713
3714 // Initial/Default Entry
3715 if(buffer[0x20]!=0x88)return 11; // Bootable
3716
3717 write_byte(ebda_seg,&EbdaData->cdemu.media,buffer[0x21]);
3718 if(buffer[0x21]==0){
3719 // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
3720 // Win2000 cd boot needs to know it booted from cd
3721 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0xE0);
3722 }
3723 else if(buffer[0x21]<4)
3724 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x00);
3725 else
3726 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x80);
3727
3728 write_byte(ebda_seg,&EbdaData->cdemu.controller_index,device/2);
3729 write_byte(ebda_seg,&EbdaData->cdemu.device_spec,device%2);
3730
3731 boot_segment=buffer[0x23]*0x100+buffer[0x22];
3732 if(boot_segment==0x0000)boot_segment=0x07C0;
3733
3734 write_word(ebda_seg,&EbdaData->cdemu.load_segment,boot_segment);
3735 write_word(ebda_seg,&EbdaData->cdemu.buffer_segment,0x0000);
3736
3737 nbsectors=buffer[0x27]*0x100+buffer[0x26];
3738 write_word(ebda_seg,&EbdaData->cdemu.sector_count,nbsectors);
3739
3740 lba=buffer[0x2B]*0x1000000+buffer[0x2A]*0x10000+buffer[0x29]*0x100+buffer[0x28];
3741 write_dword(ebda_seg,&EbdaData->cdemu.ilba,lba);
3742
3743 // And we read the image in memory
3744 memsetb(get_SS(),atacmd,0,12);
3745 atacmd[0]=0x28; // READ command
3746 atacmd[7]=((1+(nbsectors-1)/4) & 0xff00) >> 8; // Sectors
3747 atacmd[8]=((1+(nbsectors-1)/4) & 0x00ff); // Sectors
3748 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3749 atacmd[3]=(lba & 0x00ff0000) >> 16;
3750 atacmd[4]=(lba & 0x0000ff00) >> 8;
3751 atacmd[5]=(lba & 0x000000ff);
3752 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, nbsectors*512L, ATA_DATA_IN, boot_segment,0)) != 0)
3753 return 12;
3754
3755 // Remember the media type
3756 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
3757 case 0x01: // 1.2M floppy
3758 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,15);
3759 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3760 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3761 break;
3762 case 0x02: // 1.44M floppy
3763 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,18);
3764 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3765 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3766 break;
3767 case 0x03: // 2.88M floppy
3768 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,36);
3769 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3770 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3771 break;
3772 case 0x04: // Harddrive
3773 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,read_byte(boot_segment,446+6)&0x3f);
3774 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,
3775 (read_byte(boot_segment,446+6)<<2) + read_byte(boot_segment,446+7) + 1);
3776 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,read_byte(boot_segment,446+5) + 1);
3777 break;
3778 }
3779
3780 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0) {
3781 // Increase bios installed hardware number of devices
3782 if(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)==0x00)
3783 write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
3784 else
3785 write_byte(ebda_seg, &EbdaData->ata.hdcount, read_byte(ebda_seg, &EbdaData->ata.hdcount) + 1);
3786 }
3787
3788
3789 // everything is ok, so from now on, the emulation is active
3790 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0)
3791 write_byte(ebda_seg,&EbdaData->cdemu.active,0x01);
3792
3793 // return the boot drive + no error
3794 return (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)*0x100)+0;
3795}
3796
3797// ---------------------------------------------------------------------------
3798// End of El-Torito boot functions
3799// ---------------------------------------------------------------------------
3800#endif // BX_ELTORITO_BOOT
3801
3802#ifdef VBOX_WITH_SCSI
3803# include "scsi.c"
3804#endif
3805
3806 void
3807int14_function(regs, ds, iret_addr)
3808 pusha_regs_t regs; // regs pushed from PUSHA instruction
3809 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
3810 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
3811{
3812 Bit16u addr,timer,val16;
3813 Bit8u timeout;
3814
3815 ASM_START
3816 sti
3817 ASM_END
3818
3819 addr = read_word(0x0040, (regs.u.r16.dx << 1));
3820 timeout = read_byte(0x0040, 0x007C + regs.u.r16.dx);
3821 if ((regs.u.r16.dx < 4) && (addr > 0)) {
3822 switch (regs.u.r8.ah) {
3823 case 0:
3824 outb(addr+3, inb(addr+3) | 0x80);
3825 if (regs.u.r8.al & 0xE0 == 0) {
3826 outb(addr, 0x17);
3827 outb(addr+1, 0x04);
3828 } else {
3829 val16 = 0x600 >> ((regs.u.r8.al & 0xE0) >> 5);
3830 outb(addr, val16 & 0xFF);
3831 outb(addr+1, val16 >> 8);
3832 }
3833 outb(addr+3, regs.u.r8.al & 0x1F);
3834 regs.u.r8.ah = inb(addr+5);
3835 regs.u.r8.al = inb(addr+6);
3836 ClearCF(iret_addr.flags);
3837 break;
3838 case 1:
3839 timer = read_word(0x0040, 0x006C);
3840 while (((inb(addr+5) & 0x60) != 0x60) && (timeout)) {
3841 val16 = read_word(0x0040, 0x006C);
3842 if (val16 != timer) {
3843 timer = val16;
3844 timeout--;
3845 }
3846 }
3847 if (timeout) outb(addr, regs.u.r8.al);
3848 regs.u.r8.ah = inb(addr+5);
3849 if (!timeout) regs.u.r8.ah |= 0x80;
3850 ClearCF(iret_addr.flags);
3851 break;
3852 case 2:
3853 timer = read_word(0x0040, 0x006C);
3854 while (((inb(addr+5) & 0x01) == 0) && (timeout)) {
3855 val16 = read_word(0x0040, 0x006C);
3856 if (val16 != timer) {
3857 timer = val16;
3858 timeout--;
3859 }
3860 }
3861 if (timeout) {
3862 regs.u.r8.ah = 0;
3863 regs.u.r8.al = inb(addr);
3864 } else {
3865 regs.u.r8.ah = inb(addr+5);
3866 }
3867 ClearCF(iret_addr.flags);
3868 break;
3869 case 3:
3870 regs.u.r8.ah = inb(addr+5);
3871 regs.u.r8.al = inb(addr+6);
3872 ClearCF(iret_addr.flags);
3873 break;
3874 default:
3875 SetCF(iret_addr.flags); // Unsupported
3876 }
3877 } else {
3878 SetCF(iret_addr.flags); // Unsupported
3879 }
3880}
3881
3882 void
3883int15_function(regs, ES, DS, FLAGS)
3884 pusha_regs_t regs; // REGS pushed via pusha
3885 Bit16u ES, DS, FLAGS;
3886{
3887 Bit16u ebda_seg=read_word(0x0040,0x000E);
3888 bx_bool prev_a20_enable;
3889 Bit16u base15_00;
3890 Bit8u base23_16;
3891 Bit16u ss;
3892 Bit16u BX,CX,DX;
3893
3894 Bit16u bRegister;
3895 Bit8u irqDisable;
3896
3897BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
3898
3899 switch (regs.u.r8.ah) {
3900#ifdef VBOX
3901 case 0x00: /* assorted functions */
3902 if (regs.u.r8.al != 0xc0)
3903 goto undecoded;
3904 /* GRUB calls int15 with ax=0x00c0 to get the ROM configuration table,
3905 * which we don't support, but logging that event is annoying. In fact
3906 * it is likely that they just misread some specs, because there is a
3907 * int15 BIOS function AH=0xc0 which sounds quite similar to what GRUB
3908 * wants to achieve. */
3909 SET_CF();
3910 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3911 break;
3912#endif
3913 case 0x24: /* A20 Control */
3914 switch (regs.u.r8.al) {
3915 case 0x00:
3916 set_enable_a20(0);
3917 CLEAR_CF();
3918 regs.u.r8.ah = 0;
3919 break;
3920 case 0x01:
3921 set_enable_a20(1);
3922 CLEAR_CF();
3923 regs.u.r8.ah = 0;
3924 break;
3925 case 0x02:
3926 regs.u.r8.al = (inb(0x92) >> 1) & 0x01;
3927 CLEAR_CF();
3928 regs.u.r8.ah = 0;
3929 break;
3930 case 0x03:
3931 CLEAR_CF();
3932 regs.u.r8.ah = 0;
3933 regs.u.r16.bx = 3;
3934 break;
3935 default:
3936 BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs.u.r8.al);
3937 SET_CF();
3938 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3939 }
3940 break;
3941
3942 case 0x41:
3943 SET_CF();
3944 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3945 break;
3946
3947 case 0x4f:
3948 /* keyboard intercept */
3949#if BX_CPU < 2
3950 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3951#else
3952 // nop
3953#endif
3954 SET_CF();
3955 break;
3956
3957 case 0x52: // removable media eject
3958 CLEAR_CF();
3959 regs.u.r8.ah = 0; // "ok ejection may proceed"
3960 break;
3961
3962 case 0x83: {
3963 if( regs.u.r8.al == 0 ) {
3964 // Set Interval requested.
3965 if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
3966 // Interval not already set.
3967 write_byte( 0x40, 0xA0, 1 ); // Set status byte.
3968 write_word( 0x40, 0x98, ES ); // Byte location, segment
3969 write_word( 0x40, 0x9A, regs.u.r16.bx ); // Byte location, offset
3970 write_word( 0x40, 0x9C, regs.u.r16.dx ); // Low word, delay
3971 write_word( 0x40, 0x9E, regs.u.r16.cx ); // High word, delay.
3972 CLEAR_CF( );
3973 irqDisable = inb( 0xA1 );
3974 outb( 0xA1, irqDisable & 0xFE );
3975 bRegister = inb_cmos( 0xB ); // Unmask IRQ8 so INT70 will get through.
3976 outb_cmos( 0xB, bRegister | 0x40 ); // Turn on the Periodic Interrupt timer
3977 } else {
3978 // Interval already set.
3979 BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
3980 SET_CF();
3981 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3982 }
3983 } else if( regs.u.r8.al == 1 ) {
3984 // Clear Interval requested
3985 write_byte( 0x40, 0xA0, 0 ); // Clear status byte
3986 CLEAR_CF( );
3987 bRegister = inb_cmos( 0xB );
3988 outb_cmos( 0xB, bRegister & ~0x40 ); // Turn off the Periodic Interrupt timer
3989 } else {
3990 BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
3991 SET_CF();
3992 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3993 regs.u.r8.al--;
3994 }
3995
3996 break;
3997 }
3998
3999 case 0x87:
4000#if BX_CPU < 3
4001# error "Int15 function 87h not supported on < 80386"
4002#endif
4003 // +++ should probably have descriptor checks
4004 // +++ should have exception handlers
4005
4006 // turn off interrupts
4007ASM_START
4008 cli
4009ASM_END
4010
4011 prev_a20_enable = set_enable_a20(1); // enable A20 line
4012
4013 // 128K max of transfer on 386+ ???
4014 // source == destination ???
4015
4016 // ES:SI points to descriptor table
4017 // offset use initially comments
4018 // ==============================================
4019 // 00..07 Unused zeros Null descriptor
4020 // 08..0f GDT zeros filled in by BIOS
4021 // 10..17 source ssssssss source of data
4022 // 18..1f dest dddddddd destination of data
4023 // 20..27 CS zeros filled in by BIOS
4024 // 28..2f SS zeros filled in by BIOS
4025
4026 //es:si
4027 //eeee0
4028 //0ssss
4029 //-----
4030
4031// check for access rights of source & dest here
4032
4033 // Initialize GDT descriptor
4034 base15_00 = (ES << 4) + regs.u.r16.si;
4035 base23_16 = ES >> 12;
4036 if (base15_00 < (ES<<4))
4037 base23_16++;
4038 write_word(ES, regs.u.r16.si+0x08+0, 47); // limit 15:00 = 6 * 8bytes/descriptor
4039 write_word(ES, regs.u.r16.si+0x08+2, base15_00);// base 15:00
4040 write_byte(ES, regs.u.r16.si+0x08+4, base23_16);// base 23:16
4041 write_byte(ES, regs.u.r16.si+0x08+5, 0x93); // access
4042 write_word(ES, regs.u.r16.si+0x08+6, 0x0000); // base 31:24/reserved/limit 19:16
4043
4044 // Initialize CS descriptor
4045 write_word(ES, regs.u.r16.si+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
4046 write_word(ES, regs.u.r16.si+0x20+2, 0x0000);// base 15:00
4047 write_byte(ES, regs.u.r16.si+0x20+4, 0x000f);// base 23:16
4048 write_byte(ES, regs.u.r16.si+0x20+5, 0x9b); // access
4049 write_word(ES, regs.u.r16.si+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
4050
4051 // Initialize SS descriptor
4052 ss = get_SS();
4053 base15_00 = ss << 4;
4054 base23_16 = ss >> 12;
4055 write_word(ES, regs.u.r16.si+0x28+0, 0xffff); // limit 15:00 = normal 64K limit
4056 write_word(ES, regs.u.r16.si+0x28+2, base15_00);// base 15:00
4057 write_byte(ES, regs.u.r16.si+0x28+4, base23_16);// base 23:16
4058 write_byte(ES, regs.u.r16.si+0x28+5, 0x93); // access
4059 write_word(ES, regs.u.r16.si+0x28+6, 0x0000); // base 31:24/reserved/limit 19:16
4060
4061 CX = regs.u.r16.cx;
4062ASM_START
4063 // Compile generates locals offset info relative to SP.
4064 // Get CX (word count) from stack.
4065 mov bx, sp
4066 SEG SS
4067 mov cx, _int15_function.CX [bx]
4068
4069 // since we need to set SS:SP, save them to the BDA
4070 // for future restore
4071 push eax
4072 xor eax, eax
4073 mov ds, ax
4074 mov 0x0469, ss
4075 mov 0x0467, sp
4076
4077 SEG ES
4078 lgdt [si + 0x08]
4079 SEG CS
4080 lidt [pmode_IDT_info]
4081 ;; perhaps do something with IDT here
4082
4083 ;; set PE bit in CR0
4084 mov eax, cr0
4085 or al, #0x01
4086 mov cr0, eax
4087 ;; far jump to flush CPU queue after transition to protected mode
4088 JMP_AP(0x0020, protected_mode)
4089
4090protected_mode:
4091 ;; GDT points to valid descriptor table, now load SS, DS, ES
4092 mov ax, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
4093 mov ss, ax
4094 mov ax, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
4095 mov ds, ax
4096 mov ax, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
4097 mov es, ax
4098 xor si, si
4099 xor di, di
4100 cld
4101 rep
4102 movsw ;; move CX words from DS:SI to ES:DI
4103
4104 ;; make sure DS and ES limits are 64KB
4105 mov ax, #0x28
4106 mov ds, ax
4107 mov es, ax
4108
4109 ;; reset PG bit in CR0 ???
4110 mov eax, cr0
4111 and al, #0xFE
4112 mov cr0, eax
4113
4114 ;; far jump to flush CPU queue after transition to real mode
4115 JMP_AP(0xf000, real_mode)
4116
4117real_mode:
4118 ;; restore IDT to normal real-mode defaults
4119 SEG CS
4120 lidt [rmode_IDT_info]
4121
4122 // restore SS:SP from the BDA
4123 xor ax, ax
4124 mov ds, ax
4125 mov ss, 0x0469
4126 mov sp, 0x0467
4127 pop eax
4128ASM_END
4129
4130 set_enable_a20(prev_a20_enable);
4131
4132 // turn back on interrupts
4133ASM_START
4134 sti
4135ASM_END
4136
4137 regs.u.r8.ah = 0;
4138 CLEAR_CF();
4139 break;
4140
4141
4142 case 0x88:
4143 // Get the amount of extended memory (above 1M)
4144#if BX_CPU < 2
4145 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4146 SET_CF();
4147#else
4148 regs.u.r8.al = inb_cmos(0x30);
4149 regs.u.r8.ah = inb_cmos(0x31);
4150
4151 // According to Ralf Brown's interrupt the limit should be 15M,
4152 // but real machines mostly return max. 63M.
4153 if(regs.u.r16.ax > 0xffc0)
4154 regs.u.r16.ax = 0xffc0;
4155
4156 CLEAR_CF();
4157#endif
4158 break;
4159
4160#ifdef VBOX
4161 case 0x89:
4162 // Switch to Protected Mode.
4163 // ES:DI points to user-supplied GDT
4164 // BH/BL contains starting interrupt numbers for PIC0/PIC1
4165 // This subfunction does not return!
4166
4167// turn off interrupts
4168ASM_START
4169 cli
4170ASM_END
4171
4172 set_enable_a20(1); // enable A20 line; we're supposed to fail if that fails
4173
4174 // Initialize CS descriptor for BIOS
4175 write_word(ES, regs.u.r16.si+0x38+0, 0xffff);// limit 15:00 = normal 64K limit
4176 write_word(ES, regs.u.r16.si+0x38+2, 0x0000);// base 15:00
4177 write_byte(ES, regs.u.r16.si+0x38+4, 0x000f);// base 23:16 (hardcoded to f000:0000)
4178 write_byte(ES, regs.u.r16.si+0x38+5, 0x9b); // access
4179 write_word(ES, regs.u.r16.si+0x38+6, 0x0000);// base 31:24/reserved/limit 19:16
4180
4181 BX = regs.u.r16.bx;
4182ASM_START
4183 // Compiler generates locals offset info relative to SP.
4184 // Get BX (PIC offsets) from stack.
4185 mov bx, sp
4186 SEG SS
4187 mov bx, _int15_function.BX [bx]
4188
4189 // Program PICs
4190 mov al, #0x11 ; send initialisation commands
4191 out 0x20, al
4192 out 0xa0, al
4193 mov al, bh
4194 out 0x21, al
4195 mov al, bl
4196 out 0xa1, al
4197 mov al, #0x04
4198 out 0x21, al
4199 mov al, #0x02
4200 out 0xa1, al
4201 mov al, #0x01
4202 out 0x21, al
4203 out 0xa1, al
4204 mov al, #0xff ; mask all IRQs, user must re-enable
4205 out 0x21, al
4206 out 0xa1, al
4207
4208 // Load GDT and IDT from supplied data
4209 SEG ES
4210 lgdt [si + 0x08]
4211 SEG ES
4212 lidt [si + 0x10]
4213
4214 // set PE bit in CR0
4215 mov eax, cr0
4216 or al, #0x01
4217 mov cr0, eax
4218 // far jump to flush CPU queue after transition to protected mode
4219 JMP_AP(0x0038, protmode_switch)
4220
4221protmode_switch:
4222 ;; GDT points to valid descriptor table, now load SS, DS, ES
4223 mov ax, #0x28
4224 mov ss, ax
4225 mov ax, #0x18
4226 mov ds, ax
4227 mov ax, #0x20
4228 mov es, ax
4229
4230 // unwind the stack - this will break if calling sequence changes!
4231 mov sp,bp
4232 add sp,#4 ; skip return address
4233 popa ; restore regs
4234 pop ax ; skip saved es
4235 pop ax ; skip saved ds
4236 pop ax ; skip saved flags
4237
4238 // return to caller - note that we do not use IRET because
4239 // we cannot enable interrupts
4240 pop cx ; get return offset
4241 pop ax ; skip return segment
4242 pop ax ; skip flags
4243 mov ax, #0x30 ; ah must be 0 on successful exit
4244 push ax
4245 push cx ; re-create modified ret address on stack
4246 retf
4247
4248ASM_END
4249
4250 break;
4251#endif /* VBOX */
4252
4253 case 0x90:
4254 /* Device busy interrupt. Called by Int 16h when no key available */
4255 break;
4256
4257 case 0x91:
4258 /* Interrupt complete. Called by Int 16h when key becomes available */
4259 break;
4260
4261 case 0xbf:
4262 BX_INFO("*** int 15h function AH=bf not yet supported!\n");
4263 SET_CF();
4264 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4265 break;
4266
4267 case 0xC0:
4268#if 0
4269 SET_CF();
4270 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4271 break;
4272#endif
4273 CLEAR_CF();
4274 regs.u.r8.ah = 0;
4275 regs.u.r16.bx = BIOS_CONFIG_TABLE;
4276 ES = 0xF000;
4277 break;
4278
4279 case 0xc1:
4280 ES = ebda_seg;
4281 CLEAR_CF();
4282 break;
4283
4284 case 0xd8:
4285 bios_printf(BIOS_PRINTF_DEBUG, "EISA BIOS not present\n");
4286 SET_CF();
4287 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4288 break;
4289
4290#ifdef VBOX
4291 /* Make the BIOS warning for pretty much every Linux kernel start
4292 * disappear - it calls with ax=0xe980 to figure out SMI info. */
4293 case 0xe9: /* SMI functions (SpeedStep and similar things) */
4294 SET_CF();
4295 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4296 break;
4297 case 0xec: /* AMD64 target operating mode callback */
4298 if (regs.u.r8.al != 0)
4299 goto undecoded;
4300 regs.u.r8.ah = 0;
4301 if (regs.u.r8.bl >= 1 && regs.u.r8.bl <= 3)
4302 CLEAR_CF(); /* Accepted value. */
4303 else
4304 SET_CF(); /* Reserved, error. */
4305 break;
4306undecoded:
4307#endif /* VBOX */
4308 default:
4309 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4310 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4311 SET_CF();
4312 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4313 break;
4314 }
4315}
4316
4317#if BX_USE_PS2_MOUSE
4318 void
4319int15_function_mouse(regs, ES, DS, FLAGS)
4320 pusha_regs_t regs; // REGS pushed via pusha
4321 Bit16u ES, DS, FLAGS;
4322{
4323 Bit16u ebda_seg=read_word(0x0040,0x000E);
4324 Bit8u mouse_flags_1, mouse_flags_2;
4325 Bit16u mouse_driver_seg;
4326 Bit16u mouse_driver_offset;
4327 Bit8u mouse_cmd;
4328 Bit8u ret, mouse_data1, mouse_data2, mouse_data3;
4329
4330BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4331
4332 switch (regs.u.r8.ah) {
4333 case 0xC2:
4334 // Return Codes status in AH
4335 // =========================
4336 // 00: success
4337 // 01: invalid subfunction (AL > 7)
4338 // 02: invalid input value (out of allowable range)
4339 // 03: interface error
4340 // 04: resend command received from mouse controller,
4341 // device driver should attempt command again
4342 // 05: cannot enable mouse, since no far call has been installed
4343 // 80/86: mouse service not implemented
4344
4345 if (regs.u.r8.al > 7) {
4346BX_DEBUG_INT15("unsupported subfn\n");
4347 // invalid function
4348 SET_CF();
4349 regs.u.r8.ah = 1;
4350 break;
4351 }
4352
4353 // Valid subfn; disable AUX input and IRQ12, assume no error
4354 set_kbd_command_byte(0x65);
4355 CLEAR_CF();
4356 regs.u.r8.ah = 0;
4357
4358 switch (regs.u.r8.al) {
4359 case 0: // Disable/Enable Mouse
4360BX_DEBUG_INT15("case 0: ");
4361 if (regs.u.r8.bh > 1) {
4362 BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs.u.r8.bh);
4363 // invalid subfunction
4364 SET_CF();
4365 regs.u.r8.ah = 1;
4366 break;
4367 }
4368 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4369 if ( (mouse_flags_2 & 0x80) == 0 ) {
4370 BX_DEBUG_INT15("INT 15h C2 Enable/Disable Mouse, no far call handler\n");
4371 SET_CF();
4372 regs.u.r8.ah = 5; // no far call installed
4373 break;
4374 }
4375 if (regs.u.r8.bh == 0) {
4376BX_DEBUG_INT15("Disable Mouse\n");
4377 mouse_cmd = 0xF5; // disable mouse command
4378 } else {
4379BX_DEBUG_INT15("Enable Mouse\n");
4380 mouse_cmd = 0xF4; // enable mouse command
4381 }
4382
4383 ret = send_to_mouse_ctrl(mouse_cmd); // disable mouse command
4384 if (ret == 0) {
4385 ret = get_mouse_data(&mouse_data1);
4386 if ( (ret == 0) || (mouse_data1 == 0xFA) ) {
4387 // success
4388 break;
4389 }
4390 }
4391
4392 // interface error
4393 SET_CF();
4394 regs.u.r8.ah = 3;
4395 break;
4396
4397 case 5: // Initialize Mouse
4398 // Valid package sizes are 1 to 8
4399 if ( (regs.u.r8.bh < 1) || (regs.u.r8.bh > 8) ) {
4400 SET_CF();
4401 regs.u.r8.ah = 2; // invalid input
4402 break;
4403 }
4404 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4405 mouse_flags_2 = (mouse_flags_2 & 0xf8) | (regs.u.r8.bh - 1);
4406 write_byte(ebda_seg, 0x0027, mouse_flags_2);
4407 // fall through!
4408
4409 case 1: // Reset Mouse
4410BX_DEBUG_INT15("case 1 or 5:\n");
4411 // clear current package byte index
4412 mouse_flags_1 = read_byte(ebda_seg, 0x0026);
4413 mouse_flags_1 = mouse_flags_1 & 0xf8;
4414 write_byte(ebda_seg, 0x0026, mouse_flags_1);
4415 ret = send_to_mouse_ctrl(0xFF); // reset mouse command
4416 if (ret == 0) {
4417 ret = get_mouse_data(&mouse_data3);
4418 // if no mouse attached, it will return RESEND
4419 if (mouse_data3 == 0xfe) {
4420 SET_CF();
4421 regs.u.r8.ah = 4; // resend
4422 break;
4423 }
4424 if (mouse_data3 != 0xfa)
4425 BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3);
4426 if ( ret == 0 ) {
4427 ret = get_mouse_data(&mouse_data1);
4428 if ( ret == 0 ) {
4429 ret = get_mouse_data(&mouse_data2);
4430 if ( ret == 0 ) {
4431 // success
4432 regs.u.r8.bl = mouse_data1;
4433 regs.u.r8.bh = mouse_data2;
4434 break;
4435 }
4436 }
4437 }
4438 }
4439
4440 // interface error
4441 SET_CF();
4442 regs.u.r8.ah = 3;
4443 break;
4444
4445 case 2: // Set Sample Rate
4446BX_DEBUG_INT15("case 2:\n");
4447 switch (regs.u.r8.bh) {
4448 case 0: mouse_data1 = 10; break; // 10 reports/sec
4449 case 1: mouse_data1 = 20; break; // 20 reports/sec
4450 case 2: mouse_data1 = 40; break; // 40 reports/sec
4451 case 3: mouse_data1 = 60; break; // 60 reports/sec
4452 case 4: mouse_data1 = 80; break; // 80 reports/sec
4453 case 5: mouse_data1 = 100; break; // 100 reports/sec (default)
4454 case 6: mouse_data1 = 200; break; // 200 reports/sec
4455 default: mouse_data1 = 0;
4456 }
4457 if (mouse_data1 > 0) {
4458 ret = send_to_mouse_ctrl(0xF3); // set sample rate command
4459 if (ret == 0) {
4460 ret = get_mouse_data(&mouse_data2);
4461 ret = send_to_mouse_ctrl(mouse_data1);
4462 ret = get_mouse_data(&mouse_data2);
4463 // success
4464 } else {
4465 // interface error
4466 SET_CF();
4467 regs.u.r8.ah = 3;
4468 }
4469 } else {
4470 // invalid input
4471 SET_CF();
4472 regs.u.r8.ah = 2;
4473 }
4474 break;
4475
4476 case 3: // Set Resolution
4477BX_DEBUG_INT15("case 3:\n");
4478 // BX:
4479 // 0 = 25 dpi, 1 count per millimeter
4480 // 1 = 50 dpi, 2 counts per millimeter
4481 // 2 = 100 dpi, 4 counts per millimeter
4482 // 3 = 200 dpi, 8 counts per millimeter
4483 if (regs.u.r8.bh < 4) {
4484 ret = send_to_mouse_ctrl(0xE8); // set resolution command
4485 if (ret == 0) {
4486 ret = get_mouse_data(&mouse_data1);
4487 if (mouse_data1 != 0xfa)
4488 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4489 ret = send_to_mouse_ctrl(regs.u.r8.bh);
4490 ret = get_mouse_data(&mouse_data1);
4491 if (mouse_data1 != 0xfa)
4492 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4493 // success
4494 } else {
4495 // interface error
4496 SET_CF();
4497 regs.u.r8.ah = 3;
4498 }
4499 } else {
4500 // invalid input
4501 SET_CF();
4502 regs.u.r8.ah = 2;
4503 }
4504 break;
4505
4506 case 4: // Get Device ID
4507BX_DEBUG_INT15("case 4:\n");
4508 ret = send_to_mouse_ctrl(0xF2); // get mouse ID command
4509 if (ret == 0) {
4510 ret = get_mouse_data(&mouse_data1);
4511 ret = get_mouse_data(&mouse_data2);
4512 regs.u.r8.bh = mouse_data2;
4513 // success
4514 } else {
4515 // interface error
4516 SET_CF();
4517 regs.u.r8.ah = 3;
4518 }
4519 break;
4520
4521 case 6: // Return Status & Set Scaling Factor...
4522BX_DEBUG_INT15("case 6:\n");
4523 switch (regs.u.r8.bh) {
4524 case 0: // Return Status
4525 ret = send_to_mouse_ctrl(0xE9); // get mouse info command
4526 if (ret == 0) {
4527 ret = get_mouse_data(&mouse_data1);
4528 if (mouse_data1 != 0xfa)
4529 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4530 if (ret == 0) {
4531 ret = get_mouse_data(&mouse_data1);
4532 if ( ret == 0 ) {
4533 ret = get_mouse_data(&mouse_data2);
4534 if ( ret == 0 ) {
4535 ret = get_mouse_data(&mouse_data3);
4536 if ( ret == 0 ) {
4537 regs.u.r8.bl = mouse_data1;
4538 regs.u.r8.cl = mouse_data2;
4539 regs.u.r8.dl = mouse_data3;
4540 // success
4541 break;
4542 }
4543 }
4544 }
4545 }
4546 }
4547
4548 // interface error
4549 SET_CF();
4550 regs.u.r8.ah = 3;
4551 break;
4552
4553 case 1: // Set Scaling Factor to 1:1
4554 case 2: // Set Scaling Factor to 2:1
4555 if (regs.u.r8.bh == 1) {
4556 ret = send_to_mouse_ctrl(0xE6);
4557 } else {
4558 ret = send_to_mouse_ctrl(0xE7);
4559 }
4560 if (ret == 0) {
4561 get_mouse_data(&mouse_data1);
4562 ret = (mouse_data1 != 0xFA);
4563 }
4564 if (ret != 0) {
4565 // interface error
4566 SET_CF();
4567 regs.u.r8.ah = 3;
4568 }
4569 break;
4570
4571 default:
4572 BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs.u.r8.bh);
4573 // invalid subfunction
4574 SET_CF();
4575 regs.u.r8.ah = 1;
4576 }
4577 break;
4578
4579 case 7: // Set Mouse Handler Address
4580BX_DEBUG_INT15("case 7:\n");
4581 mouse_driver_seg = ES;
4582 mouse_driver_offset = regs.u.r16.bx;
4583 write_word(ebda_seg, 0x0022, mouse_driver_offset);
4584 write_word(ebda_seg, 0x0024, mouse_driver_seg);
4585 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4586 if (mouse_driver_offset == 0 && mouse_driver_seg == 0) {
4587 /* remove handler */
4588 if ( (mouse_flags_2 & 0x80) != 0 ) {
4589 mouse_flags_2 &= ~0x80;
4590 }
4591 }
4592 else {
4593 /* install handler */
4594 mouse_flags_2 |= 0x80;
4595 }
4596 write_byte(ebda_seg, 0x0027, mouse_flags_2);
4597 break;
4598
4599 default:
4600 BX_PANIC("INT 15h C2 default case entered\n");
4601 // invalid subfunction
4602 SET_CF();
4603 regs.u.r8.ah = 1;
4604 }
4605BX_DEBUG_INT15("returning cf = %u, ah = %02x\n", (unsigned)GET_CF(), (unsigned)regs.u.r8.ah);
4606 // Re-enable AUX input and IRQ12
4607 set_kbd_command_byte(0x47);
4608 break;
4609
4610 default:
4611 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4612 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4613 SET_CF();
4614 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4615 break;
4616 }
4617}
4618#endif // BX_USE_PS2_MOUSE
4619
4620
4621void set_e820_range(ES, DI, start, end, extra_start, extra_end, type)
4622 Bit16u ES;
4623 Bit16u DI;
4624 Bit32u start;
4625 Bit32u end;
4626 Bit8u extra_start;
4627 Bit8u extra_end;
4628 Bit16u type;
4629{
4630 write_word(ES, DI, start);
4631 write_word(ES, DI+2, start >> 16);
4632 write_word(ES, DI+4, extra_start);
4633 write_word(ES, DI+6, 0x00);
4634
4635 end -= start;
4636 extra_end -= extra_start;
4637 write_word(ES, DI+8, end);
4638 write_word(ES, DI+10, end >> 16);
4639 write_word(ES, DI+12, extra_end);
4640 write_word(ES, DI+14, 0x0000);
4641
4642 write_word(ES, DI+16, type);
4643 write_word(ES, DI+18, 0x0);
4644}
4645
4646 void
4647int15_function32(regs, ES, DS, FLAGS)
4648 pushad_regs_t regs; // REGS pushed via pushad
4649 Bit16u ES, DS, FLAGS;
4650{
4651 Bit32u extended_memory_size=0; // 64bits long
4652 Bit32u extra_lowbits_memory_size=0;
4653 Bit16u CX,DX;
4654 Bit8u extra_highbits_memory_size=0;
4655
4656BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4657
4658 switch (regs.u.r8.ah) {
4659 case 0x86:
4660 // Wait for CX:DX microseconds. currently using the
4661 // refresh request port 0x61 bit4, toggling every 15usec
4662
4663 CX = regs.u.r16.cx;
4664 DX = regs.u.r16.dx;
4665
4666ASM_START
4667 sti
4668
4669 ;; Get the count in eax
4670 ;; VBOX: corrected _int15_function -> _int15_function32 here.
4671 mov bx, sp
4672 SEG SS
4673 mov ax, _int15_function32.CX [bx]
4674 shl eax, #16
4675 SEG SS
4676 mov ax, _int15_function32.DX [bx]
4677
4678 ;; convert to numbers of 15usec ticks
4679 mov ebx, #15
4680 xor edx, edx
4681 div eax, ebx
4682 mov ecx, eax
4683
4684 ;; wait for ecx number of refresh requests
4685 in al, #0x61
4686 and al,#0x10
4687 mov ah, al
4688
4689 or ecx, ecx
4690 je int1586_tick_end
4691int1586_tick:
4692 in al, #0x61
4693 and al,#0x10
4694 cmp al, ah
4695 je int1586_tick
4696 mov ah, al
4697 dec ecx
4698 jnz int1586_tick
4699int1586_tick_end:
4700ASM_END
4701
4702 break;
4703
4704 case 0xe8:
4705 switch(regs.u.r8.al)
4706 {
4707 case 0x20: // coded by osmaker aka K.J.
4708 if(regs.u.r32.edx == 0x534D4150)
4709 {
4710 extended_memory_size = inb_cmos(0x35);
4711 extended_memory_size <<= 8;
4712 extended_memory_size |= inb_cmos(0x34);
4713 extended_memory_size *= 64;
4714#ifndef VBOX /* The following excludes 0xf0000000 thru 0xffffffff. Trust DevPcBios.cpp to get this right. */
4715 // greater than EFF00000???
4716 if(extended_memory_size > 0x3bc000) {
4717 extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4718 }
4719#endif /* !VBOX */
4720 extended_memory_size *= 1024;
4721 extended_memory_size += (16L * 1024 * 1024);
4722
4723 if(extended_memory_size <= (16L * 1024 * 1024)) {
4724 extended_memory_size = inb_cmos(0x31);
4725 extended_memory_size <<= 8;
4726 extended_memory_size |= inb_cmos(0x30);
4727 extended_memory_size *= 1024;
4728 extended_memory_size += (1L * 1024 * 1024);
4729 }
4730
4731#ifdef VBOX /* We've already used the CMOS entries for SATA.
4732 BTW. This is the amount of memory above 4GB measured in 64KB units. */
4733 extra_lowbits_memory_size = inb_cmos(0x62);
4734 extra_lowbits_memory_size <<= 8;
4735 extra_lowbits_memory_size |= inb_cmos(0x61);
4736 extra_lowbits_memory_size <<= 16;
4737 extra_highbits_memory_size = inb_cmos(0x63);
4738 /* 0x64 and 0x65 can be used if we need to dig 1 TB or more at a later point. */
4739#else
4740 extra_lowbits_memory_size = inb_cmos(0x5c);
4741 extra_lowbits_memory_size <<= 8;
4742 extra_lowbits_memory_size |= inb_cmos(0x5b);
4743 extra_lowbits_memory_size *= 64;
4744 extra_lowbits_memory_size *= 1024;
4745 extra_highbits_memory_size = inb_cmos(0x5d);
4746#endif /* !VBOX */
4747
4748 switch(regs.u.r16.bx)
4749 {
4750 case 0:
4751 set_e820_range(ES, regs.u.r16.di,
4752#ifndef VBOX /** @todo Upstream suggests the following, needs checking. (see next as well) */
4753 0x0000000L, 0x0009f000L, 0, 0, 1);
4754#else
4755 0x0000000L, 0x0009fc00L, 0, 0, 1);
4756#endif
4757 regs.u.r32.ebx = 1;
4758 break;
4759 case 1:
4760 set_e820_range(ES, regs.u.r16.di,
4761#ifndef VBOX /** @todo Upstream suggests the following, needs checking. (see next as well) */
4762 0x0009f000L, 0x000a0000L, 0, 0, 2);
4763#else
4764 0x0009fc00L, 0x000a0000L, 0, 0, 2);
4765#endif
4766 regs.u.r32.ebx = 2;
4767 break;
4768 case 2:
4769#ifdef VBOX
4770 /* Mark the BIOS as reserved. VBox doesn't currently
4771 * use the 0xe0000-0xeffff area. It does use the
4772 * 0xd0000-0xdffff area for the BIOS logo, but it's
4773 * not worth marking it as reserved. Note that various
4774 * Windows versions don't accept (read: in debug builds
4775 * they trigger the "Too many similar traps" assertion)
4776 * a single reserved range from 0xd0000 to 0xffffff.
4777 * A 128K area starting from 0xd0000 works. */
4778 set_e820_range(ES, regs.u.r16.di,
4779 0x000f0000L, 0x00100000L, 0, 0, 2);
4780#else /* !VBOX */
4781 set_e820_range(ES, regs.u.r16.di,
4782 0x000e8000L, 0x00100000L, 0, 0, 2);
4783#endif /* !VBOX */
4784 regs.u.r32.ebx = 3;
4785 break;
4786 case 3:
4787#if BX_ROMBIOS32 || defined(VBOX)
4788 set_e820_range(ES, regs.u.r16.di,
4789 0x00100000L,
4790 extended_memory_size - ACPI_DATA_SIZE, 0, 0, 1);
4791 regs.u.r32.ebx = 4;
4792#else
4793 set_e820_range(ES, regs.u.r16.di,
4794 0x00100000L,
4795 extended_memory_size, 1);
4796 regs.u.r32.ebx = 5;
4797#endif
4798 break;
4799 case 4:
4800 set_e820_range(ES, regs.u.r16.di,
4801 extended_memory_size - ACPI_DATA_SIZE,
4802 extended_memory_size, 0, 0, 3); // ACPI RAM
4803 regs.u.r32.ebx = 5;
4804 break;
4805 case 5:
4806 /* 256KB BIOS area at the end of 4 GB */
4807#ifdef VBOX
4808 /* We don't set the end to 1GB here and rely on the 32-bit
4809 unsigned wrap around effect (0-0xfffc0000L). */
4810#endif
4811 set_e820_range(ES, regs.u.r16.di,
4812 0xfffc0000L, 0x00000000L, 0, 0, 2);
4813 /* Temporary disabled MCFG code */
4814#if 0
4815 regs.u.r32.ebx = 6;
4816 break;
4817 case 6:
4818 /* PCI MMIO config space */
4819 set_e820_range(ES, regs.u.r16.di,
4820 0xd0000000L, 0xe0000000L, 0, 0, 2);
4821 if (extra_highbits_memory_size || extra_lowbits_memory_size)
4822 regs.u.r32.ebx = 7;
4823 else
4824 regs.u.r32.ebx = 0;
4825 break;
4826 case 7:
4827#else
4828 if (extra_highbits_memory_size || extra_lowbits_memory_size)
4829 regs.u.r32.ebx = 6;
4830 else
4831 regs.u.r32.ebx = 0;
4832 break;
4833 case 6:
4834#endif
4835#ifdef VBOX /* Don't succeeded if no memory above 4 GB. */
4836 /* Mapping of memory above 4 GB if present.
4837 Note: set_e820_range needs do no borrowing in the
4838 subtraction because of the nice numbers. */
4839 if (extra_highbits_memory_size || extra_lowbits_memory_size)
4840 {
4841 set_e820_range(ES, regs.u.r16.di,
4842 0x00000000L, extra_lowbits_memory_size,
4843 1 /*GB*/, extra_highbits_memory_size + 1 /*GB*/, 1);
4844 regs.u.r32.ebx = 0;
4845 }
4846 break;
4847 /* fall thru */
4848#else /* !VBOX */
4849 /* Mapping of memory above 4 GB */
4850 set_e820_range(ES, regs.u.r16.di, 0x00000000L,
4851 extra_lowbits_memory_size, 1, extra_highbits_memory_size
4852 + 1, 1);
4853 regs.u.r32.ebx = 0;
4854 break;
4855#endif /* !VBOX */
4856 default: /* AX=E820, DX=534D4150, BX unrecognized */
4857 goto int15_unimplemented;
4858 break;
4859 }
4860 regs.u.r32.eax = 0x534D4150;
4861 regs.u.r32.ecx = 0x14;
4862 CLEAR_CF();
4863 } else {
4864 // if DX != 0x534D4150)
4865 goto int15_unimplemented;
4866 }
4867 break;
4868
4869 case 0x01:
4870 // do we have any reason to fail here ?
4871 CLEAR_CF();
4872
4873 // my real system sets ax and bx to 0
4874 // this is confirmed by Ralph Brown list
4875 // but syslinux v1.48 is known to behave
4876 // strangely if ax is set to 0
4877 // regs.u.r16.ax = 0;
4878 // regs.u.r16.bx = 0;
4879
4880 // Get the amount of extended memory (above 1M)
4881 regs.u.r8.cl = inb_cmos(0x30);
4882 regs.u.r8.ch = inb_cmos(0x31);
4883
4884 // limit to 15M
4885 if(regs.u.r16.cx > 0x3c00)
4886 {
4887 regs.u.r16.cx = 0x3c00;
4888 }
4889
4890 // Get the amount of extended memory above 16M in 64k blocs
4891 regs.u.r8.dl = inb_cmos(0x34);
4892 regs.u.r8.dh = inb_cmos(0x35);
4893
4894 // Set configured memory equal to extended memory
4895 regs.u.r16.ax = regs.u.r16.cx;
4896 regs.u.r16.bx = regs.u.r16.dx;
4897 break;
4898 default: /* AH=0xE8?? but not implemented */
4899 goto int15_unimplemented;
4900 }
4901 break;
4902 int15_unimplemented:
4903 // fall into the default
4904 default:
4905 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4906 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4907 SET_CF();
4908 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4909 break;
4910 }
4911}
4912
4913 void
4914int16_function(DI, SI, BP, SP, BX, DX, CX, AX, FLAGS)
4915 Bit16u DI, SI, BP, SP, BX, DX, CX, AX, FLAGS;
4916{
4917 Bit8u scan_code, ascii_code, shift_flags, led_flags, count;
4918 Bit16u kbd_code, max;
4919
4920 BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX, BX, CX, DX);
4921
4922 shift_flags = read_byte(0x0040, 0x17);
4923 led_flags = read_byte(0x0040, 0x97);
4924 if ((((shift_flags >> 4) & 0x07) ^ (led_flags & 0x07)) != 0) {
4925ASM_START
4926 cli
4927ASM_END
4928 outb(0x60, 0xed);
4929 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
4930 if ((inb(0x60) == 0xfa)) {
4931 led_flags &= 0xf8;
4932 led_flags |= ((shift_flags >> 4) & 0x07);
4933 outb(0x60, led_flags & 0x07);
4934 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
4935 inb(0x60);
4936 write_byte(0x0040, 0x97, led_flags);
4937 }
4938ASM_START
4939 sti
4940ASM_END
4941 }
4942
4943 switch (GET_AH()) {
4944 case 0x00: /* read keyboard input */
4945
4946 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4947 BX_PANIC("KBD: int16h: out of keyboard input\n");
4948 }
4949 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4950 else if (ascii_code == 0xE0) ascii_code = 0;
4951 AX = (scan_code << 8) | ascii_code;
4952 break;
4953
4954 case 0x01: /* check keyboard status */
4955 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4956 SET_ZF();
4957 return;
4958 }
4959 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4960 else if (ascii_code == 0xE0) ascii_code = 0;
4961 AX = (scan_code << 8) | ascii_code;
4962 CLEAR_ZF();
4963 break;
4964
4965 case 0x02: /* get shift flag status */
4966 shift_flags = read_byte(0x0040, 0x17);
4967 SET_AL(shift_flags);
4968 break;
4969
4970 case 0x05: /* store key-stroke into buffer */
4971 if ( !enqueue_key(GET_CH(), GET_CL()) ) {
4972 SET_AL(1);
4973 }
4974 else {
4975 SET_AL(0);
4976 }
4977 break;
4978
4979 case 0x09: /* GET KEYBOARD FUNCTIONALITY */
4980 // bit Bochs Description
4981 // 7 0 reserved
4982 // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
4983 // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
4984 // 4 1 INT 16/AH=0Ah supported
4985 // 3 0 INT 16/AX=0306h supported
4986 // 2 0 INT 16/AX=0305h supported
4987 // 1 0 INT 16/AX=0304h supported
4988 // 0 0 INT 16/AX=0300h supported
4989 //
4990 SET_AL(0x30);
4991 break;
4992
4993 case 0x0A: /* GET KEYBOARD ID */
4994 count = 2;
4995 kbd_code = 0x0;
4996 outb(0x60, 0xf2);
4997 /* Wait for data */
4998 max=0xffff;
4999 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
5000 if (max>0x0) {
5001 if ((inb(0x60) == 0xfa)) {
5002 do {
5003 max=0xffff;
5004 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
5005 if (max>0x0) {
5006 kbd_code >>= 8;
5007 kbd_code |= (inb(0x60) << 8);
5008 }
5009 } while (--count>0);
5010 }
5011 }
5012 BX=kbd_code;
5013 break;
5014
5015 case 0x10: /* read MF-II keyboard input */
5016
5017 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
5018 BX_PANIC("KBD: int16h: out of keyboard input\n");
5019 }
5020 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
5021 AX = (scan_code << 8) | ascii_code;
5022 break;
5023
5024 case 0x11: /* check MF-II keyboard status */
5025 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
5026 SET_ZF();
5027 return;
5028 }
5029 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
5030 AX = (scan_code << 8) | ascii_code;
5031 CLEAR_ZF();
5032 break;
5033
5034 case 0x12: /* get extended keyboard status */
5035 shift_flags = read_byte(0x0040, 0x17);
5036 SET_AL(shift_flags);
5037 shift_flags = read_byte(0x0040, 0x18) & 0x73;
5038 shift_flags |= read_byte(0x0040, 0x96) & 0x0c;
5039 SET_AH(shift_flags);
5040 BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX);
5041 break;
5042
5043 case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
5044 SET_AH(0x80); // function int16 ah=0x10-0x12 supported
5045 break;
5046
5047 case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
5048 // don't change AH : function int16 ah=0x20-0x22 NOT supported
5049 break;
5050
5051 case 0x6F:
5052 if (GET_AL() == 0x08)
5053 SET_AH(0x02); // unsupported, aka normal keyboard
5054
5055 default:
5056 BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
5057 }
5058}
5059
5060 unsigned int
5061dequeue_key(scan_code, ascii_code, incr)
5062 Bit8u *scan_code;
5063 Bit8u *ascii_code;
5064 unsigned int incr;
5065{
5066 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail;
5067 Bit16u ss;
5068 Bit8u acode, scode;
5069
5070#if BX_CPU < 2
5071 buffer_start = 0x001E;
5072 buffer_end = 0x003E;
5073#else
5074 buffer_start = read_word(0x0040, 0x0080);
5075 buffer_end = read_word(0x0040, 0x0082);
5076#endif
5077
5078 buffer_head = read_word(0x0040, 0x001a);
5079 buffer_tail = read_word(0x0040, 0x001c);
5080
5081 if (buffer_head != buffer_tail) {
5082 ss = get_SS();
5083 acode = read_byte(0x0040, buffer_head);
5084 scode = read_byte(0x0040, buffer_head+1);
5085 write_byte(ss, ascii_code, acode);
5086 write_byte(ss, scan_code, scode);
5087
5088 if (incr) {
5089 buffer_head += 2;
5090 if (buffer_head >= buffer_end)
5091 buffer_head = buffer_start;
5092 write_word(0x0040, 0x001a, buffer_head);
5093 }
5094 return(1);
5095 }
5096 else {
5097 return(0);
5098 }
5099}
5100
5101static char panic_msg_keyb_buffer_full[] = "%s: keyboard input buffer full\n";
5102
5103 Bit8u
5104send_to_mouse_ctrl(sendbyte)
5105 Bit8u sendbyte;
5106{
5107 Bit8u response;
5108
5109 // wait for chance to write to ctrl
5110 if ( inb(0x64) & 0x02 )
5111 BX_PANIC(panic_msg_keyb_buffer_full,"sendmouse");
5112 outb(0x64, 0xD4);
5113 outb(0x60, sendbyte);
5114 return(0);
5115}
5116
5117
5118 Bit8u
5119get_mouse_data(data)
5120 Bit8u *data;
5121{
5122 Bit8u response;
5123 Bit16u ss;
5124
5125 while ( (inb(0x64) & 0x21) != 0x21 ) {
5126 }
5127
5128 response = inb(0x60);
5129
5130 ss = get_SS();
5131 write_byte(ss, data, response);
5132 return(0);
5133}
5134
5135 void
5136set_kbd_command_byte(command_byte)
5137 Bit8u command_byte;
5138{
5139 if ( inb(0x64) & 0x02 )
5140 BX_PANIC(panic_msg_keyb_buffer_full,"setkbdcomm");
5141
5142 outb(0x64, 0x60); // write command byte
5143 outb(0x60, command_byte);
5144}
5145
5146 void
5147int09_function(DI, SI, BP, SP, BX, DX, CX, AX)
5148 Bit16u DI, SI, BP, SP, BX, DX, CX, AX;
5149{
5150 Bit8u scancode, asciicode, shift_flags;
5151 Bit8u mf2_flags, mf2_state;
5152
5153 //
5154 // DS has been set to F000 before call
5155 //
5156
5157
5158 scancode = GET_AL();
5159
5160 if (scancode == 0) {
5161 BX_INFO("KBD: int09 handler: AL=0\n");
5162 return;
5163 }
5164
5165
5166 shift_flags = read_byte(0x0040, 0x17);
5167 mf2_flags = read_byte(0x0040, 0x18);
5168 mf2_state = read_byte(0x0040, 0x96);
5169 asciicode = 0;
5170
5171 switch (scancode) {
5172 case 0x3a: /* Caps Lock press */
5173 shift_flags ^= 0x40;
5174 write_byte(0x0040, 0x17, shift_flags);
5175 mf2_flags |= 0x40;
5176 write_byte(0x0040, 0x18, mf2_flags);
5177 break;
5178 case 0xba: /* Caps Lock release */
5179 mf2_flags &= ~0x40;
5180 write_byte(0x0040, 0x18, mf2_flags);
5181 break;
5182
5183 case 0x2a: /* L Shift press */
5184 shift_flags |= 0x02;
5185 write_byte(0x0040, 0x17, shift_flags);
5186 break;
5187 case 0xaa: /* L Shift release */
5188 shift_flags &= ~0x02;
5189 write_byte(0x0040, 0x17, shift_flags);
5190 break;
5191
5192 case 0x36: /* R Shift press */
5193 shift_flags |= 0x01;
5194 write_byte(0x0040, 0x17, shift_flags);
5195 break;
5196 case 0xb6: /* R Shift release */
5197 shift_flags &= ~0x01;
5198 write_byte(0x0040, 0x17, shift_flags);
5199 break;
5200
5201 case 0x1d: /* Ctrl press */
5202 if ((mf2_state & 0x01) == 0) {
5203 shift_flags |= 0x04;
5204 write_byte(0x0040, 0x17, shift_flags);
5205 if (mf2_state & 0x02) {
5206 mf2_state |= 0x04;
5207 write_byte(0x0040, 0x96, mf2_state);
5208 } else {
5209 mf2_flags |= 0x01;
5210 write_byte(0x0040, 0x18, mf2_flags);
5211 }
5212 }
5213 break;
5214 case 0x9d: /* Ctrl release */
5215 if ((mf2_state & 0x01) == 0) {
5216 shift_flags &= ~0x04;
5217 write_byte(0x0040, 0x17, shift_flags);
5218 if (mf2_state & 0x02) {
5219 mf2_state &= ~0x04;
5220 write_byte(0x0040, 0x96, mf2_state);
5221 } else {
5222 mf2_flags &= ~0x01;
5223 write_byte(0x0040, 0x18, mf2_flags);
5224 }
5225 }
5226 break;
5227
5228 case 0x38: /* Alt press */
5229 shift_flags |= 0x08;
5230 write_byte(0x0040, 0x17, shift_flags);
5231 if (mf2_state & 0x02) {
5232 mf2_state |= 0x08;
5233 write_byte(0x0040, 0x96, mf2_state);
5234 } else {
5235 mf2_flags |= 0x02;
5236 write_byte(0x0040, 0x18, mf2_flags);
5237 }
5238 break;
5239 case 0xb8: /* Alt release */
5240 shift_flags &= ~0x08;
5241 write_byte(0x0040, 0x17, shift_flags);
5242 if (mf2_state & 0x02) {
5243 mf2_state &= ~0x08;
5244 write_byte(0x0040, 0x96, mf2_state);
5245 } else {
5246 mf2_flags &= ~0x02;
5247 write_byte(0x0040, 0x18, mf2_flags);
5248 }
5249 break;
5250
5251 case 0x45: /* Num Lock press */
5252 if ((mf2_state & 0x03) == 0) {
5253 mf2_flags |= 0x20;
5254 write_byte(0x0040, 0x18, mf2_flags);
5255 shift_flags ^= 0x20;
5256 write_byte(0x0040, 0x17, shift_flags);
5257 }
5258 break;
5259 case 0xc5: /* Num Lock release */
5260 if ((mf2_state & 0x03) == 0) {
5261 mf2_flags &= ~0x20;
5262 write_byte(0x0040, 0x18, mf2_flags);
5263 }
5264 break;
5265
5266 case 0x46: /* Scroll Lock press */
5267 mf2_flags |= 0x10;
5268 write_byte(0x0040, 0x18, mf2_flags);
5269 shift_flags ^= 0x10;
5270 write_byte(0x0040, 0x17, shift_flags);
5271 break;
5272
5273 case 0xc6: /* Scroll Lock release */
5274 mf2_flags &= ~0x10;
5275 write_byte(0x0040, 0x18, mf2_flags);
5276 break;
5277
5278#ifdef VBOX
5279 case 0x53: /* Del press */
5280 if ((shift_flags & 0x0f) == 0x0c)
5281 {
5282ASM_START
5283 /* Ctrl+Alt+Del => Reboot */
5284 jmp 0xf000:post
5285ASM_END
5286 }
5287 /* fall through */
5288#endif
5289
5290 default:
5291 if (scancode & 0x80) {
5292 break; /* toss key releases ... */
5293 }
5294 if (scancode > MAX_SCAN_CODE) {
5295 BX_INFO("KBD: int09h_handler(): unknown scancode read: 0x%02x!\n", scancode);
5296 return;
5297 }
5298 if (shift_flags & 0x08) { /* ALT */
5299 asciicode = scan_to_scanascii[scancode].alt;
5300 scancode = scan_to_scanascii[scancode].alt >> 8;
5301 } else if (shift_flags & 0x04) { /* CONTROL */
5302 asciicode = scan_to_scanascii[scancode].control;
5303 scancode = scan_to_scanascii[scancode].control >> 8;
5304 } else if (((mf2_state & 0x02) > 0) && ((scancode >= 0x47) && (scancode <= 0x53))) {
5305 /* extended keys handling */
5306 asciicode = 0xe0;
5307 scancode = scan_to_scanascii[scancode].normal >> 8;
5308 } else if (shift_flags & 0x03) { /* LSHIFT + RSHIFT */
5309 /* check if lock state should be ignored
5310 * because a SHIFT key are pressed */
5311
5312 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
5313 asciicode = scan_to_scanascii[scancode].normal;
5314 scancode = scan_to_scanascii[scancode].normal >> 8;
5315 } else {
5316 asciicode = scan_to_scanascii[scancode].shift;
5317 scancode = scan_to_scanascii[scancode].shift >> 8;
5318 }
5319 } else {
5320 /* check if lock is on */
5321 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
5322 asciicode = scan_to_scanascii[scancode].shift;
5323 scancode = scan_to_scanascii[scancode].shift >> 8;
5324 } else {
5325 asciicode = scan_to_scanascii[scancode].normal;
5326 scancode = scan_to_scanascii[scancode].normal >> 8;
5327 }
5328 }
5329 if (scancode==0 && asciicode==0) {
5330 BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
5331 }
5332 enqueue_key(scancode, asciicode);
5333 break;
5334 }
5335 if ((scancode & 0x7f) != 0x1d) {
5336 mf2_state &= ~0x01;
5337 }
5338 mf2_state &= ~0x02;
5339 write_byte(0x0040, 0x96, mf2_state);
5340}
5341
5342 unsigned int
5343enqueue_key(scan_code, ascii_code)
5344 Bit8u scan_code, ascii_code;
5345{
5346 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail, temp_tail;
5347
5348#if BX_CPU < 2
5349 buffer_start = 0x001E;
5350 buffer_end = 0x003E;
5351#else
5352 buffer_start = read_word(0x0040, 0x0080);
5353 buffer_end = read_word(0x0040, 0x0082);
5354#endif
5355
5356 buffer_head = read_word(0x0040, 0x001A);
5357 buffer_tail = read_word(0x0040, 0x001C);
5358
5359 temp_tail = buffer_tail;
5360 buffer_tail += 2;
5361 if (buffer_tail >= buffer_end)
5362 buffer_tail = buffer_start;
5363
5364 if (buffer_tail == buffer_head) {
5365 return(0);
5366 }
5367
5368 write_byte(0x0040, temp_tail, ascii_code);
5369 write_byte(0x0040, temp_tail+1, scan_code);
5370 write_word(0x0040, 0x001C, buffer_tail);
5371 return(1);
5372}
5373
5374
5375 void
5376int74_function(make_farcall, Z, Y, X, status)
5377 Bit16u make_farcall, Z, Y, X, status;
5378{
5379 Bit16u ebda_seg=read_word(0x0040,0x000E);
5380 Bit8u in_byte, index, package_count;
5381 Bit8u mouse_flags_1, mouse_flags_2;
5382
5383BX_DEBUG_INT74("entering int74_function\n");
5384 make_farcall = 0;
5385
5386 in_byte = inb(0x64);
5387 if ( (in_byte & 0x21) != 0x21 ) {
5388 return;
5389 }
5390 in_byte = inb(0x60);
5391BX_DEBUG_INT74("int74: read byte %02x\n", in_byte);
5392
5393 mouse_flags_1 = read_byte(ebda_seg, 0x0026);
5394 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
5395
5396 if ( (mouse_flags_2 & 0x80) != 0x80 ) {
5397 return;
5398 }
5399
5400 package_count = mouse_flags_2 & 0x07;
5401 index = mouse_flags_1 & 0x07;
5402 write_byte(ebda_seg, 0x28 + index, in_byte);
5403
5404 if ( index >= package_count ) {
5405BX_DEBUG_INT74("int74_function: make_farcall=1\n");
5406 status = read_byte(ebda_seg, 0x0028 + 0);
5407 X = read_byte(ebda_seg, 0x0028 + 1);
5408 Y = read_byte(ebda_seg, 0x0028 + 2);
5409 Z = 0;
5410 mouse_flags_1 = 0;
5411 // check if far call handler installed
5412 if (mouse_flags_2 & 0x80)
5413 make_farcall = 1;
5414 }
5415 else {
5416 mouse_flags_1++;
5417 }
5418 write_byte(ebda_seg, 0x0026, mouse_flags_1);
5419}
5420
5421#define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
5422
5423#if BX_USE_ATADRV
5424
5425 void
5426int13_harddisk(EHBX, EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5427 Bit16u EHBX, EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5428{
5429 Bit32u lba;
5430 Bit16u ebda_seg=read_word(0x0040,0x000E);
5431 Bit16u cylinder, head, sector;
5432 Bit16u segment, offset;
5433 Bit16u npc, nph, npspt, nlc, nlh, nlspt;
5434 Bit16u size, count;
5435 Bit8u device, status;
5436
5437 BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5438
5439 write_byte(0x0040, 0x008e, 0); // clear completion flag
5440
5441#ifdef VBOX_WITH_SCSI
5442 // basic check : device has to be defined
5443 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_STORAGE_DEVICES) ) {
5444 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5445 goto int13_fail;
5446 }
5447#else
5448 // basic check : device has to be defined
5449 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES) ) {
5450 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5451 goto int13_fail;
5452 }
5453#endif
5454
5455 // Get the ata channel
5456 device=read_byte(ebda_seg,&EbdaData->ata.hdidmap[GET_ELDL()-0x80]);
5457
5458#ifdef VBOX_WITH_SCSI
5459 // basic check : device has to be valid
5460 if (device >= BX_MAX_STORAGE_DEVICES) {
5461 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5462 goto int13_fail;
5463 }
5464#else
5465 // basic check : device has to be valid
5466 if (device >= BX_MAX_ATA_DEVICES) {
5467 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5468 goto int13_fail;
5469 }
5470#endif
5471
5472 switch (GET_AH()) {
5473
5474 case 0x00: /* disk controller reset */
5475#ifdef VBOX_WITH_SCSI
5476 /* SCSI controller does not need a reset. */
5477 if (!VBOX_IS_SCSI_DEVICE(device))
5478#endif
5479 ata_reset (device);
5480 goto int13_success;
5481 break;
5482
5483 case 0x01: /* read disk status */
5484 status = read_byte(0x0040, 0x0074);
5485 SET_AH(status);
5486 SET_DISK_RET_STATUS(0);
5487 /* set CF if error status read */
5488 if (status) goto int13_fail_nostatus;
5489 else goto int13_success_noah;
5490 break;
5491
5492 case 0x02: // read disk sectors
5493 case 0x03: // write disk sectors
5494 case 0x04: // verify disk sectors
5495
5496 count = GET_AL();
5497 cylinder = GET_CH();
5498 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
5499 sector = (GET_CL() & 0x3f);
5500 head = GET_DH();
5501
5502 segment = ES;
5503 offset = BX;
5504
5505 if ( (count > 128) || (count == 0) ) {
5506 BX_INFO("int13_harddisk: function %02x, count out of range!\n",GET_AH());
5507 goto int13_fail;
5508 }
5509
5510#ifdef VBOX_WITH_SCSI
5511 if (!VBOX_IS_SCSI_DEVICE(device))
5512#endif
5513 {
5514 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
5515 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
5516 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
5517 }
5518#ifdef VBOX_WITH_SCSI
5519 else
5520 {
5521 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5522
5523 nlc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.cylinders);
5524 nlh = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.heads);
5525 nlspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.spt);
5526 }
5527#endif
5528
5529 // sanity check on cyl heads, sec
5530 if( (cylinder >= nlc) || (head >= nlh) || (sector > nlspt )) {
5531 BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder, head, sector);
5532 goto int13_fail;
5533 }
5534
5535 // FIXME verify
5536 if ( GET_AH() == 0x04 ) goto int13_success;
5537
5538#ifdef VBOX_WITH_SCSI
5539 if (!VBOX_IS_SCSI_DEVICE(device))
5540#endif
5541 {
5542 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5543 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5544 }
5545#ifdef VBOX_WITH_SCSI
5546 else
5547 {
5548 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5549 nph = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.heads);
5550 npspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.spt);
5551 }
5552#endif
5553
5554 // if needed, translate lchs to lba, and execute command
5555#ifdef VBOX_WITH_SCSI
5556 if (( (nph != nlh) || (npspt != nlspt)) || VBOX_IS_SCSI_DEVICE(device)) {
5557 lba = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
5558 sector = 0; // this forces the command to be lba
5559 }
5560#else
5561 if (( (nph != nlh) || (npspt != nlspt)) ) {
5562 lba = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
5563 sector = 0; // this forces the command to be lba
5564 }
5565#endif
5566
5567 if ( GET_AH() == 0x02 )
5568 {
5569#ifdef VBOX_WITH_SCSI
5570 if (VBOX_IS_SCSI_DEVICE(device))
5571 status=scsi_read_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5572 else
5573#endif
5574 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, cylinder, head, sector, lba, segment, offset);
5575 }
5576 else
5577 {
5578#ifdef VBOX_WITH_SCSI
5579 if (VBOX_IS_SCSI_DEVICE(device))
5580 status=scsi_write_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5581 else
5582#endif
5583 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, cylinder, head, sector, lba, segment, offset);
5584 }
5585
5586 // Set nb of sector transferred
5587 SET_AL(read_word(ebda_seg, &EbdaData->ata.trsfsectors));
5588
5589 if (status != 0) {
5590 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5591 SET_AH(0x0c);
5592 goto int13_fail_noah;
5593 }
5594
5595 goto int13_success;
5596 break;
5597
5598 case 0x05: /* format disk track */
5599 BX_INFO("format disk track called\n");
5600 goto int13_success;
5601 return;
5602 break;
5603
5604 case 0x08: /* read disk drive parameters */
5605
5606 // Get logical geometry from table
5607#ifdef VBOX_WITH_SCSI
5608 if (!VBOX_IS_SCSI_DEVICE(device))
5609#endif
5610 {
5611 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
5612 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
5613 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
5614 }
5615#ifdef VBOX_WITH_SCSI
5616 else
5617 {
5618 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5619 nlc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.cylinders);
5620 nlh = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.heads);
5621 nlspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.spt);
5622 }
5623#endif
5624
5625 count = read_byte(ebda_seg, &EbdaData->ata.hdcount);
5626#ifndef VBOX
5627 nlc = nlc - 2; /* 0 based , last sector not used */
5628#else /* VBOX */
5629 /* Maximum cylinder number is just one less than the number of cylinders. */
5630 nlc = nlc - 1; /* 0 based , last sector not used */
5631#endif /* VBOX */
5632 SET_AL(0);
5633 SET_CH(nlc & 0xff);
5634 SET_CL(((nlc >> 2) & 0xc0) | (nlspt & 0x3f));
5635 SET_DH(nlh - 1);
5636 SET_DL(count); /* FIXME returns 0, 1, or n hard drives */
5637
5638 // FIXME should set ES & DI
5639
5640 goto int13_success;
5641 break;
5642
5643 case 0x10: /* check drive ready */
5644 // should look at 40:8E also???
5645
5646 // Read the status from controller
5647 status = inb(read_word(ebda_seg, &EbdaData->ata.channels[device/2].iobase1) + ATA_CB_STAT);
5648 if ( (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY ) {
5649 goto int13_success;
5650 }
5651 else {
5652 SET_AH(0xAA);
5653 goto int13_fail_noah;
5654 }
5655 break;
5656
5657 case 0x15: /* read disk drive size */
5658
5659 // Get physical geometry from table
5660#ifdef VBOX_WITH_SCSI
5661 if (!VBOX_IS_SCSI_DEVICE(device))
5662#endif
5663 {
5664 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5665 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5666 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5667 }
5668#ifdef VBOX_WITH_SCSI
5669 else
5670 {
5671 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5672 npc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.cylinders);
5673 nph = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.heads);
5674 npspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.spt);
5675 }
5676#endif
5677
5678 // Compute sector count seen by int13
5679#ifndef VBOX
5680 lba = (Bit32u)(npc - 1) * (Bit32u)nph * (Bit32u)npspt;
5681#else /* VBOX */
5682 /* Is it so hard to multiply a couple of counts (without introducing
5683 * arbitrary off by one errors)? */
5684 lba = (Bit32u)npc * (Bit32u)nph * (Bit32u)npspt;
5685#endif /* VBOX */
5686 CX = lba >> 16;
5687 DX = lba & 0xffff;
5688
5689 SET_AH(3); // hard disk accessible
5690 goto int13_success_noah;
5691 break;
5692
5693 case 0x41: // IBM/MS installation check
5694 BX=0xaa55; // install check
5695 SET_AH(0x30); // EDD 3.0
5696 CX=0x0007; // ext disk access and edd, removable supported
5697 goto int13_success_noah;
5698 break;
5699
5700 case 0x42: // IBM/MS extended read
5701 case 0x43: // IBM/MS extended write
5702 case 0x44: // IBM/MS verify
5703 case 0x47: // IBM/MS extended seek
5704
5705 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5706 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5707 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5708
5709 // Can't use 64 bits lba
5710 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5711 if (lba != 0L) {
5712 BX_PANIC("int13_harddisk: function %02x. Can't use 64bits lba\n",GET_AH());
5713 goto int13_fail;
5714 }
5715
5716 // Get 32 bits lba and check
5717 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5718
5719#ifdef VBOX_WITH_SCSI
5720 if (VBOX_IS_SCSI_DEVICE(device))
5721 {
5722 if (lba >= read_dword(ebda_seg, &EbdaData->scsi.devices[VBOX_GET_SCSI_DEVICE(device)].device_info.sectors) ) {
5723 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5724 goto int13_fail;
5725 }
5726 }
5727 else
5728#endif
5729 if (lba >= read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors) ) {
5730 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5731 goto int13_fail;
5732 }
5733
5734
5735 // If verify or seek
5736 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5737 goto int13_success;
5738
5739 // Execute the command
5740 if ( GET_AH() == 0x42 )
5741#ifdef VBOX
5742 {
5743#ifdef VBOX_WITH_SCSI
5744 if (VBOX_IS_SCSI_DEVICE(device))
5745 status=scsi_read_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5746 else
5747#endif
5748 {
5749 if (count >= 256 || lba + count >= 268435456)
5750 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS_EXT, count, 0, 0, 0, lba, segment, offset);
5751 else
5752 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba, segment, offset);
5753 }
5754 }
5755#else /* !VBOX */
5756 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba, segment, offset);
5757#endif /* VBOX */
5758 else
5759#ifdef VBOX
5760 {
5761#ifdef VBOX_WITH_SCSI
5762 if (VBOX_IS_SCSI_DEVICE(device))
5763 status=scsi_write_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5764 else
5765#endif
5766 {
5767 if (count >= 256 || lba + count >= 268435456)
5768 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS_EXT, count, 0, 0, 0, lba, segment, offset);
5769 else
5770 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
5771 }
5772 }
5773#else /* !VBOX */
5774 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
5775#endif /* VBOX */
5776
5777 count=read_word(ebda_seg, &EbdaData->ata.trsfsectors);
5778 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5779
5780 if (status != 0) {
5781 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5782 SET_AH(0x0c);
5783 goto int13_fail_noah;
5784 }
5785
5786 goto int13_success;
5787 break;
5788
5789 case 0x45: // IBM/MS lock/unlock drive
5790 case 0x49: // IBM/MS extended media change
5791 goto int13_success; // Always success for HD
5792 break;
5793
5794 case 0x46: // IBM/MS eject media
5795 SET_AH(0xb2); // Volume Not Removable
5796 goto int13_fail_noah; // Always fail for HD
5797 break;
5798
5799 case 0x48: // IBM/MS get drive parameters
5800 size=read_word(DS,SI+(Bit16u)&Int13DPT->size);
5801
5802 // Buffer is too small
5803 if(size < 0x1a)
5804 goto int13_fail;
5805
5806 // EDD 1.x
5807 if(size >= 0x1a) {
5808 Bit16u blksize;
5809
5810#ifdef VBOX_WITH_SCSI
5811 if (!VBOX_IS_SCSI_DEVICE(device))
5812#endif
5813 {
5814 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5815 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5816 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5817 lba = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors);
5818 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5819 }
5820#ifdef VBOX_WITH_SCSI
5821 else
5822 {
5823 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5824 npc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.cylinders);
5825 nph = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.heads);
5826 npspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.spt);
5827 lba = read_dword(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.sectors);
5828 blksize = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.blksize);
5829 }
5830#endif
5831
5832 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5833 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x02); // geometry is valid
5834 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, (Bit32u)npc);
5835 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, (Bit32u)nph);
5836 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, (Bit32u)npspt);
5837 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, lba); // FIXME should be Bit64
5838 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0L);
5839 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5840 }
5841
5842 // EDD 2.x
5843 if(size >= 0x1e) {
5844 Bit8u channel, dev, irq, mode, checksum, i, translation;
5845 Bit16u iobase1, iobase2, options;
5846
5847 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5848
5849 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5850 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5851
5852 // Fill in dpte
5853 channel = device / 2;
5854 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5855 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5856 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5857 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5858 translation = read_byte(ebda_seg, &EbdaData->ata.devices[device].translation);
5859
5860 options = (translation==ATA_TRANSLATION_NONE?0:1<<3); // chs translation
5861 options |= (1<<4); // lba translation
5862 options |= (mode==ATA_MODE_PIO32?1:0<<7);
5863 options |= (translation==ATA_TRANSLATION_LBA?1:0<<9);
5864 options |= (translation==ATA_TRANSLATION_RECHS?3:0<<9);
5865
5866 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5867 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5868 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5869 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5870 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5871 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5872 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5873 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5874 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5875 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5876 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5877
5878 checksum=0;
5879 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5880 checksum = ~checksum;
5881 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5882 }
5883
5884 // EDD 3.x
5885 if(size >= 0x42) {
5886 Bit8u channel, iface, checksum, i;
5887 Bit16u iobase1;
5888
5889 channel = device / 2;
5890 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5891 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5892
5893 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5894 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5895 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5896 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5897 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5898
5899 if (iface==ATA_IFACE_ISA) {
5900 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5901 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5902 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5903 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5904 }
5905 else {
5906 // FIXME PCI
5907 }
5908 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5909 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5910 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5911 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5912
5913 if (iface==ATA_IFACE_ISA) {
5914 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5915 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5916 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5917 }
5918 else {
5919 // FIXME PCI
5920 }
5921 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5922 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5923 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5924 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5925
5926 checksum=0;
5927 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5928 checksum = ~checksum;
5929 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5930 }
5931
5932 goto int13_success;
5933 break;
5934
5935 case 0x4e: // // IBM/MS set hardware configuration
5936 // DMA, prefetch, PIO maximum not supported
5937 switch (GET_AL()) {
5938 case 0x01:
5939 case 0x03:
5940 case 0x04:
5941 case 0x06:
5942 goto int13_success;
5943 break;
5944 default :
5945 goto int13_fail;
5946 }
5947 break;
5948
5949 case 0x09: /* initialize drive parameters */
5950 case 0x0c: /* seek to specified cylinder */
5951 case 0x0d: /* alternate disk reset */
5952 case 0x11: /* recalibrate */
5953 case 0x14: /* controller internal diagnostic */
5954 BX_INFO("int13_harddisk: function %02xh unimplemented, returns success\n", GET_AH());
5955 goto int13_success;
5956 break;
5957
5958 case 0x0a: /* read disk sectors with ECC */
5959 case 0x0b: /* write disk sectors with ECC */
5960 case 0x18: // set media type for format
5961 case 0x50: // IBM/MS send packet command
5962 default:
5963 BX_INFO("int13_harddisk: function %02xh unsupported, returns fail\n", GET_AH());
5964 goto int13_fail;
5965 break;
5966 }
5967
5968int13_fail:
5969 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5970int13_fail_noah:
5971 SET_DISK_RET_STATUS(GET_AH());
5972int13_fail_nostatus:
5973 SET_CF(); // error occurred
5974 return;
5975
5976int13_success:
5977 SET_AH(0x00); // no error
5978int13_success_noah:
5979 SET_DISK_RET_STATUS(0x00);
5980 CLEAR_CF(); // no error
5981 return;
5982}
5983
5984// ---------------------------------------------------------------------------
5985// Start of int13 for cdrom
5986// ---------------------------------------------------------------------------
5987
5988 void
5989int13_cdrom(EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5990 Bit16u EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5991{
5992 Bit16u ebda_seg=read_word(0x0040,0x000E);
5993 Bit8u device, status, locks;
5994 Bit8u atacmd[12];
5995 Bit32u lba;
5996 Bit16u count, segment, offset, i, size;
5997
5998 BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5999
6000 SET_DISK_RET_STATUS(0x00);
6001
6002 /* basic check : device should be 0xE0+ */
6003 if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES) ) {
6004 BX_INFO("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
6005 goto int13_fail;
6006 }
6007
6008 // Get the ata channel
6009 device=read_byte(ebda_seg,&EbdaData->ata.cdidmap[GET_ELDL()-0xE0]);
6010
6011 /* basic check : device has to be valid */
6012 if (device >= BX_MAX_ATA_DEVICES) {
6013 BX_INFO("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
6014 goto int13_fail;
6015 }
6016
6017 switch (GET_AH()) {
6018
6019 // all those functions return SUCCESS
6020 case 0x00: /* disk controller reset */
6021 case 0x09: /* initialize drive parameters */
6022 case 0x0c: /* seek to specified cylinder */
6023 case 0x0d: /* alternate disk reset */
6024 case 0x10: /* check drive ready */
6025 case 0x11: /* recalibrate */
6026 case 0x14: /* controller internal diagnostic */
6027 case 0x16: /* detect disk change */
6028 goto int13_success;
6029 break;
6030
6031 // all those functions return disk write-protected
6032 case 0x03: /* write disk sectors */
6033 case 0x05: /* format disk track */
6034 case 0x43: // IBM/MS extended write
6035 SET_AH(0x03);
6036 goto int13_fail_noah;
6037 break;
6038
6039 case 0x01: /* read disk status */
6040 status = read_byte(0x0040, 0x0074);
6041 SET_AH(status);
6042 SET_DISK_RET_STATUS(0);
6043
6044 /* set CF if error status read */
6045 if (status) goto int13_fail_nostatus;
6046 else goto int13_success_noah;
6047 break;
6048
6049 case 0x15: /* read disk drive size */
6050 SET_AH(0x02);
6051 goto int13_fail_noah;
6052 break;
6053
6054 case 0x41: // IBM/MS installation check
6055 BX=0xaa55; // install check
6056 SET_AH(0x30); // EDD 2.1
6057 CX=0x0007; // ext disk access, removable and edd
6058 goto int13_success_noah;
6059 break;
6060
6061 case 0x42: // IBM/MS extended read
6062 case 0x44: // IBM/MS verify sectors
6063 case 0x47: // IBM/MS extended seek
6064
6065 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
6066 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
6067 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
6068
6069 // Can't use 64 bits lba
6070 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
6071 if (lba != 0L) {
6072 BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
6073 goto int13_fail;
6074 }
6075
6076 // Get 32 bits lba
6077 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
6078
6079 // If verify or seek
6080 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
6081 goto int13_success;
6082
6083 memsetb(get_SS(),atacmd,0,12);
6084 atacmd[0]=0x28; // READ command
6085 atacmd[7]=(count & 0xff00) >> 8; // Sectors
6086 atacmd[8]=(count & 0x00ff); // Sectors
6087 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
6088 atacmd[3]=(lba & 0x00ff0000) >> 16;
6089 atacmd[4]=(lba & 0x0000ff00) >> 8;
6090 atacmd[5]=(lba & 0x000000ff);
6091 status = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, count*2048L, ATA_DATA_IN, segment,offset);
6092
6093 count = (Bit16u)(read_dword(ebda_seg, &EbdaData->ata.trsfbytes) >> 11);
6094 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
6095
6096 if (status != 0) {
6097 BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status);
6098 SET_AH(0x0c);
6099 goto int13_fail_noah;
6100 }
6101
6102 goto int13_success;
6103 break;
6104
6105 case 0x45: // IBM/MS lock/unlock drive
6106 if (GET_AL() > 2) goto int13_fail;
6107
6108 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
6109
6110 switch (GET_AL()) {
6111 case 0 : // lock
6112 if (locks == 0xff) {
6113 SET_AH(0xb4);
6114 SET_AL(1);
6115 goto int13_fail_noah;
6116 }
6117 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, ++locks);
6118 SET_AL(1);
6119 break;
6120 case 1 : // unlock
6121 if (locks == 0x00) {
6122 SET_AH(0xb0);
6123 SET_AL(0);
6124 goto int13_fail_noah;
6125 }
6126 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, --locks);
6127 SET_AL(locks==0?0:1);
6128 break;
6129 case 2 : // status
6130 SET_AL(locks==0?0:1);
6131 break;
6132 }
6133 goto int13_success;
6134 break;
6135
6136 case 0x46: // IBM/MS eject media
6137 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
6138
6139 if (locks != 0) {
6140 SET_AH(0xb1); // media locked
6141 goto int13_fail_noah;
6142 }
6143 // FIXME should handle 0x31 no media in device
6144 // FIXME should handle 0xb5 valid request failed
6145
6146 // Call removable media eject
6147 ASM_START
6148 push bp
6149 mov bp, sp
6150
6151 mov ah, #0x52
6152 int #0x15
6153 mov _int13_cdrom.status + 2[bp], ah
6154 jnc int13_cdrom_rme_end
6155 mov _int13_cdrom.status, #1
6156int13_cdrom_rme_end:
6157 pop bp
6158 ASM_END
6159
6160 if (status != 0) {
6161 SET_AH(0xb1); // media locked
6162 goto int13_fail_noah;
6163 }
6164
6165 goto int13_success;
6166 break;
6167
6168 case 0x48: // IBM/MS get drive parameters
6169 size = read_word(DS,SI+(Bit16u)&Int13Ext->size);
6170
6171 // Buffer is too small
6172 if(size < 0x1a)
6173 goto int13_fail;
6174
6175 // EDD 1.x
6176 if(size >= 0x1a) {
6177 Bit16u cylinders, heads, spt, blksize;
6178
6179 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
6180
6181 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
6182 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x74); // removable, media change, lockable, max values
6183 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, 0xffffffff);
6184 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, 0xffffffff);
6185 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, 0xffffffff);
6186 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, 0xffffffff); // FIXME should be Bit64
6187 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0xffffffff);
6188 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
6189 }
6190
6191 // EDD 2.x
6192 if(size >= 0x1e) {
6193 Bit8u channel, dev, irq, mode, checksum, i;
6194 Bit16u iobase1, iobase2, options;
6195
6196 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
6197
6198 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
6199 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
6200
6201 // Fill in dpte
6202 channel = device / 2;
6203 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
6204 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
6205 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
6206 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
6207
6208 // FIXME atapi device
6209 options = (1<<4); // lba translation
6210 options |= (1<<5); // removable device
6211 options |= (1<<6); // atapi device
6212 options |= (mode==ATA_MODE_PIO32?1:0<<7);
6213
6214 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
6215 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
6216 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
6217 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
6218 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
6219 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
6220 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
6221 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
6222 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
6223 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
6224 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
6225
6226 checksum=0;
6227 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
6228 checksum = ~checksum;
6229 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
6230 }
6231
6232 // EDD 3.x
6233 if(size >= 0x42) {
6234 Bit8u channel, iface, checksum, i;
6235 Bit16u iobase1;
6236
6237 channel = device / 2;
6238 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
6239 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
6240
6241 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
6242 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
6243 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
6244 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
6245 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
6246
6247 if (iface==ATA_IFACE_ISA) {
6248 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
6249 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
6250 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
6251 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
6252 }
6253 else {
6254 // FIXME PCI
6255 }
6256 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
6257 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
6258 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
6259 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
6260
6261 if (iface==ATA_IFACE_ISA) {
6262 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
6263 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
6264 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
6265 }
6266 else {
6267 // FIXME PCI
6268 }
6269 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
6270 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
6271 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
6272 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
6273
6274 checksum=0;
6275 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
6276 checksum = ~checksum;
6277 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
6278 }
6279
6280 goto int13_success;
6281 break;
6282
6283 case 0x49: // IBM/MS extended media change
6284 // always send changed ??
6285 SET_AH(06);
6286 goto int13_fail_nostatus;
6287 break;
6288
6289 case 0x4e: // // IBM/MS set hardware configuration
6290 // DMA, prefetch, PIO maximum not supported
6291 switch (GET_AL()) {
6292 case 0x01:
6293 case 0x03:
6294 case 0x04:
6295 case 0x06:
6296 goto int13_success;
6297 break;
6298 default :
6299 goto int13_fail;
6300 }
6301 break;
6302
6303 // all those functions return unimplemented
6304 case 0x02: /* read sectors */
6305 case 0x04: /* verify sectors */
6306 case 0x08: /* read disk drive parameters */
6307 case 0x0a: /* read disk sectors with ECC */
6308 case 0x0b: /* write disk sectors with ECC */
6309 case 0x18: /* set media type for format */
6310 case 0x50: // ? - send packet command
6311 default:
6312 BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
6313 goto int13_fail;
6314 break;
6315 }
6316
6317int13_fail:
6318 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6319int13_fail_noah:
6320 SET_DISK_RET_STATUS(GET_AH());
6321int13_fail_nostatus:
6322 SET_CF(); // error occurred
6323 return;
6324
6325int13_success:
6326 SET_AH(0x00); // no error
6327int13_success_noah:
6328 SET_DISK_RET_STATUS(0x00);
6329 CLEAR_CF(); // no error
6330 return;
6331}
6332
6333// ---------------------------------------------------------------------------
6334// End of int13 for cdrom
6335// ---------------------------------------------------------------------------
6336
6337#if BX_ELTORITO_BOOT
6338// ---------------------------------------------------------------------------
6339// Start of int13 for eltorito functions
6340// ---------------------------------------------------------------------------
6341
6342 void
6343int13_eltorito(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
6344 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
6345{
6346 Bit16u ebda_seg=read_word(0x0040,0x000E);
6347
6348 BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6349 // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
6350
6351 switch (GET_AH()) {
6352
6353 // FIXME ElTorito Various. Should be implemented
6354 case 0x4a: // ElTorito - Initiate disk emu
6355 case 0x4c: // ElTorito - Initiate disk emu and boot
6356 case 0x4d: // ElTorito - Return Boot catalog
6357 BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX);
6358 goto int13_fail;
6359 break;
6360
6361 case 0x4b: // ElTorito - Terminate disk emu
6362 // FIXME ElTorito Hardcoded
6363 write_byte(DS,SI+0x00,0x13);
6364 write_byte(DS,SI+0x01,read_byte(ebda_seg,&EbdaData->cdemu.media));
6365 write_byte(DS,SI+0x02,read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
6366 write_byte(DS,SI+0x03,read_byte(ebda_seg,&EbdaData->cdemu.controller_index));
6367 write_dword(DS,SI+0x04,read_dword(ebda_seg,&EbdaData->cdemu.ilba));
6368 write_word(DS,SI+0x08,read_word(ebda_seg,&EbdaData->cdemu.device_spec));
6369 write_word(DS,SI+0x0a,read_word(ebda_seg,&EbdaData->cdemu.buffer_segment));
6370 write_word(DS,SI+0x0c,read_word(ebda_seg,&EbdaData->cdemu.load_segment));
6371 write_word(DS,SI+0x0e,read_word(ebda_seg,&EbdaData->cdemu.sector_count));
6372 write_byte(DS,SI+0x10,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.cylinders));
6373 write_byte(DS,SI+0x11,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.spt));
6374 write_byte(DS,SI+0x12,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.heads));
6375
6376 // If we have to terminate emulation
6377 if(GET_AL() == 0x00) {
6378 // FIXME ElTorito Various. Should be handled accordingly to spec
6379 write_byte(ebda_seg,&EbdaData->cdemu.active, 0x00); // bye bye
6380 }
6381
6382 goto int13_success;
6383 break;
6384
6385 default:
6386 BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
6387 goto int13_fail;
6388 break;
6389 }
6390
6391int13_fail:
6392 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6393 SET_DISK_RET_STATUS(GET_AH());
6394 SET_CF(); // error occurred
6395 return;
6396
6397int13_success:
6398 SET_AH(0x00); // no error
6399 SET_DISK_RET_STATUS(0x00);
6400 CLEAR_CF(); // no error
6401 return;
6402}
6403
6404// ---------------------------------------------------------------------------
6405// End of int13 for eltorito functions
6406// ---------------------------------------------------------------------------
6407
6408// ---------------------------------------------------------------------------
6409// Start of int13 when emulating a device from the cd
6410// ---------------------------------------------------------------------------
6411
6412 void
6413int13_cdemu(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
6414 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
6415{
6416 Bit16u ebda_seg=read_word(0x0040,0x000E);
6417 Bit8u device, status;
6418 Bit16u vheads, vspt, vcylinders;
6419 Bit16u head, sector, cylinder, nbsectors;
6420 Bit32u vlba, ilba, slba, elba;
6421 Bit16u before, segment, offset;
6422 Bit8u atacmd[12];
6423
6424 BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6425
6426 /* at this point, we are emulating a floppy/harddisk */
6427
6428 // Recompute the device number
6429 device = read_byte(ebda_seg,&EbdaData->cdemu.controller_index) * 2;
6430 device += read_byte(ebda_seg,&EbdaData->cdemu.device_spec);
6431
6432 SET_DISK_RET_STATUS(0x00);
6433
6434 /* basic checks : emulation should be active, dl should equal the emulated drive */
6435 if( (read_byte(ebda_seg,&EbdaData->cdemu.active) ==0 )
6436 || (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive ) != GET_DL())) {
6437 BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
6438 goto int13_fail;
6439 }
6440
6441 switch (GET_AH()) {
6442
6443 // all those functions return SUCCESS
6444 case 0x00: /* disk controller reset */
6445 case 0x09: /* initialize drive parameters */
6446 case 0x0c: /* seek to specified cylinder */
6447 case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
6448 case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
6449 case 0x11: /* recalibrate */
6450 case 0x14: /* controller internal diagnostic */
6451 case 0x16: /* detect disk change */
6452 goto int13_success;
6453 break;
6454
6455 // all those functions return disk write-protected
6456 case 0x03: /* write disk sectors */
6457 case 0x05: /* format disk track */
6458 SET_AH(0x03);
6459 goto int13_fail_noah;
6460 break;
6461
6462 case 0x01: /* read disk status */
6463 status=read_byte(0x0040, 0x0074);
6464 SET_AH(status);
6465 SET_DISK_RET_STATUS(0);
6466
6467 /* set CF if error status read */
6468 if (status) goto int13_fail_nostatus;
6469 else goto int13_success_noah;
6470 break;
6471
6472 case 0x02: // read disk sectors
6473 case 0x04: // verify disk sectors
6474 vspt = read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
6475 vcylinders = read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders);
6476 vheads = read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads);
6477
6478 ilba = read_dword(ebda_seg,&EbdaData->cdemu.ilba);
6479
6480 sector = GET_CL() & 0x003f;
6481 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
6482 head = GET_DH();
6483 nbsectors = GET_AL();
6484 segment = ES;
6485 offset = BX;
6486
6487 // no sector to read ?
6488 if(nbsectors==0) goto int13_success;
6489
6490 // sanity checks sco openserver needs this!
6491 if ((sector > vspt)
6492 || (cylinder >= vcylinders)
6493 || (head >= vheads)) {
6494 goto int13_fail;
6495 }
6496
6497 // After controls, verify do nothing
6498 if (GET_AH() == 0x04) goto int13_success;
6499
6500 segment = ES+(BX / 16);
6501 offset = BX % 16;
6502
6503 // calculate the virtual lba inside the image
6504 vlba=((((Bit32u)cylinder*(Bit32u)vheads)+(Bit32u)head)*(Bit32u)vspt)+((Bit32u)(sector-1));
6505
6506 // In advance so we don't loose the count
6507 SET_AL(nbsectors);
6508
6509 // start lba on cd
6510 slba = (Bit32u)vlba/4;
6511 before= (Bit16u)vlba%4;
6512
6513 // end lba on cd
6514 elba = (Bit32u)(vlba+nbsectors-1)/4;
6515
6516 memsetb(get_SS(),atacmd,0,12);
6517 atacmd[0]=0x28; // READ command
6518 atacmd[7]=((Bit16u)(elba-slba+1) & 0xff00) >> 8; // Sectors
6519 atacmd[8]=((Bit16u)(elba-slba+1) & 0x00ff); // Sectors
6520 atacmd[2]=(ilba+slba & 0xff000000) >> 24; // LBA
6521 atacmd[3]=(ilba+slba & 0x00ff0000) >> 16;
6522 atacmd[4]=(ilba+slba & 0x0000ff00) >> 8;
6523 atacmd[5]=(ilba+slba & 0x000000ff);
6524 if((status = ata_cmd_packet(device, 12, get_SS(), atacmd, before*512, nbsectors*512L, ATA_DATA_IN, segment,offset)) != 0) {
6525 BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status);
6526 SET_AH(0x02);
6527 SET_AL(0);
6528 goto int13_fail_noah;
6529 }
6530
6531 goto int13_success;
6532 break;
6533
6534 case 0x08: /* read disk drive parameters */
6535 vspt=read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
6536 vcylinders=read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders) - 1;
6537 vheads=read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads) - 1;
6538
6539 SET_AL( 0x00 );
6540 SET_BL( 0x00 );
6541 SET_CH( vcylinders & 0xff );
6542 SET_CL((( vcylinders >> 2) & 0xc0) | ( vspt & 0x3f ));
6543 SET_DH( vheads );
6544 SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2
6545 // FIXME ElTorito Harddisk. should send the HD count
6546
6547 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
6548 case 0x01: SET_BL( 0x02 ); break;
6549 case 0x02: SET_BL( 0x04 ); break;
6550 case 0x03: SET_BL( 0x06 ); break;
6551 }
6552
6553ASM_START
6554 push bp
6555 mov bp, sp
6556 mov ax, #diskette_param_table2
6557 mov _int13_cdemu.DI+2[bp], ax
6558 mov _int13_cdemu.ES+2[bp], cs
6559 pop bp
6560ASM_END
6561 goto int13_success;
6562 break;
6563
6564 case 0x15: /* read disk drive size */
6565 // FIXME ElTorito Harddisk. What geometry to send ?
6566 SET_AH(0x03);
6567 goto int13_success_noah;
6568 break;
6569
6570 // all those functions return unimplemented
6571 case 0x0a: /* read disk sectors with ECC */
6572 case 0x0b: /* write disk sectors with ECC */
6573 case 0x18: /* set media type for format */
6574 case 0x41: // IBM/MS installation check
6575 // FIXME ElTorito Harddisk. Darwin would like to use EDD
6576 case 0x42: // IBM/MS extended read
6577 case 0x43: // IBM/MS extended write
6578 case 0x44: // IBM/MS verify sectors
6579 case 0x45: // IBM/MS lock/unlock drive
6580 case 0x46: // IBM/MS eject media
6581 case 0x47: // IBM/MS extended seek
6582 case 0x48: // IBM/MS get drive parameters
6583 case 0x49: // IBM/MS extended media change
6584 case 0x4e: // ? - set hardware configuration
6585 case 0x50: // ? - send packet command
6586 default:
6587 BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
6588 goto int13_fail;
6589 break;
6590 }
6591
6592int13_fail:
6593 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6594int13_fail_noah:
6595 SET_DISK_RET_STATUS(GET_AH());
6596int13_fail_nostatus:
6597 SET_CF(); // error occurred
6598 return;
6599
6600int13_success:
6601 SET_AH(0x00); // no error
6602int13_success_noah:
6603 SET_DISK_RET_STATUS(0x00);
6604 CLEAR_CF(); // no error
6605 return;
6606}
6607
6608// ---------------------------------------------------------------------------
6609// End of int13 when emulating a device from the cd
6610// ---------------------------------------------------------------------------
6611
6612#endif // BX_ELTORITO_BOOT
6613
6614#else //BX_USE_ATADRV
6615
6616 void
6617outLBA(cylinder,hd_heads,head,hd_sectors,sector,dl)
6618 Bit16u cylinder;
6619 Bit16u hd_heads;
6620 Bit16u head;
6621 Bit16u hd_sectors;
6622 Bit16u sector;
6623 Bit16u dl;
6624{
6625ASM_START
6626 push bp
6627 mov bp, sp
6628 push eax
6629 push ebx
6630 push edx
6631 xor eax,eax
6632 mov ax,4[bp] // cylinder
6633 xor ebx,ebx
6634 mov bl,6[bp] // hd_heads
6635 imul ebx
6636
6637 mov bl,8[bp] // head
6638 add eax,ebx
6639 mov bl,10[bp] // hd_sectors
6640 imul ebx
6641 mov bl,12[bp] // sector
6642 add eax,ebx
6643
6644 dec eax
6645 mov dx,#0x1f3
6646 out dx,al
6647 mov dx,#0x1f4
6648 mov al,ah
6649 out dx,al
6650 shr eax,#16
6651 mov dx,#0x1f5
6652 out dx,al
6653 and ah,#0xf
6654 mov bl,14[bp] // dl
6655 and bl,#1
6656 shl bl,#4
6657 or ah,bl
6658 or ah,#0xe0
6659 mov al,ah
6660 mov dx,#0x01f6
6661 out dx,al
6662 pop edx
6663 pop ebx
6664 pop eax
6665 pop bp
6666ASM_END
6667}
6668
6669 void
6670int13_harddisk(EHBX, EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
6671 Bit16u EHBX, EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
6672{
6673 Bit8u drive, num_sectors, sector, head, status, mod;
6674 Bit8u drive_map;
6675 Bit8u n_drives;
6676 Bit16u cyl_mod, ax;
6677 Bit16u max_cylinder, cylinder, total_sectors;
6678 Bit16u hd_cylinders;
6679 Bit8u hd_heads, hd_sectors;
6680 Bit16u val16;
6681 Bit8u sector_count;
6682 unsigned int i;
6683 Bit16u tempbx;
6684 Bit16u dpsize;
6685
6686 Bit16u count, segment, offset;
6687 Bit32u lba;
6688 Bit16u error;
6689
6690 BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6691
6692 write_byte(0x0040, 0x008e, 0); // clear completion flag
6693
6694 /* at this point, DL is >= 0x80 to be passed from the floppy int13h
6695 handler code */
6696 /* check how many disks first (cmos reg 0x12), return an error if
6697 drive not present */
6698 drive_map = inb_cmos(0x12);
6699 drive_map = (((drive_map & 0xf0)==0) ? 0 : 1) |
6700 (((drive_map & 0x0f)==0) ? 0 : 2);
6701 n_drives = (drive_map==0) ? 0 :
6702 ((drive_map==3) ? 2 : 1);
6703
6704 if (!(drive_map & (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
6705 SET_AH(0x01);
6706 SET_DISK_RET_STATUS(0x01);
6707 SET_CF(); /* error occurred */
6708 return;
6709 }
6710
6711 switch (GET_AH()) {
6712
6713 case 0x00: /* disk controller reset */
6714BX_DEBUG_INT13_HD("int13_f00\n");
6715
6716 SET_AH(0);
6717 SET_DISK_RET_STATUS(0);
6718 set_diskette_ret_status(0);
6719 set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
6720 set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
6721 CLEAR_CF(); /* successful */
6722 return;
6723 break;
6724
6725 case 0x01: /* read disk status */
6726BX_DEBUG_INT13_HD("int13_f01\n");
6727 status = read_byte(0x0040, 0x0074);
6728 SET_AH(status);
6729 SET_DISK_RET_STATUS(0);
6730 /* set CF if error status read */
6731 if (status) SET_CF();
6732 else CLEAR_CF();
6733 return;
6734 break;
6735
6736 case 0x04: // verify disk sectors
6737 case 0x02: // read disk sectors
6738 drive = GET_ELDL();
6739 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6740
6741 num_sectors = GET_AL();
6742 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
6743 sector = (GET_CL() & 0x3f);
6744 head = GET_DH();
6745
6746
6747 if (hd_cylinders > 1024) {
6748 if (hd_cylinders <= 2048) {
6749 cylinder <<= 1;
6750 }
6751 else if (hd_cylinders <= 4096) {
6752 cylinder <<= 2;
6753 }
6754 else if (hd_cylinders <= 8192) {
6755 cylinder <<= 3;
6756 }
6757 else { // hd_cylinders <= 16384
6758 cylinder <<= 4;
6759 }
6760
6761 ax = head / hd_heads;
6762 cyl_mod = ax & 0xff;
6763 head = ax >> 8;
6764 cylinder |= cyl_mod;
6765 }
6766
6767 if ( (cylinder >= hd_cylinders) ||
6768 (sector > hd_sectors) ||
6769 (head >= hd_heads) ) {
6770 SET_AH(1);
6771 SET_DISK_RET_STATUS(1);
6772 SET_CF(); /* error occurred */
6773 return;
6774 }
6775
6776 if ( (num_sectors > 128) || (num_sectors == 0) )
6777 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6778
6779 if (head > 15)
6780 BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
6781
6782 if ( GET_AH() == 0x04 ) {
6783 SET_AH(0);
6784 SET_DISK_RET_STATUS(0);
6785 CLEAR_CF();
6786 return;
6787 }
6788
6789 status = inb(0x1f7);
6790 if (status & 0x80) {
6791 BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
6792 }
6793 outb(0x01f2, num_sectors);
6794 /* activate LBA? (tomv) */
6795 if (hd_heads > 16) {
6796BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder, head, sector);
6797 outLBA(cylinder,hd_heads,head,hd_sectors,sector,drive);
6798 }
6799 else {
6800 outb(0x01f3, sector);
6801 outb(0x01f4, cylinder & 0x00ff);
6802 outb(0x01f5, cylinder >> 8);
6803 outb(0x01f6, 0xa0 | ((drive & 0x01)<<4) | (head & 0x0f));
6804 }
6805 outb(0x01f7, 0x20);
6806
6807 while (1) {
6808 status = inb(0x1f7);
6809 if ( !(status & 0x80) ) break;
6810 }
6811
6812 if (status & 0x01) {
6813 BX_PANIC("hard drive BIOS:(read/verify) read error\n");
6814 } else if ( !(status & 0x08) ) {
6815 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6816 BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
6817 }
6818
6819 sector_count = 0;
6820 tempbx = BX;
6821
6822ASM_START
6823 sti ;; enable higher priority interrupts
6824ASM_END
6825
6826 while (1) {
6827ASM_START
6828 ;; store temp bx in real DI register
6829 push bp
6830 mov bp, sp
6831 mov di, _int13_harddisk.tempbx + 2 [bp]
6832 pop bp
6833
6834 ;; adjust if there will be an overrun
6835 cmp di, #0xfe00
6836 jbe i13_f02_no_adjust
6837i13_f02_adjust:
6838 sub di, #0x0200 ; sub 512 bytes from offset
6839 mov ax, es
6840 add ax, #0x0020 ; add 512 to segment
6841 mov es, ax
6842
6843i13_f02_no_adjust:
6844 mov cx, #0x0100 ;; counter (256 words = 512b)
6845 mov dx, #0x01f0 ;; AT data read port
6846
6847 rep
6848 insw ;; CX words transferred from port(DX) to ES:[DI]
6849
6850i13_f02_done:
6851 ;; store real DI register back to temp bx
6852 push bp
6853 mov bp, sp
6854 mov _int13_harddisk.tempbx + 2 [bp], di
6855 pop bp
6856ASM_END
6857
6858 sector_count++;
6859 num_sectors--;
6860 if (num_sectors == 0) {
6861 status = inb(0x1f7);
6862 if ( (status & 0xc9) != 0x40 )
6863 BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status);
6864 break;
6865 }
6866 else {
6867 status = inb(0x1f7);
6868 if ( (status & 0xc9) != 0x48 )
6869 BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status);
6870 continue;
6871 }
6872 }
6873
6874 SET_AH(0);
6875 SET_DISK_RET_STATUS(0);
6876 SET_AL(sector_count);
6877 CLEAR_CF(); /* successful */
6878 return;
6879 break;
6880
6881
6882 case 0x03: /* write disk sectors */
6883BX_DEBUG_INT13_HD("int13_f03\n");
6884 drive = GET_ELDL ();
6885 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6886
6887 num_sectors = GET_AL();
6888 cylinder = GET_CH();
6889 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
6890 sector = (GET_CL() & 0x3f);
6891 head = GET_DH();
6892
6893 if (hd_cylinders > 1024) {
6894 if (hd_cylinders <= 2048) {
6895 cylinder <<= 1;
6896 }
6897 else if (hd_cylinders <= 4096) {
6898 cylinder <<= 2;
6899 }
6900 else if (hd_cylinders <= 8192) {
6901 cylinder <<= 3;
6902 }
6903 else { // hd_cylinders <= 16384
6904 cylinder <<= 4;
6905 }
6906
6907 ax = head / hd_heads;
6908 cyl_mod = ax & 0xff;
6909 head = ax >> 8;
6910 cylinder |= cyl_mod;
6911 }
6912
6913 if ( (cylinder >= hd_cylinders) ||
6914 (sector > hd_sectors) ||
6915 (head >= hd_heads) ) {
6916 SET_AH( 1);
6917 SET_DISK_RET_STATUS(1);
6918 SET_CF(); /* error occurred */
6919 return;
6920 }
6921
6922 if ( (num_sectors > 128) || (num_sectors == 0) )
6923 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6924
6925 if (head > 15)
6926 BX_PANIC("hard drive BIOS:(read) head > 15\n");
6927
6928 status = inb(0x1f7);
6929 if (status & 0x80) {
6930 BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
6931 }
6932// should check for Drive Ready Bit also in status reg
6933 outb(0x01f2, num_sectors);
6934
6935 /* activate LBA? (tomv) */
6936 if (hd_heads > 16) {
6937BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder, head, sector);
6938 outLBA(cylinder,hd_heads,head,hd_sectors,sector,GET_ELDL());
6939 }
6940 else {
6941 outb(0x01f3, sector);
6942 outb(0x01f4, cylinder & 0x00ff);
6943 outb(0x01f5, cylinder >> 8);
6944 outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head & 0x0f));
6945 }
6946 outb(0x01f7, 0x30);
6947
6948 // wait for busy bit to turn off after seeking
6949 while (1) {
6950 status = inb(0x1f7);
6951 if ( !(status & 0x80) ) break;
6952 }
6953
6954 if ( !(status & 0x08) ) {
6955 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6956 BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
6957 }
6958
6959 sector_count = 0;
6960 tempbx = BX;
6961
6962ASM_START
6963 sti ;; enable higher priority interrupts
6964ASM_END
6965
6966 while (1) {
6967ASM_START
6968 ;; store temp bx in real SI register
6969 push bp
6970 mov bp, sp
6971 mov si, _int13_harddisk.tempbx + 2 [bp]
6972 pop bp
6973
6974 ;; adjust if there will be an overrun
6975 cmp si, #0xfe00
6976 jbe i13_f03_no_adjust
6977i13_f03_adjust:
6978 sub si, #0x0200 ; sub 512 bytes from offset
6979 mov ax, es
6980 add ax, #0x0020 ; add 512 to segment
6981 mov es, ax
6982
6983i13_f03_no_adjust:
6984 mov cx, #0x0100 ;; counter (256 words = 512b)
6985 mov dx, #0x01f0 ;; AT data read port
6986
6987 seg ES
6988 rep
6989 outsw ;; CX words transferred from ES:[SI] to port(DX)
6990
6991 ;; store real SI register back to temp bx
6992 push bp
6993 mov bp, sp
6994 mov _int13_harddisk.tempbx + 2 [bp], si
6995 pop bp
6996ASM_END
6997
6998 sector_count++;
6999 num_sectors--;
7000 if (num_sectors == 0) {
7001 status = inb(0x1f7);
7002 if ( (status & 0xe9) != 0x40 )
7003 BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status);
7004 break;
7005 }
7006 else {
7007 status = inb(0x1f7);
7008 if ( (status & 0xc9) != 0x48 )
7009 BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status);
7010 continue;
7011 }
7012 }
7013
7014 SET_AH(0);
7015 SET_DISK_RET_STATUS(0);
7016 SET_AL(sector_count);
7017 CLEAR_CF(); /* successful */
7018 return;
7019 break;
7020
7021 case 0x05: /* format disk track */
7022BX_DEBUG_INT13_HD("int13_f05\n");
7023 BX_PANIC("format disk track called\n");
7024 /* nop */
7025 SET_AH(0);
7026 SET_DISK_RET_STATUS(0);
7027 CLEAR_CF(); /* successful */
7028 return;
7029 break;
7030
7031 case 0x08: /* read disk drive parameters */
7032BX_DEBUG_INT13_HD("int13_f08\n");
7033
7034 drive = GET_ELDL ();
7035 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
7036
7037 // translate CHS
7038 //
7039 if (hd_cylinders <= 1024) {
7040 // hd_cylinders >>= 0;
7041 // hd_heads <<= 0;
7042 }
7043 else if (hd_cylinders <= 2048) {
7044 hd_cylinders >>= 1;
7045 hd_heads <<= 1;
7046 }
7047 else if (hd_cylinders <= 4096) {
7048 hd_cylinders >>= 2;
7049 hd_heads <<= 2;
7050 }
7051 else if (hd_cylinders <= 8192) {
7052 hd_cylinders >>= 3;
7053 hd_heads <<= 3;
7054 }
7055 else { // hd_cylinders <= 16384
7056 hd_cylinders >>= 4;
7057 hd_heads <<= 4;
7058 }
7059
7060 max_cylinder = hd_cylinders - 2; /* 0 based */
7061 SET_AL(0);
7062 SET_CH(max_cylinder & 0xff);
7063 SET_CL(((max_cylinder >> 2) & 0xc0) | (hd_sectors & 0x3f));
7064 SET_DH(hd_heads - 1);
7065 SET_DL(n_drives); /* returns 0, 1, or 2 hard drives */
7066 SET_AH(0);
7067 SET_DISK_RET_STATUS(0);
7068 CLEAR_CF(); /* successful */
7069
7070 return;
7071 break;
7072
7073 case 0x09: /* initialize drive parameters */
7074BX_DEBUG_INT13_HD("int13_f09\n");
7075 SET_AH(0);
7076 SET_DISK_RET_STATUS(0);
7077 CLEAR_CF(); /* successful */
7078 return;
7079 break;
7080
7081 case 0x0a: /* read disk sectors with ECC */
7082BX_DEBUG_INT13_HD("int13_f0a\n");
7083 case 0x0b: /* write disk sectors with ECC */
7084BX_DEBUG_INT13_HD("int13_f0b\n");
7085 BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
7086 return;
7087 break;
7088
7089 case 0x0c: /* seek to specified cylinder */
7090BX_DEBUG_INT13_HD("int13_f0c\n");
7091 BX_INFO("int13h function 0ch (seek) not implemented!\n");
7092 SET_AH(0);
7093 SET_DISK_RET_STATUS(0);
7094 CLEAR_CF(); /* successful */
7095 return;
7096 break;
7097
7098 case 0x0d: /* alternate disk reset */
7099BX_DEBUG_INT13_HD("int13_f0d\n");
7100 SET_AH(0);
7101 SET_DISK_RET_STATUS(0);
7102 CLEAR_CF(); /* successful */
7103 return;
7104 break;
7105
7106 case 0x10: /* check drive ready */
7107BX_DEBUG_INT13_HD("int13_f10\n");
7108 //SET_AH(0);
7109 //SET_DISK_RET_STATUS(0);
7110 //CLEAR_CF(); /* successful */
7111 //return;
7112 //break;
7113
7114 // should look at 40:8E also???
7115 status = inb(0x01f7);
7116 if ( (status & 0xc0) == 0x40 ) {
7117 SET_AH(0);
7118 SET_DISK_RET_STATUS(0);
7119 CLEAR_CF(); // drive ready
7120 return;
7121 }
7122 else {
7123 SET_AH(0xAA);
7124 SET_DISK_RET_STATUS(0xAA);
7125 SET_CF(); // not ready
7126 return;
7127 }
7128 break;
7129
7130 case 0x11: /* recalibrate */
7131BX_DEBUG_INT13_HD("int13_f11\n");
7132 SET_AH(0);
7133 SET_DISK_RET_STATUS(0);
7134 CLEAR_CF(); /* successful */
7135 return;
7136 break;
7137
7138 case 0x14: /* controller internal diagnostic */
7139BX_DEBUG_INT13_HD("int13_f14\n");
7140 SET_AH(0);
7141 SET_DISK_RET_STATUS(0);
7142 CLEAR_CF(); /* successful */
7143 SET_AL(0);
7144 return;
7145 break;
7146
7147 case 0x15: /* read disk drive size */
7148 drive = GET_ELDL();
7149 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
7150ASM_START
7151 push bp
7152 mov bp, sp
7153 mov al, _int13_harddisk.hd_heads + 2 [bp]
7154 mov ah, _int13_harddisk.hd_sectors + 2 [bp]
7155 mul al, ah ;; ax = heads * sectors
7156 mov bx, _int13_harddisk.hd_cylinders + 2 [bp]
7157 dec bx ;; use (cylinders - 1) ???
7158 mul ax, bx ;; dx:ax = (cylinders -1) * (heads * sectors)
7159 ;; now we need to move the 32bit result dx:ax to what the
7160 ;; BIOS wants which is cx:dx.
7161 ;; and then into CX:DX on the stack
7162 mov _int13_harddisk.CX + 2 [bp], dx
7163 mov _int13_harddisk.DX + 2 [bp], ax
7164 pop bp
7165ASM_END
7166 SET_AH(3); // hard disk accessible
7167 SET_DISK_RET_STATUS(0); // ??? should this be 0
7168 CLEAR_CF(); // successful
7169 return;
7170 break;
7171
7172 case 0x18: // set media type for format
7173 case 0x41: // IBM/MS
7174 case 0x42: // IBM/MS
7175 case 0x43: // IBM/MS
7176 case 0x44: // IBM/MS
7177 case 0x45: // IBM/MS lock/unlock drive
7178 case 0x46: // IBM/MS eject media
7179 case 0x47: // IBM/MS extended seek
7180 case 0x49: // IBM/MS extended media change
7181 case 0x50: // IBM/MS send packet command
7182 default:
7183 BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
7184
7185 SET_AH(1); // code=invalid function in AH or invalid parameter
7186 SET_DISK_RET_STATUS(1);
7187 SET_CF(); /* unsuccessful */
7188 return;
7189 break;
7190 }
7191}
7192
7193static char panic_msg_reg12h[] = "HD%d cmos reg 12h not type F\n";
7194static char panic_msg_reg19h[] = "HD%d cmos reg %02xh not user definable type 47\n";
7195
7196 void
7197get_hd_geometry(drive, hd_cylinders, hd_heads, hd_sectors)
7198 Bit8u drive;
7199 Bit16u *hd_cylinders;
7200 Bit8u *hd_heads;
7201 Bit8u *hd_sectors;
7202{
7203 Bit8u hd_type;
7204 Bit16u ss;
7205 Bit16u cylinders;
7206 Bit8u iobase;
7207
7208 ss = get_SS();
7209 if (drive == 0x80) {
7210 hd_type = inb_cmos(0x12) & 0xf0;
7211 if (hd_type != 0xf0)
7212 BX_INFO(panic_msg_reg12h,0);
7213 hd_type = inb_cmos(0x19); // HD0: extended type
7214 if (hd_type != 47)
7215 BX_INFO(panic_msg_reg19h,0,0x19);
7216 iobase = 0x1b;
7217 } else {
7218 hd_type = inb_cmos(0x12) & 0x0f;
7219 if (hd_type != 0x0f)
7220 BX_INFO(panic_msg_reg12h,1);
7221 hd_type = inb_cmos(0x1a); // HD1: extended type
7222 if (hd_type != 47)
7223 BX_INFO(panic_msg_reg19h,0,0x1a);
7224 iobase = 0x24;
7225 }
7226
7227 // cylinders
7228 cylinders = inb_cmos(iobase) | (inb_cmos(iobase+1) << 8);
7229 write_word(ss, hd_cylinders, cylinders);
7230
7231 // heads
7232 write_byte(ss, hd_heads, inb_cmos(iobase+2));
7233
7234 // sectors per track
7235 write_byte(ss, hd_sectors, inb_cmos(iobase+8));
7236}
7237
7238#endif //else BX_USE_ATADRV
7239
7240#if BX_SUPPORT_FLOPPY
7241
7242//////////////////////
7243// FLOPPY functions //
7244//////////////////////
7245
7246void floppy_reset_controller()
7247{
7248 Bit8u val8;
7249
7250 // Reset controller
7251 val8 = inb(0x03f2);
7252 outb(0x03f2, val8 & ~0x04);
7253 outb(0x03f2, val8 | 0x04);
7254
7255 // Wait for controller to come out of reset
7256 do {
7257 val8 = inb(0x3f4);
7258 } while ( (val8 & 0xc0) != 0x80 );
7259}
7260
7261void floppy_prepare_controller(drive)
7262 Bit16u drive;
7263{
7264 Bit8u val8, dor, prev_reset;
7265
7266 // set 40:3e bit 7 to 0
7267 val8 = read_byte(0x0040, 0x003e);
7268 val8 &= 0x7f;
7269 write_byte(0x0040, 0x003e, val8);
7270
7271 // turn on motor of selected drive, DMA & int enabled, normal operation
7272 prev_reset = inb(0x03f2) & 0x04;
7273 if (drive)
7274 dor = 0x20;
7275 else
7276 dor = 0x10;
7277 dor |= 0x0c;
7278 dor |= drive;
7279 outb(0x03f2, dor);
7280
7281 // reset the disk motor timeout value of INT 08
7282 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
7283
7284#ifdef VBOX
7285 // program data rate
7286 val8 = read_byte(0x0040, 0x008b);
7287 val8 >>= 6;
7288 outb(0x03f7, val8);
7289#endif
7290
7291 // wait for drive readiness
7292 do {
7293 val8 = inb(0x3f4);
7294 } while ( (val8 & 0xc0) != 0x80 );
7295
7296 if (prev_reset == 0) {
7297 // turn on interrupts
7298ASM_START
7299 sti
7300ASM_END
7301 // wait on 40:3e bit 7 to become 1
7302 do {
7303 val8 = read_byte(0x0040, 0x003e);
7304 } while ( (val8 & 0x80) == 0 );
7305 val8 &= 0x7f;
7306ASM_START
7307 cli
7308ASM_END
7309 write_byte(0x0040, 0x003e, val8);
7310 }
7311}
7312
7313 bx_bool
7314floppy_media_known(drive)
7315 Bit16u drive;
7316{
7317 Bit8u val8;
7318 Bit16u media_state_offset;
7319
7320 val8 = read_byte(0x0040, 0x003e); // diskette recal status
7321 if (drive)
7322 val8 >>= 1;
7323 val8 &= 0x01;
7324 if (val8 == 0)
7325 return(0);
7326
7327 media_state_offset = 0x0090;
7328 if (drive)
7329 media_state_offset += 1;
7330
7331 val8 = read_byte(0x0040, media_state_offset);
7332 val8 = (val8 >> 4) & 0x01;
7333 if (val8 == 0)
7334 return(0);
7335
7336 // check pass, return KNOWN
7337 return(1);
7338}
7339
7340 bx_bool
7341floppy_media_sense(drive)
7342 Bit16u drive;
7343{
7344 bx_bool retval;
7345 Bit16u media_state_offset;
7346 Bit8u drive_type, config_data, media_state;
7347
7348 if (floppy_drive_recal(drive) == 0) {
7349 return(0);
7350 }
7351
7352 // for now cheat and get drive type from CMOS,
7353 // assume media is same as drive type
7354
7355 // ** config_data **
7356 // Bitfields for diskette media control:
7357 // Bit(s) Description (Table M0028)
7358 // 7-6 last data rate set by controller
7359 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
7360 // 5-4 last diskette drive step rate selected
7361 // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
7362 // 3-2 {data rate at start of operation}
7363 // 1-0 reserved
7364
7365 // ** media_state **
7366 // Bitfields for diskette drive media state:
7367 // Bit(s) Description (Table M0030)
7368 // 7-6 data rate
7369 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
7370 // 5 double stepping required (e.g. 360kB in 1.2MB)
7371 // 4 media type established
7372 // 3 drive capable of supporting 4MB media
7373 // 2-0 on exit from BIOS, contains
7374 // 000 trying 360kB in 360kB
7375 // 001 trying 360kB in 1.2MB
7376 // 010 trying 1.2MB in 1.2MB
7377 // 011 360kB in 360kB established
7378 // 100 360kB in 1.2MB established
7379 // 101 1.2MB in 1.2MB established
7380 // 110 reserved
7381 // 111 all other formats/drives
7382
7383 drive_type = inb_cmos(0x10);
7384 if (drive == 0)
7385 drive_type >>= 4;
7386 else
7387 drive_type &= 0x0f;
7388 if ( drive_type == 1 ) {
7389 // 360K 5.25" drive
7390 config_data = 0x00; // 0000 0000
7391 media_state = 0x25; // 0010 0101
7392 retval = 1;
7393 }
7394 else if ( drive_type == 2 ) {
7395 // 1.2 MB 5.25" drive
7396 config_data = 0x00; // 0000 0000
7397 media_state = 0x25; // 0010 0101 // need double stepping??? (bit 5)
7398 retval = 1;
7399 }
7400 else if ( drive_type == 3 ) {
7401 // 720K 3.5" drive
7402 config_data = 0x00; // 0000 0000 ???
7403 media_state = 0x17; // 0001 0111
7404 retval = 1;
7405 }
7406 else if ( drive_type == 4 ) {
7407 // 1.44 MB 3.5" drive
7408 config_data = 0x00; // 0000 0000
7409 media_state = 0x17; // 0001 0111
7410 retval = 1;
7411 }
7412 else if ( drive_type == 5 ) {
7413 // 2.88 MB 3.5" drive
7414 config_data = 0xCC; // 1100 1100
7415 media_state = 0xD7; // 1101 0111
7416 retval = 1;
7417 }
7418 //
7419 // Extended floppy size uses special cmos setting
7420 else if ( drive_type == 6 ) {
7421 // 160k 5.25" drive
7422 config_data = 0x00; // 0000 0000
7423 media_state = 0x27; // 0010 0111
7424 retval = 1;
7425 }
7426 else if ( drive_type == 7 ) {
7427 // 180k 5.25" drive
7428 config_data = 0x00; // 0000 0000
7429 media_state = 0x27; // 0010 0111
7430 retval = 1;
7431 }
7432 else if ( drive_type == 8 ) {
7433 // 320k 5.25" drive
7434 config_data = 0x00; // 0000 0000
7435 media_state = 0x27; // 0010 0111
7436 retval = 1;
7437 }
7438
7439 else {
7440 // not recognized
7441 config_data = 0x00; // 0000 0000
7442 media_state = 0x00; // 0000 0000
7443 retval = 0;
7444 }
7445
7446 if (drive == 0)
7447 media_state_offset = 0x90;
7448 else
7449 media_state_offset = 0x91;
7450 write_byte(0x0040, 0x008B, config_data);
7451 write_byte(0x0040, media_state_offset, media_state);
7452
7453 return(retval);
7454}
7455
7456 bx_bool
7457floppy_drive_recal(drive)
7458 Bit16u drive;
7459{
7460 Bit8u val8;
7461 Bit16u curr_cyl_offset;
7462
7463 floppy_prepare_controller(drive);
7464
7465 // send Recalibrate command (2 bytes) to controller
7466 outb(0x03f5, 0x07); // 07: Recalibrate
7467 outb(0x03f5, drive); // 0=drive0, 1=drive1
7468
7469 // turn on interrupts
7470ASM_START
7471 sti
7472ASM_END
7473
7474 // wait on 40:3e bit 7 to become 1
7475 do {
7476 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7477 } while ( val8 == 0 );
7478
7479 val8 = 0; // separate asm from while() loop
7480 // turn off interrupts
7481ASM_START
7482 cli
7483ASM_END
7484
7485 // set 40:3e bit 7 to 0, and calibrated bit
7486 val8 = read_byte(0x0040, 0x003e);
7487 val8 &= 0x7f;
7488 if (drive) {
7489 val8 |= 0x02; // Drive 1 calibrated
7490 curr_cyl_offset = 0x0095;
7491 } else {
7492 val8 |= 0x01; // Drive 0 calibrated
7493 curr_cyl_offset = 0x0094;
7494 }
7495 write_byte(0x0040, 0x003e, val8);
7496 write_byte(0x0040, curr_cyl_offset, 0); // current cylinder is 0
7497
7498 return(1);
7499}
7500
7501
7502
7503 bx_bool
7504floppy_drive_exists(drive)
7505 Bit16u drive;
7506{
7507 Bit8u drive_type;
7508
7509 // check CMOS to see if drive exists
7510 drive_type = inb_cmos(0x10);
7511 if (drive == 0)
7512 drive_type >>= 4;
7513 else
7514 drive_type &= 0x0f;
7515 if ( drive_type == 0 )
7516 return(0);
7517 else
7518 return(1);
7519}
7520
7521 void
7522int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
7523 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
7524{
7525 Bit8u drive, num_sectors, track, sector, head, status;
7526 Bit16u base_address, base_count, base_es;
7527 Bit8u page, mode_register, val8, dor;
7528 Bit8u return_status[7];
7529 Bit8u drive_type, num_floppies, ah;
7530 Bit16u es, last_addr;
7531
7532 BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
7533
7534 ah = GET_AH();
7535
7536 switch ( ah ) {
7537 case 0x00: // diskette controller reset
7538BX_DEBUG_INT13_FL("floppy f00\n");
7539 drive = GET_ELDL();
7540 if (drive > 1) {
7541 SET_AH(1); // invalid param
7542 set_diskette_ret_status(1);
7543 SET_CF();
7544 return;
7545 }
7546 drive_type = inb_cmos(0x10);
7547
7548 if (drive == 0)
7549 drive_type >>= 4;
7550 else
7551 drive_type &= 0x0f;
7552 if (drive_type == 0) {
7553 SET_AH(0x80); // drive not responding
7554 set_diskette_ret_status(0x80);
7555 SET_CF();
7556 return;
7557 }
7558 SET_AH(0);
7559 set_diskette_ret_status(0);
7560 CLEAR_CF(); // successful
7561 set_diskette_current_cyl(drive, 0); // current cylinder
7562 return;
7563
7564 case 0x01: // Read Diskette Status
7565 CLEAR_CF();
7566 val8 = read_byte(0x0000, 0x0441);
7567 SET_AH(val8);
7568 if (val8) {
7569 SET_CF();
7570 }
7571 return;
7572
7573 case 0x02: // Read Diskette Sectors
7574 case 0x03: // Write Diskette Sectors
7575 case 0x04: // Verify Diskette Sectors
7576 num_sectors = GET_AL();
7577 track = GET_CH();
7578 sector = GET_CL();
7579 head = GET_DH();
7580 drive = GET_ELDL();
7581
7582 if ( (drive > 1) || (head > 1) ||
7583 (num_sectors == 0) || (num_sectors > 72) ) {
7584BX_INFO("floppy: drive>1 || head>1 ...\n");
7585 SET_AH(1);
7586 set_diskette_ret_status(1);
7587 SET_AL(0); // no sectors read
7588 SET_CF(); // error occurred
7589 return;
7590 }
7591
7592 // see if drive exists
7593 if (floppy_drive_exists(drive) == 0) {
7594 SET_AH(0x80); // not responding
7595 set_diskette_ret_status(0x80);
7596 SET_AL(0); // no sectors read
7597 SET_CF(); // error occurred
7598 return;
7599 }
7600
7601 // see if media in drive, and type is known
7602 if (floppy_media_known(drive) == 0) {
7603 if (floppy_media_sense(drive) == 0) {
7604 SET_AH(0x0C); // Media type not found
7605 set_diskette_ret_status(0x0C);
7606 SET_AL(0); // no sectors read
7607 SET_CF(); // error occurred
7608 return;
7609 }
7610 }
7611
7612 if (ah == 0x02) {
7613 // Read Diskette Sectors
7614
7615 //-----------------------------------
7616 // set up DMA controller for transfer
7617 //-----------------------------------
7618
7619 // es:bx = pointer to where to place information from diskette
7620 // port 04: DMA-1 base and current address, channel 2
7621 // port 05: DMA-1 base and current count, channel 2
7622 page = (ES >> 12); // upper 4 bits
7623 base_es = (ES << 4); // lower 16bits contributed by ES
7624 base_address = base_es + BX; // lower 16 bits of address
7625 // contributed by ES:BX
7626 if ( base_address < base_es ) {
7627 // in case of carry, adjust page by 1
7628 page++;
7629 }
7630 base_count = (num_sectors * 512) - 1;
7631
7632 // check for 64K boundary overrun
7633 last_addr = base_address + base_count;
7634 if (last_addr < base_address) {
7635 SET_AH(0x09);
7636 set_diskette_ret_status(0x09);
7637 SET_AL(0); // no sectors read
7638 SET_CF(); // error occurred
7639 return;
7640 }
7641
7642 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7643 outb(0x000a, 0x06);
7644
7645 BX_DEBUG_INT13_FL("clear flip-flop\n");
7646 outb(0x000c, 0x00); // clear flip-flop
7647 outb(0x0004, base_address);
7648 outb(0x0004, base_address>>8);
7649 BX_DEBUG_INT13_FL("clear flip-flop\n");
7650 outb(0x000c, 0x00); // clear flip-flop
7651 outb(0x0005, base_count);
7652 outb(0x0005, base_count>>8);
7653
7654 // port 0b: DMA-1 Mode Register
7655 mode_register = 0x46; // single mode, increment, autoinit disable,
7656 // transfer type=write, channel 2
7657 BX_DEBUG_INT13_FL("setting mode register\n");
7658 outb(0x000b, mode_register);
7659
7660 BX_DEBUG_INT13_FL("setting page register\n");
7661 // port 81: DMA-1 Page Register, channel 2
7662 outb(0x0081, page);
7663
7664 BX_DEBUG_INT13_FL("unmask chan 2\n");
7665 outb(0x000a, 0x02); // unmask channel 2
7666
7667 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7668 outb(0x000a, 0x02);
7669
7670 //--------------------------------------
7671 // set up floppy controller for transfer
7672 //--------------------------------------
7673 floppy_prepare_controller(drive);
7674
7675 // send read-normal-data command (9 bytes) to controller
7676 outb(0x03f5, 0xe6); // e6: read normal data
7677 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7678 outb(0x03f5, track);
7679 outb(0x03f5, head);
7680 outb(0x03f5, sector);
7681 outb(0x03f5, 2); // 512 byte sector size
7682 outb(0x03f5, sector + num_sectors - 1); // last sector to read on track
7683 outb(0x03f5, 0); // Gap length
7684 outb(0x03f5, 0xff); // Gap length
7685
7686 // turn on interrupts
7687 ASM_START
7688 sti
7689 ASM_END
7690
7691 // wait on 40:3e bit 7 to become 1
7692 do {
7693 val8 = read_byte(0x0040, 0x0040);
7694 if (val8 == 0) {
7695 floppy_reset_controller();
7696 SET_AH(0x80); // drive not ready (timeout)
7697 set_diskette_ret_status(0x80);
7698 SET_AL(0); // no sectors read
7699 SET_CF(); // error occurred
7700 return;
7701 }
7702 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7703 } while ( val8 == 0 );
7704
7705 val8 = 0; // separate asm from while() loop
7706 // turn off interrupts
7707 ASM_START
7708 cli
7709 ASM_END
7710
7711 // set 40:3e bit 7 to 0
7712 val8 = read_byte(0x0040, 0x003e);
7713 val8 &= 0x7f;
7714 write_byte(0x0040, 0x003e, val8);
7715
7716 // check port 3f4 for accessibility to status bytes
7717 val8 = inb(0x3f4);
7718 if ( (val8 & 0xc0) != 0xc0 )
7719 BX_PANIC("int13_diskette: ctrl not ready\n");
7720
7721 // read 7 return status bytes from controller
7722 // using loop index broken, have to unroll...
7723 return_status[0] = inb(0x3f5);
7724 return_status[1] = inb(0x3f5);
7725 return_status[2] = inb(0x3f5);
7726 return_status[3] = inb(0x3f5);
7727 return_status[4] = inb(0x3f5);
7728 return_status[5] = inb(0x3f5);
7729 return_status[6] = inb(0x3f5);
7730 // record in BIOS Data Area
7731 write_byte(0x0040, 0x0042, return_status[0]);
7732 write_byte(0x0040, 0x0043, return_status[1]);
7733 write_byte(0x0040, 0x0044, return_status[2]);
7734 write_byte(0x0040, 0x0045, return_status[3]);
7735 write_byte(0x0040, 0x0046, return_status[4]);
7736 write_byte(0x0040, 0x0047, return_status[5]);
7737 write_byte(0x0040, 0x0048, return_status[6]);
7738
7739 if ( (return_status[0] & 0xc0) != 0 ) {
7740 SET_AH(0x20);
7741 set_diskette_ret_status(0x20);
7742 SET_AL(0); // no sectors read
7743 SET_CF(); // error occurred
7744 return;
7745 }
7746
7747 // ??? should track be new val from return_status[3] ?
7748 set_diskette_current_cyl(drive, track);
7749 // AL = number of sectors read (same value as passed)
7750 SET_AH(0x00); // success
7751 CLEAR_CF(); // success
7752 return;
7753 } else if (ah == 0x03) {
7754 // Write Diskette Sectors
7755
7756 //-----------------------------------
7757 // set up DMA controller for transfer
7758 //-----------------------------------
7759
7760 // es:bx = pointer to where to place information from diskette
7761 // port 04: DMA-1 base and current address, channel 2
7762 // port 05: DMA-1 base and current count, channel 2
7763 page = (ES >> 12); // upper 4 bits
7764 base_es = (ES << 4); // lower 16bits contributed by ES
7765 base_address = base_es + BX; // lower 16 bits of address
7766 // contributed by ES:BX
7767 if ( base_address < base_es ) {
7768 // in case of carry, adjust page by 1
7769 page++;
7770 }
7771 base_count = (num_sectors * 512) - 1;
7772
7773 // check for 64K boundary overrun
7774 last_addr = base_address + base_count;
7775 if (last_addr < base_address) {
7776 SET_AH(0x09);
7777 set_diskette_ret_status(0x09);
7778 SET_AL(0); // no sectors read
7779 SET_CF(); // error occurred
7780 return;
7781 }
7782
7783 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7784 outb(0x000a, 0x06);
7785
7786 outb(0x000c, 0x00); // clear flip-flop
7787 outb(0x0004, base_address);
7788 outb(0x0004, base_address>>8);
7789 outb(0x000c, 0x00); // clear flip-flop
7790 outb(0x0005, base_count);
7791 outb(0x0005, base_count>>8);
7792
7793 // port 0b: DMA-1 Mode Register
7794 mode_register = 0x4a; // single mode, increment, autoinit disable,
7795 // transfer type=read, channel 2
7796 outb(0x000b, mode_register);
7797
7798 // port 81: DMA-1 Page Register, channel 2
7799 outb(0x0081, page);
7800
7801 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7802 outb(0x000a, 0x02);
7803
7804 //--------------------------------------
7805 // set up floppy controller for transfer
7806 //--------------------------------------
7807 floppy_prepare_controller(drive);
7808
7809 // send write-normal-data command (9 bytes) to controller
7810 outb(0x03f5, 0xc5); // c5: write normal data
7811 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7812 outb(0x03f5, track);
7813 outb(0x03f5, head);
7814 outb(0x03f5, sector);
7815 outb(0x03f5, 2); // 512 byte sector size
7816 outb(0x03f5, sector + num_sectors - 1); // last sector to write on track
7817 outb(0x03f5, 0); // Gap length
7818 outb(0x03f5, 0xff); // Gap length
7819
7820 // turn on interrupts
7821 ASM_START
7822 sti
7823 ASM_END
7824
7825 // wait on 40:3e bit 7 to become 1
7826 do {
7827 val8 = read_byte(0x0040, 0x0040);
7828 if (val8 == 0) {
7829 floppy_reset_controller();
7830 SET_AH(0x80); // drive not ready (timeout)
7831 set_diskette_ret_status(0x80);
7832 SET_AL(0); // no sectors written
7833 SET_CF(); // error occurred
7834 return;
7835 }
7836 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7837 } while ( val8 == 0 );
7838
7839 val8 = 0; // separate asm from while() loop
7840 // turn off interrupts
7841 ASM_START
7842 cli
7843 ASM_END
7844
7845 // set 40:3e bit 7 to 0
7846 val8 = read_byte(0x0040, 0x003e);
7847 val8 &= 0x7f;
7848 write_byte(0x0040, 0x003e, val8);
7849
7850 // check port 3f4 for accessibility to status bytes
7851 val8 = inb(0x3f4);
7852 if ( (val8 & 0xc0) != 0xc0 )
7853 BX_PANIC("int13_diskette: ctrl not ready\n");
7854
7855 // read 7 return status bytes from controller
7856 // using loop index broken, have to unroll...
7857 return_status[0] = inb(0x3f5);
7858 return_status[1] = inb(0x3f5);
7859 return_status[2] = inb(0x3f5);
7860 return_status[3] = inb(0x3f5);
7861 return_status[4] = inb(0x3f5);
7862 return_status[5] = inb(0x3f5);
7863 return_status[6] = inb(0x3f5);
7864 // record in BIOS Data Area
7865 write_byte(0x0040, 0x0042, return_status[0]);
7866 write_byte(0x0040, 0x0043, return_status[1]);
7867 write_byte(0x0040, 0x0044, return_status[2]);
7868 write_byte(0x0040, 0x0045, return_status[3]);
7869 write_byte(0x0040, 0x0046, return_status[4]);
7870 write_byte(0x0040, 0x0047, return_status[5]);
7871 write_byte(0x0040, 0x0048, return_status[6]);
7872
7873 if ( (return_status[0] & 0xc0) != 0 ) {
7874 if ( (return_status[1] & 0x02) != 0 ) {
7875 // diskette not writable.
7876 // AH=status code=0x03 (tried to write on write-protected disk)
7877 // AL=number of sectors written=0
7878 AX = 0x0300;
7879 SET_CF();
7880 return;
7881 } else {
7882 BX_PANIC("int13_diskette_function: read error\n");
7883 }
7884 }
7885
7886 // ??? should track be new val from return_status[3] ?
7887 set_diskette_current_cyl(drive, track);
7888 // AL = number of sectors read (same value as passed)
7889 SET_AH(0x00); // success
7890 CLEAR_CF(); // success
7891 return;
7892 } else { // if (ah == 0x04)
7893 // Verify Diskette Sectors
7894
7895 // ??? should track be new val from return_status[3] ?
7896 set_diskette_current_cyl(drive, track);
7897 // AL = number of sectors verified (same value as passed)
7898 CLEAR_CF(); // success
7899 SET_AH(0x00); // success
7900 return;
7901 }
7902 break;
7903
7904 case 0x05: // format diskette track
7905BX_DEBUG_INT13_FL("floppy f05\n");
7906
7907 num_sectors = GET_AL();
7908 track = GET_CH();
7909 head = GET_DH();
7910 drive = GET_ELDL();
7911
7912 if ((drive > 1) || (head > 1) || (track > 79) ||
7913 (num_sectors == 0) || (num_sectors > 18)) {
7914 SET_AH(1);
7915 set_diskette_ret_status(1);
7916 SET_CF(); // error occurred
7917 }
7918
7919 // see if drive exists
7920 if (floppy_drive_exists(drive) == 0) {
7921 SET_AH(0x80); // drive not responding
7922 set_diskette_ret_status(0x80);
7923 SET_CF(); // error occurred
7924 return;
7925 }
7926
7927 // see if media in drive, and type is known
7928 if (floppy_media_known(drive) == 0) {
7929 if (floppy_media_sense(drive) == 0) {
7930 SET_AH(0x0C); // Media type not found
7931 set_diskette_ret_status(0x0C);
7932 SET_AL(0); // no sectors read
7933 SET_CF(); // error occurred
7934 return;
7935 }
7936 }
7937
7938 // set up DMA controller for transfer
7939 page = (ES >> 12); // upper 4 bits
7940 base_es = (ES << 4); // lower 16bits contributed by ES
7941 base_address = base_es + BX; // lower 16 bits of address
7942 // contributed by ES:BX
7943 if ( base_address < base_es ) {
7944 // in case of carry, adjust page by 1
7945 page++;
7946 }
7947 base_count = (num_sectors * 4) - 1;
7948
7949 // check for 64K boundary overrun
7950 last_addr = base_address + base_count;
7951 if (last_addr < base_address) {
7952 SET_AH(0x09);
7953 set_diskette_ret_status(0x09);
7954 SET_AL(0); // no sectors read
7955 SET_CF(); // error occurred
7956 return;
7957 }
7958
7959 outb(0x000a, 0x06);
7960 outb(0x000c, 0x00); // clear flip-flop
7961 outb(0x0004, base_address);
7962 outb(0x0004, base_address>>8);
7963 outb(0x000c, 0x00); // clear flip-flop
7964 outb(0x0005, base_count);
7965 outb(0x0005, base_count>>8);
7966 mode_register = 0x4a; // single mode, increment, autoinit disable,
7967 // transfer type=read, channel 2
7968 outb(0x000b, mode_register);
7969 // port 81: DMA-1 Page Register, channel 2
7970 outb(0x0081, page);
7971 outb(0x000a, 0x02);
7972
7973 // set up floppy controller for transfer
7974 floppy_prepare_controller(drive);
7975
7976 // send format-track command (6 bytes) to controller
7977 outb(0x03f5, 0x4d); // 4d: format track
7978 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7979 outb(0x03f5, 2); // 512 byte sector size
7980 outb(0x03f5, num_sectors); // number of sectors per track
7981 outb(0x03f5, 0); // Gap length
7982 outb(0x03f5, 0xf6); // Fill byte
7983 // turn on interrupts
7984 ASM_START
7985 sti
7986 ASM_END
7987
7988 // wait on 40:3e bit 7 to become 1
7989 do {
7990 val8 = read_byte(0x0040, 0x0040);
7991 if (val8 == 0) {
7992 floppy_reset_controller();
7993 SET_AH(0x80); // drive not ready (timeout)
7994 set_diskette_ret_status(0x80);
7995 SET_CF(); // error occurred
7996 return;
7997 }
7998 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7999 } while ( val8 == 0 );
8000
8001 val8 = 0; // separate asm from while() loop
8002 // turn off interrupts
8003 ASM_START
8004 cli
8005 ASM_END
8006 // set 40:3e bit 7 to 0
8007 val8 = read_byte(0x0040, 0x003e);
8008 val8 &= 0x7f;
8009 write_byte(0x0040, 0x003e, val8);
8010 // check port 3f4 for accessibility to status bytes
8011 val8 = inb(0x3f4);
8012 if ( (val8 & 0xc0) != 0xc0 )
8013 BX_PANIC("int13_diskette: ctrl not ready\n");
8014
8015 // read 7 return status bytes from controller
8016 // using loop index broken, have to unroll...
8017 return_status[0] = inb(0x3f5);
8018 return_status[1] = inb(0x3f5);
8019 return_status[2] = inb(0x3f5);
8020 return_status[3] = inb(0x3f5);
8021 return_status[4] = inb(0x3f5);
8022 return_status[5] = inb(0x3f5);
8023 return_status[6] = inb(0x3f5);
8024 // record in BIOS Data Area
8025 write_byte(0x0040, 0x0042, return_status[0]);
8026 write_byte(0x0040, 0x0043, return_status[1]);
8027 write_byte(0x0040, 0x0044, return_status[2]);
8028 write_byte(0x0040, 0x0045, return_status[3]);
8029 write_byte(0x0040, 0x0046, return_status[4]);
8030 write_byte(0x0040, 0x0047, return_status[5]);
8031 write_byte(0x0040, 0x0048, return_status[6]);
8032
8033 if ( (return_status[0] & 0xc0) != 0 ) {
8034 if ( (return_status[1] & 0x02) != 0 ) {
8035 // diskette not writable.
8036 // AH=status code=0x03 (tried to write on write-protected disk)
8037 // AL=number of sectors written=0
8038 AX = 0x0300;
8039 SET_CF();
8040 return;
8041 } else {
8042 BX_PANIC("int13_diskette_function: write error\n");
8043 }
8044 }
8045
8046 SET_AH(0);
8047 set_diskette_ret_status(0);
8048 set_diskette_current_cyl(drive, 0);
8049 CLEAR_CF(); // successful
8050 return;
8051
8052
8053 case 0x08: // read diskette drive parameters
8054BX_DEBUG_INT13_FL("floppy f08\n");
8055 drive = GET_ELDL();
8056
8057 if (drive > 1) {
8058 AX = 0;
8059 BX = 0;
8060 CX = 0;
8061 DX = 0;
8062 ES = 0;
8063 DI = 0;
8064 SET_DL(num_floppies);
8065 SET_CF();
8066 return;
8067 }
8068
8069 drive_type = inb_cmos(0x10);
8070 num_floppies = 0;
8071 if (drive_type & 0xf0)
8072 num_floppies++;
8073 if (drive_type & 0x0f)
8074 num_floppies++;
8075
8076 if (drive == 0)
8077 drive_type >>= 4;
8078 else
8079 drive_type &= 0x0f;
8080
8081 SET_BH(0);
8082 SET_BL(drive_type);
8083 SET_AH(0);
8084 SET_AL(0);
8085 SET_DL(num_floppies);
8086
8087 switch (drive_type) {
8088 case 0: // none
8089 CX = 0;
8090 SET_DH(0); // max head #
8091 break;
8092
8093 case 1: // 360KB, 5.25"
8094 CX = 0x2709; // 40 tracks, 9 sectors
8095 SET_DH(1); // max head #
8096 break;
8097
8098 case 2: // 1.2MB, 5.25"
8099 CX = 0x4f0f; // 80 tracks, 15 sectors
8100 SET_DH(1); // max head #
8101 break;
8102
8103 case 3: // 720KB, 3.5"
8104 CX = 0x4f09; // 80 tracks, 9 sectors
8105 SET_DH(1); // max head #
8106 break;
8107
8108 case 4: // 1.44MB, 3.5"
8109 CX = 0x4f12; // 80 tracks, 18 sectors
8110 SET_DH(1); // max head #
8111 break;
8112
8113 case 5: // 2.88MB, 3.5"
8114 CX = 0x4f24; // 80 tracks, 36 sectors
8115 SET_DH(1); // max head #
8116 break;
8117
8118 case 6: // 160k, 5.25"
8119 CX = 0x2708; // 40 tracks, 8 sectors
8120 SET_DH(0); // max head #
8121 break;
8122
8123 case 7: // 180k, 5.25"
8124 CX = 0x2709; // 40 tracks, 9 sectors
8125 SET_DH(0); // max head #
8126 break;
8127
8128 case 8: // 320k, 5.25"
8129 CX = 0x2708; // 40 tracks, 8 sectors
8130 SET_DH(1); // max head #
8131 break;
8132
8133 default: // ?
8134 BX_PANIC("floppy: int13: bad floppy type\n");
8135 }
8136
8137 /* set es & di to point to 11 byte diskette param table in ROM */
8138ASM_START
8139 push bp
8140 mov bp, sp
8141 mov ax, #diskette_param_table2
8142 mov _int13_diskette_function.DI+2[bp], ax
8143 mov _int13_diskette_function.ES+2[bp], cs
8144 pop bp
8145ASM_END
8146 CLEAR_CF(); // success
8147 /* disk status not changed upon success */
8148 return;
8149
8150
8151 case 0x15: // read diskette drive type
8152BX_DEBUG_INT13_FL("floppy f15\n");
8153 drive = GET_ELDL();
8154 if (drive > 1) {
8155 SET_AH(0); // only 2 drives supported
8156 // set_diskette_ret_status here ???
8157 SET_CF();
8158 return;
8159 }
8160 drive_type = inb_cmos(0x10);
8161
8162 if (drive == 0)
8163 drive_type >>= 4;
8164 else
8165 drive_type &= 0x0f;
8166 CLEAR_CF(); // successful, not present
8167 if (drive_type==0) {
8168 SET_AH(0); // drive not present
8169 }
8170 else {
8171 SET_AH(1); // drive present, does not support change line
8172 }
8173
8174 return;
8175
8176 case 0x16: // get diskette change line status
8177BX_DEBUG_INT13_FL("floppy f16\n");
8178 drive = GET_ELDL();
8179 if (drive > 1) {
8180 SET_AH(0x01); // invalid drive
8181 set_diskette_ret_status(0x01);
8182 SET_CF();
8183 return;
8184 }
8185
8186 SET_AH(0x06); // change line not supported
8187 set_diskette_ret_status(0x06);
8188 SET_CF();
8189 return;
8190
8191 case 0x17: // set diskette type for format(old)
8192BX_DEBUG_INT13_FL("floppy f17\n");
8193 /* not used for 1.44M floppies */
8194 SET_AH(0x01); // not supported
8195 set_diskette_ret_status(1); /* not supported */
8196 SET_CF();
8197 return;
8198
8199 case 0x18: // set diskette type for format(new)
8200BX_DEBUG_INT13_FL("floppy f18\n");
8201 SET_AH(0x01); // do later
8202 set_diskette_ret_status(1);
8203 SET_CF();
8204 return;
8205
8206 default:
8207 BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
8208
8209 // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
8210 SET_AH(0x01); // ???
8211 set_diskette_ret_status(1);
8212 SET_CF();
8213 return;
8214 // }
8215 }
8216}
8217#else // #if BX_SUPPORT_FLOPPY
8218 void
8219int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
8220 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
8221{
8222 Bit8u val8;
8223
8224 switch ( GET_AH() ) {
8225
8226 case 0x01: // Read Diskette Status
8227 CLEAR_CF();
8228 val8 = read_byte(0x0000, 0x0441);
8229 SET_AH(val8);
8230 if (val8) {
8231 SET_CF();
8232 }
8233 return;
8234
8235 default:
8236 SET_CF();
8237 write_byte(0x0000, 0x0441, 0x01);
8238 SET_AH(0x01);
8239 }
8240}
8241#endif // #if BX_SUPPORT_FLOPPY
8242
8243 void
8244set_diskette_ret_status(value)
8245 Bit8u value;
8246{
8247 write_byte(0x0040, 0x0041, value);
8248}
8249
8250 void
8251set_diskette_current_cyl(drive, cyl)
8252 Bit8u drive;
8253 Bit8u cyl;
8254{
8255 if (drive > 1)
8256 BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
8257 write_byte(0x0040, 0x0094+drive, cyl);
8258}
8259
8260 void
8261determine_floppy_media(drive)
8262 Bit16u drive;
8263{
8264#if 0
8265 Bit8u val8, DOR, ctrl_info;
8266
8267 ctrl_info = read_byte(0x0040, 0x008F);
8268 if (drive==1)
8269 ctrl_info >>= 4;
8270 else
8271 ctrl_info &= 0x0f;
8272
8273#if 0
8274 if (drive == 0) {
8275 DOR = 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
8276 }
8277 else {
8278 DOR = 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
8279 }
8280#endif
8281
8282 if ( (ctrl_info & 0x04) != 0x04 ) {
8283 // Drive not determined means no drive exists, done.
8284 return;
8285 }
8286
8287#if 0
8288 // check Main Status Register for readiness
8289 val8 = inb(0x03f4) & 0x80; // Main Status Register
8290 if (val8 != 0x80)
8291 BX_PANIC("d_f_m: MRQ bit not set\n");
8292
8293 // change line
8294
8295 // existing BDA values
8296
8297 // turn on drive motor
8298 outb(0x03f2, DOR); // Digital Output Register
8299 //
8300#endif
8301 BX_PANIC("d_f_m: OK so far\n");
8302#endif
8303}
8304
8305 void
8306int17_function(regs, ds, iret_addr)
8307 pusha_regs_t regs; // regs pushed from PUSHA instruction
8308 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8309 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8310{
8311 Bit16u addr,timeout;
8312 Bit8u val8;
8313
8314 ASM_START
8315 sti
8316 ASM_END
8317
8318 addr = read_word(0x0040, (regs.u.r16.dx << 1) + 8);
8319 if ((regs.u.r8.ah < 3) && (regs.u.r16.dx < 3) && (addr > 0)) {
8320 timeout = read_byte(0x0040, 0x0078 + regs.u.r16.dx) << 8;
8321 if (regs.u.r8.ah == 0) {
8322 outb(addr, regs.u.r8.al);
8323 val8 = inb(addr+2);
8324 outb(addr+2, val8 | 0x01); // send strobe
8325 ASM_START
8326 nop
8327 ASM_END
8328 outb(addr+2, val8 & ~0x01);
8329 while (((inb(addr+1) & 0x40) == 0x40) && (timeout)) {
8330 timeout--;
8331 }
8332 }
8333 if (regs.u.r8.ah == 1) {
8334 val8 = inb(addr+2);
8335 outb(addr+2, val8 & ~0x04); // send init
8336 ASM_START
8337 nop
8338 ASM_END
8339 outb(addr+2, val8 | 0x04);
8340 }
8341 val8 = inb(addr+1);
8342 regs.u.r8.ah = (val8 ^ 0x48);
8343 if (!timeout) regs.u.r8.ah |= 0x01;
8344 ClearCF(iret_addr.flags);
8345 } else {
8346 SetCF(iret_addr.flags); // Unsupported
8347 }
8348}
8349
8350// returns bootsegment in ax, drive in bl
8351 Bit32u
8352int19_function(bseqnr)
8353Bit8u bseqnr;
8354{
8355 Bit16u ebda_seg=read_word(0x0040,0x000E);
8356 Bit16u bootseq;
8357 Bit8u bootdrv;
8358 Bit8u bootcd;
8359#ifdef VBOX
8360 Bit8u bootlan;
8361#endif /* VBOX */
8362 Bit8u bootchk;
8363 Bit16u bootseg;
8364 Bit16u status;
8365 Bit8u lastdrive=0;
8366
8367 // if BX_ELTORITO_BOOT is not defined, old behavior
8368 // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
8369 // in preparation for the initial INT 13h (0=floppy A:, 0x80=C:)
8370 // 0: system boot sequence, first drive C: then A:
8371 // 1: system boot sequence, first drive A: then C:
8372 // else BX_ELTORITO_BOOT is defined
8373 // CMOS regs 0x3D and 0x38 contain the boot sequence:
8374 // CMOS reg 0x3D & 0x0f : 1st boot device
8375 // CMOS reg 0x3D & 0xf0 : 2nd boot device
8376 // CMOS reg 0x38 & 0xf0 : 3rd boot device
8377#ifdef VBOX
8378 // CMOS reg 0x3C & 0x0f : 4th boot device
8379#endif /* VBOX */
8380 // boot device codes:
8381 // 0x00 : not defined
8382 // 0x01 : first floppy
8383 // 0x02 : first harddrive
8384 // 0x03 : first cdrom
8385#ifdef VBOX
8386 // 0x04 : local area network
8387#endif /* VBOX */
8388 // else : boot failure
8389
8390 // Get the boot sequence
8391#if BX_ELTORITO_BOOT
8392 bootseq=inb_cmos(0x3d);
8393 bootseq|=((inb_cmos(0x38) & 0xf0) << 4);
8394#ifdef VBOX
8395 bootseq|=((inb_cmos(0x3c) & 0x0f) << 12);
8396 if (read_byte(ebda_seg, &EbdaData->uForceBootDevice))
8397 bootseq = read_byte(ebda_seg, &EbdaData->uForceBootDevice);
8398 /* Boot delay hack. */
8399 if (bseqnr == 1)
8400 delay_boot((inb_cmos(0x3c) & 0xf0) >> 4); /* Implemented in logo.c */
8401#endif /* VBOX */
8402
8403 if (bseqnr==2) bootseq >>= 4;
8404 if (bseqnr==3) bootseq >>= 8;
8405#ifdef VBOX
8406 if (bseqnr==4) bootseq >>= 12;
8407#endif /* VBOX */
8408 if (bootseq<0x10) lastdrive = 1;
8409 bootdrv=0x00; bootcd=0;
8410#ifdef VBOX
8411 bootlan=0;
8412#endif /* VBOX */
8413
8414 switch(bootseq & 0x0f) {
8415 case 0x01:
8416 bootdrv=0x00;
8417 bootcd=0;
8418 break;
8419 case 0x02:
8420 {
8421 // Get the Boot drive.
8422 Bit8u boot_drive = read_byte(ebda_seg, &EbdaData->uForceBootDrive);
8423
8424 bootdrv = boot_drive + 0x80;
8425 bootcd=0;
8426 break;
8427 }
8428 case 0x03:
8429 bootdrv=0x00;
8430 bootcd=1;
8431 break;
8432#ifdef VBOX
8433 case 0x04: bootlan=1; break;
8434#endif /* VBOX */
8435 default: return 0x00000000;
8436 }
8437#else
8438 bootseq=inb_cmos(0x2d);
8439
8440 if (bseqnr==2) {
8441 bootseq ^= 0x20;
8442 lastdrive = 1;
8443 }
8444 bootdrv=0x00; bootcd=0;
8445 if((bootseq&0x20)==0) bootdrv=0x80;
8446#endif // BX_ELTORITO_BOOT
8447
8448#if BX_ELTORITO_BOOT
8449 // We have to boot from cd
8450 if (bootcd != 0) {
8451 status = cdrom_boot();
8452
8453 // If failure
8454 if ( (status & 0x00ff) !=0 ) {
8455 print_cdromboot_failure(status);
8456#ifdef VBOX
8457 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
8458#else /* !VBOX */
8459 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
8460#endif /* !VBOX */
8461 return 0x00000000;
8462 }
8463
8464 bootseg = read_word(ebda_seg,&EbdaData->cdemu.load_segment);
8465 bootdrv = (Bit8u)(status>>8);
8466 }
8467
8468#endif // BX_ELTORITO_BOOT
8469
8470#ifdef VBOX
8471 // Check for boot from LAN first
8472 if (bootlan == 1) {
8473 if (read_word(VBOX_LANBOOT_SEG,0) == 0xaa55) {
8474 Bit16u pnpoff;
8475 Bit32u manuf;
8476 // This is NOT a generic PnP implementation, but an Etherboot-specific hack.
8477 pnpoff = read_word(VBOX_LANBOOT_SEG,0x1a);
8478 if (read_dword(VBOX_LANBOOT_SEG,pnpoff) == 0x506e5024) {
8479 // Found PnP signature
8480 manuf = read_dword(VBOX_LANBOOT_SEG,read_word(VBOX_LANBOOT_SEG,pnpoff+0xe));
8481 if (manuf == 0x65687445) {
8482 // Found Etherboot ROM
8483 print_boot_device(bootcd, bootlan, bootdrv);
8484ASM_START
8485 push ds
8486 push es
8487 pusha
8488 calli 0x0006,VBOX_LANBOOT_SEG
8489 popa
8490 pop es
8491 pop ds
8492ASM_END
8493 } else if (manuf == 0x65746E49) {
8494 // Found Intel PXE ROM
8495 print_boot_device(bootcd, bootlan, bootdrv);
8496ASM_START
8497 push ds
8498 push es
8499 pusha
8500 sti ; Why are interrupts disabled now? Because we were called through an INT!
8501 push #VBOX_LANBOOT_SEG
8502 pop ds
8503 mov bx,#0x1a ; PnP header offset
8504 mov bx,[bx]
8505 add bx,#0x1a ; BEV offset in PnP header
8506 mov ax,[bx]
8507 test ax,ax
8508 jz no_rom
8509bev_jump:
8510 push cs
8511 push #no_rom
8512 push #VBOX_LANBOOT_SEG
8513 push ax
8514 retf ; call Boot Entry Vector
8515no_rom:
8516 popa
8517 pop es
8518 pop ds
8519ASM_END
8520 }
8521 }
8522 }
8523
8524 // boot from LAN will not return if successful.
8525 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
8526 return 0x00000000;
8527 }
8528#endif /* VBOX */
8529 // We have to boot from harddisk or floppy
8530#ifdef VBOX
8531 if (bootcd == 0 && bootlan == 0) {
8532#else /* !VBOX */
8533 if (bootcd == 0) {
8534#endif /* !VBOX */
8535 bootseg=0x07c0;
8536
8537ASM_START
8538 push bp
8539 mov bp, sp
8540
8541 xor ax, ax
8542 mov _int19_function.status + 2[bp], ax
8543 mov dl, _int19_function.bootdrv + 2[bp]
8544 mov ax, _int19_function.bootseg + 2[bp]
8545 mov es, ax ;; segment
8546 xor bx, bx ;; offset
8547 mov ah, #0x02 ;; function 2, read diskette sector
8548 mov al, #0x01 ;; read 1 sector
8549 mov ch, #0x00 ;; track 0
8550 mov cl, #0x01 ;; sector 1
8551 mov dh, #0x00 ;; head 0
8552 int #0x13 ;; read sector
8553 jnc int19_load_done
8554 mov ax, #0x0001
8555 mov _int19_function.status + 2[bp], ax
8556
8557int19_load_done:
8558 pop bp
8559ASM_END
8560
8561 if (status != 0) {
8562#ifdef VBOX
8563 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
8564#else /* !VBOX */
8565 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
8566#endif /* !VBOX */
8567 return 0x00000000;
8568 }
8569 }
8570
8571#ifdef VBOX
8572 // Don't check boot sectors on floppies and don't read CMOS - byte
8573 // 0x38 in CMOS always has the low bit clear.
8574 // There is *no* requirement whatsoever for a valid boot sector to
8575 // have a 55AAh signature. UNIX boot floppies typically have no such
8576 // signature. In general, it is impossible to tell a valid bootsector
8577 // from an invalid one.
8578 // NB: It is somewhat common for failed OS installs to have the
8579 // 0x55AA signature and a valid partition table but zeros in the
8580 // rest of the boot sector. We do a quick check by comparing the first
8581 // two words of boot sector; if identical, the boot sector is
8582 // extremely unlikely to be valid.
8583#endif
8584 // check signature if instructed by cmos reg 0x38, only for floppy
8585 // bootchk = 1 : signature check disabled
8586 // bootchk = 0 : signature check enabled
8587 if (bootdrv != 0) bootchk = 0;
8588#ifdef VBOX
8589 else bootchk = 1; /* disable 0x55AA signature check on drive A: */
8590#else
8591 else bootchk = inb_cmos(0x38) & 0x01;
8592#endif
8593
8594#if BX_ELTORITO_BOOT
8595 // if boot from cd, no signature check
8596 if (bootcd != 0)
8597 bootchk = 1;
8598#endif // BX_ELTORITO_BOOT
8599
8600 if (bootchk == 0) {
8601 if (read_word(bootseg,0x1fe) != 0xaa55 ||
8602 read_word(bootseg,0) == read_word(bootseg,2)) {
8603#ifdef VBOX
8604 print_boot_failure(bootcd, bootlan, bootdrv, 0, lastdrive);
8605#else /* !VBOX */
8606 print_boot_failure(bootcd, bootdrv, 0, lastdrive);
8607#endif /* VBOX */
8608 return 0x00000000;
8609 }
8610 }
8611
8612#if BX_ELTORITO_BOOT
8613 // Print out the boot string
8614#ifdef VBOX
8615 print_boot_device(bootcd, bootlan, bootdrv);
8616#else /* !VBOX */
8617 print_boot_device(bootcd, bootdrv);
8618#endif /* !VBOX */
8619#else // BX_ELTORITO_BOOT
8620#ifdef VBOX
8621 print_boot_device(0, bootlan, bootdrv);
8622#else /* !VBOX */
8623 print_boot_device(0, bootdrv);
8624#endif /* !VBOX */
8625#endif // BX_ELTORITO_BOOT
8626
8627 // return the boot segment
8628 return (((Bit32u)bootdrv) << 16) + bootseg;
8629}
8630
8631 void
8632int1a_function(regs, ds, iret_addr)
8633 pusha_regs_t regs; // regs pushed from PUSHA instruction
8634 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8635 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8636{
8637 Bit8u val8;
8638
8639 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);
8640
8641 ASM_START
8642 sti
8643 ASM_END
8644
8645 switch (regs.u.r8.ah) {
8646 case 0: // get current clock count
8647 ASM_START
8648 cli
8649 ASM_END
8650 regs.u.r16.cx = BiosData->ticks_high;
8651 regs.u.r16.dx = BiosData->ticks_low;
8652 regs.u.r8.al = BiosData->midnight_flag;
8653 BiosData->midnight_flag = 0; // reset flag
8654 ASM_START
8655 sti
8656 ASM_END
8657 // AH already 0
8658 ClearCF(iret_addr.flags); // OK
8659 break;
8660
8661 case 1: // Set Current Clock Count
8662 ASM_START
8663 cli
8664 ASM_END
8665 BiosData->ticks_high = regs.u.r16.cx;
8666 BiosData->ticks_low = regs.u.r16.dx;
8667 BiosData->midnight_flag = 0; // reset flag
8668 ASM_START
8669 sti
8670 ASM_END
8671 regs.u.r8.ah = 0;
8672 ClearCF(iret_addr.flags); // OK
8673 break;
8674
8675
8676 case 2: // Read CMOS Time
8677 if (rtc_updating()) {
8678 SetCF(iret_addr.flags);
8679 break;
8680 }
8681
8682 regs.u.r8.dh = inb_cmos(0x00); // Seconds
8683 regs.u.r8.cl = inb_cmos(0x02); // Minutes
8684 regs.u.r8.ch = inb_cmos(0x04); // Hours
8685 regs.u.r8.dl = inb_cmos(0x0b) & 0x01; // Stat Reg B
8686 regs.u.r8.ah = 0;
8687 regs.u.r8.al = regs.u.r8.ch;
8688 ClearCF(iret_addr.flags); // OK
8689 break;
8690
8691 case 3: // Set CMOS Time
8692 // Using a debugger, I notice the following masking/setting
8693 // of bits in Status Register B, by setting Reg B to
8694 // a few values and getting its value after INT 1A was called.
8695 //
8696 // try#1 try#2 try#3
8697 // before 1111 1101 0111 1101 0000 0000
8698 // after 0110 0010 0110 0010 0000 0010
8699 //
8700 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8701 // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
8702 if (rtc_updating()) {
8703 init_rtc();
8704 // fall through as if an update were not in progress
8705 }
8706 outb_cmos(0x00, regs.u.r8.dh); // Seconds
8707 outb_cmos(0x02, regs.u.r8.cl); // Minutes
8708 outb_cmos(0x04, regs.u.r8.ch); // Hours
8709 // Set Daylight Savings time enabled bit to requested value
8710 val8 = (inb_cmos(0x0b) & 0x60) | 0x02 | (regs.u.r8.dl & 0x01);
8711 // (reg B already selected)
8712 outb_cmos(0x0b, val8);
8713 regs.u.r8.ah = 0;
8714 regs.u.r8.al = val8; // val last written to Reg B
8715 ClearCF(iret_addr.flags); // OK
8716 break;
8717
8718 case 4: // Read CMOS Date
8719 regs.u.r8.ah = 0;
8720 if (rtc_updating()) {
8721 SetCF(iret_addr.flags);
8722 break;
8723 }
8724 regs.u.r8.cl = inb_cmos(0x09); // Year
8725 regs.u.r8.dh = inb_cmos(0x08); // Month
8726 regs.u.r8.dl = inb_cmos(0x07); // Day of Month
8727 regs.u.r8.ch = inb_cmos(0x32); // Century
8728 regs.u.r8.al = regs.u.r8.ch;
8729 ClearCF(iret_addr.flags); // OK
8730 break;
8731
8732 case 5: // Set CMOS Date
8733 // Using a debugger, I notice the following masking/setting
8734 // of bits in Status Register B, by setting Reg B to
8735 // a few values and getting its value after INT 1A was called.
8736 //
8737 // try#1 try#2 try#3 try#4
8738 // before 1111 1101 0111 1101 0000 0010 0000 0000
8739 // after 0110 1101 0111 1101 0000 0010 0000 0000
8740 //
8741 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8742 // My assumption: RegB = (RegB & 01111111b)
8743 if (rtc_updating()) {
8744 init_rtc();
8745 SetCF(iret_addr.flags);
8746 break;
8747 }
8748 outb_cmos(0x09, regs.u.r8.cl); // Year
8749 outb_cmos(0x08, regs.u.r8.dh); // Month
8750 outb_cmos(0x07, regs.u.r8.dl); // Day of Month
8751 outb_cmos(0x32, regs.u.r8.ch); // Century
8752 val8 = inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
8753 outb_cmos(0x0b, val8);
8754 regs.u.r8.ah = 0;
8755 regs.u.r8.al = val8; // AL = val last written to Reg B
8756 ClearCF(iret_addr.flags); // OK
8757 break;
8758
8759 case 6: // Set Alarm Time in CMOS
8760 // Using a debugger, I notice the following masking/setting
8761 // of bits in Status Register B, by setting Reg B to
8762 // a few values and getting its value after INT 1A was called.
8763 //
8764 // try#1 try#2 try#3
8765 // before 1101 1111 0101 1111 0000 0000
8766 // after 0110 1111 0111 1111 0010 0000
8767 //
8768 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8769 // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
8770 val8 = inb_cmos(0x0b); // Get Status Reg B
8771 regs.u.r16.ax = 0;
8772 if (val8 & 0x20) {
8773 // Alarm interrupt enabled already
8774 SetCF(iret_addr.flags); // Error: alarm in use
8775 break;
8776 }
8777 if (rtc_updating()) {
8778 init_rtc();
8779 // fall through as if an update were not in progress
8780 }
8781 outb_cmos(0x01, regs.u.r8.dh); // Seconds alarm
8782 outb_cmos(0x03, regs.u.r8.cl); // Minutes alarm
8783 outb_cmos(0x05, regs.u.r8.ch); // Hours alarm
8784 outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
8785 // enable Status Reg B alarm bit, clear halt clock bit
8786 outb_cmos(0x0b, (val8 & 0x7f) | 0x20);
8787 ClearCF(iret_addr.flags); // OK
8788 break;
8789
8790 case 7: // Turn off Alarm
8791 // Using a debugger, I notice the following masking/setting
8792 // of bits in Status Register B, by setting Reg B to
8793 // a few values and getting its value after INT 1A was called.
8794 //
8795 // try#1 try#2 try#3 try#4
8796 // before 1111 1101 0111 1101 0010 0000 0010 0010
8797 // after 0100 0101 0101 0101 0000 0000 0000 0010
8798 //
8799 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8800 // My assumption: RegB = (RegB & 01010111b)
8801 val8 = inb_cmos(0x0b); // Get Status Reg B
8802 // clear clock-halt bit, disable alarm bit
8803 outb_cmos(0x0b, val8 & 0x57); // disable alarm bit
8804 regs.u.r8.ah = 0;
8805 regs.u.r8.al = val8; // val last written to Reg B
8806 ClearCF(iret_addr.flags); // OK
8807 break;
8808#if BX_PCIBIOS
8809 case 0xb1:
8810 // real mode PCI BIOS functions now handled in assembler code
8811 // this C code handles the error code for information only
8812 if (regs.u.r8.bl == 0xff) {
8813 BX_INFO("PCI BIOS: PCI not present\n");
8814 } else if (regs.u.r8.bl == 0x81) {
8815 BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs.u.r8.al);
8816 } else if (regs.u.r8.bl == 0x83) {
8817 BX_INFO("bad PCI vendor ID %04x\n", regs.u.r16.dx);
8818 } else if (regs.u.r8.bl == 0x86) {
8819 if (regs.u.r8.al == 0x02) {
8820 BX_INFO("PCI device %04x:%04x not found at index %d\n", regs.u.r16.dx, regs.u.r16.cx, regs.u.r16.si);
8821 } else {
8822 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);
8823 }
8824 }
8825 regs.u.r8.ah = regs.u.r8.bl;
8826 SetCF(iret_addr.flags);
8827 break;
8828#endif
8829
8830 default:
8831 SetCF(iret_addr.flags); // Unsupported
8832 }
8833}
8834
8835 void
8836int70_function(regs, ds, iret_addr)
8837 pusha_regs_t regs; // regs pushed from PUSHA instruction
8838 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8839 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8840{
8841 // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
8842 Bit8u registerB = 0, registerC = 0;
8843
8844 // Check which modes are enabled and have occurred.
8845 registerB = inb_cmos( 0xB );
8846 registerC = inb_cmos( 0xC );
8847
8848 if( ( registerB & 0x60 ) != 0 ) {
8849 if( ( registerC & 0x20 ) != 0 ) {
8850 // Handle Alarm Interrupt.
8851ASM_START
8852 sti
8853 int #0x4a
8854 cli
8855ASM_END
8856 }
8857 if( ( registerC & 0x40 ) != 0 ) {
8858 // Handle Periodic Interrupt.
8859
8860 if( read_byte( 0x40, 0xA0 ) != 0 ) {
8861 // Wait Interval (Int 15, AH=83) active.
8862 Bit32u time, toggle;
8863
8864 time = read_dword( 0x40, 0x9C ); // Time left in microseconds.
8865 if( time < 0x3D1 ) {
8866 // Done waiting.
8867 Bit16u segment, offset;
8868
8869 segment = read_word( 0x40, 0x98 );
8870 offset = read_word( 0x40, 0x9A );
8871 write_byte( 0x40, 0xA0, 0 ); // Turn of status byte.
8872 outb_cmos( 0xB, registerB & 0x37 ); // Clear the Periodic Interrupt.
8873 write_byte(segment, offset, read_byte(segment, offset) | 0x80 ); // Write to specified flag byte.
8874 } else {
8875 // Continue waiting.
8876 time -= 0x3D1;
8877 write_dword( 0x40, 0x9C, time );
8878 }
8879 }
8880 }
8881 }
8882
8883ASM_START
8884 call eoi_both_pics
8885ASM_END
8886}
8887
8888 void
8889dummy_isr_function(regs, ds, iret_addr)
8890 pusha_regs_t regs; // regs pushed from PUSHA instruction
8891 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8892 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8893{
8894 // Interrupt handler for unexpected hardware interrupts. We have to clear
8895 // the PIC because if we don't, the next EOI will clear the wrong interrupt
8896 // and all hell will break loose! This routine also masks the unexpected
8897 // interrupt so it will generally be called only once for each unexpected
8898 // interrupt level.
8899 Bit8u isrA, isrB, imr, last_int = 0xFF;
8900
8901 outb( 0x20, 0x0B );
8902 isrA = inb( 0x20 );
8903 if (isrA) {
8904 outb( 0xA0, 0x0B );
8905 isrB = inb( 0xA0 );
8906 if (isrB) {
8907 imr = inb( 0xA1 );
8908 outb( 0xA1, imr | isrB ); // Mask this interrupt
8909 outb( 0xA0, 0x20 ); // Send EOI on slave PIC
8910 } else {
8911 imr = inb( 0x21 );
8912 isrA &= 0xFB; // Never mask the cascade interrupt
8913 outb( 0x21, imr | isrA); // Mask this interrupt
8914 }
8915 outb( 0x20, 0x20 ); // Send EOI on master PIC
8916 last_int = isrA;
8917 }
8918 write_byte( 0x40, 0x6B, last_int ); // Write INTR_FLAG
8919}
8920
8921ASM_START
8922;------------------------------------------
8923;- INT74h : PS/2 mouse hardware interrupt -
8924;------------------------------------------
8925int74_handler:
8926 sti
8927 pusha
8928 push ds ;; save DS
8929 push #0x00 ;; placeholder for status
8930 push #0x00 ;; placeholder for X
8931 push #0x00 ;; placeholder for Y
8932 push #0x00 ;; placeholder for Z
8933 push #0x00 ;; placeholder for make_far_call boolean
8934 call _int74_function
8935 pop cx ;; remove make_far_call from stack
8936 jcxz int74_done
8937
8938 ;; make far call to EBDA:0022
8939 push #0x00
8940 pop ds
8941 push 0x040E ;; push 0000:040E (opcodes 0xff, 0x36, 0x0E, 0x04)
8942 pop ds
8943 //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
8944 call far ptr[0x22]
8945int74_done:
8946 cli
8947 call eoi_both_pics
8948 add sp, #8 ;; pop status, x, y, z
8949
8950 pop ds ;; restore DS
8951 popa
8952 iret
8953
8954
8955;; This will perform an IRET, but will retain value of current CF
8956;; by altering flags on stack. Better than RETF #02.
8957iret_modify_cf:
8958 jc carry_set
8959 push bp
8960 mov bp, sp
8961 and BYTE [bp + 0x06], #0xfe
8962 pop bp
8963 iret
8964carry_set:
8965 push bp
8966 mov bp, sp
8967 or BYTE [bp + 0x06], #0x01
8968 pop bp
8969 iret
8970
8971
8972;----------------------
8973;- INT13h (relocated) -
8974;----------------------
8975;
8976; int13_relocated is a little bit messed up since I played with it
8977; I have to rewrite it:
8978; - call a function that detect which function to call
8979; - make all called C function get the same parameters list
8980;
8981int13_relocated:
8982 cld ;; we will be doing some string I/O
8983
8984#if BX_ELTORITO_BOOT
8985 ;; check for an eltorito function
8986 cmp ah,#0x4a
8987 jb int13_not_eltorito
8988 cmp ah,#0x4d
8989 ja int13_not_eltorito
8990
8991 pusha
8992 push es
8993 push ds
8994 push ss
8995 pop ds
8996
8997 push #int13_out
8998 jmp _int13_eltorito ;; ELDX not used
8999
9000int13_not_eltorito:
9001 push ax
9002 push bx
9003 push cx
9004 push dx
9005
9006 ;; check if emulation active
9007 call _cdemu_isactive
9008 cmp al,#0x00
9009 je int13_cdemu_inactive
9010
9011 ;; check if access to the emulated drive
9012 call _cdemu_emulated_drive
9013 pop dx
9014 push dx
9015 cmp al,dl ;; int13 on emulated drive
9016 jne int13_nocdemu
9017
9018 pop dx
9019 pop cx
9020 pop bx
9021 pop ax
9022
9023 pusha
9024 push es
9025 push ds
9026 push ss
9027 pop ds
9028
9029 push #int13_out
9030 jmp _int13_cdemu ;; ELDX not used
9031
9032int13_nocdemu:
9033 and dl,#0xE0 ;; mask to get device class, including cdroms
9034 cmp al,dl ;; al is 0x00 or 0x80
9035 jne int13_cdemu_inactive ;; inactive for device class
9036
9037 pop dx
9038 pop cx
9039 pop bx
9040 pop ax
9041
9042 push ax
9043 push cx
9044 push dx
9045 push bx
9046
9047 dec dl ;; real drive is dl - 1
9048 jmp int13_legacy
9049
9050int13_cdemu_inactive:
9051 pop dx
9052 pop cx
9053 pop bx
9054 pop ax
9055
9056#endif // BX_ELTORITO_BOOT
9057
9058int13_noeltorito:
9059
9060 push ax
9061 push cx
9062 push dx
9063 push bx
9064
9065int13_legacy:
9066
9067 push dx ;; push eltorito value of dx instead of sp
9068
9069 push bp
9070 push si
9071 push di
9072
9073 push es
9074 push ds
9075 push ss
9076 pop ds
9077
9078 ;; now the 16-bit registers can be restored with:
9079 ;; pop ds; pop es; popa; iret
9080 ;; arguments passed to functions should be
9081 ;; DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS
9082
9083 test dl, #0x80
9084 jnz int13_notfloppy
9085
9086 push #int13_out
9087 jmp _int13_diskette_function
9088
9089int13_notfloppy:
9090
9091#if BX_USE_ATADRV
9092
9093 cmp dl, #0xE0
9094 jb int13_notcdrom
9095
9096 // ebx is modified: BSD 5.2.1 boot loader problem
9097 // someone should figure out which 32 bit register that actually are used
9098
9099 shr ebx, #16
9100 push bx
9101
9102 call _int13_cdrom
9103
9104 pop bx
9105 shl ebx, #16
9106
9107 jmp int13_out
9108
9109int13_notcdrom:
9110
9111#endif
9112
9113int13_disk:
9114 ;; int13_harddisk modifies high word of EAX and EBX
9115 shr eax, #16
9116 push ax
9117 shr ebx, #16
9118 push bx
9119 call _int13_harddisk
9120 pop bx
9121 shl ebx, #16
9122 pop ax
9123 shl eax, #16
9124
9125int13_out:
9126 pop ds
9127 pop es
9128 popa
9129 iret
9130
9131;----------
9132;- INT18h -
9133;----------
9134int18_handler: ;; Boot Failure routing
9135 call _int18_panic_msg
9136 hlt
9137 iret
9138
9139;----------
9140;- INT19h -
9141;----------
9142int19_relocated: ;; Boot function, relocated
9143
9144#ifdef VBOX
9145 // If an already booted OS calls int 0x19 to reboot, it is not sufficient
9146 // just to try booting from the configured drives. All BIOS variables and
9147 // interrupt vectors need to be reset, otherwise strange things may happen.
9148 // The approach used is faking a warm reboot (which just skips showing the
9149 // logo), which is a bit more than what we need, but hey, it's fast.
9150 mov bp, sp
9151 mov ax, 2[bp]
9152 cmp ax, #0xf000
9153 jz bios_initiated_boot
9154 xor ax, ax
9155 mov ds, ax
9156 mov ax, #0x1234
9157 mov 0x472, ax
9158 jmp post
9159bios_initiated_boot:
9160#endif /* VBOX */
9161
9162 ;; int19 was beginning to be really complex, so now it
9163 ;; just calls a C function that does the work
9164 ;; it returns in BL the boot drive, and in AX the boot segment
9165 ;; the boot segment will be 0x0000 if something has failed
9166
9167 push bp
9168 mov bp, sp
9169
9170 ;; drop ds
9171 xor ax, ax
9172 mov ds, ax
9173
9174 ;; 1st boot device
9175 mov ax, #0x0001
9176 push ax
9177 call _int19_function
9178 inc sp
9179 inc sp
9180 ;; bl contains the boot drive
9181 ;; ax contains the boot segment or 0 if failure
9182
9183 test ax, ax ;; if ax is 0 try next boot device
9184 jnz boot_setup
9185
9186 ;; 2nd boot device
9187 mov ax, #0x0002
9188 push ax
9189 call _int19_function
9190 inc sp
9191 inc sp
9192 test ax, ax ;; if ax is 0 try next boot device
9193 jnz boot_setup
9194
9195 ;; 3rd boot device
9196 mov ax, #0x0003
9197 push ax
9198 call _int19_function
9199 inc sp
9200 inc sp
9201#ifdef VBOX
9202 test ax, ax ;; if ax is 0 try next boot device
9203 jnz boot_setup
9204
9205 ;; 4th boot device
9206 mov ax, #0x0004
9207 push ax
9208 call _int19_function
9209 inc sp
9210 inc sp
9211#endif /* VBOX */
9212 test ax, ax ;; if ax is 0 call int18
9213 jz int18_handler
9214
9215boot_setup:
9216 mov dl, bl ;; set drive so guest os find it
9217 shl eax, #0x04 ;; convert seg to ip
9218 mov 2[bp], ax ;; set ip
9219
9220 shr eax, #0x04 ;; get cs back
9221 and ax, #0xF000 ;; remove what went in ip
9222 mov 4[bp], ax ;; set cs
9223 xor ax, ax
9224 mov es, ax ;; set es to zero fixes [ 549815 ]
9225 mov [bp], ax ;; set bp to zero
9226 mov ax, #0xaa55 ;; set ok flag
9227
9228 pop bp
9229 iret ;; Beam me up Scotty
9230
9231;----------
9232;- INT1Ch -
9233;----------
9234int1c_handler: ;; User Timer Tick
9235 iret
9236
9237
9238;----------------------
9239;- POST: Floppy Drive -
9240;----------------------
9241floppy_drive_post:
9242 xor ax, ax
9243 mov ds, ax
9244
9245 mov al, #0x00
9246 mov 0x043e, al ;; drive 0 & 1 uncalibrated, no interrupt has occurred
9247
9248 mov 0x043f, al ;; diskette motor status: read op, drive0, motors off
9249
9250 mov 0x0440, al ;; diskette motor timeout counter: not active
9251 mov 0x0441, al ;; diskette controller status return code
9252
9253 mov 0x0442, al ;; disk & diskette controller status register 0
9254 mov 0x0443, al ;; diskette controller status register 1
9255 mov 0x0444, al ;; diskette controller status register 2
9256 mov 0x0445, al ;; diskette controller cylinder number
9257 mov 0x0446, al ;; diskette controller head number
9258 mov 0x0447, al ;; diskette controller sector number
9259 mov 0x0448, al ;; diskette controller bytes written
9260
9261 mov 0x048b, al ;; diskette configuration data
9262
9263 ;; -----------------------------------------------------------------
9264 ;; (048F) diskette controller information
9265 ;;
9266 mov al, #0x10 ;; get CMOS diskette drive type
9267 out 0x70, AL
9268 in AL, 0x71
9269 mov ah, al ;; save byte to AH
9270
9271look_drive0:
9272 shr al, #4 ;; look at top 4 bits for drive 0
9273 jz f0_missing ;; jump if no drive0
9274 mov bl, #0x07 ;; drive0 determined, multi-rate, has changed line
9275 jmp look_drive1
9276f0_missing:
9277 mov bl, #0x00 ;; no drive0
9278
9279look_drive1:
9280 mov al, ah ;; restore from AH
9281 and al, #0x0f ;; look at bottom 4 bits for drive 1
9282 jz f1_missing ;; jump if no drive1
9283 or bl, #0x70 ;; drive1 determined, multi-rate, has changed line
9284f1_missing:
9285 ;; leave high bits in BL zerod
9286 mov 0x048f, bl ;; put new val in BDA (diskette controller information)
9287 ;; -----------------------------------------------------------------
9288
9289 mov al, #0x00
9290 mov 0x0490, al ;; diskette 0 media state
9291 mov 0x0491, al ;; diskette 1 media state
9292
9293 ;; diskette 0,1 operational starting state
9294 ;; drive type has not been determined,
9295 ;; has no changed detection line
9296 mov 0x0492, al
9297 mov 0x0493, al
9298
9299 mov 0x0494, al ;; diskette 0 current cylinder
9300 mov 0x0495, al ;; diskette 1 current cylinder
9301
9302 mov al, #0x02
9303 out #0x0a, al ;; clear DMA-1 channel 2 mask bit
9304
9305 SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
9306 SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
9307 SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
9308
9309 ret
9310
9311
9312;--------------------
9313;- POST: HARD DRIVE -
9314;--------------------
9315; relocated here because the primary POST area isnt big enough.
9316hard_drive_post:
9317 // IRQ 14 = INT 76h
9318 // INT 76h calls INT 15h function ax=9100
9319
9320 mov al, #0x0a ; 0000 1010 = reserved, disable IRQ 14
9321 mov dx, #0x03f6
9322 out dx, al
9323
9324 xor ax, ax
9325 mov ds, ax
9326 mov 0x0474, al /* hard disk status of last operation */
9327 mov 0x0477, al /* hard disk port offset (XT only ???) */
9328 mov 0x048c, al /* hard disk status register */
9329 mov 0x048d, al /* hard disk error register */
9330 mov 0x048e, al /* hard disk task complete flag */
9331 mov al, #0x01
9332 mov 0x0475, al /* hard disk number attached */
9333 mov al, #0xc0
9334 mov 0x0476, al /* hard disk control byte */
9335 SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
9336 SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
9337 ;; INT 41h: hard disk 0 configuration pointer
9338 ;; INT 46h: hard disk 1 configuration pointer
9339 SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D)
9340 SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D)
9341
9342#ifndef VBOX /* This is done later (and the CMOS format is now different). */
9343 ;; move disk geometry data from CMOS to EBDA disk parameter table(s)
9344 mov al, #0x12
9345 out #0x70, al
9346 in al, #0x71
9347 and al, #0xf0
9348 cmp al, #0xf0
9349 je post_d0_extended
9350 jmp check_for_hd1
9351post_d0_extended:
9352 mov al, #0x19
9353 out #0x70, al
9354 in al, #0x71
9355 cmp al, #47 ;; decimal 47 - user definable
9356 je post_d0_type47
9357 HALT(__LINE__)
9358post_d0_type47:
9359 ;; CMOS purpose param table offset
9360 ;; 1b cylinders low 0
9361 ;; 1c cylinders high 1
9362 ;; 1d heads 2
9363 ;; 1e write pre-comp low 5
9364 ;; 1f write pre-comp high 6
9365 ;; 20 retries/bad map/heads>8 8
9366 ;; 21 landing zone low C
9367 ;; 22 landing zone high D
9368 ;; 23 sectors/track E
9369
9370 mov ax, #EBDA_SEG
9371 mov ds, ax
9372
9373 ;;; Filling EBDA table for hard disk 0.
9374 mov al, #0x1f
9375 out #0x70, al
9376 in al, #0x71
9377 mov ah, al
9378 mov al, #0x1e
9379 out #0x70, al
9380 in al, #0x71
9381 mov (0x003d + 0x05), ax ;; write precomp word
9382
9383 mov al, #0x20
9384 out #0x70, al
9385 in al, #0x71
9386 mov (0x003d + 0x08), al ;; drive control byte
9387
9388 mov al, #0x22
9389 out #0x70, al
9390 in al, #0x71
9391 mov ah, al
9392 mov al, #0x21
9393 out #0x70, al
9394 in al, #0x71
9395 mov (0x003d + 0x0C), ax ;; landing zone word
9396
9397 mov al, #0x1c ;; get cylinders word in AX
9398 out #0x70, al
9399 in al, #0x71 ;; high byte
9400 mov ah, al
9401 mov al, #0x1b
9402 out #0x70, al
9403 in al, #0x71 ;; low byte
9404 mov bx, ax ;; BX = cylinders
9405
9406 mov al, #0x1d
9407 out #0x70, al
9408 in al, #0x71
9409 mov cl, al ;; CL = heads
9410
9411 mov al, #0x23
9412 out #0x70, al
9413 in al, #0x71
9414 mov dl, al ;; DL = sectors
9415
9416 cmp bx, #1024
9417 jnbe hd0_post_logical_chs ;; if cylinders > 1024, use translated style CHS
9418
9419hd0_post_physical_chs:
9420 ;; no logical CHS mapping used, just physical CHS
9421 ;; use Standard Fixed Disk Parameter Table (FDPT)
9422 mov (0x003d + 0x00), bx ;; number of physical cylinders
9423 mov (0x003d + 0x02), cl ;; number of physical heads
9424 mov (0x003d + 0x0E), dl ;; number of physical sectors
9425 jmp check_for_hd1
9426
9427hd0_post_logical_chs:
9428 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
9429 mov (0x003d + 0x09), bx ;; number of physical cylinders
9430 mov (0x003d + 0x0b), cl ;; number of physical heads
9431 mov (0x003d + 0x04), dl ;; number of physical sectors
9432 mov (0x003d + 0x0e), dl ;; number of logical sectors (same)
9433 mov al, #0xa0
9434 mov (0x003d + 0x03), al ;; A0h signature, indicates translated table
9435
9436 cmp bx, #2048
9437 jnbe hd0_post_above_2048
9438 ;; 1024 < c <= 2048 cylinders
9439 shr bx, #0x01
9440 shl cl, #0x01
9441 jmp hd0_post_store_logical
9442
9443hd0_post_above_2048:
9444 cmp bx, #4096
9445 jnbe hd0_post_above_4096
9446 ;; 2048 < c <= 4096 cylinders
9447 shr bx, #0x02
9448 shl cl, #0x02
9449 jmp hd0_post_store_logical
9450
9451hd0_post_above_4096:
9452 cmp bx, #8192
9453 jnbe hd0_post_above_8192
9454 ;; 4096 < c <= 8192 cylinders
9455 shr bx, #0x03
9456 shl cl, #0x03
9457 jmp hd0_post_store_logical
9458
9459hd0_post_above_8192:
9460 ;; 8192 < c <= 16384 cylinders
9461 shr bx, #0x04
9462 shl cl, #0x04
9463
9464hd0_post_store_logical:
9465 mov (0x003d + 0x00), bx ;; number of physical cylinders
9466 mov (0x003d + 0x02), cl ;; number of physical heads
9467 ;; checksum
9468 mov cl, #0x0f ;; repeat count
9469 mov si, #0x003d ;; offset to disk0 FDPT
9470 mov al, #0x00 ;; sum
9471hd0_post_checksum_loop:
9472 add al, [si]
9473 inc si
9474 dec cl
9475 jnz hd0_post_checksum_loop
9476 not al ;; now take 2s complement
9477 inc al
9478 mov [si], al
9479;;; Done filling EBDA table for hard disk 0.
9480
9481
9482check_for_hd1:
9483 ;; is there really a second hard disk? if not, return now
9484 mov al, #0x12
9485 out #0x70, al
9486 in al, #0x71
9487 and al, #0x0f
9488 jnz post_d1_exists
9489 ret
9490post_d1_exists:
9491 ;; check that the hd type is really 0x0f.
9492 cmp al, #0x0f
9493 jz post_d1_extended
9494 HALT(__LINE__)
9495post_d1_extended:
9496 ;; check that the extended type is 47 - user definable
9497 mov al, #0x1a
9498 out #0x70, al
9499 in al, #0x71
9500 cmp al, #47 ;; decimal 47 - user definable
9501 je post_d1_type47
9502 HALT(__LINE__)
9503post_d1_type47:
9504 ;; Table for disk1.
9505 ;; CMOS purpose param table offset
9506 ;; 0x24 cylinders low 0
9507 ;; 0x25 cylinders high 1
9508 ;; 0x26 heads 2
9509 ;; 0x27 write pre-comp low 5
9510 ;; 0x28 write pre-comp high 6
9511 ;; 0x29 heads>8 8
9512 ;; 0x2a landing zone low C
9513 ;; 0x2b landing zone high D
9514 ;; 0x2c sectors/track E
9515;;; Fill EBDA table for hard disk 1.
9516 mov ax, #EBDA_SEG
9517 mov ds, ax
9518 mov al, #0x28
9519 out #0x70, al
9520 in al, #0x71
9521 mov ah, al
9522 mov al, #0x27
9523 out #0x70, al
9524 in al, #0x71
9525 mov (0x004d + 0x05), ax ;; write precomp word
9526
9527 mov al, #0x29
9528 out #0x70, al
9529 in al, #0x71
9530 mov (0x004d + 0x08), al ;; drive control byte
9531
9532 mov al, #0x2b
9533 out #0x70, al
9534 in al, #0x71
9535 mov ah, al
9536 mov al, #0x2a
9537 out #0x70, al
9538 in al, #0x71
9539 mov (0x004d + 0x0C), ax ;; landing zone word
9540
9541 mov al, #0x25 ;; get cylinders word in AX
9542 out #0x70, al
9543 in al, #0x71 ;; high byte
9544 mov ah, al
9545 mov al, #0x24
9546 out #0x70, al
9547 in al, #0x71 ;; low byte
9548 mov bx, ax ;; BX = cylinders
9549
9550 mov al, #0x26
9551 out #0x70, al
9552 in al, #0x71
9553 mov cl, al ;; CL = heads
9554
9555 mov al, #0x2c
9556 out #0x70, al
9557 in al, #0x71
9558 mov dl, al ;; DL = sectors
9559
9560 cmp bx, #1024
9561 jnbe hd1_post_logical_chs ;; if cylinders > 1024, use translated style CHS
9562
9563hd1_post_physical_chs:
9564 ;; no logical CHS mapping used, just physical CHS
9565 ;; use Standard Fixed Disk Parameter Table (FDPT)
9566 mov (0x004d + 0x00), bx ;; number of physical cylinders
9567 mov (0x004d + 0x02), cl ;; number of physical heads
9568 mov (0x004d + 0x0E), dl ;; number of physical sectors
9569 ret
9570
9571hd1_post_logical_chs:
9572 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
9573 mov (0x004d + 0x09), bx ;; number of physical cylinders
9574 mov (0x004d + 0x0b), cl ;; number of physical heads
9575 mov (0x004d + 0x04), dl ;; number of physical sectors
9576 mov (0x004d + 0x0e), dl ;; number of logical sectors (same)
9577 mov al, #0xa0
9578 mov (0x004d + 0x03), al ;; A0h signature, indicates translated table
9579
9580 cmp bx, #2048
9581 jnbe hd1_post_above_2048
9582 ;; 1024 < c <= 2048 cylinders
9583 shr bx, #0x01
9584 shl cl, #0x01
9585 jmp hd1_post_store_logical
9586
9587hd1_post_above_2048:
9588 cmp bx, #4096
9589 jnbe hd1_post_above_4096
9590 ;; 2048 < c <= 4096 cylinders
9591 shr bx, #0x02
9592 shl cl, #0x02
9593 jmp hd1_post_store_logical
9594
9595hd1_post_above_4096:
9596 cmp bx, #8192
9597 jnbe hd1_post_above_8192
9598 ;; 4096 < c <= 8192 cylinders
9599 shr bx, #0x03
9600 shl cl, #0x03
9601 jmp hd1_post_store_logical
9602
9603hd1_post_above_8192:
9604 ;; 8192 < c <= 16384 cylinders
9605 shr bx, #0x04
9606 shl cl, #0x04
9607
9608hd1_post_store_logical:
9609 mov (0x004d + 0x00), bx ;; number of physical cylinders
9610 mov (0x004d + 0x02), cl ;; number of physical heads
9611 ;; checksum
9612 mov cl, #0x0f ;; repeat count
9613 mov si, #0x004d ;; offset to disk0 FDPT
9614 mov al, #0x00 ;; sum
9615hd1_post_checksum_loop:
9616 add al, [si]
9617 inc si
9618 dec cl
9619 jnz hd1_post_checksum_loop
9620 not al ;; now take 2s complement
9621 inc al
9622 mov [si], al
9623;;; Done filling EBDA table for hard disk 1.
9624#endif /* !VBOX */
9625
9626 ret
9627
9628;--------------------
9629;- POST: EBDA segment
9630;--------------------
9631; relocated here because the primary POST area isnt big enough.
9632; the SET_INT_VECTORs have nothing to do with EBDA but do not
9633; fit into the primary POST area either
9634ebda_post:
9635 SET_INT_VECTOR(0x0D, #0xF000, #dummy_isr); IRQ 5
9636 SET_INT_VECTOR(0x0F, #0xF000, #dummy_isr); IRQ 7
9637 SET_INT_VECTOR(0x72, #0xF000, #dummy_isr); IRQ 11
9638 SET_INT_VECTOR(0x77, #0xF000, #dummy_isr); IRQ 15
9639
9640#if BX_USE_EBDA
9641 mov ax, #EBDA_SEG
9642 mov ds, ax
9643 mov byte ptr [0x0], #EBDA_SIZE
9644#endif
9645 xor ax, ax ; mov EBDA seg into 40E
9646 mov ds, ax
9647 mov word ptr [0x40E], #EBDA_SEG
9648 ret;;
9649
9650;--------------------
9651;- POST: EOI + jmp via [0x40:67)
9652;--------------------
9653; relocated here because the primary POST area isnt big enough.
9654eoi_jmp_post:
9655 call eoi_both_pics
9656
9657 xor ax, ax
9658 mov ds, ax
9659
9660 jmp far ptr [0x467]
9661
9662
9663;--------------------
9664eoi_both_pics:
9665 mov al, #0x20
9666 out #0xA0, al ;; slave PIC EOI
9667eoi_master_pic:
9668 mov al, #0x20
9669 out #0x20, al ;; master PIC EOI
9670 ret
9671
9672;--------------------
9673BcdToBin:
9674 ;; in: AL in BCD format
9675 ;; out: AL in binary format, AH will always be 0
9676 ;; trashes BX
9677 mov bl, al
9678 and bl, #0x0f ;; bl has low digit
9679 shr al, #4 ;; al has high digit
9680 mov bh, #10
9681 mul al, bh ;; multiply high digit by 10 (result in AX)
9682 add al, bl ;; then add low digit
9683 ret
9684
9685;--------------------
9686timer_tick_post:
9687 ;; Setup the Timer Ticks Count (0x46C:dword) and
9688 ;; Timer Ticks Roller Flag (0x470:byte)
9689 ;; The Timer Ticks Count needs to be set according to
9690 ;; the current CMOS time, as if ticks have been occurring
9691 ;; at 18.2hz since midnight up to this point. Calculating
9692 ;; this is a little complicated. Here are the factors I gather
9693 ;; regarding this. 14,318,180 hz was the original clock speed,
9694 ;; chosen so it could be divided by either 3 to drive the 5Mhz CPU
9695 ;; at the time, or 4 to drive the CGA video adapter. The div3
9696 ;; source was divided again by 4 to feed a 1.193Mhz signal to
9697 ;; the timer. With a maximum 16bit timer count, this is again
9698 ;; divided down by 65536 to 18.2hz.
9699 ;;
9700 ;; 14,318,180 Hz clock
9701 ;; /3 = 4,772,726 Hz fed to original 5Mhz CPU
9702 ;; /4 = 1,193,181 Hz fed to timer
9703 ;; /65536 (maximum timer count) = 18.20650736 ticks/second
9704 ;; 1 second = 18.20650736 ticks
9705 ;; 1 minute = 1092.390442 ticks
9706 ;; 1 hour = 65543.42651 ticks
9707 ;;
9708 ;; Given the values in the CMOS clock, one could calculate
9709 ;; the number of ticks by the following:
9710 ;; ticks = (BcdToBin(seconds) * 18.206507) +
9711 ;; (BcdToBin(minutes) * 1092.3904)
9712 ;; (BcdToBin(hours) * 65543.427)
9713 ;; To get a little more accuracy, since Im using integer
9714 ;; arithmetic, I use:
9715 ;; ticks = (BcdToBin(seconds) * 18206507) / 1000000 +
9716 ;; (BcdToBin(minutes) * 10923904) / 10000 +
9717 ;; (BcdToBin(hours) * 65543427) / 1000
9718
9719 ;; assuming DS=0000
9720
9721 ;; get CMOS seconds
9722 xor eax, eax ;; clear EAX
9723 mov al, #0x00
9724 out #0x70, al
9725 in al, #0x71 ;; AL has CMOS seconds in BCD
9726 call BcdToBin ;; EAX now has seconds in binary
9727 mov edx, #18206507
9728 mul eax, edx
9729 mov ebx, #1000000
9730 xor edx, edx
9731 div eax, ebx
9732 mov ecx, eax ;; ECX will accumulate total ticks
9733
9734 ;; get CMOS minutes
9735 xor eax, eax ;; clear EAX
9736 mov al, #0x02
9737 out #0x70, al
9738 in al, #0x71 ;; AL has CMOS minutes in BCD
9739 call BcdToBin ;; EAX now has minutes in binary
9740 mov edx, #10923904
9741 mul eax, edx
9742 mov ebx, #10000
9743 xor edx, edx
9744 div eax, ebx
9745 add ecx, eax ;; add to total ticks
9746
9747 ;; get CMOS hours
9748 xor eax, eax ;; clear EAX
9749 mov al, #0x04
9750 out #0x70, al
9751 in al, #0x71 ;; AL has CMOS hours in BCD
9752 call BcdToBin ;; EAX now has hours in binary
9753 mov edx, #65543427
9754 mul eax, edx
9755 mov ebx, #1000
9756 xor edx, edx
9757 div eax, ebx
9758 add ecx, eax ;; add to total ticks
9759
9760 mov 0x46C, ecx ;; Timer Ticks Count
9761 xor al, al
9762 mov 0x470, al ;; Timer Ticks Rollover Flag
9763 ret
9764
9765;--------------------
9766int76_handler:
9767 ;; record completion in BIOS task complete flag
9768 push ax
9769 push ds
9770 mov ax, #0x0040
9771 mov ds, ax
9772 mov 0x008E, #0xff
9773 call eoi_both_pics
9774 pop ds
9775 pop ax
9776 iret
9777
9778
9779;--------------------
9780#ifdef VBOX
9781init_pic:
9782 ;; init PIC
9783 mov al, #0x11 ; send initialisation commands
9784 out 0x20, al
9785 out 0xa0, al
9786 mov al, #0x08
9787 out 0x21, al
9788 mov al, #0x70
9789 out 0xa1, al
9790 mov al, #0x04
9791 out 0x21, al
9792 mov al, #0x02
9793 out 0xa1, al
9794 mov al, #0x01
9795 out 0x21, al
9796 out 0xa1, al
9797 mov al, #0xb8
9798 out 0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6
9799#if BX_USE_PS2_MOUSE
9800 mov al, #0x8f
9801#else
9802 mov al, #0x9f
9803#endif
9804 out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14
9805 ret
9806#endif /* VBOX */
9807
9808;--------------------
9809#if BX_APM
9810
9811use32 386
9812#define APM_PROT32
9813#include "apmbios.S"
9814
9815use16 386
9816#define APM_PROT16
9817#include "apmbios.S"
9818
9819#define APM_REAL
9820#include "apmbios.S"
9821
9822#endif
9823
9824;--------------------
9825#if BX_PCIBIOS
9826use32 386
9827.align 16
9828bios32_structure:
9829 db 0x5f, 0x33, 0x32, 0x5f ;; "_32_" signature
9830 dw bios32_entry_point, 0xf ;; 32 bit physical address
9831 db 0 ;; revision level
9832 ;; length in paragraphs and checksum stored in a word to prevent errors
9833 dw (~(((bios32_entry_point >> 8) + (bios32_entry_point & 0xff) + 0x32) \
9834 & 0xff) << 8) + 0x01
9835 db 0,0,0,0,0 ;; reserved
9836
9837.align 16
9838bios32_entry_point:
9839 pushfd
9840 cmp eax, #0x49435024 ;; "$PCI"
9841 jne unknown_service
9842
9843#ifdef PCI_FIXED_HOST_BRIDGE_1
9844 mov eax, #0x80000000
9845 mov dx, #0x0cf8
9846 out dx, eax
9847 mov dx, #0x0cfc
9848 in eax, dx
9849 cmp eax, #PCI_FIXED_HOST_BRIDGE_1
9850 je device_ok
9851#endif
9852
9853#ifdef PCI_FIXED_HOST_BRIDGE_2
9854 /* 0x1e << 11 */
9855 mov eax, #0x8000f000
9856 mov dx, #0x0cf8
9857 out dx, eax
9858 mov dx, #0x0cfc
9859 in eax, dx
9860 cmp eax, #PCI_FIXED_HOST_BRIDGE_2
9861 je device_ok
9862#endif
9863 jmp unknown_service
9864device_ok:
9865 mov ebx, #0x000f0000
9866 mov ecx, #0
9867 mov edx, #pcibios_protected
9868 xor al, al
9869 jmp bios32_end
9870unknown_service:
9871 mov al, #0x80
9872bios32_end:
9873#ifdef BX_QEMU
9874 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
9875#endif
9876 popfd
9877 retf
9878
9879.align 16
9880pcibios_protected:
9881 pushfd
9882 cli
9883 push esi
9884 push edi
9885 cmp al, #0x01 ;; installation check
9886 jne pci_pro_f02
9887 mov bx, #0x0210
9888 mov cx, #0
9889 mov edx, #0x20494350 ;; "PCI "
9890 mov al, #0x01
9891 jmp pci_pro_ok
9892pci_pro_f02: ;; find pci device
9893 cmp al, #0x02
9894 jne pci_pro_f03
9895 shl ecx, #16
9896 mov cx, dx
9897 xor ebx, ebx
9898 mov di, #0x00
9899pci_pro_devloop:
9900 call pci_pro_select_reg
9901 mov dx, #0x0cfc
9902 in eax, dx
9903 cmp eax, ecx
9904 jne pci_pro_nextdev
9905 cmp si, #0
9906 je pci_pro_ok
9907 dec si
9908pci_pro_nextdev:
9909 inc ebx
9910 cmp ebx, #0x10000
9911 jne pci_pro_devloop
9912 mov ah, #0x86
9913 jmp pci_pro_fail
9914pci_pro_f03: ;; find class code
9915 cmp al, #0x03
9916 jne pci_pro_f08
9917 xor ebx, ebx
9918 mov di, #0x08
9919pci_pro_devloop2:
9920 call pci_pro_select_reg
9921 mov dx, #0x0cfc
9922 in eax, dx
9923 shr eax, #8
9924 cmp eax, ecx
9925 jne pci_pro_nextdev2
9926 cmp si, #0
9927 je pci_pro_ok
9928 dec si
9929pci_pro_nextdev2:
9930 inc ebx
9931 cmp ebx, #0x10000
9932 jne pci_pro_devloop2
9933 mov ah, #0x86
9934 jmp pci_pro_fail
9935pci_pro_f08: ;; read configuration byte
9936 cmp al, #0x08
9937 jne pci_pro_f09
9938 call pci_pro_select_reg
9939 push edx
9940 mov dx, di
9941 and dx, #0x03
9942 add dx, #0x0cfc
9943 in al, dx
9944 pop edx
9945 mov cl, al
9946 jmp pci_pro_ok
9947pci_pro_f09: ;; read configuration word
9948 cmp al, #0x09
9949 jne pci_pro_f0a
9950 call pci_pro_select_reg
9951 push edx
9952 mov dx, di
9953 and dx, #0x02
9954 add dx, #0x0cfc
9955 in ax, dx
9956 pop edx
9957 mov cx, ax
9958 jmp pci_pro_ok
9959pci_pro_f0a: ;; read configuration dword
9960 cmp al, #0x0a
9961 jne pci_pro_f0b
9962 call pci_pro_select_reg
9963 push edx
9964 mov dx, #0x0cfc
9965 in eax, dx
9966 pop edx
9967 mov ecx, eax
9968 jmp pci_pro_ok
9969pci_pro_f0b: ;; write configuration byte
9970 cmp al, #0x0b
9971 jne pci_pro_f0c
9972 call pci_pro_select_reg
9973 push edx
9974 mov dx, di
9975 and dx, #0x03
9976 add dx, #0x0cfc
9977 mov al, cl
9978 out dx, al
9979 pop edx
9980 jmp pci_pro_ok
9981pci_pro_f0c: ;; write configuration word
9982 cmp al, #0x0c
9983 jne pci_pro_f0d
9984 call pci_pro_select_reg
9985 push edx
9986 mov dx, di
9987 and dx, #0x02
9988 add dx, #0x0cfc
9989 mov ax, cx
9990 out dx, ax
9991 pop edx
9992 jmp pci_pro_ok
9993pci_pro_f0d: ;; write configuration dword
9994 cmp al, #0x0d
9995 jne pci_pro_unknown
9996 call pci_pro_select_reg
9997 push edx
9998 mov dx, #0x0cfc
9999 mov eax, ecx
10000 out dx, eax
10001 pop edx
10002 jmp pci_pro_ok
10003pci_pro_unknown:
10004 mov ah, #0x81
10005pci_pro_fail:
10006 pop edi
10007 pop esi
10008#ifdef BX_QEMU
10009 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
10010#endif
10011 popfd
10012 stc
10013 retf
10014pci_pro_ok:
10015 xor ah, ah
10016 pop edi
10017 pop esi
10018#ifdef BX_QEMU
10019 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
10020#endif
10021 popfd
10022 clc
10023 retf
10024
10025pci_pro_select_reg:
10026 push edx
10027 mov eax, #0x800000
10028 mov ax, bx
10029 shl eax, #8
10030 and di, #0xff
10031 or ax, di
10032 and al, #0xfc
10033 mov dx, #0x0cf8
10034 out dx, eax
10035 pop edx
10036 ret
10037
10038use16 386
10039
10040pcibios_real:
10041 push eax
10042 push dx
10043#ifdef PCI_FIXED_HOST_BRIDGE_1
10044 mov eax, #0x80000000
10045 mov dx, #0x0cf8
10046 out dx, eax
10047 mov dx, #0x0cfc
10048 in eax, dx
10049 cmp eax, #PCI_FIXED_HOST_BRIDGE_1
10050 je pci_present
10051#endif
10052
10053#ifdef PCI_FIXED_HOST_BRIDGE_2
10054 /* 0x1e << 11 */
10055 mov eax, #0x8000f000
10056 mov dx, #0x0cf8
10057 out dx, eax
10058 mov dx, #0x0cfc
10059 in eax, dx
10060 cmp eax, #PCI_FIXED_HOST_BRIDGE_2
10061 je pci_present
10062#endif
10063 pop dx
10064 pop eax
10065 mov ah, #0xff
10066 stc
10067 ret
10068pci_present:
10069 pop dx
10070 pop eax
10071 cmp al, #0x01 ;; installation check
10072 jne pci_real_f02
10073 mov ax, #0x0001
10074 mov bx, #0x0210
10075 mov cx, #0
10076 mov edx, #0x20494350 ;; "PCI "
10077 mov edi, #0xf0000
10078 mov di, #pcibios_protected
10079 clc
10080 ret
10081pci_real_f02: ;; find pci device
10082 push esi
10083 push edi
10084 push edx
10085 cmp al, #0x02
10086 jne pci_real_f03
10087 shl ecx, #16
10088 mov cx, dx
10089 xor ebx, ebx
10090 mov di, #0x00
10091pci_real_devloop:
10092 call pci_real_select_reg
10093 mov dx, #0x0cfc
10094 in eax, dx
10095 cmp eax, ecx
10096 jne pci_real_nextdev
10097 cmp si, #0
10098 je pci_real_ok
10099 dec si
10100pci_real_nextdev:
10101 inc ebx
10102 cmp ebx, #0x10000
10103 jne pci_real_devloop
10104 mov dx, cx
10105 shr ecx, #16
10106 mov ax, #0x8602
10107 jmp pci_real_fail
10108pci_real_f03: ;; find class code
10109 cmp al, #0x03
10110 jne pci_real_f08
10111 xor ebx, ebx
10112 mov di, #0x08
10113pci_real_devloop2:
10114 call pci_real_select_reg
10115 mov dx, #0x0cfc
10116 in eax, dx
10117 shr eax, #8
10118 cmp eax, ecx
10119 jne pci_real_nextdev2
10120 cmp si, #0
10121 je pci_real_ok
10122 dec si
10123pci_real_nextdev2:
10124 inc ebx
10125 cmp ebx, #0x10000
10126 jne pci_real_devloop2
10127 mov ax, #0x8603
10128 jmp pci_real_fail
10129pci_real_f08: ;; read configuration byte
10130 cmp al, #0x08
10131 jne pci_real_f09
10132 call pci_real_select_reg
10133 push dx
10134 mov dx, di
10135 and dx, #0x03
10136 add dx, #0x0cfc
10137 in al, dx
10138 pop dx
10139 mov cl, al
10140 jmp pci_real_ok
10141pci_real_f09: ;; read configuration word
10142 cmp al, #0x09
10143 jne pci_real_f0a
10144 call pci_real_select_reg
10145 push dx
10146 mov dx, di
10147 and dx, #0x02
10148 add dx, #0x0cfc
10149 in ax, dx
10150 pop dx
10151 mov cx, ax
10152 jmp pci_real_ok
10153pci_real_f0a: ;; read configuration dword
10154 cmp al, #0x0a
10155 jne pci_real_f0b
10156 call pci_real_select_reg
10157 push dx
10158 mov dx, #0x0cfc
10159 in eax, dx
10160 pop dx
10161 mov ecx, eax
10162 jmp pci_real_ok
10163pci_real_f0b: ;; write configuration byte
10164 cmp al, #0x0b
10165 jne pci_real_f0c
10166 call pci_real_select_reg
10167 push dx
10168 mov dx, di
10169 and dx, #0x03
10170 add dx, #0x0cfc
10171 mov al, cl
10172 out dx, al
10173 pop dx
10174 jmp pci_real_ok
10175pci_real_f0c: ;; write configuration word
10176 cmp al, #0x0c
10177 jne pci_real_f0d
10178 call pci_real_select_reg
10179 push dx
10180 mov dx, di
10181 and dx, #0x02
10182 add dx, #0x0cfc
10183 mov ax, cx
10184 out dx, ax
10185 pop dx
10186 jmp pci_real_ok
10187pci_real_f0d: ;; write configuration dword
10188 cmp al, #0x0d
10189 jne pci_real_f0e
10190 call pci_real_select_reg
10191 push dx
10192 mov dx, #0x0cfc
10193 mov eax, ecx
10194 out dx, eax
10195 pop dx
10196 jmp pci_real_ok
10197pci_real_f0e: ;; get irq routing options
10198 cmp al, #0x0e
10199 jne pci_real_unknown
10200 SEG ES
10201 cmp word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
10202 jb pci_real_too_small
10203 SEG ES
10204 mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
10205 pushf
10206 push ds
10207 push es
10208 push cx
10209 push si
10210 push di
10211 cld
10212 mov si, #pci_routing_table_structure_start
10213 push cs
10214 pop ds
10215 SEG ES
10216 mov cx, [di+2]
10217 SEG ES
10218 mov es, [di+4]
10219 mov di, cx
10220 mov cx, #pci_routing_table_structure_end - pci_routing_table_structure_start
10221 rep
10222 movsb
10223 pop di
10224 pop si
10225 pop cx
10226 pop es
10227 pop ds
10228 popf
10229 mov bx, #(1 << 9) | (1 << 11) ;; irq 9 and 11 are used
10230 jmp pci_real_ok
10231pci_real_too_small:
10232 SEG ES
10233 mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
10234 mov ah, #0x89
10235 jmp pci_real_fail
10236
10237pci_real_unknown:
10238 mov ah, #0x81
10239pci_real_fail:
10240 pop edx
10241 pop edi
10242 pop esi
10243 stc
10244 ret
10245pci_real_ok:
10246 xor ah, ah
10247 pop edx
10248 pop edi
10249 pop esi
10250 clc
10251 ret
10252
10253;; prepare from reading the PCI config space; on input:
10254;; bx = bus/dev/fn
10255;; di = offset into config space header
10256;; destroys eax and may modify di
10257pci_real_select_reg:
10258 push dx
10259 mov eax, #0x800000
10260 mov ax, bx
10261 shl eax, #8
10262 and di, #0xff
10263 or ax, di
10264 and al, #0xfc
10265 mov dx, #0x0cf8
10266 out dx, eax
10267 pop dx
10268 ret
10269
10270.align 16
10271pci_routing_table_structure:
10272 db 0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature
10273 db 0, 1 ;; version
10274#ifdef VBOX
10275 dw 32 + (30 * 16) ;; table size
10276#else /* !VBOX */
10277 dw 32 + (6 * 16) ;; table size
10278#endif /* !VBOX */
10279 db 0 ;; PCI interrupt router bus
10280 db 0x08 ;; PCI interrupt router DevFunc
10281 dw 0x0000 ;; PCI exclusive IRQs
10282 dw 0x8086 ;; compatible PCI interrupt router vendor ID
10283 dw 0x7000 ;; compatible PCI interrupt router device ID
10284 dw 0,0 ;; Miniport data
10285 db 0,0,0,0,0,0,0,0,0,0,0 ;; reserved
10286#ifdef VBOX
10287 db 0x00 ;; checksum (set by biossums)
10288#else /* !VBOX */
10289 db 0x07 ;; checksum
10290#endif /* !VBOX */
10291pci_routing_table_structure_start:
10292 ;; first slot entry PCI-to-ISA (embedded)
10293 db 0 ;; pci bus number
10294 db 0x08 ;; pci device number (bit 7-3)
10295 db 0x60 ;; link value INTA#: pointer into PCI2ISA config space
10296 dw 0xdef8 ;; IRQ bitmap INTA#
10297 db 0x61 ;; link value INTB#
10298 dw 0xdef8 ;; IRQ bitmap INTB#
10299 db 0x62 ;; link value INTC#
10300 dw 0xdef8 ;; IRQ bitmap INTC#
10301 db 0x63 ;; link value INTD#
10302 dw 0xdef8 ;; IRQ bitmap INTD#
10303 db 0 ;; physical slot (0 = embedded)
10304 db 0 ;; reserved
10305 ;; second slot entry: 1st PCI slot
10306 db 0 ;; pci bus number
10307 db 0x10 ;; pci device number (bit 7-3)
10308 db 0x61 ;; link value INTA#
10309 dw 0xdef8 ;; IRQ bitmap INTA#
10310 db 0x62 ;; link value INTB#
10311 dw 0xdef8 ;; IRQ bitmap INTB#
10312 db 0x63 ;; link value INTC#
10313 dw 0xdef8 ;; IRQ bitmap INTC#
10314 db 0x60 ;; link value INTD#
10315 dw 0xdef8 ;; IRQ bitmap INTD#
10316 db 1 ;; physical slot (0 = embedded)
10317 db 0 ;; reserved
10318 ;; third slot entry: 2nd PCI slot
10319 db 0 ;; pci bus number
10320 db 0x18 ;; pci device number (bit 7-3)
10321 db 0x62 ;; link value INTA#
10322 dw 0xdef8 ;; IRQ bitmap INTA#
10323 db 0x63 ;; link value INTB#
10324 dw 0xdef8 ;; IRQ bitmap INTB#
10325 db 0x60 ;; link value INTC#
10326 dw 0xdef8 ;; IRQ bitmap INTC#
10327 db 0x61 ;; link value INTD#
10328 dw 0xdef8 ;; IRQ bitmap INTD#
10329 db 2 ;; physical slot (0 = embedded)
10330 db 0 ;; reserved
10331 ;; 4th slot entry: 3rd PCI slot
10332 db 0 ;; pci bus number
10333 db 0x20 ;; pci device number (bit 7-3)
10334 db 0x63 ;; link value INTA#
10335 dw 0xdef8 ;; IRQ bitmap INTA#
10336 db 0x60 ;; link value INTB#
10337 dw 0xdef8 ;; IRQ bitmap INTB#
10338 db 0x61 ;; link value INTC#
10339 dw 0xdef8 ;; IRQ bitmap INTC#
10340 db 0x62 ;; link value INTD#
10341 dw 0xdef8 ;; IRQ bitmap INTD#
10342 db 3 ;; physical slot (0 = embedded)
10343 db 0 ;; reserved
10344 ;; 5th slot entry: 4rd PCI slot
10345 db 0 ;; pci bus number
10346 db 0x28 ;; pci device number (bit 7-3)
10347 db 0x60 ;; link value INTA#
10348 dw 0xdef8 ;; IRQ bitmap INTA#
10349 db 0x61 ;; link value INTB#
10350 dw 0xdef8 ;; IRQ bitmap INTB#
10351 db 0x62 ;; link value INTC#
10352 dw 0xdef8 ;; IRQ bitmap INTC#
10353 db 0x63 ;; link value INTD#
10354 dw 0xdef8 ;; IRQ bitmap INTD#
10355 db 4 ;; physical slot (0 = embedded)
10356 db 0 ;; reserved
10357 ;; 6th slot entry: 5rd PCI slot
10358 db 0 ;; pci bus number
10359 db 0x30 ;; pci device number (bit 7-3)
10360 db 0x61 ;; link value INTA#
10361 dw 0xdef8 ;; IRQ bitmap INTA#
10362 db 0x62 ;; link value INTB#
10363 dw 0xdef8 ;; IRQ bitmap INTB#
10364 db 0x63 ;; link value INTC#
10365 dw 0xdef8 ;; IRQ bitmap INTC#
10366 db 0x60 ;; link value INTD#
10367 dw 0xdef8 ;; IRQ bitmap INTD#
10368 db 5 ;; physical slot (0 = embedded)
10369 db 0 ;; reserved
10370#ifdef VBOX
10371 ;; 7th slot entry: 6th PCI slot
10372 db 0 ;; pci bus number
10373 db 0x38 ;; pci device number (bit 7-3)
10374 db 0x62 ;; link value INTA#
10375 dw 0xdef8 ;; IRQ bitmap INTA#
10376 db 0x63 ;; link value INTB#
10377 dw 0xdef8 ;; IRQ bitmap INTB#
10378 db 0x60 ;; link value INTC#
10379 dw 0xdef8 ;; IRQ bitmap INTC#
10380 db 0x61 ;; link value INTD#
10381 dw 0xdef8 ;; IRQ bitmap INTD#
10382 db 6 ;; physical slot (0 = embedded)
10383 db 0 ;; reserved
10384 ;; 8th slot entry: 7th PCI slot
10385 db 0 ;; pci bus number
10386 db 0x40 ;; pci device number (bit 7-3)
10387 db 0x63 ;; link value INTA#
10388 dw 0xdef8 ;; IRQ bitmap INTA#
10389 db 0x60 ;; link value INTB#
10390 dw 0xdef8 ;; IRQ bitmap INTB#
10391 db 0x61 ;; link value INTC#
10392 dw 0xdef8 ;; IRQ bitmap INTC#
10393 db 0x62 ;; link value INTD#
10394 dw 0xdef8 ;; IRQ bitmap INTD#
10395 db 7 ;; physical slot (0 = embedded)
10396 db 0 ;; reserved
10397 ;; 9th slot entry: 8th PCI slot
10398 db 0 ;; pci bus number
10399 db 0x48 ;; pci device number (bit 7-3)
10400 db 0x60 ;; link value INTA#
10401 dw 0xdef8 ;; IRQ bitmap INTA#
10402 db 0x61 ;; link value INTB#
10403 dw 0xdef8 ;; IRQ bitmap INTB#
10404 db 0x62 ;; link value INTC#
10405 dw 0xdef8 ;; IRQ bitmap INTC#
10406 db 0x63 ;; link value INTD#
10407 dw 0xdef8 ;; IRQ bitmap INTD#
10408 db 8 ;; physical slot (0 = embedded)
10409 db 0 ;; reserved
10410 ;; 10th slot entry: 9th PCI slot
10411 db 0 ;; pci bus number
10412 db 0x50 ;; pci device number (bit 7-3)
10413 db 0x61 ;; link value INTA#
10414 dw 0xdef8 ;; IRQ bitmap INTA#
10415 db 0x62 ;; link value INTB#
10416 dw 0xdef8 ;; IRQ bitmap INTB#
10417 db 0x63 ;; link value INTC#
10418 dw 0xdef8 ;; IRQ bitmap INTC#
10419 db 0x60 ;; link value INTD#
10420 dw 0xdef8 ;; IRQ bitmap INTD#
10421 db 9 ;; physical slot (0 = embedded)
10422 db 0 ;; reserved
10423 ;; 11th slot entry: 10th PCI slot
10424 db 0 ;; pci bus number
10425 db 0x58 ;; pci device number (bit 7-3)
10426 db 0x62 ;; link value INTA#
10427 dw 0xdef8 ;; IRQ bitmap INTA#
10428 db 0x63 ;; link value INTB#
10429 dw 0xdef8 ;; IRQ bitmap INTB#
10430 db 0x60 ;; link value INTC#
10431 dw 0xdef8 ;; IRQ bitmap INTC#
10432 db 0x61 ;; link value INTD#
10433 dw 0xdef8 ;; IRQ bitmap INTD#
10434 db 10 ;; physical slot (0 = embedded)
10435 db 0 ;; reserved
10436 ;; 12th slot entry: 11th PCI slot
10437 db 0 ;; pci bus number
10438 db 0x60 ;; pci device number (bit 7-3)
10439 db 0x63 ;; link value INTA#
10440 dw 0xdef8 ;; IRQ bitmap INTA#
10441 db 0x60 ;; link value INTB#
10442 dw 0xdef8 ;; IRQ bitmap INTB#
10443 db 0x61 ;; link value INTC#
10444 dw 0xdef8 ;; IRQ bitmap INTC#
10445 db 0x62 ;; link value INTD#
10446 dw 0xdef8 ;; IRQ bitmap INTD#
10447 db 11 ;; physical slot (0 = embedded)
10448 db 0 ;; reserved
10449 ;; 13th slot entry: 12th PCI slot
10450 db 0 ;; pci bus number
10451 db 0x68 ;; pci device number (bit 7-3)
10452 db 0x60 ;; link value INTA#
10453 dw 0xdef8 ;; IRQ bitmap INTA#
10454 db 0x61 ;; link value INTB#
10455 dw 0xdef8 ;; IRQ bitmap INTB#
10456 db 0x62 ;; link value INTC#
10457 dw 0xdef8 ;; IRQ bitmap INTC#
10458 db 0x63 ;; link value INTD#
10459 dw 0xdef8 ;; IRQ bitmap INTD#
10460 db 12 ;; physical slot (0 = embedded)
10461 db 0 ;; reserved
10462 ;; 14th slot entry: 13th PCI slot
10463 db 0 ;; pci bus number
10464 db 0x70 ;; pci device number (bit 7-3)
10465 db 0x61 ;; link value INTA#
10466 dw 0xdef8 ;; IRQ bitmap INTA#
10467 db 0x62 ;; link value INTB#
10468 dw 0xdef8 ;; IRQ bitmap INTB#
10469 db 0x63 ;; link value INTC#
10470 dw 0xdef8 ;; IRQ bitmap INTC#
10471 db 0x60 ;; link value INTD#
10472 dw 0xdef8 ;; IRQ bitmap INTD#
10473 db 13 ;; physical slot (0 = embedded)
10474 db 0 ;; reserved
10475 ;; 15th slot entry: 14th PCI slot
10476 db 0 ;; pci bus number
10477 db 0x78 ;; pci device number (bit 7-3)
10478 db 0x62 ;; link value INTA#
10479 dw 0xdef8 ;; IRQ bitmap INTA#
10480 db 0x63 ;; link value INTB#
10481 dw 0xdef8 ;; IRQ bitmap INTB#
10482 db 0x60 ;; link value INTC#
10483 dw 0xdef8 ;; IRQ bitmap INTC#
10484 db 0x61 ;; link value INTD#
10485 dw 0xdef8 ;; IRQ bitmap INTD#
10486 db 14 ;; physical slot (0 = embedded)
10487 db 0 ;; reserved
10488 ;; 16th slot entry: 15th PCI slot
10489 db 0 ;; pci bus number
10490 db 0x80 ;; pci device number (bit 7-3)
10491 db 0x63 ;; link value INTA#
10492 dw 0xdef8 ;; IRQ bitmap INTA#
10493 db 0x60 ;; link value INTB#
10494 dw 0xdef8 ;; IRQ bitmap INTB#
10495 db 0x61 ;; link value INTC#
10496 dw 0xdef8 ;; IRQ bitmap INTC#
10497 db 0x62 ;; link value INTD#
10498 dw 0xdef8 ;; IRQ bitmap INTD#
10499 db 15 ;; physical slot (0 = embedded)
10500 db 0 ;; reserved
10501 ;; 17th slot entry: 16th PCI slot
10502 db 0 ;; pci bus number
10503 db 0x88 ;; pci device number (bit 7-3)
10504 db 0x60 ;; link value INTA#
10505 dw 0xdef8 ;; IRQ bitmap INTA#
10506 db 0x61 ;; link value INTB#
10507 dw 0xdef8 ;; IRQ bitmap INTB#
10508 db 0x62 ;; link value INTC#
10509 dw 0xdef8 ;; IRQ bitmap INTC#
10510 db 0x63 ;; link value INTD#
10511 dw 0xdef8 ;; IRQ bitmap INTD#
10512 db 16 ;; physical slot (0 = embedded)
10513 db 0 ;; reserved
10514 ;; 18th slot entry: 17th PCI slot
10515 db 0 ;; pci bus number
10516 db 0x90 ;; pci device number (bit 7-3)
10517 db 0x61 ;; link value INTA#
10518 dw 0xdef8 ;; IRQ bitmap INTA#
10519 db 0x62 ;; link value INTB#
10520 dw 0xdef8 ;; IRQ bitmap INTB#
10521 db 0x63 ;; link value INTC#
10522 dw 0xdef8 ;; IRQ bitmap INTC#
10523 db 0x60 ;; link value INTD#
10524 dw 0xdef8 ;; IRQ bitmap INTD#
10525 db 17 ;; physical slot (0 = embedded)
10526 db 0 ;; reserved
10527 ;; 19th slot entry: 18th PCI slot
10528 db 0 ;; pci bus number
10529 db 0x98 ;; pci device number (bit 7-3)
10530 db 0x62 ;; link value INTA#
10531 dw 0xdef8 ;; IRQ bitmap INTA#
10532 db 0x63 ;; link value INTB#
10533 dw 0xdef8 ;; IRQ bitmap INTB#
10534 db 0x60 ;; link value INTC#
10535 dw 0xdef8 ;; IRQ bitmap INTC#
10536 db 0x61 ;; link value INTD#
10537 dw 0xdef8 ;; IRQ bitmap INTD#
10538 db 18 ;; physical slot (0 = embedded)
10539 db 0 ;; reserved
10540 ;; 20th slot entry: 19th PCI slot
10541 db 0 ;; pci bus number
10542 db 0xa0 ;; pci device number (bit 7-3)
10543 db 0x63 ;; link value INTA#
10544 dw 0xdef8 ;; IRQ bitmap INTA#
10545 db 0x60 ;; link value INTB#
10546 dw 0xdef8 ;; IRQ bitmap INTB#
10547 db 0x61 ;; link value INTC#
10548 dw 0xdef8 ;; IRQ bitmap INTC#
10549 db 0x62 ;; link value INTD#
10550 dw 0xdef8 ;; IRQ bitmap INTD#
10551 db 19 ;; physical slot (0 = embedded)
10552 db 0 ;; reserved
10553 ;; 21st slot entry: 20th PCI slot
10554 db 0 ;; pci bus number
10555 db 0xa8 ;; pci device number (bit 7-3)
10556 db 0x60 ;; link value INTA#
10557 dw 0xdef8 ;; IRQ bitmap INTA#
10558 db 0x61 ;; link value INTB#
10559 dw 0xdef8 ;; IRQ bitmap INTB#
10560 db 0x62 ;; link value INTC#
10561 dw 0xdef8 ;; IRQ bitmap INTC#
10562 db 0x63 ;; link value INTD#
10563 dw 0xdef8 ;; IRQ bitmap INTD#
10564 db 20 ;; physical slot (0 = embedded)
10565 db 0 ;; reserved
10566 ;; 22nd slot entry: 21st PCI slot
10567 db 0 ;; pci bus number
10568 db 0xb0 ;; pci device number (bit 7-3)
10569 db 0x61 ;; link value INTA#
10570 dw 0xdef8 ;; IRQ bitmap INTA#
10571 db 0x62 ;; link value INTB#
10572 dw 0xdef8 ;; IRQ bitmap INTB#
10573 db 0x63 ;; link value INTC#
10574 dw 0xdef8 ;; IRQ bitmap INTC#
10575 db 0x60 ;; link value INTD#
10576 dw 0xdef8 ;; IRQ bitmap INTD#
10577 db 21 ;; physical slot (0 = embedded)
10578 db 0 ;; reserved
10579 ;; 23rd slot entry: 22nd PCI slot
10580 db 0 ;; pci bus number
10581 db 0xb8 ;; pci device number (bit 7-3)
10582 db 0x62 ;; link value INTA#
10583 dw 0xdef8 ;; IRQ bitmap INTA#
10584 db 0x63 ;; link value INTB#
10585 dw 0xdef8 ;; IRQ bitmap INTB#
10586 db 0x60 ;; link value INTC#
10587 dw 0xdef8 ;; IRQ bitmap INTC#
10588 db 0x61 ;; link value INTD#
10589 dw 0xdef8 ;; IRQ bitmap INTD#
10590 db 22 ;; physical slot (0 = embedded)
10591 db 0 ;; reserved
10592 ;; 24th slot entry: 23rd PCI slot
10593 db 0 ;; pci bus number
10594 db 0xc0 ;; pci device number (bit 7-3)
10595 db 0x63 ;; link value INTA#
10596 dw 0xdef8 ;; IRQ bitmap INTA#
10597 db 0x60 ;; link value INTB#
10598 dw 0xdef8 ;; IRQ bitmap INTB#
10599 db 0x61 ;; link value INTC#
10600 dw 0xdef8 ;; IRQ bitmap INTC#
10601 db 0x62 ;; link value INTD#
10602 dw 0xdef8 ;; IRQ bitmap INTD#
10603 db 23 ;; physical slot (0 = embedded)
10604 db 0 ;; reserved
10605 ;; 25th slot entry: 24th PCI slot
10606 db 0 ;; pci bus number
10607 db 0xc8 ;; pci device number (bit 7-3)
10608 db 0x60 ;; link value INTA#
10609 dw 0xdef8 ;; IRQ bitmap INTA#
10610 db 0x61 ;; link value INTB#
10611 dw 0xdef8 ;; IRQ bitmap INTB#
10612 db 0x62 ;; link value INTC#
10613 dw 0xdef8 ;; IRQ bitmap INTC#
10614 db 0x63 ;; link value INTD#
10615 dw 0xdef8 ;; IRQ bitmap INTD#
10616 db 24 ;; physical slot (0 = embedded)
10617 db 0 ;; reserved
10618 ;; 26th slot entry: 25th PCI slot
10619 db 0 ;; pci bus number
10620 db 0xd0 ;; pci device number (bit 7-3)
10621 db 0x61 ;; link value INTA#
10622 dw 0xdef8 ;; IRQ bitmap INTA#
10623 db 0x62 ;; link value INTB#
10624 dw 0xdef8 ;; IRQ bitmap INTB#
10625 db 0x63 ;; link value INTC#
10626 dw 0xdef8 ;; IRQ bitmap INTC#
10627 db 0x60 ;; link value INTD#
10628 dw 0xdef8 ;; IRQ bitmap INTD#
10629 db 25 ;; physical slot (0 = embedded)
10630 db 0 ;; reserved
10631 ;; 27th slot entry: 26th PCI slot
10632 db 0 ;; pci bus number
10633 db 0xd8 ;; pci device number (bit 7-3)
10634 db 0x62 ;; link value INTA#
10635 dw 0xdef8 ;; IRQ bitmap INTA#
10636 db 0x63 ;; link value INTB#
10637 dw 0xdef8 ;; IRQ bitmap INTB#
10638 db 0x60 ;; link value INTC#
10639 dw 0xdef8 ;; IRQ bitmap INTC#
10640 db 0x61 ;; link value INTD#
10641 dw 0xdef8 ;; IRQ bitmap INTD#
10642 db 26 ;; physical slot (0 = embedded)
10643 db 0 ;; reserved
10644 ;; 28th slot entry: 27th PCI slot
10645 db 0 ;; pci bus number
10646 db 0xe0 ;; pci device number (bit 7-3)
10647 db 0x63 ;; link value INTA#
10648 dw 0xdef8 ;; IRQ bitmap INTA#
10649 db 0x60 ;; link value INTB#
10650 dw 0xdef8 ;; IRQ bitmap INTB#
10651 db 0x61 ;; link value INTC#
10652 dw 0xdef8 ;; IRQ bitmap INTC#
10653 db 0x62 ;; link value INTD#
10654 dw 0xdef8 ;; IRQ bitmap INTD#
10655 db 27 ;; physical slot (0 = embedded)
10656 db 0 ;; reserved
10657 ;; 29th slot entry: 28th PCI slot
10658 db 0 ;; pci bus number
10659 db 0xe8 ;; pci device number (bit 7-3)
10660 db 0x60 ;; link value INTA#
10661 dw 0xdef8 ;; IRQ bitmap INTA#
10662 db 0x61 ;; link value INTB#
10663 dw 0xdef8 ;; IRQ bitmap INTB#
10664 db 0x62 ;; link value INTC#
10665 dw 0xdef8 ;; IRQ bitmap INTC#
10666 db 0x63 ;; link value INTD#
10667 dw 0xdef8 ;; IRQ bitmap INTD#
10668 db 28 ;; physical slot (0 = embedded)
10669 db 0 ;; reserved
10670 ;; 30th slot entry: 29th PCI slot
10671 db 0 ;; pci bus number
10672 db 0xf0 ;; pci device number (bit 7-3)
10673 db 0x61 ;; link value INTA#
10674 dw 0xdef8 ;; IRQ bitmap INTA#
10675 db 0x62 ;; link value INTB#
10676 dw 0xdef8 ;; IRQ bitmap INTB#
10677 db 0x63 ;; link value INTC#
10678 dw 0xdef8 ;; IRQ bitmap INTC#
10679 db 0x60 ;; link value INTD#
10680 dw 0xdef8 ;; IRQ bitmap INTD#
10681 db 29 ;; physical slot (0 = embedded)
10682 db 0 ;; reserved
10683#endif /* VBOX */
10684pci_routing_table_structure_end:
10685
10686#if !BX_ROMBIOS32
10687pci_irq_list:
10688 db 11, 10, 9, 5;
10689
10690pcibios_init_sel_reg:
10691 push eax
10692 mov eax, #0x800000
10693 mov ax, bx
10694 shl eax, #8
10695 and dl, #0xfc
10696 or al, dl
10697 mov dx, #0x0cf8
10698 out dx, eax
10699 pop eax
10700 ret
10701
10702pcibios_init_iomem_bases:
10703 push bp
10704 mov bp, sp
10705 mov eax, #0xe0000000 ;; base for memory init
10706 push eax
10707 mov ax, #0xc000 ;; base for i/o init
10708 push ax
10709 mov ax, #0x0010 ;; start at base address #0
10710 push ax
10711 mov bx, #0x0008
10712pci_init_io_loop1:
10713 mov dl, #0x00
10714 call pcibios_init_sel_reg
10715 mov dx, #0x0cfc
10716 in ax, dx
10717 cmp ax, #0xffff
10718 jz next_pci_dev
10719#ifndef VBOX /* This currently breaks restoring a previously saved state. */
10720 mov dl, #0x04 ;; disable i/o and memory space access
10721 call pcibios_init_sel_reg
10722 mov dx, #0x0cfc
10723 in al, dx
10724 and al, #0xfc
10725 out dx, al
10726pci_init_io_loop2:
10727 mov dl, [bp-8]
10728 call pcibios_init_sel_reg
10729 mov dx, #0x0cfc
10730 in eax, dx
10731 test al, #0x01
10732 jnz init_io_base
10733 mov ecx, eax
10734 mov eax, #0xffffffff
10735 out dx, eax
10736 in eax, dx
10737 cmp eax, ecx
10738 je next_pci_base
10739 xor eax, #0xffffffff
10740 mov ecx, eax
10741 mov eax, [bp-4]
10742 out dx, eax
10743 add eax, ecx ;; calculate next free mem base
10744 add eax, #0x01000000
10745 and eax, #0xff000000
10746 mov [bp-4], eax
10747 jmp next_pci_base
10748init_io_base:
10749 mov cx, ax
10750 mov ax, #0xffff
10751 out dx, ax
10752 in ax, dx
10753 cmp ax, cx
10754 je next_pci_base
10755 xor ax, #0xfffe
10756 mov cx, ax
10757 mov ax, [bp-6]
10758 out dx, ax
10759 add ax, cx ;; calculate next free i/o base
10760 add ax, #0x0100
10761 and ax, #0xff00
10762 mov [bp-6], ax
10763next_pci_base:
10764 mov al, [bp-8]
10765 add al, #0x04
10766 cmp al, #0x28
10767 je enable_iomem_space
10768 mov byte ptr[bp-8], al
10769 jmp pci_init_io_loop2
10770#endif /* !VBOX */
10771enable_iomem_space:
10772 mov dl, #0x04 ;; enable i/o and memory space access if available
10773 call pcibios_init_sel_reg
10774 mov dx, #0x0cfc
10775 in al, dx
10776 or al, #0x07
10777 out dx, al
10778#ifdef VBOX
10779 mov dl, #0x00 ;; check if PCI device is AMD PCNet
10780 call pcibios_init_sel_reg
10781 mov dx, #0x0cfc
10782 in eax, dx
10783 cmp eax, #0x20001022
10784 jne next_pci_dev
10785 mov dl, #0x10 ;; get I/O address
10786 call pcibios_init_sel_reg
10787 mov dx, #0x0cfc
10788 in ax, dx
10789 and ax, #0xfffc
10790 mov cx, ax
10791 mov dx, cx
10792 add dx, #0x14 ;; reset register if PCNet is in word I/O mode
10793 in ax, dx ;; reset is performed by reading the reset register
10794 mov dx, cx
10795 add dx, #0x18 ;; reset register if PCNet is in word I/O mode
10796 in eax, dx ;; reset is performed by reading the reset register
10797#endif /* VBOX */
10798next_pci_dev:
10799 mov byte ptr[bp-8], #0x10
10800 inc bx
10801 cmp bx, #0x0100
10802 jne pci_init_io_loop1
10803 mov sp, bp
10804 pop bp
10805 ret
10806
10807pcibios_init_set_elcr:
10808 push ax
10809 push cx
10810 mov dx, #0x04d0
10811 test al, #0x08
10812 jz is_master_pic
10813 inc dx
10814 and al, #0x07
10815is_master_pic:
10816 mov cl, al
10817 mov bl, #0x01
10818 shl bl, cl
10819 in al, dx
10820 or al, bl
10821 out dx, al
10822 pop cx
10823 pop ax
10824 ret
10825
10826pcibios_init_irqs:
10827 push ds
10828 push bp
10829 mov ax, #0xf000
10830 mov ds, ax
10831 mov dx, #0x04d0 ;; reset ELCR1 + ELCR2
10832 mov al, #0x00
10833 out dx, al
10834 inc dx
10835 out dx, al
10836 mov si, #pci_routing_table_structure
10837 mov bh, [si+8]
10838 mov bl, [si+9]
10839 mov dl, #0x00
10840 call pcibios_init_sel_reg
10841 mov dx, #0x0cfc
10842 in eax, dx
10843 cmp eax, [si+12] ;; check irq router
10844 jne pci_init_end
10845 mov dl, [si+34]
10846 call pcibios_init_sel_reg
10847 push bx ;; save irq router bus + devfunc
10848 mov dx, #0x0cfc
10849 mov ax, #0x8080
10850 out dx, ax ;; reset PIRQ route control
10851 add dx, #2
10852 out dx, ax
10853 mov ax, [si+6]
10854 sub ax, #0x20
10855 shr ax, #4
10856 mov cx, ax
10857 add si, #0x20 ;; set pointer to 1st entry
10858 mov bp, sp
10859 mov ax, #pci_irq_list
10860 push ax
10861 xor ax, ax
10862 push ax
10863pci_init_irq_loop1:
10864 mov bh, [si]
10865 mov bl, [si+1]
10866pci_init_irq_loop2:
10867 mov dl, #0x00
10868 call pcibios_init_sel_reg
10869 mov dx, #0x0cfc
10870 in ax, dx
10871 cmp ax, #0xffff
10872 jnz pci_test_int_pin
10873 test bl, #0x07
10874 jz next_pir_entry
10875 jmp next_pci_func
10876pci_test_int_pin:
10877 mov dl, #0x3c
10878 call pcibios_init_sel_reg
10879 mov dx, #0x0cfd
10880 in al, dx
10881 and al, #0x07
10882 jz next_pci_func
10883 dec al ;; determine pirq reg
10884 mov dl, #0x03
10885 mul al, dl
10886 add al, #0x02
10887 xor ah, ah
10888 mov bx, ax
10889 mov al, [si+bx]
10890 mov dl, al
10891 mov bx, [bp]
10892 call pcibios_init_sel_reg
10893 mov dx, #0x0cfc
10894 and al, #0x03
10895 add dl, al
10896 in al, dx
10897 cmp al, #0x80
10898 jb pirq_found
10899 mov bx, [bp-2] ;; pci irq list pointer
10900 mov al, [bx]
10901 out dx, al
10902 inc bx
10903 mov [bp-2], bx
10904 call pcibios_init_set_elcr
10905pirq_found:
10906 mov bh, [si]
10907 mov bl, [si+1]
10908 add bl, [bp-3] ;; pci function number
10909 mov dl, #0x3c
10910 call pcibios_init_sel_reg
10911 mov dx, #0x0cfc
10912 out dx, al
10913next_pci_func:
10914 inc byte ptr[bp-3]
10915 inc bl
10916 test bl, #0x07
10917 jnz pci_init_irq_loop2
10918next_pir_entry:
10919 add si, #0x10
10920 mov byte ptr[bp-3], #0x00
10921 loop pci_init_irq_loop1
10922 mov sp, bp
10923 pop bx
10924pci_init_end:
10925 pop bp
10926 pop ds
10927 ret
10928#endif // !BX_ROMBIOS32
10929#endif // BX_PCIBIOS
10930
10931#if BX_ROMBIOS32
10932rombios32_init:
10933 ;; save a20 and enable it
10934 in al, 0x92
10935 push ax
10936 or al, #0x02
10937 out 0x92, al
10938
10939 ;; save SS:SP to the BDA
10940 xor ax, ax
10941 mov ds, ax
10942 mov 0x0469, ss
10943 mov 0x0467, sp
10944
10945 SEG CS
10946 lidt [pmode_IDT_info]
10947 SEG CS
10948 lgdt [rombios32_gdt_48]
10949 ;; set PE bit in CR0
10950 mov eax, cr0
10951 or al, #0x01
10952 mov cr0, eax
10953 ;; start protected mode code: ljmpl 0x10:rombios32_init1
10954 db 0x66, 0xea
10955 dw rombios32_05
10956 dw 0x000f ;; high 16 bit address
10957 dw 0x0010
10958
10959use32 386
10960rombios32_05:
10961 ;; init data segments
10962 mov eax, #0x18
10963 mov ds, ax
10964 mov es, ax
10965 mov ss, ax
10966 xor eax, eax
10967 mov fs, ax
10968 mov gs, ax
10969 cld
10970
10971 ;; copy rombios32 code to ram (ram offset = 1MB)
10972 mov esi, #0xfffe0000
10973 mov edi, #0x00040000
10974 mov ecx, #0x10000 / 4
10975 rep
10976 movsd
10977
10978 ;; init the stack pointer
10979 mov esp, #0x00080000
10980
10981 ;; call rombios32 code
10982 mov eax, #0x00040000
10983 call eax
10984
10985 ;; return to 16 bit protected mode first
10986 db 0xea
10987 dd rombios32_10
10988 dw 0x20
10989
10990use16 386
10991rombios32_10:
10992 ;; restore data segment limits to 0xffff
10993 mov ax, #0x28
10994 mov ds, ax
10995 mov es, ax
10996 mov ss, ax
10997 mov fs, ax
10998 mov gs, ax
10999
11000 ;; reset PE bit in CR0
11001 mov eax, cr0
11002 and al, #0xFE
11003 mov cr0, eax
11004
11005 ;; far jump to flush CPU queue after transition to real mode
11006 JMP_AP(0xf000, rombios32_real_mode)
11007
11008rombios32_real_mode:
11009 ;; restore IDT to normal real-mode defaults
11010 SEG CS
11011 lidt [rmode_IDT_info]
11012
11013 xor ax, ax
11014 mov ds, ax
11015 mov es, ax
11016 mov fs, ax
11017 mov gs, ax
11018
11019 ;; restore SS:SP from the BDA
11020 mov ss, 0x0469
11021 xor esp, esp
11022 mov sp, 0x0467
11023 ;; restore a20
11024 pop ax
11025 out 0x92, al
11026 ret
11027
11028rombios32_gdt_48:
11029 dw 0x30
11030 dw rombios32_gdt
11031 dw 0x000f
11032
11033rombios32_gdt:
11034 dw 0, 0, 0, 0
11035 dw 0, 0, 0, 0
11036 dw 0xffff, 0, 0x9b00, 0x00cf ; 32 bit flat code segment (0x10)
11037 dw 0xffff, 0, 0x9300, 0x00cf ; 32 bit flat data segment (0x18)
11038 dw 0xffff, 0, 0x9b0f, 0x0000 ; 16 bit code segment base=0xf0000 limit=0xffff
11039 dw 0xffff, 0, 0x9300, 0x0000 ; 16 bit data segment base=0x0 limit=0xffff
11040#endif // BX_ROMBIOS32
11041
11042
11043; parallel port detection: base address in DX, index in BX, timeout in CL
11044detect_parport:
11045 push dx
11046 add dx, #2
11047 in al, dx
11048 and al, #0xdf ; clear input mode
11049 out dx, al
11050 pop dx
11051 mov al, #0xaa
11052 out dx, al
11053 in al, dx
11054 cmp al, #0xaa
11055 jne no_parport
11056 push bx
11057 shl bx, #1
11058 mov [bx+0x408], dx ; Parallel I/O address
11059 pop bx
11060 mov [bx+0x478], cl ; Parallel printer timeout
11061 inc bx
11062no_parport:
11063 ret
11064
11065; serial port detection: base address in DX, index in BX, timeout in CL
11066detect_serial:
11067 push dx
11068 inc dx
11069 mov al, #0x02
11070 out dx, al
11071 in al, dx
11072 cmp al, #0x02
11073 jne no_serial
11074 inc dx
11075 in al, dx
11076 cmp al, #0x02
11077 jne no_serial
11078 dec dx
11079 xor al, al
11080 out dx, al
11081 pop dx
11082 push bx
11083 shl bx, #1
11084 mov [bx+0x400], dx ; Serial I/O address
11085 pop bx
11086 mov [bx+0x47c], cl ; Serial timeout
11087 inc bx
11088 ret
11089no_serial:
11090 pop dx
11091 ret
11092
11093rom_checksum:
11094 push ax
11095 push bx
11096 push cx
11097 xor ax, ax
11098 xor bx, bx
11099 xor cx, cx
11100 mov ch, [2]
11101 shl cx, #1
11102checksum_loop:
11103 add al, [bx]
11104 inc bx
11105 loop checksum_loop
11106 and al, #0xff
11107 pop cx
11108 pop bx
11109 pop ax
11110 ret
11111
11112rom_scan:
11113 ;; Scan for existence of valid expansion ROMS.
11114 ;; Video ROM: from 0xC0000..0xC7FFF in 2k increments
11115 ;; General ROM: from 0xC8000..0xDFFFF in 2k increments
11116 ;; System ROM: only 0xE0000
11117 ;;
11118 ;; Header:
11119 ;; Offset Value
11120 ;; 0 0x55
11121 ;; 1 0xAA
11122 ;; 2 ROM length in 512-byte blocks
11123 ;; 3 ROM initialization entry point (FAR CALL)
11124
11125 mov cx, #0xc000
11126rom_scan_loop:
11127 mov ds, cx
11128 mov ax, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
11129 cmp [0], #0xAA55 ;; look for signature
11130 jne rom_scan_increment
11131 call rom_checksum
11132 jnz rom_scan_increment
11133 mov al, [2] ;; change increment to ROM length in 512-byte blocks
11134
11135 ;; We want our increment in 512-byte quantities, rounded to
11136 ;; the nearest 2k quantity, since we only scan at 2k intervals.
11137 test al, #0x03
11138 jz block_count_rounded
11139 and al, #0xfc ;; needs rounding up
11140 add al, #0x04
11141block_count_rounded:
11142
11143 xor bx, bx ;; Restore DS back to 0000:
11144 mov ds, bx
11145 push ax ;; Save AX
11146 ;; Push addr of ROM entry point
11147 push cx ;; Push seg
11148 push #0x0003 ;; Push offset
11149 mov bp, sp ;; Call ROM init routine using seg:off on stack
11150 db 0xff ;; call_far ss:[bp+0]
11151 db 0x5e
11152 db 0
11153 cli ;; In case expansion ROM BIOS turns IF on
11154 add sp, #2 ;; Pop offset value
11155 pop cx ;; Pop seg value (restore CX)
11156 pop ax ;; Restore AX
11157rom_scan_increment:
11158 shl ax, #5 ;; convert 512-bytes blocks to 16-byte increments
11159 ;; because the segment selector is shifted left 4 bits.
11160 add cx, ax
11161 cmp cx, #0xe800 ;; Must encompass VBOX_LANBOOT_SEG!
11162 jbe rom_scan_loop
11163
11164 xor ax, ax ;; Restore DS back to 0000:
11165 mov ds, ax
11166 ret
11167
11168#define LVT0 0xFEE00350
11169#define LVT1 0xFEE00360
11170
11171;; Program LVT0/LVT1 entries in the local APIC. Some Linux kernels (e.g., RHEL4
11172;; SMP 32-bit) expect the entries to be unmasked in virtual wire mode.
11173
11174setup_lapic:
11175 pushf
11176 cli ;; Interrupts would kill us!
11177 call pmode_enter
11178 mov esi, #LVT0 ;; Program LVT0 to ExtINT and unmask
11179 mov eax, [esi]
11180 and eax, #0xfffe00ff
11181 or ah, #0x07
11182 mov [esi], eax
11183 mov esi, #LVT1 ;; Program LVT1 to NMI and unmask
11184 mov eax, [esi]
11185 and eax, #0xfffe00ff
11186 or ah, #0x04
11187 mov [esi], eax
11188 call pmode_exit
11189 popf
11190 ret
11191
11192;; Enter and exit minimal protected-mode environment. May only be called from
11193;; the F000 segment (16-bit). Does not switch stacks. Must be run with disabled
11194;; interrupts(!). On return from pmode_enter, DS contains a selector which can
11195;; address the entire 4GB address space.
11196
11197pmode_enter:
11198 push cs
11199 pop ds
11200 lgdt [pmbios_gdt_desc]
11201 mov eax, cr0
11202 or al, #0x1
11203 mov cr0, eax
11204 JMP_AP(0x20, really_enter_pm)
11205really_enter_pm:
11206 mov ax, #0x18
11207 mov ds, ax
11208 ret
11209
11210pmode_exit:
11211 mov eax, cr0
11212 and al, #0xfe
11213 mov cr0, eax
11214 JMP_AP(0xF000, really_exit_pm)
11215really_exit_pm:
11216 ret
11217
11218pmbios_gdt_desc:
11219 dw 0x30
11220 dw pmbios_gdt
11221 dw 0x000f
11222
11223pmbios_gdt:
11224 dw 0, 0, 0, 0
11225 dw 0, 0, 0, 0
11226 dw 0xffff, 0, 0x9b00, 0x00cf ; 32 bit flat code segment (0x10)
11227 dw 0xffff, 0, 0x9300, 0x00cf ; 32 bit flat data segment (0x18)
11228 dw 0xffff, 0, 0x9b0f, 0x0000 ; 16 bit code segment base=0xf0000 limit=0xffff
11229 dw 0xffff, 0, 0x9300, 0x0000 ; 16 bit data segment base=0x0 limit=0xffff
11230
11231;; for 'C' strings and other data, insert them here with
11232;; a the following hack:
11233;; DATA_SEG_DEFS_HERE
11234
11235
11236;; the following area can be used to write dynamically generated tables
11237 .align 16
11238bios_table_area_start:
11239 dd 0xaafb4442
11240 dd bios_table_area_end - bios_table_area_start - 8;
11241
11242;--------
11243;- POST -
11244;--------
11245.org 0xe05b ; POST Entry Point
11246bios_table_area_end:
11247post:
11248
11249 xor ax, ax
11250
11251 ;; first reset the DMA controllers
11252 out 0x0d,al
11253 out 0xda,al
11254
11255 ;; then initialize the DMA controllers
11256 mov al, #0xC0
11257 out 0xD6, al ; cascade mode of channel 4 enabled
11258 mov al, #0x00
11259 out 0xD4, al ; unmask channel 4
11260
11261 ;; Examine CMOS shutdown status.
11262 mov AL, #0x0f
11263 out 0x70, AL
11264 in AL, 0x71
11265
11266 ;; backup status
11267 mov bl, al
11268
11269 ;; Reset CMOS shutdown status.
11270 mov AL, #0x0f
11271 out 0x70, AL ; select CMOS register Fh
11272 mov AL, #0x00
11273 out 0x71, AL ; set shutdown action to normal
11274
11275 ;; Examine CMOS shutdown status.
11276 mov al, bl
11277
11278 ;; 0x00, 0x09, 0x0D+ = normal startup
11279 cmp AL, #0x00
11280 jz normal_post
11281 cmp AL, #0x0d
11282 jae normal_post
11283 cmp AL, #0x09
11284 je normal_post
11285
11286 ;; 0x05 = eoi + jmp via [0x40:0x67] jump
11287 cmp al, #0x05
11288 je eoi_jmp_post
11289
11290#ifdef VBOX
11291 ;; just ignore all other CMOS shutdown status values (OpenSolaris sets it to 0xA for some reason in certain cases)
11292 ;; (shutdown_status_panic just crashes the VM as it calls int 0x10 before the IDT table has been initialized)
11293 jmp normal_post
11294#else
11295 ;; Examine CMOS shutdown status.
11296 ;; 0x01,0x02,0x03,0x04,0x06,0x07,0x08, 0x0a, 0x0b, 0x0c = Unimplemented shutdown status.
11297 push bx
11298 call _shutdown_status_panic
11299#endif
11300
11301#if 0
11302 HALT(__LINE__)
11303 ;
11304 ;#if 0
11305 ; 0xb0, 0x20, /* mov al, #0x20 */
11306 ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */
11307 ;#endif
11308 ;
11309 pop es
11310 pop ds
11311 popa
11312 iret
11313#endif
11314
11315normal_post:
11316 ; case 0: normal startup
11317
11318 cli
11319 mov ax, #0xfffe
11320 mov sp, ax
11321 xor ax, ax
11322 mov ds, ax
11323 mov ss, ax
11324
11325#ifndef VBOX
11326 ;; zero out BIOS data area (40:00..40:ff)
11327 mov es, ax
11328 mov cx, #0x0080 ;; 128 words
11329 mov di, #0x0400
11330 cld
11331 rep
11332 stosw
11333#else /* VBOX */
11334 ;; zero out segment 0 (includes BIOS data area) except word at 40:72
11335 mov es, ax
11336 xor di, di
11337 cld
11338 mov cx, #0x0239 ;; 569 words
11339 rep
11340 stosw
11341 inc di
11342 inc di
11343 mov cx, #0x7dc6 ;; 32198 words
11344 rep
11345 stosw
11346 ;; zero out remaining base memory except the last 16 bytes of the EBDA
11347 ;; because we store the MP table there
11348 xor eax, eax
11349 xor bx, bx
11350memory_zero_loop:
11351 add bx, #0x1000
11352 cmp bx, #0x9000
11353 jae memory_cleared
11354 mov es, bx
11355 xor di, di
11356 mov cx, #0x4000
11357 rep
11358 stosd
11359 jmp memory_zero_loop
11360memory_cleared:
11361 mov es, bx
11362 xor di, di
11363 mov cx, #0x3f00
11364 rep
11365 stosd
11366 xor bx, bx
11367#endif
11368
11369 call _log_bios_start
11370
11371 ;; set all interrupts to default handler
11372 xor bx, bx ;; offset index
11373 mov cx, #0x0100 ;; counter (256 interrupts)
11374 mov ax, #dummy_iret_handler
11375 mov dx, #0xF000
11376
11377post_default_ints:
11378 mov [bx], ax
11379 add bx, #2
11380 mov [bx], dx
11381 add bx, #2
11382 loop post_default_ints
11383
11384 ;; set vector 0x79 to zero
11385 ;; this is used by 'guardian angel' protection system
11386 SET_INT_VECTOR(0x79, #0, #0)
11387
11388 ;; base memory in K 40:13 (word)
11389 mov ax, #BASE_MEM_IN_K
11390 mov 0x0413, ax
11391
11392
11393 ;; Manufacturing Test 40:12
11394 ;; zerod out above
11395
11396#ifndef VBOX
11397 ;; Warm Boot Flag 0040:0072
11398 ;; value of 1234h = skip memory checks
11399 ;; zerod out above
11400#endif /* !VBOX */
11401
11402
11403 ;; Printer Services vector
11404 SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
11405
11406 ;; Bootstrap failure vector
11407 SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
11408
11409 ;; Bootstrap Loader vector
11410 SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
11411
11412 ;; User Timer Tick vector
11413 SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
11414
11415 ;; Memory Size Check vector
11416 SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
11417
11418 ;; Equipment Configuration Check vector
11419 SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
11420
11421 ;; System Services
11422 SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
11423
11424 ;; EBDA setup
11425 call ebda_post
11426
11427 ;; PIT setup
11428 SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
11429 ;; int 1C already points at dummy_iret_handler (above)
11430 mov al, #0x34 ; timer0: binary count, 16bit count, mode 2
11431 out 0x43, al
11432 mov al, #0x00 ; maximum count of 0000H = 18.2Hz
11433 out 0x40, al
11434 out 0x40, al
11435
11436 ;; Keyboard
11437 SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
11438 SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
11439
11440 xor ax, ax
11441 mov ds, ax
11442 mov 0x0417, al /* keyboard shift flags, set 1 */
11443 mov 0x0418, al /* keyboard shift flags, set 2 */
11444 mov 0x0419, al /* keyboard alt-numpad work area */
11445 mov 0x0471, al /* keyboard ctrl-break flag */
11446 mov 0x0497, al /* keyboard status flags 4 */
11447 mov al, #0x10
11448 mov 0x0496, al /* keyboard status flags 3 */
11449
11450
11451 /* keyboard head of buffer pointer */
11452 mov bx, #0x001E
11453 mov 0x041A, bx
11454
11455 /* keyboard end of buffer pointer */
11456 mov 0x041C, bx
11457
11458 /* keyboard pointer to start of buffer */
11459 mov bx, #0x001E
11460 mov 0x0480, bx
11461
11462 /* keyboard pointer to end of buffer */
11463 mov bx, #0x003E
11464 mov 0x0482, bx
11465
11466 /* init the keyboard */
11467 call _keyboard_init
11468
11469 ;; mov CMOS Equipment Byte to BDA Equipment Word
11470 mov ax, 0x0410
11471 mov al, #0x14
11472 out 0x70, al
11473 in al, 0x71
11474 mov 0x0410, ax
11475
11476
11477 ;; Parallel setup
11478 SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
11479 xor ax, ax
11480 mov ds, ax
11481 xor bx, bx
11482 mov cl, #0x14 ; timeout value
11483 mov dx, #0x378 ; Parallel I/O address, port 1
11484 call detect_parport
11485 mov dx, #0x278 ; Parallel I/O address, port 2
11486 call detect_parport
11487 shl bx, #0x0e
11488 mov ax, 0x410 ; Equipment word bits 14..15 determine # parallel ports
11489 and ax, #0x3fff
11490 or ax, bx ; set number of parallel ports
11491 mov 0x410, ax
11492
11493 ;; Serial setup
11494 SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
11495 SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
11496 xor bx, bx
11497 mov cl, #0x0a ; timeout value
11498 mov dx, #0x03f8 ; Serial I/O address, port 1
11499 call detect_serial
11500 mov dx, #0x02f8 ; Serial I/O address, port 2
11501 call detect_serial
11502 mov dx, #0x03e8 ; Serial I/O address, port 3
11503 call detect_serial
11504 mov dx, #0x02e8 ; Serial I/O address, port 4
11505 call detect_serial
11506 shl bx, #0x09
11507 mov ax, 0x410 ; Equipment word bits 9..11 determine # serial ports
11508 and ax, #0xf1ff
11509 or ax, bx ; set number of serial port
11510 mov 0x410, ax
11511
11512 ;; CMOS RTC
11513 SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
11514 SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
11515 SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
11516 ;; BIOS DATA AREA 0x4CE ???
11517 call timer_tick_post
11518
11519 ;; PS/2 mouse setup
11520 SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
11521
11522 ;; IRQ13 (FPU exception) setup
11523 SET_INT_VECTOR(0x75, #0xF000, #int75_handler)
11524
11525 ;; Video setup
11526 SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
11527
11528#ifdef VBOX
11529 ;; moved the PIC initialization to another place as we need
11530 ;; some space for additions init calls. Otherwise this code
11531 ;; overlaps with the NMI handler at 0xe2c3 (fixed BIOS entry)
11532 call init_pic
11533#else /* !VBOX */
11534 ;; PIC
11535 mov al, #0x11 ; send initialisation commands
11536 out 0x20, al
11537 out 0xa0, al
11538 mov al, #0x08
11539 out 0x21, al
11540 mov al, #0x70
11541 out 0xa1, al
11542 mov al, #0x04
11543 out 0x21, al
11544 mov al, #0x02
11545 out 0xa1, al
11546 mov al, #0x01
11547 out 0x21, al
11548 out 0xa1, al
11549 mov al, #0xb8
11550 out 0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6
11551#if BX_USE_PS2_MOUSE
11552 mov al, #0x8f
11553#else
11554 mov al, #0x9f
11555#endif
11556 out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14
11557#endif /* !VBOX */
11558
11559#if BX_ROMBIOS32
11560 call rombios32_init
11561#else
11562 call pcibios_init_iomem_bases
11563 call pcibios_init_irqs
11564#endif
11565 call setup_lapic
11566 call rom_scan
11567
11568#if BX_USE_ATADRV
11569 ;;
11570 ;; ATA/ATAPI driver setup
11571 ;;
11572 call _ata_init
11573 call _ata_detect
11574 ;;
11575#endif
11576
11577#ifdef VBOX_WITH_SCSI
11578 ;;
11579 ;; SCSI driver setup
11580 ;;
11581 call _scsi_init
11582 ;;
11583#endif
11584
11585 call _print_bios_banner
11586
11587 ;;
11588 ;; Floppy setup
11589 ;;
11590 call floppy_drive_post
11591
11592 ;;
11593 ;; Hard Drive setup
11594 ;;
11595 call hard_drive_post
11596
11597#if BX_ELTORITO_BOOT
11598 ;;
11599 ;; eltorito floppy/harddisk emulation from cd
11600 ;;
11601 call _cdemu_init
11602 ;;
11603#endif // BX_ELTORITO_BOOT
11604
11605 sti ;; enable interrupts
11606 int #0x19
11607
11608.org 0xe2c3 ; NMI Handler Entry Point
11609nmi:
11610 ;; FIXME the NMI handler should not panic
11611 ;; but iret when called from int75 (fpu exception)
11612 call _nmi_handler_msg
11613 iret
11614
11615int75_handler:
11616 out 0xf0, al // clear irq13
11617 call eoi_both_pics // clear interrupt
11618 int 2 // legacy nmi call
11619 iret
11620
11621;-------------------------------------------
11622;- INT 13h Fixed Disk Services Entry Point -
11623;-------------------------------------------
11624.org 0xe3fe ; INT 13h Fixed Disk Services Entry Point
11625int13_handler:
11626 //JMPL(int13_relocated)
11627 jmp int13_relocated
11628
11629.org 0xe401 ; Fixed Disk Parameter Table
11630
11631;----------
11632;- INT19h -
11633;----------
11634.org 0xe6f2 ; INT 19h Boot Load Service Entry Point
11635int19_handler:
11636
11637 jmp int19_relocated
11638;-------------------------------------------
11639;- System BIOS Configuration Data Table
11640;-------------------------------------------
11641.org BIOS_CONFIG_TABLE
11642db 0x08 ; Table size (bytes) -Lo
11643db 0x00 ; Table size (bytes) -Hi
11644db SYS_MODEL_ID
11645db SYS_SUBMODEL_ID
11646db BIOS_REVISION
11647; Feature byte 1
11648; b7: 1=DMA channel 3 used by hard disk
11649; b6: 1=2 interrupt controllers present
11650; b5: 1=RTC present
11651; b4: 1=BIOS calls int 15h/4Fh every key
11652; b3: 1=wait for extern event supported (Int 15h/41h)
11653; b2: 1=extended BIOS data area used
11654; b1: 0=AT or ESDI bus, 1=MicroChannel
11655; b0: 1=Dual bus (MicroChannel + ISA)
11656db (0 << 7) | \
11657 (1 << 6) | \
11658 (1 << 5) | \
11659 (BX_CALL_INT15_4F << 4) | \
11660 (0 << 3) | \
11661 (BX_USE_EBDA << 2) | \
11662 (0 << 1) | \
11663 (0 << 0)
11664; Feature byte 2
11665; b7: 1=32-bit DMA supported
11666; b6: 1=int16h, function 9 supported
11667; b5: 1=int15h/C6h (get POS data) supported
11668; b4: 1=int15h/C7h (get mem map info) supported
11669; b3: 1=int15h/C8h (en/dis CPU) supported
11670; b2: 1=non-8042 kb controller
11671; b1: 1=data streaming supported
11672; b0: reserved
11673db (0 << 7) | \
11674 (1 << 6) | \
11675 (0 << 5) | \
11676 (0 << 4) | \
11677 (0 << 3) | \
11678 (0 << 2) | \
11679 (0 << 1) | \
11680 (0 << 0)
11681; Feature byte 3
11682; b7: not used
11683; b6: reserved
11684; b5: reserved
11685; b4: POST supports ROM-to-RAM enable/disable
11686; b3: SCSI on system board
11687; b2: info panel installed
11688; b1: Initial Machine Load (IML) system - BIOS on disk
11689; b0: SCSI supported in IML
11690db 0x00
11691; Feature byte 4
11692; b7: IBM private
11693; b6: EEPROM present
11694; b5-3: ABIOS presence (011 = not supported)
11695; b2: private
11696; b1: memory split above 16Mb supported
11697; b0: POSTEXT directly supported by POST
11698db 0x00
11699; Feature byte 5 (IBM)
11700; b1: enhanced mouse
11701; b0: flash EPROM
11702db 0x00
11703
11704
11705
11706.org 0xe729 ; Baud Rate Generator Table
11707
11708;----------
11709;- INT14h -
11710;----------
11711.org 0xe739 ; INT 14h Serial Communications Service Entry Point
11712int14_handler:
11713 push ds
11714 pusha
11715 xor ax, ax
11716 mov ds, ax
11717 call _int14_function
11718 popa
11719 pop ds
11720 iret
11721
11722
11723;----------------------------------------
11724;- INT 16h Keyboard Service Entry Point -
11725;----------------------------------------
11726.org 0xe82e
11727int16_handler:
11728
11729 sti
11730 push ds
11731 pushf
11732 pusha
11733
11734 cmp ah, #0x00
11735 je int16_F00
11736 cmp ah, #0x10
11737 je int16_F00
11738
11739 mov bx, #0xf000
11740 mov ds, bx
11741 call _int16_function
11742 popa
11743 popf
11744 pop ds
11745 jz int16_zero_set
11746
11747int16_zero_clear:
11748 push bp
11749 mov bp, sp
11750 //SEG SS
11751 and BYTE [bp + 0x06], #0xbf
11752 pop bp
11753 iret
11754
11755int16_zero_set:
11756 push bp
11757 mov bp, sp
11758 //SEG SS
11759 or BYTE [bp + 0x06], #0x40
11760 pop bp
11761 iret
11762
11763int16_F00:
11764 mov bx, #0x0040
11765 mov ds, bx
11766
11767int16_wait_for_key:
11768 cli
11769 mov bx, 0x001a
11770 cmp bx, 0x001c
11771 jne int16_key_found
11772 sti
11773 nop
11774#if 0
11775 /* no key yet, call int 15h, function AX=9002 */
11776 0x50, /* push AX */
11777 0xb8, 0x02, 0x90, /* mov AX, #0x9002 */
11778 0xcd, 0x15, /* int 15h */
11779 0x58, /* pop AX */
11780 0xeb, 0xea, /* jmp WAIT_FOR_KEY */
11781#endif
11782 jmp int16_wait_for_key
11783
11784int16_key_found:
11785 mov bx, #0xf000
11786 mov ds, bx
11787 call _int16_function
11788 popa
11789 popf
11790 pop ds
11791#if 0
11792 /* notify int16 complete w/ int 15h, function AX=9102 */
11793 0x50, /* push AX */
11794 0xb8, 0x02, 0x91, /* mov AX, #0x9102 */
11795 0xcd, 0x15, /* int 15h */
11796 0x58, /* pop AX */
11797#endif
11798 iret
11799
11800
11801
11802;-------------------------------------------------
11803;- INT09h : Keyboard Hardware Service Entry Point -
11804;-------------------------------------------------
11805.org 0xe987
11806int09_handler:
11807 cli
11808 push ax
11809
11810 mov al, #0xAD ;;disable keyboard
11811 out #0x64, al
11812
11813 mov al, #0x0B
11814 out #0x20, al
11815 in al, #0x20
11816 and al, #0x02
11817 jz int09_finish
11818
11819 in al, #0x60 ;;read key from keyboard controller
11820 sti
11821 push ds
11822 pusha
11823#ifdef BX_CALL_INT15_4F
11824 mov ah, #0x4f ;; allow for keyboard intercept
11825 stc
11826 int #0x15
11827 jnc int09_done
11828#endif
11829
11830 ;; check for extended key
11831 cmp al, #0xe0
11832 jne int09_check_pause
11833 xor ax, ax
11834 mov ds, ax
11835 mov al, BYTE [0x496] ;; mf2_state |= 0x02
11836 or al, #0x02
11837 mov BYTE [0x496], al
11838 jmp int09_done
11839
11840int09_check_pause: ;; check for pause key
11841 cmp al, #0xe1
11842 jne int09_process_key
11843 xor ax, ax
11844 mov ds, ax
11845 mov al, BYTE [0x496] ;; mf2_state |= 0x01
11846 or al, #0x01
11847 mov BYTE [0x496], al
11848 jmp int09_done
11849
11850int09_process_key:
11851 mov bx, #0xf000
11852 mov ds, bx
11853 call _int09_function
11854
11855int09_done:
11856 popa
11857 pop ds
11858 cli
11859 call eoi_master_pic
11860
11861int09_finish:
11862 mov al, #0xAE ;;enable keyboard
11863 out #0x64, al
11864 pop ax
11865 iret
11866
11867
11868;----------------------------------------
11869;- INT 13h Diskette Service Entry Point -
11870;----------------------------------------
11871.org 0xec59
11872int13_diskette:
11873 jmp int13_noeltorito
11874
11875;---------------------------------------------
11876;- INT 0Eh Diskette Hardware ISR Entry Point -
11877;---------------------------------------------
11878.org 0xef57 ; INT 0Eh Diskette Hardware ISR Entry Point
11879int0e_handler:
11880 push ax
11881 push dx
11882 mov dx, #0x03f4
11883 in al, dx
11884 and al, #0xc0
11885 cmp al, #0xc0
11886 je int0e_normal
11887 mov dx, #0x03f5
11888 mov al, #0x08 ; sense interrupt status
11889 out dx, al
11890int0e_loop1:
11891 mov dx, #0x03f4
11892 in al, dx
11893 and al, #0xc0
11894 cmp al, #0xc0
11895 jne int0e_loop1
11896int0e_loop2:
11897 mov dx, #0x03f5
11898 in al, dx
11899 mov dx, #0x03f4
11900 in al, dx
11901 and al, #0xc0
11902 cmp al, #0xc0
11903 je int0e_loop2
11904int0e_normal:
11905 push ds
11906 xor ax, ax ;; segment 0000
11907 mov ds, ax
11908 call eoi_master_pic
11909 mov al, 0x043e
11910 or al, #0x80 ;; diskette interrupt has occurred
11911 mov 0x043e, al
11912 pop ds
11913 pop dx
11914 pop ax
11915 iret
11916
11917
11918.org 0xefc7 ; Diskette Controller Parameter Table
11919diskette_param_table:
11920;; Since no provisions are made for multiple drive types, most
11921;; values in this table are ignored. I set parameters for 1.44M
11922;; floppy here
11923db 0xAF
11924db 0x02 ;; head load time 0000001, DMA used
11925db 0x25
11926db 0x02
11927db 18
11928db 0x1B
11929db 0xFF
11930db 0x6C
11931db 0xF6
11932db 0x0F
11933db 0x08
11934
11935
11936;----------------------------------------
11937;- INT17h : Printer Service Entry Point -
11938;----------------------------------------
11939.org 0xefd2
11940int17_handler:
11941 push ds
11942 pusha
11943 xor ax, ax
11944 mov ds, ax
11945 call _int17_function
11946 popa
11947 pop ds
11948 iret
11949
11950diskette_param_table2:
11951;; New diskette parameter table adding 3 parameters from IBM
11952;; Since no provisions are made for multiple drive types, most
11953;; values in this table are ignored. I set parameters for 1.44M
11954;; floppy here
11955db 0xAF
11956db 0x02 ;; head load time 0000001, DMA used
11957db 0x25
11958db 0x02
11959db 18
11960db 0x1B
11961db 0xFF
11962db 0x6C
11963db 0xF6
11964db 0x0F
11965db 0x08
11966db 79 ;; maximum track
11967db 0 ;; data transfer rate
11968db 4 ;; drive type in cmos
11969
11970.org 0xf045 ; INT 10 Functions 0-Fh Entry Point
11971 HALT(__LINE__)
11972 iret
11973
11974;----------
11975;- INT10h -
11976;----------
11977.org 0xf065 ; INT 10h Video Support Service Entry Point
11978int10_handler:
11979 ;; dont do anything, since the VGA BIOS handles int10h requests
11980 iret
11981
11982.org 0xf0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
11983
11984;----------
11985;- INT12h -
11986;----------
11987.org 0xf841 ; INT 12h Memory Size Service Entry Point
11988; ??? different for Pentium (machine check)?
11989int12_handler:
11990 push ds
11991 mov ax, #0x0040
11992 mov ds, ax
11993 mov ax, 0x0013
11994 pop ds
11995 iret
11996
11997;----------
11998;- INT11h -
11999;----------
12000.org 0xf84d ; INT 11h Equipment List Service Entry Point
12001int11_handler:
12002 push ds
12003 mov ax, #0x0040
12004 mov ds, ax
12005 mov ax, 0x0010
12006 pop ds
12007 iret
12008
12009;----------
12010;- INT15h -
12011;----------
12012.org 0xf859 ; INT 15h System Services Entry Point
12013int15_handler:
12014 pushf
12015#if BX_APM
12016 cmp ah, #0x53
12017 je apm_call
12018#endif
12019 push ds
12020 push es
12021 cmp ah, #0x86
12022 je int15_handler32
12023 cmp ah, #0xE8
12024 je int15_handler32
12025 pusha
12026#if BX_USE_PS2_MOUSE
12027 cmp ah, #0xC2
12028 je int15_handler_mouse
12029#endif
12030 call _int15_function
12031int15_handler_mouse_ret:
12032 popa
12033int15_handler32_ret:
12034 pop es
12035 pop ds
12036 popf
12037 jmp iret_modify_cf
12038#if BX_APM
12039apm_call:
12040 jmp _apmreal_entry
12041#endif
12042
12043#if BX_USE_PS2_MOUSE
12044int15_handler_mouse:
12045 call _int15_function_mouse
12046 jmp int15_handler_mouse_ret
12047#endif
12048
12049int15_handler32:
12050 pushad
12051 call _int15_function32
12052 popad
12053 jmp int15_handler32_ret
12054
12055;; Protected mode IDT descriptor
12056;;
12057;; I just make the limit 0, so the machine will shutdown
12058;; if an exception occurs during protected mode memory
12059;; transfers.
12060;;
12061;; Set base to f0000 to correspond to beginning of BIOS,
12062;; in case I actually define an IDT later
12063;; Set limit to 0
12064
12065pmode_IDT_info:
12066dw 0x0000 ;; limit 15:00
12067dw 0x0000 ;; base 15:00
12068db 0x0f ;; base 23:16
12069
12070;; Real mode IDT descriptor
12071;;
12072;; Set to typical real-mode values.
12073;; base = 000000
12074;; limit = 03ff
12075
12076rmode_IDT_info:
12077dw 0x03ff ;; limit 15:00
12078dw 0x0000 ;; base 15:00
12079db 0x00 ;; base 23:16
12080
12081;;
12082;; Handler for unexpected hardware interrupts
12083;;
12084dummy_isr:
12085 push ds
12086 pushad
12087 xor ax, ax
12088 mov ds, ax
12089 call _dummy_isr_function
12090 popad
12091 pop ds
12092 iret
12093
12094;----------
12095;- INT1Ah -
12096;----------
12097.org 0xfe6e ; INT 1Ah Time-of-day Service Entry Point
12098int1a_handler:
12099#if BX_PCIBIOS
12100 cmp ah, #0xb1
12101 jne int1a_normal
12102 call pcibios_real
12103 jc pcibios_error
12104 retf 2
12105pcibios_error:
12106 mov bl, ah
12107 mov ah, #0xb1
12108 push ds
12109 pusha
12110 mov ax, ss ; set readable descriptor to ds, for calling pcibios
12111 mov ds, ax ; on 16bit protected mode.
12112 jmp int1a_callfunction
12113int1a_normal:
12114#endif
12115 push ds
12116 pusha
12117 xor ax, ax
12118 mov ds, ax
12119int1a_callfunction:
12120 call _int1a_function
12121 popa
12122 pop ds
12123 iret
12124
12125;;
12126;; int70h: IRQ8 - CMOS RTC
12127;;
12128int70_handler:
12129 push ds
12130 pushad
12131 xor ax, ax
12132 mov ds, ax
12133 call _int70_function
12134 popad
12135 pop ds
12136 iret
12137
12138;---------
12139;- INT08 -
12140;---------
12141.org 0xfea5 ; INT 08h System Timer ISR Entry Point
12142int08_handler:
12143 sti
12144 push eax
12145 push ds
12146 xor ax, ax
12147 mov ds, ax
12148
12149 ;; time to turn off drive(s)?
12150 mov al,0x0440
12151 or al,al
12152 jz int08_floppy_off
12153 dec al
12154 mov 0x0440,al
12155 jnz int08_floppy_off
12156 ;; turn motor(s) off
12157 push dx
12158 mov dx,#0x03f2
12159 in al,dx
12160 and al,#0xcf
12161 out dx,al
12162 pop dx
12163int08_floppy_off:
12164
12165 mov eax, 0x046c ;; get ticks dword
12166 inc eax
12167
12168 ;; compare eax to one days worth of timer ticks at 18.2 hz
12169 cmp eax, #0x001800B0
12170 jb int08_store_ticks
12171 ;; there has been a midnight rollover at this point
12172 xor eax, eax ;; zero out counter
12173 inc BYTE 0x0470 ;; increment rollover flag
12174
12175int08_store_ticks:
12176 mov 0x046c, eax ;; store new ticks dword
12177 ;; chain to user timer tick INT #0x1c
12178 //pushf
12179 //;; call_ep [ds:loc]
12180 //CALL_EP( 0x1c << 2 )
12181 int #0x1c
12182 cli
12183 call eoi_master_pic
12184 pop ds
12185 pop eax
12186 iret
12187
12188.org 0xfef3 ; Initial Interrupt Vector Offsets Loaded by POST
12189
12190
12191.org 0xff00
12192.ascii BIOS_COPYRIGHT_STRING
12193
12194#ifdef VBOX
12195// The SMBIOS header
12196.org 0xff30
12197.align 16
12198 db 0x5f, 0x53, 0x4d, 0x5f ; "_SM_" signature
12199 db 0x00 ; checksum (set by biossums)
12200 db 0x1f ; EPS length, defined by standard
12201 db VBOX_SMBIOS_MAJOR_VER ; SMBIOS major version
12202 db VBOX_SMBIOS_MINOR_VER ; SMBIOS minor version
12203 dw VBOX_SMBIOS_MAXSS ; Maximum structure size
12204 db 0x00 ; Entry point revision
12205 db 0x00, 0x00, 0x00, 0x00, 0x00
12206
12207// The DMI header
12208 db 0x5f, 0x44, 0x4d, 0x49, 0x5f ; "_DMI_" signature
12209 db 0x00 ; checksum (set by biossums)
12210 dw VBOX_DMI_TABLE_SIZE ; DMI tables length
12211 dd VBOX_DMI_TABLE_BASE ; DMI tables base
12212 dw VBOX_DMI_TABLE_ENTR ; DMI tables entries
12213 db VBOX_DMI_TABLE_VER ; DMI version
12214 db 0x00 ; Just for alignment
12215#endif
12216
12217;------------------------------------------------
12218;- IRET Instruction for Dummy Interrupt Handler -
12219;------------------------------------------------
12220.org 0xff53 ; IRET Instruction for Dummy Interrupt Handler
12221dummy_iret_handler:
12222 iret
12223
12224.org 0xff54 ; INT 05h Print Screen Service Entry Point
12225 HALT(__LINE__)
12226 iret
12227
12228.org 0xfff0 ; Power-up Entry Point
12229 jmp 0xf000:post
12230
12231.org 0xfff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
12232.ascii BIOS_BUILD_DATE
12233
12234.org 0xfffe ; System Model ID
12235db SYS_MODEL_ID
12236db 0x00 ; filler
12237
12238.org 0xfa6e ;; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
12239ASM_END
12240/*
12241 * This font comes from the fntcol16.zip package (c) by Joseph Gil
12242 * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
12243 * This font is public domain
12244 */
12245static Bit8u vgafont8[128*8]=
12246{
12247 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
12248 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
12249 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
12250 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
12251 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
12252 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
12253 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
12254 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
12255 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
12256 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
12257 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
12258 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
12259 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
12260 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
12261 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
12262 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
12263 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
12264 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
12265 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
12266 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
12267 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
12268 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
12269 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
12270 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
12271 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
12272 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
12273 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
12274 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
12275 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
12276 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
12277 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
12278 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
12279 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
12280 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
12281 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
12282 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
12283 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
12284 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
12285 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
12286 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
12287 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
12288 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
12289 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
12290 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
12291 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
12292 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
12293 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
12294 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
12295 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
12296 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
12297 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
12298 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
12299 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
12300 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
12301 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
12302 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
12303 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
12304 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
12305 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
12306 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
12307 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
12308 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
12309 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
12310 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
12311 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
12312 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
12313 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
12314 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
12315 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
12316 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
12317 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
12318 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
12319 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
12320 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
12321 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
12322 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
12323 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
12324 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
12325 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
12326 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
12327 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
12328 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
12329 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
12330 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
12331 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
12332 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
12333 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
12334 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
12335 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
12336 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
12337 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
12338 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
12339 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
12340 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
12341 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
12342 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
12343 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
12344 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
12345 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
12346 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
12347 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
12348 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
12349 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
12350 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
12351 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
12352 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
12353 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
12354 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
12355 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
12356 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
12357 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
12358 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
12359 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
12360 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
12361 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
12362 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
12363 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
12364 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
12365 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
12366 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
12367 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
12368 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
12369 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
12370 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
12371 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
12372 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
12373 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
12374 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
12375};
12376
12377ASM_START
12378.org 0xcc00
12379// bcc-generated data will be placed here
12380ASM_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