VirtualBox

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

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

BIOS: fix booting from more than 4 drives

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

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