VirtualBox

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

Last change on this file since 10719 was 9440, checked in by vboxsync, 17 years ago

Added SMBIOS header for DMI data to make Vista and Solaris recognize the data.

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