VirtualBox

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

最後變更 在這個檔案從7099是 7099,由 vboxsync 提交於 17 年 前

Use CMOS to store hard disk geometry for more than 4 disks

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

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