VirtualBox

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

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

Make the BIOS booting from any attached disk.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette