VirtualBox

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

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

PCI: BIOS & ACPI work

  • 屬性 svn:eol-style 設為 native
檔案大小: 334.5 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
28/*
29 * Sun LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
30 * other than GPL or LGPL is available it will apply instead, Sun elects to use only
31 * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
32 * a choice of LGPL license versions is made available with the language indicating
33 * that LGPLv2 or any later version may be used, or where a choice of which version
34 * of the LGPL is applied is otherwise unspecified.
35 */
36// ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
37
38
39// ROM BIOS compatability entry points:
40// ===================================
41// $e05b ; POST Entry Point
42// $e2c3 ; NMI Handler Entry Point
43// $e3fe ; INT 13h Fixed Disk Services Entry Point
44// $e401 ; Fixed Disk Parameter Table
45// $e6f2 ; INT 19h Boot Load Service Entry Point
46// $e6f5 ; Configuration Data Table
47// $e729 ; Baud Rate Generator Table
48// $e739 ; INT 14h Serial Communications Service Entry Point
49// $e82e ; INT 16h Keyboard Service Entry Point
50// $e987 ; INT 09h Keyboard Service Entry Point
51// $ec59 ; INT 13h Diskette Service Entry Point
52// $ef57 ; INT 0Eh Diskette Hardware ISR Entry Point
53// $efc7 ; Diskette Controller Parameter Table
54// $efd2 ; INT 17h Printer Service Entry Point
55// $f045 ; INT 10 Functions 0-Fh Entry Point
56// $f065 ; INT 10h Video Support Service Entry Point
57// $f0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
58// $f841 ; INT 12h Memory Size Service Entry Point
59// $f84d ; INT 11h Equipment List Service Entry Point
60// $f859 ; INT 15h System Services Entry Point
61// $fa6e ; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
62// $fe6e ; INT 1Ah Time-of-day Service Entry Point
63// $fea5 ; INT 08h System Timer ISR Entry Point
64// $fef3 ; Initial Interrupt Vector Offsets Loaded by POST
65// $ff53 ; IRET Instruction for Dummy Interrupt Handler
66// $ff54 ; INT 05h Print Screen Service Entry Point
67// $fff0 ; Power-up Entry Point
68// $fff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
69// $fffe ; System Model ID
70
71// NOTES for ATA/ATAPI driver ([email protected])
72// Features
73// - supports up to 4 ATA interfaces
74// - device/geometry detection
75// - 16bits/32bits device access
76// - pchs/lba access
77// - datain/dataout/packet command support
78//
79// NOTES for El-Torito Boot ([email protected])
80// - CD-ROM booting is only available if ATA/ATAPI Driver is available
81// - Current code is only able to boot mono-session cds
82// - Current code can not boot and emulate a hard-disk
83// the bios will panic otherwise
84// - Current code also use memory in EBDA segement.
85// - I used cmos byte 0x3D to store extended information on boot-device
86// - Code has to be modified modified to handle multiple cdrom drives
87// - Here are the cdrom boot failure codes:
88// 1 : no atapi device found
89// 2 : no atapi cdrom found
90// 3 : can not read cd - BRVD
91// 4 : cd is not eltorito (BRVD)
92// 5 : cd is not eltorito (ISO TAG)
93// 6 : cd is not eltorito (ELTORITO TAG)
94// 7 : can not read cd - boot catalog
95// 8 : boot catalog : bad header
96// 9 : boot catalog : bad platform
97// 10 : boot catalog : bad signature
98// 11 : boot catalog : bootable flag not set
99// 12 : can not read cd - boot image
100//
101// ATA driver
102// - EBDA segment.
103// I used memory starting at 0x121 in the segment
104#ifndef VBOX
105// - the translation policy is defined in cmos regs 0x39 & 0x3a
106#endif /* !VBOX */
107//
108// TODO :
109//
110// int74
111// - needs to be reworked. Uses direct [bp] offsets. (?)
112//
113// int13:
114// - f04 (verify sectors) isn't complete (?)
115// - f02/03/04 should set current cyl,etc in BDA (?)
116// - rewrite int13_relocated & clean up int13 entry code
117//
118// NOTES:
119// - NMI access (bit7 of addr written to 70h)
120//
121// ATA driver
122// - should handle the "don't detect" bit (cmos regs 0x3b & 0x3c)
123// - could send the multiple-sector read/write commands
124//
125// El-Torito
126// - Emulate a Hard-disk (currently only diskette can be emulated) see "FIXME ElTorito Harddisk"
127// - Implement remaining int13_cdemu functions (as defined by El-Torito specs)
128// - cdrom drive is hardcoded to ide 0 device 1 in several places. see "FIXME ElTorito Hardcoded"
129// - int13 Fix DL when emulating a cd. In that case DL is decremented before calling real int13.
130// This is ok. But DL should be reincremented afterwards.
131// - Fix all "FIXME ElTorito Various"
132// - should be able to boot any cdrom instead of the first one
133//
134// BCC Bug: find a generic way to handle the bug of #asm after an "if" (fixed in 0.16.7)
135
136#ifdef VBOX
137#include "DevPcBios.h"
138#include <VBox/version.h>
139#endif
140
141#define BX_ROMBIOS32 0
142#define DEBUG_ROMBIOS 0
143
144#define DEBUG_ATA 0
145#define DEBUG_INT13_HD 0
146#define DEBUG_INT13_CD 0
147#define DEBUG_INT13_ET 0
148#define DEBUG_INT13_FL 0
149#define DEBUG_INT15 0
150#define DEBUG_INT16 0
151#define DEBUG_INT1A 0
152#define DEBUG_INT74 0
153#define DEBUG_APM 0
154
155#define BX_CPU 3
156#define BX_USE_PS2_MOUSE 1
157#define BX_CALL_INT15_4F 1
158#define BX_USE_EBDA 1
159#define BX_SUPPORT_FLOPPY 1
160#define BX_FLOPPY_ON_CNT 37 /* 2 seconds */
161#define BX_PCIBIOS 1
162#define BX_APM 1
163
164#define BX_USE_ATADRV 1
165#define BX_ELTORITO_BOOT 1
166
167#define BX_MAX_ATA_INTERFACES 4
168#define BX_MAX_ATA_DEVICES (BX_MAX_ATA_INTERFACES*2)
169
170#define BX_VIRTUAL_PORTS 1 /* normal output to Bochs ports */
171#define BX_DEBUG_SERIAL 0 /* output to COM1 */
172
173 /* model byte 0xFC = AT */
174#define SYS_MODEL_ID 0xFC
175#define SYS_SUBMODEL_ID 0x00
176#define BIOS_REVISION 1
177#define BIOS_CONFIG_TABLE 0xe6f5
178
179#ifndef BIOS_BUILD_DATE
180# define BIOS_BUILD_DATE "06/23/99"
181#endif
182
183 // 1K of base memory used for Extended Bios Data Area (EBDA)
184 // EBDA is used for PS/2 mouse support, and IDE BIOS, etc.
185#define EBDA_SEG 0x9FC0
186#define EBDA_SIZE 1 // In KiB
187#define BASE_MEM_IN_K (640 - EBDA_SIZE)
188
189#define ACPI_DATA_SIZE 0x00010000L
190
191 // Define the application NAME
192#if defined(BX_QEMU)
193# define BX_APPNAME "QEMU"
194#elif defined(PLEX86)
195# define BX_APPNAME "Plex86"
196#else
197# define BX_APPNAME "Bochs"
198#endif
199
200 // Sanity Checks
201#if BX_USE_ATADRV && BX_CPU<3
202# error The ATA/ATAPI Driver can only to be used with a 386+ cpu
203#endif
204#if BX_USE_ATADRV && !BX_USE_EBDA
205# error ATA/ATAPI Driver can only be used if EBDA is available
206#endif
207#if BX_ELTORITO_BOOT && !BX_USE_ATADRV
208# error El-Torito Boot can only be use if ATA/ATAPI Driver is available
209#endif
210#if BX_PCIBIOS && BX_CPU<3
211# error PCI BIOS can only be used with 386+ cpu
212#endif
213#if BX_APM && BX_CPU<3
214# error APM BIOS can only be used with 386+ cpu
215#endif
216
217#if defined(VBOX) && !BX_USE_ATADRV
218# error VBOX requires enabling the ATA/ATAPI driver
219#endif
220
221#ifdef VBOX_WITH_SCSI
222/* Enough for now */
223# define BX_MAX_SCSI_DEVICES 4
224# define BX_MAX_STORAGE_DEVICES (BX_MAX_ATA_DEVICES + BX_MAX_SCSI_DEVICES)
225
226/* A SCSI device starts always at BX_MAX_ATA_DEVICES. */
227# define VBOX_IS_SCSI_DEVICE(device_id) (device_id >= BX_MAX_ATA_DEVICES)
228# define VBOX_GET_SCSI_DEVICE(device_id) (device_id - BX_MAX_ATA_DEVICES)
229#endif
230
231#ifndef VBOX
232#define PANIC_PORT 0x400
233#define PANIC_PORT2 0x401
234#define INFO_PORT 0x402
235#define DEBUG_PORT 0x403
236#else /* VBOX */
237/* Redirect INFO output to backdoor logging port. */
238#define PANIC_PORT 0x400
239#define PANIC_PORT2 0x401
240#define INFO_PORT 0x504
241#define DEBUG_PORT 0x403
242#endif /* VBOX */
243
244// define this if you want to make PCIBIOS working on a specific bridge only
245// undef enables PCIBIOS when at least one PCI device is found
246// i440FX is emulated by Bochs and QEMU
247#define PCI_FIXED_HOST_BRIDGE_1 0x12378086 ;; i440FX PCI bridge
248#define PCI_FIXED_HOST_BRIDGE_2 0x244e8086 ;; ICH9 PCI bridge
249
250// #20 is dec 20
251// #$20 is hex 20 = 32
252// #0x20 is hex 20 = 32
253// LDA #$20
254// JSR $E820
255// LDD .i,S
256// JSR $C682
257// mov al, #$20
258
259// all hex literals should be prefixed with '0x'
260// grep "#[0-9a-fA-F][0-9a-fA-F]" rombios.c
261// no mov SEG-REG, #value, must mov register into seg-reg
262// grep -i "mov[ ]*.s" rombios.c
263
264// This is for compiling with gcc2 and gcc3
265#define ASM_START #asm
266#define ASM_END #endasm
267
268ASM_START
269.rom
270
271.org 0x0000
272
273#if BX_CPU >= 3
274use16 386
275#else
276use16 286
277#endif
278
279MACRO HALT
280 ;; the HALT macro is called with the line number of the HALT call.
281 ;; The line number is then sent to the PANIC_PORT, causing Bochs/Plex
282 ;; to print a BX_PANIC message. This will normally halt the simulation
283 ;; with a message such as "BIOS panic at rombios.c, line 4091".
284 ;; However, users can choose to make panics non-fatal and continue.
285#if BX_VIRTUAL_PORTS
286 mov dx,#PANIC_PORT
287 mov ax,#?1
288 out dx,ax
289#else
290 mov dx,#0x80
291 mov ax,#?1
292 out dx,al
293#endif
294MEND
295
296MACRO JMP_AP
297 db 0xea
298 dw ?2
299 dw ?1
300MEND
301
302MACRO SET_INT_VECTOR
303 mov ax, ?3
304 mov ?1*4, ax
305 mov ax, ?2
306 mov ?1*4+2, ax
307MEND
308
309ASM_END
310
311typedef unsigned char Bit8u;
312typedef unsigned short Bit16u;
313typedef unsigned short bx_bool;
314typedef unsigned long Bit32u;
315
316#if BX_USE_ATADRV
317
318 void memsetb(seg,offset,value,count);
319 void memcpyb(dseg,doffset,sseg,soffset,count);
320 void memcpyd(dseg,doffset,sseg,soffset,count);
321
322 // memset of count bytes
323 void
324 memsetb(seg,offset,value,count)
325 Bit16u seg;
326 Bit16u offset;
327 Bit16u value;
328 Bit16u count;
329 {
330 ASM_START
331 push bp
332 mov bp, sp
333
334 push ax
335 push cx
336 push es
337 push di
338
339 mov cx, 10[bp] ; count
340 test cx, cx
341 je memsetb_end
342 mov ax, 4[bp] ; segment
343 mov es, ax
344 mov ax, 6[bp] ; offset
345 mov di, ax
346 mov al, 8[bp] ; value
347 cld
348 rep
349 stosb
350
351 memsetb_end:
352 pop di
353 pop es
354 pop cx
355 pop ax
356
357 pop bp
358 ASM_END
359 }
360
361#if 0
362 // memcpy of count bytes
363 void
364 memcpyb(dseg,doffset,sseg,soffset,count)
365 Bit16u dseg;
366 Bit16u doffset;
367 Bit16u sseg;
368 Bit16u soffset;
369 Bit16u count;
370 {
371 ASM_START
372 push bp
373 mov bp, sp
374
375 push ax
376 push cx
377 push es
378 push di
379 push ds
380 push si
381
382 mov cx, 12[bp] ; count
383 cmp cx, #0x0000
384 je memcpyb_end
385 mov ax, 4[bp] ; dsegment
386 mov es, ax
387 mov ax, 6[bp] ; doffset
388 mov di, ax
389 mov ax, 8[bp] ; ssegment
390 mov ds, ax
391 mov ax, 10[bp] ; soffset
392 mov si, ax
393 cld
394 rep
395 movsb
396
397 memcpyb_end:
398 pop si
399 pop ds
400 pop di
401 pop es
402 pop cx
403 pop ax
404
405 pop bp
406 ASM_END
407 }
408
409 // memcpy of count dword
410 void
411 memcpyd(dseg,doffset,sseg,soffset,count)
412 Bit16u dseg;
413 Bit16u doffset;
414 Bit16u sseg;
415 Bit16u soffset;
416 Bit16u count;
417 {
418 ASM_START
419 push bp
420 mov bp, sp
421
422 push ax
423 push cx
424 push es
425 push di
426 push ds
427 push si
428
429 mov cx, 12[bp] ; count
430 test cx, cx
431 je memcpyd_end
432 mov ax, 4[bp] ; dsegment
433 mov es, ax
434 mov ax, 6[bp] ; doffset
435 mov di, ax
436 mov ax, 8[bp] ; ssegment
437 mov ds, ax
438 mov ax, 10[bp] ; soffset
439 mov si, ax
440 cld
441 rep
442 movsd
443
444 memcpyd_end:
445 pop si
446 pop ds
447 pop di
448 pop es
449 pop cx
450 pop ax
451
452 pop bp
453 ASM_END
454 }
455#endif
456#endif //BX_USE_ATADRV
457
458 // read_dword and write_dword functions
459 static Bit32u read_dword();
460 static void write_dword();
461
462 Bit32u
463 read_dword(seg, offset)
464 Bit16u seg;
465 Bit16u offset;
466 {
467 ASM_START
468 push bp
469 mov bp, sp
470
471 push bx
472 push ds
473 mov ax, 4[bp] ; segment
474 mov ds, ax
475 mov bx, 6[bp] ; offset
476 mov ax, [bx]
477 add bx, #2
478 mov dx, [bx]
479 ;; ax = return value (word)
480 ;; dx = return value (word)
481 pop ds
482 pop bx
483
484 pop bp
485 ASM_END
486 }
487
488 void
489 write_dword(seg, offset, data)
490 Bit16u seg;
491 Bit16u offset;
492 Bit32u data;
493 {
494 ASM_START
495 push bp
496 mov bp, sp
497
498 push ax
499 push bx
500 push ds
501 mov ax, 4[bp] ; segment
502 mov ds, ax
503 mov bx, 6[bp] ; offset
504 mov ax, 8[bp] ; data word
505 mov [bx], ax ; write data word
506 add bx, #2
507 mov ax, 10[bp] ; data word
508 mov [bx], ax ; write data word
509 pop ds
510 pop bx
511 pop ax
512
513 pop bp
514 ASM_END
515 }
516
517 // Bit32u (unsigned long) and long helper functions
518 ASM_START
519
520 ;; and function
521 landl:
522 landul:
523 SEG SS
524 and ax,[di]
525 SEG SS
526 and bx,2[di]
527 ret
528
529 ;; add function
530 laddl:
531 laddul:
532 SEG SS
533 add ax,[di]
534 SEG SS
535 adc bx,2[di]
536 ret
537
538 ;; cmp function
539 lcmpl:
540 lcmpul:
541 and eax, #0x0000FFFF
542 shl ebx, #16
543 or eax, ebx
544 shr ebx, #16
545 SEG SS
546 cmp eax, dword ptr [di]
547 ret
548
549 ;; sub function
550 lsubl:
551 lsubul:
552 SEG SS
553 sub ax,[di]
554 SEG SS
555 sbb bx,2[di]
556 ret
557
558 ;; mul function
559 lmull:
560 lmulul:
561 and eax, #0x0000FFFF
562 shl ebx, #16
563 or eax, ebx
564 SEG SS
565 mul eax, dword ptr [di]
566 mov ebx, eax
567 shr ebx, #16
568 ret
569
570 ;; dec function
571 ldecl:
572 ldecul:
573 SEG SS
574 dec dword ptr [bx]
575 ret
576
577 ;; or function
578 lorl:
579 lorul:
580 SEG SS
581 or ax,[di]
582 SEG SS
583 or bx,2[di]
584 ret
585
586 ;; inc function
587 lincl:
588 lincul:
589 SEG SS
590 inc dword ptr [bx]
591 ret
592
593 ;; tst function
594 ltstl:
595 ltstul:
596 and eax, #0x0000FFFF
597 shl ebx, #16
598 or eax, ebx
599 shr ebx, #16
600 test eax, eax
601 ret
602
603 ;; sr function
604 lsrul:
605 mov cx,di
606 jcxz lsr_exit
607 and eax, #0x0000FFFF
608 shl ebx, #16
609 or eax, ebx
610 lsr_loop:
611 shr eax, #1
612 loop lsr_loop
613 mov ebx, eax
614 shr ebx, #16
615 lsr_exit:
616 ret
617
618 ;; sl function
619 lsll:
620 lslul:
621 mov cx,di
622 jcxz lsl_exit
623 and eax, #0x0000FFFF
624 shl ebx, #16
625 or eax, ebx
626 lsl_loop:
627 shl eax, #1
628 loop lsl_loop
629 mov ebx, eax
630 shr ebx, #16
631 lsl_exit:
632 ret
633
634 idiv_:
635 cwd
636 idiv bx
637 ret
638
639 idiv_u:
640 xor dx,dx
641 div bx
642 ret
643
644 ldivul:
645 and eax, #0x0000FFFF
646 shl ebx, #16
647 or eax, ebx
648 xor edx, edx
649 SEG SS
650 mov bx, 2[di]
651 shl ebx, #16
652 SEG SS
653 mov bx, [di]
654 div ebx
655 mov ebx, eax
656 shr ebx, #16
657 ret
658
659 ASM_END
660
661// for access to RAM area which is used by interrupt vectors
662// and BIOS Data Area
663
664typedef struct {
665 unsigned char filler1[0x400];
666 unsigned char filler2[0x6c];
667 Bit16u ticks_low;
668 Bit16u ticks_high;
669 Bit8u midnight_flag;
670 } bios_data_t;
671
672#define BiosData ((bios_data_t *) 0)
673
674#if BX_USE_ATADRV
675 typedef struct {
676 Bit16u heads; // # heads
677 Bit16u cylinders; // # cylinders
678 Bit16u spt; // # sectors / track
679 } chs_t;
680
681 // DPTE definition
682 typedef struct {
683 Bit16u iobase1;
684 Bit16u iobase2;
685 Bit8u prefix;
686 Bit8u unused;
687 Bit8u irq;
688 Bit8u blkcount;
689 Bit8u dma;
690 Bit8u pio;
691 Bit16u options;
692 Bit16u reserved;
693 Bit8u revision;
694 Bit8u checksum;
695 } dpte_t;
696
697 typedef struct {
698 Bit8u iface; // ISA or PCI
699 Bit16u iobase1; // IO Base 1
700 Bit16u iobase2; // IO Base 2
701 Bit8u irq; // IRQ
702 } ata_channel_t;
703
704 typedef struct {
705 Bit8u type; // Detected type of ata (ata/atapi/none/unknown/scsi)
706 Bit8u device; // Detected type of attached devices (hd/cd/none)
707 Bit8u removable; // Removable device flag
708 Bit8u lock; // Locks for removable devices
709 Bit8u mode; // transfer mode : PIO 16/32 bits - IRQ - ISADMA - PCIDMA
710 Bit16u blksize; // block size
711
712 Bit8u translation; // type of translation
713 chs_t lchs; // Logical CHS
714 chs_t pchs; // Physical CHS
715
716 Bit32u sectors; // Total sectors count
717 } ata_device_t;
718
719 typedef struct {
720 // ATA channels info
721 ata_channel_t channels[BX_MAX_ATA_INTERFACES];
722
723 // ATA devices info
724 ata_device_t devices[BX_MAX_ATA_DEVICES];
725 //
726 // map between (bios hd id - 0x80) and ata channels and scsi disks.
727#ifdef VBOX_WITH_SCSI
728 Bit8u hdcount, hdidmap[BX_MAX_ATA_DEVICES+BX_MAX_SCSI_DEVICES];
729#else
730 Bit8u hdcount, hdidmap[BX_MAX_ATA_DEVICES];
731#endif
732
733 // map between (bios cd id - 0xE0) and ata channels
734 Bit8u cdcount, cdidmap[BX_MAX_ATA_DEVICES];
735
736 // Buffer for DPTE table
737 dpte_t dpte;
738
739 // Count of transferred sectors and bytes
740 Bit16u trsfsectors;
741 Bit32u trsfbytes;
742
743 } ata_t;
744
745#if BX_ELTORITO_BOOT
746 // ElTorito Device Emulation data
747 typedef struct {
748 Bit8u active;
749 Bit8u media;
750 Bit8u emulated_drive;
751 Bit8u controller_index;
752 Bit16u device_spec;
753 Bit32u ilba;
754 Bit16u buffer_segment;
755 Bit16u load_segment;
756 Bit16u sector_count;
757
758 // Virtual device
759 chs_t vdevice;
760 } cdemu_t;
761#endif // BX_ELTORITO_BOOT
762
763#ifdef VBOX_WITH_SCSI
764 typedef struct {
765 // I/O port this device is attached to.
766 Bit16u io_base;
767 // Target Id.
768 Bit8u target_id;
769 // SCSI devices info
770 ata_device_t device_info;
771 } scsi_device_t;
772
773 typedef struct {
774 // SCSi device info
775 scsi_device_t devices[BX_MAX_SCSI_DEVICES];
776 // Number of scsi disks.
777 Bit8u hdcount;
778 } scsi_t;
779#endif
780
781 // for access to EBDA area
782 // The EBDA structure should conform to
783 // http://www.frontiernet.net/~fys/rombios.htm document
784 // I made the ata and cdemu structs begin at 0x121 in the EBDA seg
785 typedef struct {
786 unsigned char filler1[0x3D];
787
788 // FDPT - Can be splitted in data members if needed
789 unsigned char fdpt0[0x10];
790 unsigned char fdpt1[0x10];
791
792 unsigned char filler2[0xC4];
793
794 // ATA Driver data
795 ata_t ata;
796
797#if BX_ELTORITO_BOOT
798 // El Torito Emulation data
799 cdemu_t cdemu;
800#endif // BX_ELTORITO_BOOT
801
802#ifdef VBOX
803
804#ifdef VBOX_WITH_SCSI
805 // SCSI Driver data
806 scsi_t scsi;
807# endif
808
809 unsigned char uForceBootDrive;
810 unsigned char uForceBootDevice;
811#endif /* VBOX */
812
813 } ebda_data_t;
814
815#ifdef VBOX
816 // the last 16 bytes of the EBDA segment are used for the MPS floating
817 // pointer structure (only if an IOAPIC is present)
818#endif
819
820 #define EbdaData ((ebda_data_t *) 0)
821
822 // for access to the int13ext structure
823 typedef struct {
824 Bit8u size;
825 Bit8u reserved;
826 Bit16u count;
827 Bit16u offset;
828 Bit16u segment;
829 Bit32u lba1;
830 Bit32u lba2;
831 } int13ext_t;
832
833 #define Int13Ext ((int13ext_t *) 0)
834
835 // Disk Physical Table definition
836 typedef struct {
837 Bit16u size;
838 Bit16u infos;
839 Bit32u cylinders;
840 Bit32u heads;
841 Bit32u spt;
842 Bit32u sector_count1;
843 Bit32u sector_count2;
844 Bit16u blksize;
845 Bit16u dpte_offset;
846 Bit16u dpte_segment;
847 Bit16u key;
848 Bit8u dpi_length;
849 Bit8u reserved1;
850 Bit16u reserved2;
851 Bit8u host_bus[4];
852 Bit8u iface_type[8];
853 Bit8u iface_path[8];
854 Bit8u device_path[8];
855 Bit8u reserved3;
856 Bit8u checksum;
857 } dpt_t;
858
859 #define Int13DPT ((dpt_t *) 0)
860
861#endif // BX_USE_ATADRV
862
863typedef struct {
864 union {
865 struct {
866 Bit16u di, si, bp, sp;
867 Bit16u bx, dx, cx, ax;
868 } r16;
869 struct {
870 Bit16u filler[4];
871 Bit8u bl, bh, dl, dh, cl, ch, al, ah;
872 } r8;
873 } u;
874 } pusha_regs_t;
875
876typedef struct {
877 union {
878 struct {
879 Bit32u edi, esi, ebp, esp;
880 Bit32u ebx, edx, ecx, eax;
881 } r32;
882 struct {
883 Bit16u di, filler1, si, filler2, bp, filler3, sp, filler4;
884 Bit16u bx, filler5, dx, filler6, cx, filler7, ax, filler8;
885 } r16;
886 struct {
887 Bit32u filler[4];
888 Bit8u bl, bh;
889 Bit16u filler1;
890 Bit8u dl, dh;
891 Bit16u filler2;
892 Bit8u cl, ch;
893 Bit16u filler3;
894 Bit8u al, ah;
895 Bit16u filler4;
896 } r8;
897 } u;
898} pushad_regs_t;
899
900typedef struct {
901 union {
902 struct {
903 Bit16u flags;
904 } r16;
905 struct {
906 Bit8u flagsl;
907 Bit8u flagsh;
908 } r8;
909 } u;
910 } flags_t;
911
912#define SetCF(x) x.u.r8.flagsl |= 0x01
913#define SetZF(x) x.u.r8.flagsl |= 0x40
914#define ClearCF(x) x.u.r8.flagsl &= 0xfe
915#define ClearZF(x) x.u.r8.flagsl &= 0xbf
916#define GetCF(x) (x.u.r8.flagsl & 0x01)
917
918typedef struct {
919 Bit16u ip;
920 Bit16u cs;
921 flags_t flags;
922 } iret_addr_t;
923
924
925
926static Bit8u inb();
927static Bit8u inb_cmos();
928static void outb();
929static void outb_cmos();
930static Bit16u inw();
931static void outw();
932static void init_rtc();
933static bx_bool rtc_updating();
934
935static Bit8u read_byte();
936static Bit16u read_word();
937static void write_byte();
938static void write_word();
939static void bios_printf();
940
941static Bit8u send_to_mouse_ctrl();
942static Bit8u get_mouse_data();
943static void set_kbd_command_byte();
944
945static void int09_function();
946static void int13_harddisk();
947static void int13_cdrom();
948static void int13_cdemu();
949static void int13_eltorito();
950static void int13_diskette_function();
951static void int14_function();
952static void int15_function();
953static void int16_function();
954static void int17_function();
955static Bit32u int19_function();
956static void int1a_function();
957static void int70_function();
958static void int74_function();
959static void dummy_isr_function();
960static Bit16u get_CS();
961static Bit16u get_SS();
962static unsigned int enqueue_key();
963static unsigned int dequeue_key();
964static void get_hd_geometry();
965static void set_diskette_ret_status();
966static void set_diskette_current_cyl();
967static void determine_floppy_media();
968static bx_bool floppy_drive_exists();
969static bx_bool floppy_drive_recal();
970static bx_bool floppy_media_known();
971static bx_bool floppy_media_sense();
972static bx_bool set_enable_a20();
973static void debugger_on();
974static void debugger_off();
975static void keyboard_init();
976static void keyboard_panic();
977static void shutdown_status_panic();
978static void nmi_handler_msg();
979
980static void print_bios_banner();
981static void print_boot_device();
982static void print_boot_failure();
983static void print_cdromboot_failure();
984
985# if BX_USE_ATADRV
986
987// ATA / ATAPI driver
988void ata_init();
989void ata_detect();
990void ata_reset();
991
992Bit16u ata_cmd_non_data();
993Bit16u ata_cmd_data_in();
994Bit16u ata_cmd_data_out();
995Bit16u ata_cmd_packet();
996
997Bit16u atapi_get_sense();
998Bit16u atapi_is_ready();
999Bit16u atapi_is_cdrom();
1000
1001#endif // BX_USE_ATADRV
1002
1003#if BX_ELTORITO_BOOT
1004
1005void cdemu_init();
1006Bit8u cdemu_isactive();
1007Bit8u cdemu_emulated_drive();
1008
1009Bit16u cdrom_boot();
1010
1011#endif // BX_ELTORITO_BOOT
1012
1013#ifdef VBOX
1014static char bios_prefix_string[] = "BIOS: ";
1015/* Do not use build timestamps in this string. Otherwise even rebuilding the
1016 * very same code will lead to compare errors when restoring saved state. */
1017static char bios_cvs_version_string[] = "VirtualBox " VBOX_VERSION_STRING;
1018#define BIOS_COPYRIGHT_STRING "Oracle VM VirtualBox BIOS"
1019#else /* !VBOX */
1020static char bios_cvs_version_string[] = "$Revision: 1.176 $ $Date: 2006/12/30 17:13:17 $";
1021
1022#define BIOS_COPYRIGHT_STRING "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team."
1023#endif /* !VBOX */
1024
1025#define BIOS_PRINTF_HALT 1
1026#define BIOS_PRINTF_SCREEN 2
1027#define BIOS_PRINTF_INFO 4
1028#define BIOS_PRINTF_DEBUG 8
1029#define BIOS_PRINTF_ALL (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO)
1030#define BIOS_PRINTF_DEBHALT (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO | BIOS_PRINTF_HALT)
1031
1032#define printf(format, p...) bios_printf(BIOS_PRINTF_SCREEN, format, ##p)
1033
1034// Defines the output macros.
1035// BX_DEBUG goes to INFO port until we can easily choose debug info on a
1036// per-device basis. Debug info are sent only in debug mode
1037#if DEBUG_ROMBIOS
1038# define BX_DEBUG(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
1039#else
1040# define BX_DEBUG(format, p...)
1041#endif
1042#ifdef VBOX
1043#define BX_INFO(format, p...) do { put_str(BIOS_PRINTF_INFO, get_CS(), bios_prefix_string); bios_printf(BIOS_PRINTF_INFO, format, ##p); } while (0)
1044#else /* !VBOX */
1045#define BX_INFO(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
1046#endif /* !VBOX */
1047#define BX_PANIC(format, p...) bios_printf(BIOS_PRINTF_DEBHALT, format, ##p)
1048
1049#if DEBUG_ATA
1050# define BX_DEBUG_ATA(a...) BX_DEBUG(a)
1051#else
1052# define BX_DEBUG_ATA(a...)
1053#endif
1054#if DEBUG_INT13_HD
1055# define BX_DEBUG_INT13_HD(a...) BX_DEBUG(a)
1056#else
1057# define BX_DEBUG_INT13_HD(a...)
1058#endif
1059#if DEBUG_INT13_CD
1060# define BX_DEBUG_INT13_CD(a...) BX_DEBUG(a)
1061#else
1062# define BX_DEBUG_INT13_CD(a...)
1063#endif
1064#if DEBUG_INT13_ET
1065# define BX_DEBUG_INT13_ET(a...) BX_DEBUG(a)
1066#else
1067# define BX_DEBUG_INT13_ET(a...)
1068#endif
1069#if DEBUG_INT13_FL
1070# define BX_DEBUG_INT13_FL(a...) BX_DEBUG(a)
1071#else
1072# define BX_DEBUG_INT13_FL(a...)
1073#endif
1074#if DEBUG_INT15
1075# define BX_DEBUG_INT15(a...) BX_DEBUG(a)
1076#else
1077# define BX_DEBUG_INT15(a...)
1078#endif
1079#if DEBUG_INT16
1080# define BX_DEBUG_INT16(a...) BX_DEBUG(a)
1081#else
1082# define BX_DEBUG_INT16(a...)
1083#endif
1084#if DEBUG_INT1A
1085# define BX_DEBUG_INT1A(a...) BX_DEBUG(a)
1086#else
1087# define BX_DEBUG_INT1A(a...)
1088#endif
1089#if DEBUG_INT74
1090# define BX_DEBUG_INT74(a...) BX_DEBUG(a)
1091#else
1092# define BX_DEBUG_INT74(a...)
1093#endif
1094
1095#define SET_AL(val8) AX = ((AX & 0xff00) | (val8))
1096#define SET_BL(val8) BX = ((BX & 0xff00) | (val8))
1097#define SET_CL(val8) CX = ((CX & 0xff00) | (val8))
1098#define SET_DL(val8) DX = ((DX & 0xff00) | (val8))
1099#define SET_AH(val8) AX = ((AX & 0x00ff) | ((val8) << 8))
1100#define SET_BH(val8) BX = ((BX & 0x00ff) | ((val8) << 8))
1101#define SET_CH(val8) CX = ((CX & 0x00ff) | ((val8) << 8))
1102#define SET_DH(val8) DX = ((DX & 0x00ff) | ((val8) << 8))
1103
1104#define GET_AL() ( AX & 0x00ff )
1105#define GET_BL() ( BX & 0x00ff )
1106#define GET_CL() ( CX & 0x00ff )
1107#define GET_DL() ( DX & 0x00ff )
1108#define GET_AH() ( AX >> 8 )
1109#define GET_BH() ( BX >> 8 )
1110#define GET_CH() ( CX >> 8 )
1111#define GET_DH() ( DX >> 8 )
1112
1113#define GET_ELDL() ( ELDX & 0x00ff )
1114#define GET_ELDH() ( ELDX >> 8 )
1115
1116#define SET_CF() FLAGS |= 0x0001
1117#define CLEAR_CF() FLAGS &= 0xfffe
1118#define GET_CF() (FLAGS & 0x0001)
1119
1120#define SET_ZF() FLAGS |= 0x0040
1121#define CLEAR_ZF() FLAGS &= 0xffbf
1122#define GET_ZF() (FLAGS & 0x0040)
1123
1124#define UNSUPPORTED_FUNCTION 0x86
1125
1126#define none 0
1127#define MAX_SCAN_CODE 0x58
1128
1129static struct {
1130 Bit16u normal;
1131 Bit16u shift;
1132 Bit16u control;
1133 Bit16u alt;
1134 Bit8u lock_flags;
1135 } scan_to_scanascii[MAX_SCAN_CODE + 1] = {
1136 { none, none, none, none, none },
1137 { 0x011b, 0x011b, 0x011b, 0x0100, none }, /* escape */
1138 { 0x0231, 0x0221, none, 0x7800, none }, /* 1! */
1139 { 0x0332, 0x0340, 0x0300, 0x7900, none }, /* 2@ */
1140 { 0x0433, 0x0423, none, 0x7a00, none }, /* 3# */
1141 { 0x0534, 0x0524, none, 0x7b00, none }, /* 4$ */
1142 { 0x0635, 0x0625, none, 0x7c00, none }, /* 5% */
1143 { 0x0736, 0x075e, 0x071e, 0x7d00, none }, /* 6^ */
1144 { 0x0837, 0x0826, none, 0x7e00, none }, /* 7& */
1145 { 0x0938, 0x092a, none, 0x7f00, none }, /* 8* */
1146 { 0x0a39, 0x0a28, none, 0x8000, none }, /* 9( */
1147 { 0x0b30, 0x0b29, none, 0x8100, none }, /* 0) */
1148 { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200, none }, /* -_ */
1149 { 0x0d3d, 0x0d2b, none, 0x8300, none }, /* =+ */
1150 { 0x0e08, 0x0e08, 0x0e7f, none, none }, /* backspace */
1151 { 0x0f09, 0x0f00, none, none, none }, /* tab */
1152 { 0x1071, 0x1051, 0x1011, 0x1000, 0x40 }, /* Q */
1153 { 0x1177, 0x1157, 0x1117, 0x1100, 0x40 }, /* W */
1154 { 0x1265, 0x1245, 0x1205, 0x1200, 0x40 }, /* E */
1155 { 0x1372, 0x1352, 0x1312, 0x1300, 0x40 }, /* R */
1156 { 0x1474, 0x1454, 0x1414, 0x1400, 0x40 }, /* T */
1157 { 0x1579, 0x1559, 0x1519, 0x1500, 0x40 }, /* Y */
1158 { 0x1675, 0x1655, 0x1615, 0x1600, 0x40 }, /* U */
1159 { 0x1769, 0x1749, 0x1709, 0x1700, 0x40 }, /* I */
1160 { 0x186f, 0x184f, 0x180f, 0x1800, 0x40 }, /* O */
1161 { 0x1970, 0x1950, 0x1910, 0x1900, 0x40 }, /* P */
1162 { 0x1a5b, 0x1a7b, 0x1a1b, none, none }, /* [{ */
1163 { 0x1b5d, 0x1b7d, 0x1b1d, none, none }, /* ]} */
1164 { 0x1c0d, 0x1c0d, 0x1c0a, none, none }, /* Enter */
1165 { none, none, none, none, none }, /* L Ctrl */
1166 { 0x1e61, 0x1e41, 0x1e01, 0x1e00, 0x40 }, /* A */
1167 { 0x1f73, 0x1f53, 0x1f13, 0x1f00, 0x40 }, /* S */
1168 { 0x2064, 0x2044, 0x2004, 0x2000, 0x40 }, /* D */
1169 { 0x2166, 0x2146, 0x2106, 0x2100, 0x40 }, /* F */
1170 { 0x2267, 0x2247, 0x2207, 0x2200, 0x40 }, /* G */
1171 { 0x2368, 0x2348, 0x2308, 0x2300, 0x40 }, /* H */
1172 { 0x246a, 0x244a, 0x240a, 0x2400, 0x40 }, /* J */
1173 { 0x256b, 0x254b, 0x250b, 0x2500, 0x40 }, /* K */
1174 { 0x266c, 0x264c, 0x260c, 0x2600, 0x40 }, /* L */
1175 { 0x273b, 0x273a, none, none, none }, /* ;: */
1176 { 0x2827, 0x2822, none, none, none }, /* '" */
1177 { 0x2960, 0x297e, none, none, none }, /* `~ */
1178 { none, none, none, none, none }, /* L shift */
1179 { 0x2b5c, 0x2b7c, 0x2b1c, none, none }, /* |\ */
1180 { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, 0x40 }, /* Z */
1181 { 0x2d78, 0x2d58, 0x2d18, 0x2d00, 0x40 }, /* X */
1182 { 0x2e63, 0x2e43, 0x2e03, 0x2e00, 0x40 }, /* C */
1183 { 0x2f76, 0x2f56, 0x2f16, 0x2f00, 0x40 }, /* V */
1184 { 0x3062, 0x3042, 0x3002, 0x3000, 0x40 }, /* B */
1185 { 0x316e, 0x314e, 0x310e, 0x3100, 0x40 }, /* N */
1186 { 0x326d, 0x324d, 0x320d, 0x3200, 0x40 }, /* M */
1187 { 0x332c, 0x333c, none, none, none }, /* ,< */
1188 { 0x342e, 0x343e, none, none, none }, /* .> */
1189 { 0x352f, 0x353f, none, none, none }, /* /? */
1190 { none, none, none, none, none }, /* R Shift */
1191 { 0x372a, 0x372a, none, none, none }, /* * */
1192 { none, none, none, none, none }, /* L Alt */
1193 { 0x3920, 0x3920, 0x3920, 0x3920, none }, /* space */
1194 { none, none, none, none, none }, /* caps lock */
1195 { 0x3b00, 0x5400, 0x5e00, 0x6800, none }, /* F1 */
1196 { 0x3c00, 0x5500, 0x5f00, 0x6900, none }, /* F2 */
1197 { 0x3d00, 0x5600, 0x6000, 0x6a00, none }, /* F3 */
1198 { 0x3e00, 0x5700, 0x6100, 0x6b00, none }, /* F4 */
1199 { 0x3f00, 0x5800, 0x6200, 0x6c00, none }, /* F5 */
1200 { 0x4000, 0x5900, 0x6300, 0x6d00, none }, /* F6 */
1201 { 0x4100, 0x5a00, 0x6400, 0x6e00, none }, /* F7 */
1202 { 0x4200, 0x5b00, 0x6500, 0x6f00, none }, /* F8 */
1203 { 0x4300, 0x5c00, 0x6600, 0x7000, none }, /* F9 */
1204 { 0x4400, 0x5d00, 0x6700, 0x7100, none }, /* F10 */
1205 { none, none, none, none, none }, /* Num Lock */
1206 { none, none, none, none, none }, /* Scroll Lock */
1207 { 0x4700, 0x4737, 0x7700, none, 0x20 }, /* 7 Home */
1208 { 0x4800, 0x4838, none, none, 0x20 }, /* 8 UP */
1209 { 0x4900, 0x4939, 0x8400, none, 0x20 }, /* 9 PgUp */
1210 { 0x4a2d, 0x4a2d, none, none, none }, /* - */
1211 { 0x4b00, 0x4b34, 0x7300, none, 0x20 }, /* 4 Left */
1212 { 0x4c00, 0x4c35, none, none, 0x20 }, /* 5 */
1213 { 0x4d00, 0x4d36, 0x7400, none, 0x20 }, /* 6 Right */
1214 { 0x4e2b, 0x4e2b, none, none, none }, /* + */
1215 { 0x4f00, 0x4f31, 0x7500, none, 0x20 }, /* 1 End */
1216 { 0x5000, 0x5032, none, none, 0x20 }, /* 2 Down */
1217 { 0x5100, 0x5133, 0x7600, none, 0x20 }, /* 3 PgDn */
1218 { 0x5200, 0x5230, none, none, 0x20 }, /* 0 Ins */
1219 { 0x5300, 0x532e, none, none, 0x20 }, /* Del */
1220 { none, none, none, none, none },
1221 { none, none, none, none, none },
1222 { 0x565c, 0x567c, none, none, none }, /* \| */
1223#ifndef VBOX
1224 { 0x5700, 0x5700, none, none, none }, /* F11 */
1225 { 0x5800, 0x5800, none, none, none } /* F12 */
1226#else
1227 { 0x8500, 0x8700, 0x8900, 0x8b00, none }, /* F11 */
1228 { 0x8600, 0x8800, 0x8a00, 0x8c00, none } /* F12 */
1229#endif
1230 };
1231
1232 Bit8u
1233inb(port)
1234 Bit16u port;
1235{
1236ASM_START
1237 push bp
1238 mov bp, sp
1239
1240 push dx
1241 mov dx, 4[bp]
1242 in al, dx
1243 pop dx
1244
1245 pop bp
1246ASM_END
1247}
1248
1249#if BX_USE_ATADRV
1250 Bit16u
1251inw(port)
1252 Bit16u port;
1253{
1254ASM_START
1255 push bp
1256 mov bp, sp
1257
1258 push dx
1259 mov dx, 4[bp]
1260 in ax, dx
1261 pop dx
1262
1263 pop bp
1264ASM_END
1265}
1266#endif
1267
1268 void
1269outb(port, val)
1270 Bit16u port;
1271 Bit8u val;
1272{
1273ASM_START
1274 push bp
1275 mov bp, sp
1276
1277 push ax
1278 push dx
1279 mov dx, 4[bp]
1280 mov al, 6[bp]
1281 out dx, al
1282 pop dx
1283 pop ax
1284
1285 pop bp
1286ASM_END
1287}
1288
1289#if BX_USE_ATADRV
1290 void
1291outw(port, val)
1292 Bit16u port;
1293 Bit16u val;
1294{
1295ASM_START
1296 push bp
1297 mov bp, sp
1298
1299 push ax
1300 push dx
1301 mov dx, 4[bp]
1302 mov ax, 6[bp]
1303 out dx, ax
1304 pop dx
1305 pop ax
1306
1307 pop bp
1308ASM_END
1309}
1310#endif
1311
1312 void
1313outb_cmos(cmos_reg, val)
1314 Bit8u cmos_reg;
1315 Bit8u val;
1316{
1317ASM_START
1318 push bp
1319 mov bp, sp
1320
1321 mov al, 4[bp] ;; cmos_reg
1322 out 0x70, al
1323 mov al, 6[bp] ;; val
1324 out 0x71, al
1325
1326 pop bp
1327ASM_END
1328}
1329
1330 Bit8u
1331inb_cmos(cmos_reg)
1332 Bit8u cmos_reg;
1333{
1334ASM_START
1335 push bp
1336 mov bp, sp
1337
1338 mov al, 4[bp] ;; cmos_reg
1339 out 0x70, al
1340 in al, 0x71
1341
1342 pop bp
1343ASM_END
1344}
1345
1346 void
1347init_rtc()
1348{
1349 outb_cmos(0x0a, 0x26);
1350 outb_cmos(0x0b, 0x02);
1351 inb_cmos(0x0c);
1352 inb_cmos(0x0d);
1353}
1354
1355 bx_bool
1356rtc_updating()
1357{
1358 // This function checks to see if the update-in-progress bit
1359 // is set in CMOS Status Register A. If not, it returns 0.
1360 // If it is set, it tries to wait until there is a transition
1361 // to 0, and will return 0 if such a transition occurs. A 1
1362 // is returned only after timing out. The maximum period
1363 // that this bit should be set is constrained to 244useconds.
1364 // The count I use below guarantees coverage or more than
1365 // this time, with any reasonable IPS setting.
1366
1367 Bit16u count;
1368
1369 count = 25000;
1370 while (--count != 0) {
1371 if ( (inb_cmos(0x0a) & 0x80) == 0 )
1372 return(0);
1373 }
1374 return(1); // update-in-progress never transitioned to 0
1375}
1376
1377
1378 Bit8u
1379read_byte(seg, offset)
1380 Bit16u seg;
1381 Bit16u offset;
1382{
1383ASM_START
1384 push bp
1385 mov bp, sp
1386
1387 push bx
1388 push ds
1389 mov ax, 4[bp] ; segment
1390 mov ds, ax
1391 mov bx, 6[bp] ; offset
1392 mov al, [bx]
1393 ;; al = return value (byte)
1394 pop ds
1395 pop bx
1396
1397 pop bp
1398ASM_END
1399}
1400
1401 Bit16u
1402read_word(seg, offset)
1403 Bit16u seg;
1404 Bit16u offset;
1405{
1406ASM_START
1407 push bp
1408 mov bp, sp
1409
1410 push bx
1411 push ds
1412 mov ax, 4[bp] ; segment
1413 mov ds, ax
1414 mov bx, 6[bp] ; offset
1415 mov ax, [bx]
1416 ;; ax = return value (word)
1417 pop ds
1418 pop bx
1419
1420 pop bp
1421ASM_END
1422}
1423
1424 void
1425write_byte(seg, offset, data)
1426 Bit16u seg;
1427 Bit16u offset;
1428 Bit8u data;
1429{
1430ASM_START
1431 push bp
1432 mov bp, sp
1433
1434 push ax
1435 push bx
1436 push ds
1437 mov ax, 4[bp] ; segment
1438 mov ds, ax
1439 mov bx, 6[bp] ; offset
1440 mov al, 8[bp] ; data byte
1441 mov [bx], al ; write data byte
1442 pop ds
1443 pop bx
1444 pop ax
1445
1446 pop bp
1447ASM_END
1448}
1449
1450 void
1451write_word(seg, offset, data)
1452 Bit16u seg;
1453 Bit16u offset;
1454 Bit16u data;
1455{
1456ASM_START
1457 push bp
1458 mov bp, sp
1459
1460 push ax
1461 push bx
1462 push ds
1463 mov ax, 4[bp] ; segment
1464 mov ds, ax
1465 mov bx, 6[bp] ; offset
1466 mov ax, 8[bp] ; data word
1467 mov [bx], ax ; write data word
1468 pop ds
1469 pop bx
1470 pop ax
1471
1472 pop bp
1473ASM_END
1474}
1475
1476 Bit16u
1477get_CS()
1478{
1479ASM_START
1480 mov ax, cs
1481ASM_END
1482}
1483
1484 Bit16u
1485get_SS()
1486{
1487ASM_START
1488 mov ax, ss
1489ASM_END
1490}
1491
1492#if BX_DEBUG_SERIAL
1493/* serial debug port*/
1494#define BX_DEBUG_PORT 0x03f8
1495
1496/* data */
1497#define UART_RBR 0x00
1498#define UART_THR 0x00
1499
1500/* control */
1501#define UART_IER 0x01
1502#define UART_IIR 0x02
1503#define UART_FCR 0x02
1504#define UART_LCR 0x03
1505#define UART_MCR 0x04
1506#define UART_DLL 0x00
1507#define UART_DLM 0x01
1508
1509/* status */
1510#define UART_LSR 0x05
1511#define UART_MSR 0x06
1512#define UART_SCR 0x07
1513
1514int uart_can_tx_byte(base_port)
1515 Bit16u base_port;
1516{
1517 return inb(base_port + UART_LSR) & 0x20;
1518}
1519
1520void uart_wait_to_tx_byte(base_port)
1521 Bit16u base_port;
1522{
1523 while (!uart_can_tx_byte(base_port));
1524}
1525
1526void uart_wait_until_sent(base_port)
1527 Bit16u base_port;
1528{
1529 while (!(inb(base_port + UART_LSR) & 0x40));
1530}
1531
1532void uart_tx_byte(base_port, data)
1533 Bit16u base_port;
1534 Bit8u data;
1535{
1536 uart_wait_to_tx_byte(base_port);
1537 outb(base_port + UART_THR, data);
1538 uart_wait_until_sent(base_port);
1539}
1540#endif
1541
1542 void
1543wrch(c)
1544 Bit8u c;
1545{
1546 ASM_START
1547 push bp
1548 mov bp, sp
1549
1550 push bx
1551 mov ah, #0x0e
1552 mov al, 4[bp]
1553 xor bx,bx
1554 int #0x10
1555 pop bx
1556
1557 pop bp
1558 ASM_END
1559}
1560
1561 void
1562send(action, c)
1563 Bit16u action;
1564 Bit8u c;
1565{
1566#if BX_DEBUG_SERIAL
1567 if (c == '\n') uart_tx_byte(BX_DEBUG_PORT, '\r');
1568 uart_tx_byte(BX_DEBUG_PORT, c);
1569#endif
1570#if BX_VIRTUAL_PORTS
1571 if (action & BIOS_PRINTF_DEBUG) outb(DEBUG_PORT, c);
1572 if (action & BIOS_PRINTF_INFO) outb(INFO_PORT, c);
1573#endif
1574 if (action & BIOS_PRINTF_SCREEN) {
1575 if (c == '\n') wrch('\r');
1576 wrch(c);
1577 }
1578}
1579
1580 void
1581put_int(action, val, width, neg)
1582 Bit16u action;
1583 short val, width;
1584 bx_bool neg;
1585{
1586 short nval = val / 10;
1587 if (nval)
1588 put_int(action, nval, width - 1, neg);
1589 else {
1590 while (--width > 0) send(action, ' ');
1591 if (neg) send(action, '-');
1592 }
1593 send(action, val - (nval * 10) + '0');
1594}
1595
1596 void
1597put_uint(action, val, width, neg)
1598 Bit16u action;
1599 unsigned short val;
1600 short width;
1601 bx_bool neg;
1602{
1603 unsigned short nval = val / 10;
1604 if (nval)
1605 put_uint(action, nval, width - 1, neg);
1606 else {
1607 while (--width > 0) send(action, ' ');
1608 if (neg) send(action, '-');
1609 }
1610 send(action, val - (nval * 10) + '0');
1611}
1612
1613 void
1614put_luint(action, val, width, neg)
1615 Bit16u action;
1616 unsigned long val;
1617 short width;
1618 bx_bool neg;
1619{
1620 unsigned long nval = val / 10;
1621 if (nval)
1622 put_luint(action, nval, width - 1, neg);
1623 else {
1624 while (--width > 0) send(action, ' ');
1625 if (neg) send(action, '-');
1626 }
1627 send(action, val - (nval * 10) + '0');
1628}
1629
1630void put_str(action, segment, offset)
1631 Bit16u action;
1632 Bit16u segment;
1633 Bit16u offset;
1634{
1635 Bit8u c;
1636
1637 while (c = read_byte(segment, offset)) {
1638 send(action, c);
1639 offset++;
1640 }
1641}
1642
1643
1644//--------------------------------------------------------------------------
1645// bios_printf()
1646// A compact variable argument printf function.
1647//
1648// Supports %[format_width][length]format
1649// where format can be x,X,u,d,s,S,c
1650// and the optional length modifier is l (ell)
1651//--------------------------------------------------------------------------
1652 void
1653bios_printf(action, s)
1654 Bit16u action;
1655 Bit8u *s;
1656{
1657 Bit8u c, format_char;
1658 bx_bool in_format;
1659 short i;
1660 Bit16u *arg_ptr;
1661 Bit16u arg_seg, arg, nibble, hibyte, shift_count, format_width, hexadd;
1662
1663 arg_ptr = &s;
1664 arg_seg = get_SS();
1665
1666 in_format = 0;
1667 format_width = 0;
1668
1669 if ((action & BIOS_PRINTF_DEBHALT) == BIOS_PRINTF_DEBHALT) {
1670#if BX_VIRTUAL_PORTS
1671 outb(PANIC_PORT2, 0x00);
1672#endif
1673 bios_printf (BIOS_PRINTF_SCREEN, "FATAL: ");
1674 }
1675
1676 while (c = read_byte(get_CS(), s)) {
1677 if ( c == '%' ) {
1678 in_format = 1;
1679 format_width = 0;
1680 }
1681 else if (in_format) {
1682 if ( (c>='0') && (c<='9') ) {
1683 format_width = (format_width * 10) + (c - '0');
1684 }
1685 else {
1686 arg_ptr++; // increment to next arg
1687 arg = read_word(arg_seg, arg_ptr);
1688 if (c == 'x' || c == 'X') {
1689 if (format_width == 0)
1690 format_width = 4;
1691 if (c == 'x')
1692 hexadd = 'a';
1693 else
1694 hexadd = 'A';
1695 for (i=format_width-1; i>=0; i--) {
1696 nibble = (arg >> (4 * i)) & 0x000f;
1697 send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd));
1698 }
1699 }
1700 else if (c == 'u') {
1701 put_uint(action, arg, format_width, 0);
1702 }
1703 else if (c == 'l') {
1704 s++;
1705 c = read_byte(get_CS(), s); /* is it ld,lx,lu? */
1706 arg_ptr++; /* increment to next arg */
1707 hibyte = read_word(arg_seg, arg_ptr);
1708 if (c == 'd') {
1709 if (hibyte & 0x8000)
1710 put_luint(action, 0L-(((Bit32u) hibyte << 16) | arg), format_width-1, 1);
1711 else
1712 put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
1713 }
1714 else if (c == 'u') {
1715 put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
1716 }
1717 else if (c == 'x' || c == 'X')
1718 {
1719 if (format_width == 0)
1720 format_width = 8;
1721 if (c == 'x')
1722 hexadd = 'a';
1723 else
1724 hexadd = 'A';
1725 for (i=format_width-1; i>=0; i--) {
1726 nibble = ((((Bit32u) hibyte <<16) | arg) >> (4 * i)) & 0x000f;
1727 send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd));
1728 }
1729 }
1730 }
1731 else if (c == 'd') {
1732 if (arg & 0x8000)
1733 put_int(action, -arg, format_width - 1, 1);
1734 else
1735 put_int(action, arg, format_width, 0);
1736 }
1737 else if (c == 's') {
1738 put_str(action, get_CS(), arg);
1739 }
1740 else if (c == 'S') {
1741 hibyte = arg;
1742 arg_ptr++;
1743 arg = read_word(arg_seg, arg_ptr);
1744 put_str(action, hibyte, arg);
1745 }
1746 else if (c == 'c') {
1747 send(action, arg);
1748 }
1749 else
1750 BX_PANIC("bios_printf: unknown format\n");
1751 in_format = 0;
1752 }
1753 }
1754 else {
1755 send(action, c);
1756 }
1757 s ++;
1758 }
1759
1760 if (action & BIOS_PRINTF_HALT) {
1761 // freeze in a busy loop.
1762ASM_START
1763 cli
1764 halt2_loop:
1765 hlt
1766 jmp halt2_loop
1767ASM_END
1768 }
1769}
1770
1771//--------------------------------------------------------------------------
1772// keyboard_init
1773//--------------------------------------------------------------------------
1774// this file is based on LinuxBIOS implementation of keyboard.c
1775// could convert to #asm to gain space
1776 void
1777keyboard_init()
1778{
1779 Bit16u max;
1780
1781 /* ------------------- Flush buffers ------------------------*/
1782 /* Wait until buffer is empty */
1783 max=0xffff;
1784 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
1785
1786 /* flush incoming keys */
1787 max=0x2000;
1788 while (--max > 0) {
1789 outb(0x80, 0x00);
1790 if (inb(0x64) & 0x01) {
1791 inb(0x60);
1792 max = 0x2000;
1793 }
1794 }
1795
1796 // Due to timer issues, and if the IPS setting is > 15000000,
1797 // the incoming keys might not be flushed here. That will
1798 // cause a panic a few lines below. See sourceforge bug report :
1799 // [ 642031 ] FATAL: Keyboard RESET error:993
1800
1801 /* ------------------- controller side ----------------------*/
1802 /* send cmd = 0xAA, self test 8042 */
1803 outb(0x64, 0xaa);
1804
1805 /* Wait until buffer is empty */
1806 max=0xffff;
1807 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
1808 if (max==0x0) keyboard_panic(00);
1809
1810 /* Wait for data */
1811 max=0xffff;
1812 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x01);
1813 if (max==0x0) keyboard_panic(01);
1814
1815 /* read self-test result, 0x55 should be returned from 0x60 */
1816 if ((inb(0x60) != 0x55)){
1817 keyboard_panic(991);
1818 }
1819
1820 /* send cmd = 0xAB, keyboard interface test */
1821 outb(0x64,0xab);
1822
1823 /* Wait until buffer is empty */
1824 max=0xffff;
1825 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x10);
1826 if (max==0x0) keyboard_panic(10);
1827
1828 /* Wait for data */
1829 max=0xffff;
1830 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x11);
1831 if (max==0x0) keyboard_panic(11);
1832
1833 /* read keyboard interface test result, */
1834 /* 0x00 should be returned form 0x60 */
1835 if ((inb(0x60) != 0x00)) {
1836 keyboard_panic(992);
1837 }
1838
1839 /* Enable Keyboard clock */
1840 outb(0x64,0xae);
1841 outb(0x64,0xa8);
1842
1843 /* ------------------- keyboard side ------------------------*/
1844 /* reset kerboard and self test (keyboard side) */
1845 outb(0x60, 0xff);
1846
1847 /* Wait until buffer is empty */
1848 max=0xffff;
1849 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x20);
1850 if (max==0x0) keyboard_panic(20);
1851
1852 /* Wait for data */
1853 max=0xffff;
1854 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x21);
1855 if (max==0x0) keyboard_panic(21);
1856
1857 /* keyboard should return ACK */
1858 if ((inb(0x60) != 0xfa)) {
1859 keyboard_panic(993);
1860 }
1861
1862 /* Wait for data */
1863 max=0xffff;
1864 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x31);
1865 if (max==0x0) keyboard_panic(31);
1866
1867 if ((inb(0x60) != 0xaa)) {
1868 keyboard_panic(994);
1869 }
1870
1871 /* Disable keyboard */
1872 outb(0x60, 0xf5);
1873
1874 /* Wait until buffer is empty */
1875 max=0xffff;
1876 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x40);
1877 if (max==0x0) keyboard_panic(40);
1878
1879 /* Wait for data */
1880 max=0xffff;
1881 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x41);
1882 if (max==0x0) keyboard_panic(41);
1883
1884 /* keyboard should return ACK */
1885 if ((inb(0x60) != 0xfa)) {
1886 keyboard_panic(995);
1887 }
1888
1889 /* Write Keyboard Mode */
1890 outb(0x64, 0x60);
1891
1892 /* Wait until buffer is empty */
1893 max=0xffff;
1894 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x50);
1895 if (max==0x0) keyboard_panic(50);
1896
1897 /* send cmd: scan code convert, disable mouse, enable IRQ 1 */
1898 outb(0x60, 0x65);
1899
1900 /* Wait until buffer is empty */
1901 max=0xffff;
1902 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x60);
1903 if (max==0x0) keyboard_panic(60);
1904
1905 /* Enable keyboard */
1906 outb(0x60, 0xf4);
1907
1908 /* Wait until buffer is empty */
1909 max=0xffff;
1910 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x70);
1911 if (max==0x0) keyboard_panic(70);
1912
1913 /* Wait for data */
1914 max=0xffff;
1915 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x71);
1916 if (max==0x0) keyboard_panic(70);
1917
1918 /* keyboard should return ACK */
1919 if ((inb(0x60) != 0xfa)) {
1920 keyboard_panic(996);
1921 }
1922
1923 outb(0x80, 0x77);
1924}
1925
1926//--------------------------------------------------------------------------
1927// keyboard_panic
1928//--------------------------------------------------------------------------
1929 void
1930keyboard_panic(status)
1931 Bit16u status;
1932{
1933 // If you're getting a 993 keyboard panic here,
1934 // please see the comment in keyboard_init
1935
1936 BX_PANIC("Keyboard error:%u\n",status);
1937}
1938
1939//--------------------------------------------------------------------------
1940// shutdown_status_panic
1941// called when the shutdown statsu is not implemented, displays the status
1942//--------------------------------------------------------------------------
1943 void
1944shutdown_status_panic(status)
1945 Bit16u status;
1946{
1947 BX_PANIC("Unimplemented shutdown status: %02x\n",(Bit8u)status);
1948}
1949
1950#ifdef VBOX
1951#include "logo.c"
1952#endif /* VBOX */
1953
1954//--------------------------------------------------------------------------
1955// print_bios_banner
1956// displays a the bios version
1957//--------------------------------------------------------------------------
1958void
1959print_bios_banner()
1960{
1961#ifdef VBOX
1962 // Skip the logo if a warm boot is requested.
1963 Bit16u warm_boot = read_word(0x0040,0x0072);
1964 write_word(0x0040,0x0072, 0);
1965 if (warm_boot == 0x1234)
1966 return;
1967 /* show graphical logo */
1968 show_logo();
1969#else /* !VBOX */
1970 printf(BX_APPNAME" BIOS - build: %s\n%s\nOptions: ",
1971 BIOS_BUILD_DATE, bios_cvs_version_string);
1972 printf(
1973#if BX_APM
1974 "apmbios "
1975#endif
1976#if BX_PCIBIOS
1977 "pcibios "
1978#endif
1979#if BX_ELTORITO_BOOT
1980 "eltorito "
1981#endif
1982#if BX_ROMBIOS32
1983 "rombios32 "
1984#endif
1985 "\n\n");
1986#endif /* VBOX */
1987}
1988
1989//--------------------------------------------------------------------------
1990// print_boot_device
1991// displays the boot device
1992//--------------------------------------------------------------------------
1993
1994#ifdef VBOX
1995static char drivetypes[][10]={"Floppy","Hard Disk","CD-ROM","LAN"};
1996#else /* !VBOX */
1997static char drivetypes[][10]={"Floppy","Hard Disk","CD-Rom"};
1998#endif /* !VBOX */
1999
2000#ifdef VBOX
2001void
2002print_boot_device(cdboot, lanboot, drive)
2003 Bit8u cdboot; Bit8u lanboot; Bit16u drive;
2004#else /* !VBOX */
2005void
2006print_boot_device(cdboot, drive)
2007 Bit8u cdboot; Bit16u drive;
2008#endif /* !VBOX */
2009{
2010 Bit8u i;
2011
2012#ifdef VBOX
2013 // cdboot contains 0 if lan/floppy/harddisk, 1 otherwise
2014 // lanboot contains 0 if floppy/harddisk, 1 otherwise
2015#else /* !VBOX */
2016 // cdboot contains 0 if floppy/harddisk, 1 otherwise
2017#endif /* !VBOX */
2018 // drive contains real/emulated boot drive
2019
2020 if(cdboot)i=2; // CD-Rom
2021#ifdef VBOX
2022 else if(lanboot)i=3; // LAN
2023#endif /* VBOX */
2024 else if((drive&0x0080)==0x00)i=0; // Floppy
2025 else if((drive&0x0080)==0x80)i=1; // Hard drive
2026 else return;
2027
2028#ifdef VBOX
2029 BX_INFO("Booting from %s...\n",drivetypes[i]);
2030#else /* !VBOX */
2031 printf("Booting from %s...\n",drivetypes[i]);
2032#endif /* !VBOX */
2033}
2034
2035//--------------------------------------------------------------------------
2036// print_boot_failure
2037// displays the reason why boot failed
2038//--------------------------------------------------------------------------
2039#ifdef VBOX
2040 void
2041print_boot_failure(cdboot, lanboot, drive, reason, lastdrive)
2042 Bit8u cdboot; Bit8u lanboot; Bit8u drive; Bit8u reason; Bit8u lastdrive;
2043#else /* !VBOX */
2044 void
2045print_boot_failure(cdboot, drive, reason, lastdrive)
2046 Bit8u cdboot; Bit8u drive; Bit8u lastdrive;
2047#endif /* !VBOX */
2048{
2049 Bit16u drivenum = drive&0x7f;
2050
2051 // cdboot: 1 if boot from cd, 0 otherwise
2052#ifdef VBOX
2053 // lanboot: 1 if boot from lan, 0 otherwise
2054#endif /* VBOX */
2055 // drive : drive number
2056 // reason: 0 signature check failed, 1 read error
2057 // lastdrive: 1 boot drive is the last one in boot sequence
2058
2059 if (cdboot)
2060#ifndef VBOX
2061 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s failed\n",drivetypes[2]);
2062#else /* VBOX */
2063 BX_INFO("Boot from %s failed\n",drivetypes[2]);
2064 else if (lanboot)
2065 BX_INFO("Boot from %s failed\n",drivetypes[3]);
2066#endif /* VBOX */
2067 else if (drive & 0x80)
2068#ifndef VBOX
2069 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[1],drivenum);
2070#else /* VBOX */
2071 BX_INFO("Boot from %s %d failed\n", drivetypes[1],drivenum);
2072#endif /* VBOX */
2073 else
2074#ifndef VBOX
2075 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[0],drivenum);
2076#else /* VBOX */
2077 BX_INFO("Boot from %s %d failed\n", drivetypes[0],drivenum);
2078#endif /* VBOX */
2079
2080 if (lastdrive==1) {
2081 if (reason==0)
2082#ifndef VBOX
2083 BX_PANIC("Not a bootable disk\n");
2084#else /* VBOX */
2085 BX_PANIC("No bootable medium found! System halted.\n");
2086#endif /* VBOX */
2087 else
2088#ifndef VBOX
2089 BX_PANIC("Could not read the boot disk\n");
2090#else /* VBOX */
2091 BX_PANIC("Could not read from the boot medium! System halted.\n");
2092#endif /* VBOX */
2093 }
2094}
2095
2096//--------------------------------------------------------------------------
2097// print_cdromboot_failure
2098// displays the reason why boot failed
2099//--------------------------------------------------------------------------
2100 void
2101print_cdromboot_failure( code )
2102 Bit16u code;
2103{
2104#ifndef VBOX
2105 bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "CDROM boot failure code : %04x\n",code);
2106#else /* VBOX */
2107 BX_INFO("CDROM boot failure code : %04x\n",code);
2108#endif /* VBOX */
2109
2110 return;
2111}
2112
2113void
2114nmi_handler_msg()
2115{
2116 BX_PANIC("NMI Handler called\n");
2117}
2118
2119void
2120int18_panic_msg()
2121{
2122 BX_PANIC("INT18: BOOT FAILURE\n");
2123}
2124
2125void
2126log_bios_start()
2127{
2128#if BX_DEBUG_SERIAL
2129 outb(BX_DEBUG_PORT+UART_LCR, 0x03); /* setup for serial logging: 8N1 */
2130#endif
2131 BX_INFO("%s\n", bios_cvs_version_string);
2132}
2133
2134 bx_bool
2135set_enable_a20(val)
2136 bx_bool val;
2137{
2138 Bit8u oldval;
2139
2140 // Use PS2 System Control port A to set A20 enable
2141
2142 // get current setting first
2143 oldval = inb(0x92);
2144
2145 // change A20 status
2146 if (val)
2147 outb(0x92, oldval | 0x02);
2148 else
2149 outb(0x92, oldval & 0xfd);
2150
2151 return((oldval & 0x02) != 0);
2152}
2153
2154 void
2155debugger_on()
2156{
2157 outb(0xfedc, 0x01);
2158}
2159
2160 void
2161debugger_off()
2162{
2163 outb(0xfedc, 0x00);
2164}
2165
2166#if BX_USE_ATADRV
2167
2168// ---------------------------------------------------------------------------
2169// Start of ATA/ATAPI Driver
2170// ---------------------------------------------------------------------------
2171
2172// Global defines -- ATA register and register bits.
2173// command block & control block regs
2174#define ATA_CB_DATA 0 // data reg in/out pio_base_addr1+0
2175#define ATA_CB_ERR 1 // error in pio_base_addr1+1
2176#define ATA_CB_FR 1 // feature reg out pio_base_addr1+1
2177#define ATA_CB_SC 2 // sector count in/out pio_base_addr1+2
2178#define ATA_CB_SN 3 // sector number in/out pio_base_addr1+3
2179#define ATA_CB_CL 4 // cylinder low in/out pio_base_addr1+4
2180#define ATA_CB_CH 5 // cylinder high in/out pio_base_addr1+5
2181#define ATA_CB_DH 6 // device head in/out pio_base_addr1+6
2182#define ATA_CB_STAT 7 // primary status in pio_base_addr1+7
2183#define ATA_CB_CMD 7 // command out pio_base_addr1+7
2184#define ATA_CB_ASTAT 6 // alternate status in pio_base_addr2+6
2185#define ATA_CB_DC 6 // device control out pio_base_addr2+6
2186#define ATA_CB_DA 7 // device address in pio_base_addr2+7
2187
2188#define ATA_CB_ER_ICRC 0x80 // ATA Ultra DMA bad CRC
2189#define ATA_CB_ER_BBK 0x80 // ATA bad block
2190#define ATA_CB_ER_UNC 0x40 // ATA uncorrected error
2191#define ATA_CB_ER_MC 0x20 // ATA media change
2192#define ATA_CB_ER_IDNF 0x10 // ATA id not found
2193#define ATA_CB_ER_MCR 0x08 // ATA media change request
2194#define ATA_CB_ER_ABRT 0x04 // ATA command aborted
2195#define ATA_CB_ER_NTK0 0x02 // ATA track 0 not found
2196#define ATA_CB_ER_NDAM 0x01 // ATA address mark not found
2197
2198#define ATA_CB_ER_P_SNSKEY 0xf0 // ATAPI sense key (mask)
2199#define ATA_CB_ER_P_MCR 0x08 // ATAPI Media Change Request
2200#define ATA_CB_ER_P_ABRT 0x04 // ATAPI command abort
2201#define ATA_CB_ER_P_EOM 0x02 // ATAPI End of Media
2202#define ATA_CB_ER_P_ILI 0x01 // ATAPI Illegal Length Indication
2203
2204// ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC)
2205#define ATA_CB_SC_P_TAG 0xf8 // ATAPI tag (mask)
2206#define ATA_CB_SC_P_REL 0x04 // ATAPI release
2207#define ATA_CB_SC_P_IO 0x02 // ATAPI I/O
2208#define ATA_CB_SC_P_CD 0x01 // ATAPI C/D
2209
2210// bits 7-4 of the device/head (CB_DH) reg
2211#define ATA_CB_DH_DEV0 0xa0 // select device 0
2212#define ATA_CB_DH_DEV1 0xb0 // select device 1
2213
2214// status reg (CB_STAT and CB_ASTAT) bits
2215#define ATA_CB_STAT_BSY 0x80 // busy
2216#define ATA_CB_STAT_RDY 0x40 // ready
2217#define ATA_CB_STAT_DF 0x20 // device fault
2218#define ATA_CB_STAT_WFT 0x20 // write fault (old name)
2219#define ATA_CB_STAT_SKC 0x10 // seek complete
2220#define ATA_CB_STAT_SERV 0x10 // service
2221#define ATA_CB_STAT_DRQ 0x08 // data request
2222#define ATA_CB_STAT_CORR 0x04 // corrected
2223#define ATA_CB_STAT_IDX 0x02 // index
2224#define ATA_CB_STAT_ERR 0x01 // error (ATA)
2225#define ATA_CB_STAT_CHK 0x01 // check (ATAPI)
2226
2227// device control reg (CB_DC) bits
2228#define ATA_CB_DC_HD15 0x08 // bit should always be set to one
2229#define ATA_CB_DC_SRST 0x04 // soft reset
2230#define ATA_CB_DC_NIEN 0x02 // disable interrupts
2231
2232// Most mandtory and optional ATA commands (from ATA-3),
2233#define ATA_CMD_CFA_ERASE_SECTORS 0xC0
2234#define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03
2235#define ATA_CMD_CFA_TRANSLATE_SECTOR 0x87
2236#define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD
2237#define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38
2238#define ATA_CMD_CHECK_POWER_MODE1 0xE5
2239#define ATA_CMD_CHECK_POWER_MODE2 0x98
2240#define ATA_CMD_DEVICE_RESET 0x08
2241#define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90
2242#define ATA_CMD_FLUSH_CACHE 0xE7
2243#define ATA_CMD_FORMAT_TRACK 0x50
2244#define ATA_CMD_IDENTIFY_DEVICE 0xEC
2245#define ATA_CMD_IDENTIFY_DEVICE_PACKET 0xA1
2246#define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xA1
2247#define ATA_CMD_IDLE1 0xE3
2248#define ATA_CMD_IDLE2 0x97
2249#define ATA_CMD_IDLE_IMMEDIATE1 0xE1
2250#define ATA_CMD_IDLE_IMMEDIATE2 0x95
2251#define ATA_CMD_INITIALIZE_DRIVE_PARAMETERS 0x91
2252#define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
2253#define ATA_CMD_NOP 0x00
2254#define ATA_CMD_PACKET 0xA0
2255#define ATA_CMD_READ_BUFFER 0xE4
2256#define ATA_CMD_READ_DMA 0xC8
2257#define ATA_CMD_READ_DMA_QUEUED 0xC7
2258#define ATA_CMD_READ_MULTIPLE 0xC4
2259#define ATA_CMD_READ_SECTORS 0x20
2260#ifdef VBOX
2261#define ATA_CMD_READ_SECTORS_EXT 0x24
2262#endif /* VBOX */
2263#define ATA_CMD_READ_VERIFY_SECTORS 0x40
2264#define ATA_CMD_RECALIBRATE 0x10
2265#define ATA_CMD_SEEK 0x70
2266#define ATA_CMD_SET_FEATURES 0xEF
2267#define ATA_CMD_SET_MULTIPLE_MODE 0xC6
2268#define ATA_CMD_SLEEP1 0xE6
2269#define ATA_CMD_SLEEP2 0x99
2270#define ATA_CMD_STANDBY1 0xE2
2271#define ATA_CMD_STANDBY2 0x96
2272#define ATA_CMD_STANDBY_IMMEDIATE1 0xE0
2273#define ATA_CMD_STANDBY_IMMEDIATE2 0x94
2274#define ATA_CMD_WRITE_BUFFER 0xE8
2275#define ATA_CMD_WRITE_DMA 0xCA
2276#define ATA_CMD_WRITE_DMA_QUEUED 0xCC
2277#define ATA_CMD_WRITE_MULTIPLE 0xC5
2278#define ATA_CMD_WRITE_SECTORS 0x30
2279#ifdef VBOX
2280#define ATA_CMD_WRITE_SECTORS_EXT 0x34
2281#endif /* VBOX */
2282#define ATA_CMD_WRITE_VERIFY 0x3C
2283
2284#define ATA_IFACE_NONE 0x00
2285#define ATA_IFACE_ISA 0x00
2286#define ATA_IFACE_PCI 0x01
2287
2288#define ATA_TYPE_NONE 0x00
2289#define ATA_TYPE_UNKNOWN 0x01
2290#define ATA_TYPE_ATA 0x02
2291#define ATA_TYPE_ATAPI 0x03
2292#ifdef VBOX
2293#define ATA_TYPE_SCSI 0x04 // SCSI disk
2294#endif
2295
2296#define ATA_DEVICE_NONE 0x00
2297#define ATA_DEVICE_HD 0xFF
2298#define ATA_DEVICE_CDROM 0x05
2299
2300#define ATA_MODE_NONE 0x00
2301#define ATA_MODE_PIO16 0x00
2302#define ATA_MODE_PIO32 0x01
2303#define ATA_MODE_ISADMA 0x02
2304#define ATA_MODE_PCIDMA 0x03
2305#define ATA_MODE_USEIRQ 0x10
2306
2307#define ATA_TRANSLATION_NONE 0
2308#define ATA_TRANSLATION_LBA 1
2309#define ATA_TRANSLATION_LARGE 2
2310#define ATA_TRANSLATION_RECHS 3
2311
2312#define ATA_DATA_NO 0x00
2313#define ATA_DATA_IN 0x01
2314#define ATA_DATA_OUT 0x02
2315
2316// ---------------------------------------------------------------------------
2317// ATA/ATAPI driver : initialization
2318// ---------------------------------------------------------------------------
2319void ata_init( )
2320{
2321 Bit16u ebda_seg=read_word(0x0040,0x000E);
2322 Bit8u channel, device;
2323
2324 // Channels info init.
2325 for (channel=0; channel<BX_MAX_ATA_INTERFACES; channel++) {
2326 write_byte(ebda_seg,&EbdaData->ata.channels[channel].iface,ATA_IFACE_NONE);
2327 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1,0x0);
2328 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2,0x0);
2329 write_byte(ebda_seg,&EbdaData->ata.channels[channel].irq,0);
2330 }
2331
2332 // Devices info init.
2333 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2334 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
2335 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_NONE);
2336 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable,0);
2337 write_byte(ebda_seg,&EbdaData->ata.devices[device].lock,0);
2338 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode,ATA_MODE_NONE);
2339 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,0);
2340 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation,ATA_TRANSLATION_NONE);
2341 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads,0);
2342 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders,0);
2343 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt,0);
2344 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads,0);
2345 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders,0);
2346 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt,0);
2347
2348 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors,0L);
2349 }
2350
2351 // hdidmap and cdidmap init.
2352 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2353 write_byte(ebda_seg,&EbdaData->ata.hdidmap[device],BX_MAX_STORAGE_DEVICES);
2354 write_byte(ebda_seg,&EbdaData->ata.cdidmap[device],BX_MAX_STORAGE_DEVICES);
2355 }
2356
2357 write_byte(ebda_seg,&EbdaData->ata.hdcount,0);
2358 write_byte(ebda_seg,&EbdaData->ata.cdcount,0);
2359}
2360
2361// ---------------------------------------------------------------------------
2362// ATA/ATAPI driver : device detection
2363// ---------------------------------------------------------------------------
2364
2365void ata_detect( )
2366{
2367 Bit16u ebda_seg=read_word(0x0040,0x000E);
2368 Bit8u hdcount, cdcount, device, type;
2369 Bit8u buffer[0x0200];
2370
2371#if BX_MAX_ATA_INTERFACES > 0
2372 write_byte(ebda_seg,&EbdaData->ata.channels[0].iface,ATA_IFACE_ISA);
2373 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase1,0x1f0);
2374 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase2,0x3f0);
2375 write_byte(ebda_seg,&EbdaData->ata.channels[0].irq,14);
2376#endif
2377#if BX_MAX_ATA_INTERFACES > 1
2378 write_byte(ebda_seg,&EbdaData->ata.channels[1].iface,ATA_IFACE_ISA);
2379 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase1,0x170);
2380 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase2,0x370);
2381 write_byte(ebda_seg,&EbdaData->ata.channels[1].irq,15);
2382#endif
2383#if BX_MAX_ATA_INTERFACES > 2
2384 write_byte(ebda_seg,&EbdaData->ata.channels[2].iface,ATA_IFACE_ISA);
2385 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase1,0x1e8);
2386 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase2,0x3e0);
2387 write_byte(ebda_seg,&EbdaData->ata.channels[2].irq,12);
2388#endif
2389#if BX_MAX_ATA_INTERFACES > 3
2390 write_byte(ebda_seg,&EbdaData->ata.channels[3].iface,ATA_IFACE_ISA);
2391 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase1,0x168);
2392 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase2,0x360);
2393 write_byte(ebda_seg,&EbdaData->ata.channels[3].irq,11);
2394#endif
2395#if BX_MAX_ATA_INTERFACES > 4
2396#error Please fill the ATA interface informations
2397#endif
2398
2399 // Device detection
2400 hdcount=cdcount=0;
2401
2402 for(device=0; device<BX_MAX_ATA_DEVICES; device++) {
2403 Bit16u iobase1, iobase2;
2404 Bit8u channel, slave, shift;
2405 Bit8u sc, sn, cl, ch, st;
2406
2407 channel = device / 2;
2408 slave = device % 2;
2409
2410 iobase1 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1);
2411 iobase2 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2);
2412
2413 // Disable interrupts
2414 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2415
2416 // Look for device
2417 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2418 outb(iobase1+ATA_CB_SC, 0x55);
2419 outb(iobase1+ATA_CB_SN, 0xaa);
2420 outb(iobase1+ATA_CB_SC, 0xaa);
2421 outb(iobase1+ATA_CB_SN, 0x55);
2422 outb(iobase1+ATA_CB_SC, 0x55);
2423 outb(iobase1+ATA_CB_SN, 0xaa);
2424
2425 // If we found something
2426 sc = inb(iobase1+ATA_CB_SC);
2427 sn = inb(iobase1+ATA_CB_SN);
2428
2429 if ( (sc == 0x55) && (sn == 0xaa) ) {
2430 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_UNKNOWN);
2431
2432 // reset the channel
2433 ata_reset(device);
2434
2435 // check for ATA or ATAPI
2436 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2437 sc = inb(iobase1+ATA_CB_SC);
2438 sn = inb(iobase1+ATA_CB_SN);
2439 if ((sc==0x01) && (sn==0x01)) {
2440 cl = inb(iobase1+ATA_CB_CL);
2441 ch = inb(iobase1+ATA_CB_CH);
2442 st = inb(iobase1+ATA_CB_STAT);
2443
2444 if ((cl==0x14) && (ch==0xeb)) {
2445 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATAPI);
2446 } else if ((cl==0x00) && (ch==0x00) && (st!=0x00)) {
2447 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATA);
2448 } else if ((cl==0xff) && (ch==0xff)) {
2449 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
2450 }
2451 }
2452 }
2453
2454#ifdef VBOX
2455 // Enable interrupts
2456 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2457#endif /* VBOX */
2458
2459 type=read_byte(ebda_seg,&EbdaData->ata.devices[device].type);
2460
2461 // Now we send a IDENTIFY command to ATA device
2462 if(type == ATA_TYPE_ATA) {
2463 Bit32u sectors;
2464 Bit16u cylinders, heads, spt, blksize;
2465#ifdef VBOX
2466 Bit16u lcylinders, lheads, lspt;
2467 Bit8u chsgeo_base;
2468#endif /* VBOX */
2469 Bit8u translation, removable, mode;
2470
2471 //Temporary values to do the transfer
2472 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2473 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2474
2475 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE, 1, 0, 0, 0, 0L, get_SS(),buffer) !=0 )
2476 BX_PANIC("ata-detect: Failed to detect ATA device\n");
2477
2478 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2479 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2480#ifdef VBOX
2481 blksize = 512; /* There is no sector size field any more. */
2482#else /* !VBOX */
2483 blksize = read_word(get_SS(),buffer+10);
2484#endif /* !VBOX */
2485
2486 cylinders = read_word(get_SS(),buffer+(1*2)); // word 1
2487 heads = read_word(get_SS(),buffer+(3*2)); // word 3
2488 spt = read_word(get_SS(),buffer+(6*2)); // word 6
2489
2490 sectors = read_dword(get_SS(),buffer+(60*2)); // word 60 and word 61
2491#ifdef VBOX
2492 /** @todo update sectors to be a 64 bit number (also lba...). */
2493 if (sectors == 268435455)
2494 sectors = read_dword(get_SS(),buffer+(100*2)); // words 100 to 103 (someday)
2495 switch (device)
2496 {
2497 case 0:
2498 chsgeo_base = 0x1e;
2499 break;
2500 case 1:
2501 chsgeo_base = 0x26;
2502 break;
2503 case 2:
2504 chsgeo_base = 0x67;
2505 break;
2506 case 3:
2507 chsgeo_base = 0x70;
2508 break;
2509 case 4:
2510 chsgeo_base = 0x40;
2511 break;
2512 case 5:
2513 chsgeo_base = 0x48;
2514 break;
2515 case 6:
2516 chsgeo_base = 0x50;
2517 break;
2518 case 7:
2519 chsgeo_base = 0x58;
2520 break;
2521 default:
2522 chsgeo_base = 0;
2523 }
2524 if (chsgeo_base != 0)
2525 {
2526 lcylinders = inb_cmos(chsgeo_base) + (inb_cmos(chsgeo_base+1) << 8);
2527 lheads = inb_cmos(chsgeo_base+2);
2528 lspt = inb_cmos(chsgeo_base+7);
2529 }
2530 else
2531 {
2532 lcylinders = 0;
2533 lheads = 0;
2534 lspt = 0;
2535 }
2536 BX_INFO("ata%d-%d: PCHS=%u/%d/%d LCHS=%u/%u/%u\n", channel, slave, cylinders, heads, spt, lcylinders, lheads, lspt);
2537#endif /* VBOX */
2538
2539 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2540 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2541 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2542 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2543 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads, heads);
2544 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders, cylinders);
2545 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt, spt);
2546 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors, sectors);
2547#ifdef VBOX
2548 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, lheads);
2549 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, lcylinders);
2550 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, lspt);
2551 if (device < 2)
2552 {
2553 Bit8u sum, i;
2554 unsigned char *fdpt;
2555 if (device == 0)
2556 fdpt = &EbdaData->fdpt0;
2557 else
2558 fdpt = &EbdaData->fdpt1;
2559
2560 /* Update the DPT for drive 0/1 pointed to by Int41/46. This used
2561 * to be done at POST time with lots of ugly assembler code, which
2562 * isn't worth the effort of converting from AMI to Award CMOS
2563 * format. Just do it here. */
2564 write_word(ebda_seg, fdpt + 0x00, lcylinders);
2565 write_byte(ebda_seg, fdpt + 0x02, lheads);
2566 write_byte(ebda_seg, fdpt + 0x0e, lspt);
2567 write_word(ebda_seg, fdpt + 0x09, cylinders);
2568 write_byte(ebda_seg, fdpt + 0x0b, heads);
2569 write_byte(ebda_seg, fdpt + 0x04, spt);
2570 write_byte(ebda_seg, fdpt + 0x03, 0xa0);
2571 sum = 0;
2572 for (i = 0; i < 0xf; i++)
2573 sum += read_byte(ebda_seg, fdpt + i);
2574 sum = 1 - sum;
2575 write_byte(ebda_seg, fdpt + 0x0f, sum);
2576 }
2577#else /* !VBOX */
2578 BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel, slave,cylinders, heads, spt);
2579
2580 translation = inb_cmos(0x39 + channel/2);
2581 for (shift=device%4; shift>0; shift--) translation >>= 2;
2582 translation &= 0x03;
2583
2584 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation, translation);
2585
2586 switch (translation) {
2587 case ATA_TRANSLATION_NONE:
2588 BX_INFO("none");
2589 break;
2590 case ATA_TRANSLATION_LBA:
2591 BX_INFO("lba");
2592 break;
2593 case ATA_TRANSLATION_LARGE:
2594 BX_INFO("large");
2595 break;
2596 case ATA_TRANSLATION_RECHS:
2597 BX_INFO("r-echs");
2598 break;
2599 }
2600 switch (translation) {
2601 case ATA_TRANSLATION_NONE:
2602 break;
2603 case ATA_TRANSLATION_LBA:
2604 spt = 63;
2605 sectors /= 63;
2606 heads = sectors / 1024;
2607 if (heads>128) heads = 255;
2608 else if (heads>64) heads = 128;
2609 else if (heads>32) heads = 64;
2610 else if (heads>16) heads = 32;
2611 else heads=16;
2612 cylinders = sectors / heads;
2613 break;
2614 case ATA_TRANSLATION_RECHS:
2615 // Take care not to overflow
2616 if (heads==16) {
2617 if(cylinders>61439) cylinders=61439;
2618 heads=15;
2619 cylinders = (Bit16u)((Bit32u)(cylinders)*16/15);
2620 }
2621 // then go through the large bitshift process
2622 case ATA_TRANSLATION_LARGE:
2623 while(cylinders > 1024) {
2624 cylinders >>= 1;
2625 heads <<= 1;
2626
2627 // If we max out the head count
2628 if (heads > 127) break;
2629 }
2630 break;
2631 }
2632 // clip to 1024 cylinders in lchs
2633 if (cylinders > 1024) cylinders=1024;
2634 BX_INFO(" LCHS=%d/%d/%d\n", cylinders, heads, spt);
2635
2636 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, heads);
2637 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, cylinders);
2638 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, spt);
2639#endif /* VBOX */
2640
2641 // fill hdidmap
2642 write_byte(ebda_seg,&EbdaData->ata.hdidmap[hdcount], device);
2643 hdcount++;
2644 }
2645
2646 // Now we send a IDENTIFY command to ATAPI device
2647 if(type == ATA_TYPE_ATAPI) {
2648
2649 Bit8u type, removable, mode;
2650 Bit16u blksize;
2651
2652 //Temporary values to do the transfer
2653 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_CDROM);
2654 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2655
2656 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE_PACKET, 1, 0, 0, 0, 0L, get_SS(),buffer) != 0)
2657 BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
2658
2659 type = read_byte(get_SS(),buffer+1) & 0x1f;
2660 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2661 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2662 blksize = 2048;
2663
2664 write_byte(ebda_seg,&EbdaData->ata.devices[device].device, type);
2665 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2666 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2667 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2668
2669 // fill cdidmap
2670 write_byte(ebda_seg,&EbdaData->ata.cdidmap[cdcount], device);
2671 cdcount++;
2672 }
2673
2674 {
2675 Bit32u sizeinmb;
2676 Bit16u ataversion;
2677 Bit8u c, i, version, model[41];
2678
2679 switch (type) {
2680 case ATA_TYPE_ATA:
2681 sizeinmb = read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors);
2682 sizeinmb >>= 11;
2683 case ATA_TYPE_ATAPI:
2684 // Read ATA/ATAPI version
2685 ataversion=((Bit16u)(read_byte(get_SS(),buffer+161))<<8)|read_byte(get_SS(),buffer+160);
2686 for(version=15;version>0;version--) {
2687 if((ataversion&(1<<version))!=0)
2688 break;
2689 }
2690
2691 // Read model name
2692 for(i=0;i<20;i++){
2693 write_byte(get_SS(),model+(i*2),read_byte(get_SS(),buffer+(i*2)+54+1));
2694 write_byte(get_SS(),model+(i*2)+1,read_byte(get_SS(),buffer+(i*2)+54));
2695 }
2696
2697 // Reformat
2698 write_byte(get_SS(),model+40,0x00);
2699 for(i=39;i>0;i--){
2700 if(read_byte(get_SS(),model+i)==0x20)
2701 write_byte(get_SS(),model+i,0x00);
2702 else break;
2703 }
2704 break;
2705 }
2706
2707#ifdef VBOX
2708 // we don't want any noisy output for now
2709#else /* !VBOX */
2710 switch (type) {
2711 case ATA_TYPE_ATA:
2712 printf("ata%d %s: ",channel,slave?" slave":"master");
2713 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2714 printf(" ATA-%d Hard-Disk (%lu MBytes)\n", version, sizeinmb);
2715 break;
2716 case ATA_TYPE_ATAPI:
2717 printf("ata%d %s: ",channel,slave?" slave":"master");
2718 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2719 if(read_byte(ebda_seg,&EbdaData->ata.devices[device].device)==ATA_DEVICE_CDROM)
2720 printf(" ATAPI-%d CD-Rom/DVD-Rom\n",version);
2721 else
2722 printf(" ATAPI-%d Device\n",version);
2723 break;
2724 case ATA_TYPE_UNKNOWN:
2725 printf("ata%d %s: Unknown device\n",channel,slave?" slave":"master");
2726 break;
2727 }
2728#endif /* !VBOX */
2729 }
2730 }
2731
2732 // Store the devices counts
2733 write_byte(ebda_seg,&EbdaData->ata.hdcount, hdcount);
2734 write_byte(ebda_seg,&EbdaData->ata.cdcount, cdcount);
2735 write_byte(0x40,0x75, hdcount);
2736
2737#ifdef VBOX
2738 // we don't want any noisy output for now
2739#else /* !VBOX */
2740 printf("\n");
2741#endif /* !VBOX */
2742
2743 // FIXME : should use bios=cmos|auto|disable bits
2744 // FIXME : should know about translation bits
2745 // FIXME : move hard_drive_post here
2746
2747}
2748
2749// ---------------------------------------------------------------------------
2750// ATA/ATAPI driver : software reset
2751// ---------------------------------------------------------------------------
2752// ATA-3
2753// 8.2.1 Software reset - Device 0
2754
2755void ata_reset(device)
2756Bit16u device;
2757{
2758 Bit16u ebda_seg=read_word(0x0040,0x000E);
2759 Bit16u iobase1, iobase2;
2760 Bit8u channel, slave, sn, sc;
2761 Bit16u max;
2762#ifdef VBOX
2763 Bit16u pdelay;
2764#endif /* VBOX */
2765
2766 channel = device / 2;
2767 slave = device % 2;
2768
2769 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2770 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2771
2772 // Reset
2773
2774// 8.2.1 (a) -- set SRST in DC
2775 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN | ATA_CB_DC_SRST);
2776
2777// 8.2.1 (b) -- wait for BSY
2778 max=0xff;
2779 while(--max>0) {
2780 Bit8u status = inb(iobase1+ATA_CB_STAT);
2781 if ((status & ATA_CB_STAT_BSY) != 0) break;
2782 }
2783
2784// 8.2.1 (f) -- clear SRST
2785 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2786
2787 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_NONE) {
2788
2789// 8.2.1 (g) -- check for sc==sn==0x01
2790 // select device
2791 outb(iobase1+ATA_CB_DH, slave?ATA_CB_DH_DEV1:ATA_CB_DH_DEV0);
2792 sc = inb(iobase1+ATA_CB_SC);
2793 sn = inb(iobase1+ATA_CB_SN);
2794
2795 if ( (sc==0x01) && (sn==0x01) ) {
2796
2797// 8.2.1 (h) -- wait for not BSY
2798#ifdef VBOX
2799 max=0xffff; /* The ATA specification says that the drive may be busy for up to 30 seconds. */
2800#else /* !VBOX */
2801 max=0xff;
2802#endif /* !VBOX */
2803 while(--max>0) {
2804 Bit8u status = inb(iobase1+ATA_CB_STAT);
2805 if ((status & ATA_CB_STAT_BSY) == 0) break;
2806#ifdef VBOX
2807 pdelay=0xffff;
2808 while (--pdelay>0) {
2809 /* nothing */
2810 }
2811#endif /* VBOX */
2812 }
2813 }
2814 }
2815
2816// 8.2.1 (i) -- wait for DRDY
2817#ifdef VBOX
2818 max=0x10; /* Speed up for virtual drives. Disks are immediately ready, CDs never */
2819#else /* !VBOX */
2820 max=0xfff;
2821#endif /* !VBOX */
2822 while(--max>0) {
2823 Bit8u status = inb(iobase1+ATA_CB_STAT);
2824 if ((status & ATA_CB_STAT_RDY) != 0) break;
2825 }
2826
2827 // Enable interrupts
2828 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2829}
2830
2831// ---------------------------------------------------------------------------
2832// ATA/ATAPI driver : execute a non data command
2833// ---------------------------------------------------------------------------
2834
2835Bit16u ata_cmd_non_data()
2836{return 0;}
2837
2838// ---------------------------------------------------------------------------
2839// ATA/ATAPI driver : execute a data-in command
2840// ---------------------------------------------------------------------------
2841 // returns
2842 // 0 : no error
2843 // 1 : BUSY bit set
2844 // 2 : read error
2845 // 3 : expected DRQ=1
2846 // 4 : no sectors left to read/verify
2847 // 5 : more sectors to read/verify
2848 // 6 : no sectors left to write
2849 // 7 : more sectors to write
2850Bit16u ata_cmd_data_in(device, command, count, cylinder, head, sector, lba, segment, offset)
2851Bit16u device, command, count, cylinder, head, sector, segment, offset;
2852Bit32u lba;
2853{
2854 Bit16u ebda_seg=read_word(0x0040,0x000E);
2855 Bit16u iobase1, iobase2, blksize;
2856 Bit8u channel, slave;
2857 Bit8u status, current, mode;
2858
2859 channel = device / 2;
2860 slave = device % 2;
2861
2862 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2863 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2864 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2865 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2866 if (mode == ATA_MODE_PIO32) blksize>>=2;
2867 else blksize>>=1;
2868
2869#ifdef VBOX
2870 status = inb(iobase1 + ATA_CB_STAT);
2871 if (status & ATA_CB_STAT_BSY)
2872 {
2873 // Enable interrupts
2874 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2875 return 1;
2876 }
2877#endif /* VBOX */
2878
2879 // sector will be 0 only on lba access. Convert to lba-chs
2880 if (sector == 0) {
2881#ifdef VBOX
2882 if (count >= 256 || lba + count >= 268435456)
2883 {
2884 sector = (lba & 0xff000000L) >> 24;
2885 cylinder = 0; /* The parameter lba is just a 32 bit value. */
2886 outb(iobase1 + ATA_CB_SC, (count & 0xff00) >> 8);
2887 outb(iobase1 + ATA_CB_SN, sector);
2888 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2889 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2890 /* Leave the bottom 24 bits as is, they are treated correctly by the
2891 * LBA28 code path. */
2892 lba &= 0xffffff;
2893 }
2894#endif /* VBOX */
2895 sector = (Bit16u) (lba & 0x000000ffL);
2896 lba >>= 8;
2897 cylinder = (Bit16u) (lba & 0x0000ffffL);
2898 lba >>= 16;
2899 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
2900 }
2901
2902 // Reset count of transferred data
2903 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2904 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2905 current = 0;
2906
2907#ifndef VBOX
2908 status = inb(iobase1 + ATA_CB_STAT);
2909 if (status & ATA_CB_STAT_BSY) return 1;
2910#endif /* !VBOX */
2911
2912 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2913 outb(iobase1 + ATA_CB_FR, 0x00);
2914 outb(iobase1 + ATA_CB_SC, count);
2915 outb(iobase1 + ATA_CB_SN, sector);
2916 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2917 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2918 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
2919 outb(iobase1 + ATA_CB_CMD, command);
2920
2921 while (1) {
2922 status = inb(iobase1 + ATA_CB_STAT);
2923 if ( !(status & ATA_CB_STAT_BSY) ) break;
2924 }
2925
2926 if (status & ATA_CB_STAT_ERR) {
2927 BX_DEBUG_ATA("ata_cmd_data_in : read error\n");
2928#ifdef VBOX
2929 // Enable interrupts
2930 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2931#endif /* VBOX */
2932 return 2;
2933 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2934 BX_DEBUG_ATA("ata_cmd_data_in : DRQ not set (status %02x)\n", (unsigned) status);
2935#ifdef VBOX
2936 // Enable interrupts
2937 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2938#endif /* VBOX */
2939 return 3;
2940 }
2941
2942 // FIXME : move seg/off translation here
2943
2944ASM_START
2945 sti ;; enable higher priority interrupts
2946ASM_END
2947
2948 while (1) {
2949
2950ASM_START
2951 push bp
2952 mov bp, sp
2953 mov di, _ata_cmd_data_in.offset + 2[bp]
2954 mov ax, _ata_cmd_data_in.segment + 2[bp]
2955 mov cx, _ata_cmd_data_in.blksize + 2[bp]
2956
2957 ;; adjust if there will be an overrun. 2K max sector size
2958 cmp di, #0xf800 ;;
2959 jbe ata_in_no_adjust
2960
2961ata_in_adjust:
2962 sub di, #0x0800 ;; sub 2 kbytes from offset
2963 add ax, #0x0080 ;; add 2 Kbytes to segment
2964
2965ata_in_no_adjust:
2966 mov es, ax ;; segment in es
2967
2968 mov dx, _ata_cmd_data_in.iobase1 + 2[bp] ;; ATA data read port
2969
2970 mov ah, _ata_cmd_data_in.mode + 2[bp]
2971 cmp ah, #ATA_MODE_PIO32
2972 je ata_in_32
2973
2974ata_in_16:
2975 rep
2976 insw ;; CX words transfered from port(DX) to ES:[DI]
2977 jmp ata_in_done
2978
2979ata_in_32:
2980 rep
2981 insd ;; CX dwords transfered from port(DX) to ES:[DI]
2982
2983ata_in_done:
2984 mov _ata_cmd_data_in.offset + 2[bp], di
2985 mov _ata_cmd_data_in.segment + 2[bp], es
2986 pop bp
2987ASM_END
2988
2989 current++;
2990 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
2991 count--;
2992#ifdef VBOX
2993 while (1) {
2994 status = inb(iobase1 + ATA_CB_STAT);
2995 if ( !(status & ATA_CB_STAT_BSY) ) break;
2996 }
2997#else /* !VBOX */
2998 status = inb(iobase1 + ATA_CB_STAT);
2999#endif /* !VBOX */
3000 if (count == 0) {
3001 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3002 != ATA_CB_STAT_RDY ) {
3003 BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n", (unsigned) status);
3004#ifdef VBOX
3005 // Enable interrupts
3006 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3007#endif /* VBOX */
3008 return 4;
3009 }
3010 break;
3011 }
3012 else {
3013 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3014 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3015 BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n", (unsigned) status);
3016#ifdef VBOX
3017 // Enable interrupts
3018 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3019#endif /* VBOX */
3020 return 5;
3021 }
3022 continue;
3023 }
3024 }
3025 // Enable interrupts
3026 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3027 return 0;
3028}
3029
3030// ---------------------------------------------------------------------------
3031// ATA/ATAPI driver : execute a data-out command
3032// ---------------------------------------------------------------------------
3033 // returns
3034 // 0 : no error
3035 // 1 : BUSY bit set
3036 // 2 : read error
3037 // 3 : expected DRQ=1
3038 // 4 : no sectors left to read/verify
3039 // 5 : more sectors to read/verify
3040 // 6 : no sectors left to write
3041 // 7 : more sectors to write
3042Bit16u ata_cmd_data_out(device, command, count, cylinder, head, sector, lba, segment, offset)
3043Bit16u device, command, count, cylinder, head, sector, segment, offset;
3044Bit32u lba;
3045{
3046 Bit16u ebda_seg=read_word(0x0040,0x000E);
3047 Bit16u iobase1, iobase2, blksize;
3048 Bit8u channel, slave;
3049 Bit8u status, current, mode;
3050
3051 channel = device / 2;
3052 slave = device % 2;
3053
3054 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
3055 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
3056 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
3057 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
3058 if (mode == ATA_MODE_PIO32) blksize>>=2;
3059 else blksize>>=1;
3060
3061#ifdef VBOX
3062 status = inb(iobase1 + ATA_CB_STAT);
3063 if (status & ATA_CB_STAT_BSY)
3064 {
3065 // Enable interrupts
3066 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3067 return 1;
3068 }
3069#endif /* VBOX */
3070
3071 // sector will be 0 only on lba access. Convert to lba-chs
3072 if (sector == 0) {
3073#ifdef VBOX
3074 if (count >= 256 || lba + count >= 268435456)
3075 {
3076 sector = (lba & 0xff000000L) >> 24;
3077 cylinder = 0; /* The parameter lba is just a 32 bit value. */
3078 outb(iobase1 + ATA_CB_SC, (count & 0xff00) >> 8);
3079 outb(iobase1 + ATA_CB_SN, sector);
3080 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
3081 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
3082 /* Leave the bottom 24 bits as is, they are treated correctly by the
3083 * LBA28 code path. */
3084 lba &= 0xffffff;
3085 }
3086#endif /* VBOX */
3087 sector = (Bit16u) (lba & 0x000000ffL);
3088 lba >>= 8;
3089 cylinder = (Bit16u) (lba & 0x0000ffffL);
3090 lba >>= 16;
3091 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
3092 }
3093
3094 // Reset count of transferred data
3095 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
3096 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
3097 current = 0;
3098
3099#ifndef VBOX
3100 status = inb(iobase1 + ATA_CB_STAT);
3101 if (status & ATA_CB_STAT_BSY) return 1;
3102#endif /* !VBOX */
3103
3104 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
3105 outb(iobase1 + ATA_CB_FR, 0x00);
3106 outb(iobase1 + ATA_CB_SC, count);
3107 outb(iobase1 + ATA_CB_SN, sector);
3108 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
3109 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
3110 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
3111 outb(iobase1 + ATA_CB_CMD, command);
3112
3113 while (1) {
3114 status = inb(iobase1 + ATA_CB_STAT);
3115 if ( !(status & ATA_CB_STAT_BSY) ) break;
3116 }
3117
3118 if (status & ATA_CB_STAT_ERR) {
3119 BX_DEBUG_ATA("ata_cmd_data_out : read error\n");
3120#ifdef VBOX
3121 // Enable interrupts
3122 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3123#endif /* VBOX */
3124 return 2;
3125 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
3126 BX_DEBUG_ATA("ata_cmd_data_out : DRQ not set (status %02x)\n", (unsigned) status);
3127#ifdef VBOX
3128 // Enable interrupts
3129 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3130#endif /* VBOX */
3131 return 3;
3132 }
3133
3134 // FIXME : move seg/off translation here
3135
3136ASM_START
3137 sti ;; enable higher priority interrupts
3138ASM_END
3139
3140 while (1) {
3141
3142ASM_START
3143 push bp
3144 mov bp, sp
3145 mov si, _ata_cmd_data_out.offset + 2[bp]
3146 mov ax, _ata_cmd_data_out.segment + 2[bp]
3147 mov cx, _ata_cmd_data_out.blksize + 2[bp]
3148
3149 ;; adjust if there will be an overrun. 2K max sector size
3150 cmp si, #0xf800 ;;
3151 jbe ata_out_no_adjust
3152
3153ata_out_adjust:
3154 sub si, #0x0800 ;; sub 2 kbytes from offset
3155 add ax, #0x0080 ;; add 2 Kbytes to segment
3156
3157ata_out_no_adjust:
3158 mov es, ax ;; segment in es
3159
3160 mov dx, _ata_cmd_data_out.iobase1 + 2[bp] ;; ATA data write port
3161
3162 mov ah, _ata_cmd_data_out.mode + 2[bp]
3163 cmp ah, #ATA_MODE_PIO32
3164 je ata_out_32
3165
3166ata_out_16:
3167 seg ES
3168 rep
3169 outsw ;; CX words transfered from port(DX) to ES:[SI]
3170 jmp ata_out_done
3171
3172ata_out_32:
3173 seg ES
3174 rep
3175 outsd ;; CX dwords transfered from port(DX) to ES:[SI]
3176
3177ata_out_done:
3178 mov _ata_cmd_data_out.offset + 2[bp], si
3179 mov _ata_cmd_data_out.segment + 2[bp], es
3180 pop bp
3181ASM_END
3182
3183 current++;
3184 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
3185 count--;
3186#ifdef VBOX
3187 while (1) {
3188 status = inb(iobase1 + ATA_CB_STAT);
3189 if ( !(status & ATA_CB_STAT_BSY) ) break;
3190 }
3191#else /* !VBOX */
3192 status = inb(iobase1 + ATA_CB_STAT);
3193#endif /* VBOX */
3194 if (count == 0) {
3195 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3196 != ATA_CB_STAT_RDY ) {
3197 BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n", (unsigned) status);
3198#ifdef VBOX
3199 // Enable interrupts
3200 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3201#endif /* VBOX */
3202 return 6;
3203 }
3204 break;
3205 }
3206 else {
3207 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3208 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3209 BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n", (unsigned) status);
3210#ifdef VBOX
3211 // Enable interrupts
3212 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3213#endif /* VBOX */
3214 return 7;
3215 }
3216 continue;
3217 }
3218 }
3219 // Enable interrupts
3220 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3221 return 0;
3222}
3223
3224// ---------------------------------------------------------------------------
3225// ATA/ATAPI driver : execute a packet command
3226// ---------------------------------------------------------------------------
3227 // returns
3228 // 0 : no error
3229 // 1 : error in parameters
3230 // 2 : BUSY bit set
3231 // 3 : error
3232 // 4 : not ready
3233Bit16u ata_cmd_packet(device, cmdlen, cmdseg, cmdoff, header, length, inout, bufseg, bufoff)
3234Bit8u cmdlen,inout;
3235Bit16u device,cmdseg, cmdoff, bufseg, bufoff;
3236Bit16u header;
3237Bit32u length;
3238{
3239 Bit16u ebda_seg=read_word(0x0040,0x000E);
3240 Bit16u iobase1, iobase2;
3241 Bit16u lcount, lbefore, lafter, count;
3242 Bit8u channel, slave;
3243 Bit8u status, mode, lmode;
3244 Bit32u total, transfer;
3245
3246 channel = device / 2;
3247 slave = device % 2;
3248
3249 // Data out is not supported yet
3250 if (inout == ATA_DATA_OUT) {
3251 BX_INFO("ata_cmd_packet: DATA_OUT not supported yet\n");
3252 return 1;
3253 }
3254
3255 // The header length must be even
3256 if (header & 1) {
3257 BX_DEBUG_ATA("ata_cmd_packet : header must be even (%04x)\n",header);
3258 return 1;
3259 }
3260
3261 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
3262 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
3263 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
3264 transfer= 0L;
3265
3266 if (cmdlen < 12) cmdlen=12;
3267 if (cmdlen > 12) cmdlen=16;
3268 cmdlen>>=1;
3269
3270 // Reset count of transferred data
3271 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
3272 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
3273
3274 status = inb(iobase1 + ATA_CB_STAT);
3275 if (status & ATA_CB_STAT_BSY) return 2;
3276
3277 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
3278 // outb(iobase1 + ATA_CB_FR, 0x00);
3279 // outb(iobase1 + ATA_CB_SC, 0x00);
3280 // outb(iobase1 + ATA_CB_SN, 0x00);
3281 outb(iobase1 + ATA_CB_CL, 0xfff0 & 0x00ff);
3282 outb(iobase1 + ATA_CB_CH, 0xfff0 >> 8);
3283 outb(iobase1 + ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
3284 outb(iobase1 + ATA_CB_CMD, ATA_CMD_PACKET);
3285
3286 // Device should ok to receive command
3287 while (1) {
3288 status = inb(iobase1 + ATA_CB_STAT);
3289 if ( !(status & ATA_CB_STAT_BSY) ) break;
3290 }
3291
3292 if (status & ATA_CB_STAT_ERR) {
3293 BX_DEBUG_ATA("ata_cmd_packet : error, status is %02x\n",status);
3294#ifdef VBOX
3295 // Enable interrupts
3296 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3297#endif /* VBOX */
3298 return 3;
3299 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
3300 BX_DEBUG_ATA("ata_cmd_packet : DRQ not set (status %02x)\n", (unsigned) status);
3301#ifdef VBOX
3302 // Enable interrupts
3303 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3304#endif /* VBOX */
3305 return 4;
3306 }
3307
3308 // Normalize address
3309 cmdseg += (cmdoff / 16);
3310 cmdoff %= 16;
3311
3312 // Send command to device
3313ASM_START
3314 sti ;; enable higher priority interrupts
3315
3316 push bp
3317 mov bp, sp
3318
3319 mov si, _ata_cmd_packet.cmdoff + 2[bp]
3320 mov ax, _ata_cmd_packet.cmdseg + 2[bp]
3321 mov cx, _ata_cmd_packet.cmdlen + 2[bp]
3322 mov es, ax ;; segment in es
3323
3324 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data write port
3325
3326 seg ES
3327 rep
3328 outsw ;; CX words transfered from port(DX) to ES:[SI]
3329
3330 pop bp
3331ASM_END
3332
3333 if (inout == ATA_DATA_NO) {
3334 status = inb(iobase1 + ATA_CB_STAT);
3335 }
3336 else {
3337 while (1) {
3338
3339#ifdef VBOX
3340 while (1) {
3341 status = inb(iobase1 + ATA_CB_STAT);
3342 if ( !(status & ATA_CB_STAT_BSY) ) break;
3343 }
3344#else /* VBOX */
3345 status = inb(iobase1 + ATA_CB_STAT);
3346#endif /* VBOX */
3347
3348 // Check if command completed
3349 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_DRQ) ) ==0 ) break;
3350
3351 if (status & ATA_CB_STAT_ERR) {
3352 BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status);
3353#ifdef VBOX
3354 // Enable interrupts
3355 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3356#endif /* VBOX */
3357 return 3;
3358 }
3359
3360 // Device must be ready to send data
3361 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3362 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3363 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", status);
3364#ifdef VBOX
3365 // Enable interrupts
3366 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3367#endif /* VBOX */
3368 return 4;
3369 }
3370
3371 // Normalize address
3372 bufseg += (bufoff / 16);
3373 bufoff %= 16;
3374
3375 // Get the byte count
3376 lcount = ((Bit16u)(inb(iobase1 + ATA_CB_CH))<<8)+inb(iobase1 + ATA_CB_CL);
3377
3378 // adjust to read what we want
3379 if(header>lcount) {
3380 lbefore=lcount;
3381 header-=lcount;
3382 lcount=0;
3383 }
3384 else {
3385 lbefore=header;
3386 header=0;
3387 lcount-=lbefore;
3388 }
3389
3390 if(lcount>length) {
3391 lafter=lcount-length;
3392 lcount=length;
3393 length=0;
3394 }
3395 else {
3396 lafter=0;
3397 length-=lcount;
3398 }
3399
3400 // Save byte count
3401 count = lcount;
3402
3403 BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore+lcount+lafter,lbefore,lcount,lafter);
3404 BX_DEBUG_ATA("to 0x%04x:0x%04x\n",bufseg,bufoff);
3405
3406 // If counts not dividable by 4, use 16bits mode
3407 lmode = mode;
3408 if (lbefore & 0x03) lmode=ATA_MODE_PIO16;
3409 if (lcount & 0x03) lmode=ATA_MODE_PIO16;
3410 if (lafter & 0x03) lmode=ATA_MODE_PIO16;
3411
3412 // adds an extra byte if count are odd. before is always even
3413 if (lcount & 0x01) {
3414 lcount+=1;
3415 if ((lafter > 0) && (lafter & 0x01)) {
3416 lafter-=1;
3417 }
3418 }
3419
3420 if (lmode == ATA_MODE_PIO32) {
3421 lcount>>=2; lbefore>>=2; lafter>>=2;
3422 }
3423 else {
3424 lcount>>=1; lbefore>>=1; lafter>>=1;
3425 }
3426
3427 ; // FIXME bcc bug
3428
3429ASM_START
3430 push bp
3431 mov bp, sp
3432
3433 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data read port
3434
3435 mov cx, _ata_cmd_packet.lbefore + 2[bp]
3436 jcxz ata_packet_no_before
3437
3438 mov ah, _ata_cmd_packet.lmode + 2[bp]
3439 cmp ah, #ATA_MODE_PIO32
3440 je ata_packet_in_before_32
3441
3442ata_packet_in_before_16:
3443 in ax, dx
3444 loop ata_packet_in_before_16
3445 jmp ata_packet_no_before
3446
3447ata_packet_in_before_32:
3448 push eax
3449ata_packet_in_before_32_loop:
3450 in eax, dx
3451 loop ata_packet_in_before_32_loop
3452 pop eax
3453
3454ata_packet_no_before:
3455 mov cx, _ata_cmd_packet.lcount + 2[bp]
3456 jcxz ata_packet_after
3457
3458 mov di, _ata_cmd_packet.bufoff + 2[bp]
3459 mov ax, _ata_cmd_packet.bufseg + 2[bp]
3460 mov es, ax
3461
3462 mov ah, _ata_cmd_packet.lmode + 2[bp]
3463 cmp ah, #ATA_MODE_PIO32
3464 je ata_packet_in_32
3465
3466ata_packet_in_16:
3467 rep
3468 insw ;; CX words transfered tp port(DX) to ES:[DI]
3469 jmp ata_packet_after
3470
3471ata_packet_in_32:
3472 rep
3473 insd ;; CX dwords transfered to port(DX) to ES:[DI]
3474
3475ata_packet_after:
3476 mov cx, _ata_cmd_packet.lafter + 2[bp]
3477 jcxz ata_packet_done
3478
3479 mov ah, _ata_cmd_packet.lmode + 2[bp]
3480 cmp ah, #ATA_MODE_PIO32
3481 je ata_packet_in_after_32
3482
3483ata_packet_in_after_16:
3484 in ax, dx
3485 loop ata_packet_in_after_16
3486 jmp ata_packet_done
3487
3488ata_packet_in_after_32:
3489 push eax
3490ata_packet_in_after_32_loop:
3491 in eax, dx
3492 loop ata_packet_in_after_32_loop
3493 pop eax
3494
3495ata_packet_done:
3496 pop bp
3497ASM_END
3498
3499 // Compute new buffer address
3500 bufoff += count;
3501
3502 // Save transferred bytes count
3503 transfer += count;
3504 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,transfer);
3505 }
3506 }
3507
3508 // Final check, device must be ready
3509 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3510 != ATA_CB_STAT_RDY ) {
3511 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", (unsigned) status);
3512#ifdef VBOX
3513 // Enable interrupts
3514 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3515#endif /* VBOX */
3516 return 4;
3517 }
3518
3519 // Enable interrupts
3520 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3521 return 0;
3522}
3523
3524// ---------------------------------------------------------------------------
3525// End of ATA/ATAPI Driver
3526// ---------------------------------------------------------------------------
3527
3528// ---------------------------------------------------------------------------
3529// Start of ATA/ATAPI generic functions
3530// ---------------------------------------------------------------------------
3531
3532 Bit16u
3533atapi_get_sense(device)
3534 Bit16u device;
3535{
3536 Bit8u atacmd[12];
3537 Bit8u buffer[16];
3538 Bit8u i;
3539
3540 memsetb(get_SS(),atacmd,0,12);
3541
3542 // Request SENSE
3543 atacmd[0]=0x03;
3544 atacmd[4]=0x20;
3545 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 16L, ATA_DATA_IN, get_SS(), buffer) != 0)
3546 return 0x0002;
3547
3548 if ((buffer[0] & 0x7e) == 0x70) {
3549 return (((Bit16u)buffer[2]&0x0f)*0x100)+buffer[12];
3550 }
3551
3552 return 0;
3553}
3554
3555 Bit16u
3556atapi_is_ready(device)
3557 Bit16u device;
3558{
3559 Bit8u atacmd[12];
3560 Bit8u buffer[];
3561
3562 memsetb(get_SS(),atacmd,0,12);
3563
3564 // Test Unit Ready
3565 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3566 return 0x000f;
3567
3568 if (atapi_get_sense(device) !=0 ) {
3569 memsetb(get_SS(),atacmd,0,12);
3570
3571 // try to send Test Unit Ready again
3572 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3573 return 0x000f;
3574
3575 return atapi_get_sense(device);
3576 }
3577 return 0;
3578}
3579
3580 Bit16u
3581atapi_is_cdrom(device)
3582 Bit8u device;
3583{
3584 Bit16u ebda_seg=read_word(0x0040,0x000E);
3585
3586 if (device >= BX_MAX_ATA_DEVICES)
3587 return 0;
3588
3589 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_ATAPI)
3590 return 0;
3591
3592 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].device) != ATA_DEVICE_CDROM)
3593 return 0;
3594
3595 return 1;
3596}
3597
3598// ---------------------------------------------------------------------------
3599// End of ATA/ATAPI generic functions
3600// ---------------------------------------------------------------------------
3601
3602#endif // BX_USE_ATADRV
3603
3604#if BX_ELTORITO_BOOT
3605
3606// ---------------------------------------------------------------------------
3607// Start of El-Torito boot functions
3608// ---------------------------------------------------------------------------
3609
3610 void
3611cdemu_init()
3612{
3613 Bit16u ebda_seg=read_word(0x0040,0x000E);
3614
3615 // the only important data is this one for now
3616 write_byte(ebda_seg,&EbdaData->cdemu.active,0x00);
3617}
3618
3619 Bit8u
3620cdemu_isactive()
3621{
3622 Bit16u ebda_seg=read_word(0x0040,0x000E);
3623
3624 return(read_byte(ebda_seg,&EbdaData->cdemu.active));
3625}
3626
3627 Bit8u
3628cdemu_emulated_drive()
3629{
3630 Bit16u ebda_seg=read_word(0x0040,0x000E);
3631
3632 return(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
3633}
3634
3635static char isotag[6]="CD001";
3636static char eltorito[24]="EL TORITO SPECIFICATION";
3637//
3638// Returns ah: emulated drive, al: error code
3639//
3640 Bit16u
3641cdrom_boot()
3642{
3643 Bit16u ebda_seg=read_word(0x0040,0x000E);
3644 Bit8u atacmd[12], buffer[2048];
3645 Bit32u lba;
3646 Bit16u boot_segment, nbsectors, i, error;
3647 Bit8u device;
3648#ifdef VBOX
3649 Bit8u read_try;
3650#endif /* VBOX */
3651
3652 // Find out the first cdrom
3653 for (device=0; device<BX_MAX_ATA_DEVICES;device++) {
3654 if (atapi_is_cdrom(device)) break;
3655 }
3656
3657 // if not found
3658 if(device >= BX_MAX_ATA_DEVICES) return 2;
3659
3660 // Read the Boot Record Volume Descriptor
3661 memsetb(get_SS(),atacmd,0,12);
3662 atacmd[0]=0x28; // READ command
3663 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3664 atacmd[8]=(0x01 & 0x00ff); // Sectors
3665 atacmd[2]=(0x11 & 0xff000000) >> 24; // LBA
3666 atacmd[3]=(0x11 & 0x00ff0000) >> 16;
3667 atacmd[4]=(0x11 & 0x0000ff00) >> 8;
3668 atacmd[5]=(0x11 & 0x000000ff);
3669#ifdef VBOX
3670 for (read_try = 0; read_try <= 4; read_try++)
3671 {
3672 error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer);
3673 if (!error)
3674 break;
3675 }
3676 if (error)
3677 return 3;
3678#else /* !VBOX */
3679 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3680 return 3;
3681#endif /* !VBOX */
3682
3683 // Validity checks
3684 if(buffer[0]!=0)return 4;
3685 for(i=0;i<5;i++){
3686 if(buffer[1+i]!=read_byte(0xf000,&isotag[i]))return 5;
3687 }
3688 for(i=0;i<23;i++)
3689 if(buffer[7+i]!=read_byte(0xf000,&eltorito[i]))return 6;
3690
3691 // ok, now we calculate the Boot catalog address
3692 lba=buffer[0x4A]*0x1000000+buffer[0x49]*0x10000+buffer[0x48]*0x100+buffer[0x47];
3693
3694 // And we read the Boot Catalog
3695 memsetb(get_SS(),atacmd,0,12);
3696 atacmd[0]=0x28; // READ command
3697 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3698 atacmd[8]=(0x01 & 0x00ff); // Sectors
3699 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3700 atacmd[3]=(lba & 0x00ff0000) >> 16;
3701 atacmd[4]=(lba & 0x0000ff00) >> 8;
3702 atacmd[5]=(lba & 0x000000ff);
3703 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3704 return 7;
3705
3706 // Validation entry
3707 if(buffer[0x00]!=0x01)return 8; // Header
3708 if(buffer[0x01]!=0x00)return 9; // Platform
3709 if(buffer[0x1E]!=0x55)return 10; // key 1
3710 if(buffer[0x1F]!=0xAA)return 10; // key 2
3711
3712 // Initial/Default Entry
3713 if(buffer[0x20]!=0x88)return 11; // Bootable
3714
3715 write_byte(ebda_seg,&EbdaData->cdemu.media,buffer[0x21]);
3716 if(buffer[0x21]==0){
3717 // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
3718 // Win2000 cd boot needs to know it booted from cd
3719 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0xE0);
3720 }
3721 else if(buffer[0x21]<4)
3722 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x00);
3723 else
3724 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x80);
3725
3726 write_byte(ebda_seg,&EbdaData->cdemu.controller_index,device/2);
3727 write_byte(ebda_seg,&EbdaData->cdemu.device_spec,device%2);
3728
3729 boot_segment=buffer[0x23]*0x100+buffer[0x22];
3730 if(boot_segment==0x0000)boot_segment=0x07C0;
3731
3732 write_word(ebda_seg,&EbdaData->cdemu.load_segment,boot_segment);
3733 write_word(ebda_seg,&EbdaData->cdemu.buffer_segment,0x0000);
3734
3735 nbsectors=buffer[0x27]*0x100+buffer[0x26];
3736 write_word(ebda_seg,&EbdaData->cdemu.sector_count,nbsectors);
3737
3738 lba=buffer[0x2B]*0x1000000+buffer[0x2A]*0x10000+buffer[0x29]*0x100+buffer[0x28];
3739 write_dword(ebda_seg,&EbdaData->cdemu.ilba,lba);
3740
3741 // And we read the image in memory
3742 memsetb(get_SS(),atacmd,0,12);
3743 atacmd[0]=0x28; // READ command
3744 atacmd[7]=((1+(nbsectors-1)/4) & 0xff00) >> 8; // Sectors
3745 atacmd[8]=((1+(nbsectors-1)/4) & 0x00ff); // Sectors
3746 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3747 atacmd[3]=(lba & 0x00ff0000) >> 16;
3748 atacmd[4]=(lba & 0x0000ff00) >> 8;
3749 atacmd[5]=(lba & 0x000000ff);
3750 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, nbsectors*512L, ATA_DATA_IN, boot_segment,0)) != 0)
3751 return 12;
3752
3753 // Remember the media type
3754 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
3755 case 0x01: // 1.2M floppy
3756 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,15);
3757 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3758 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3759 break;
3760 case 0x02: // 1.44M floppy
3761 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,18);
3762 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3763 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3764 break;
3765 case 0x03: // 2.88M floppy
3766 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,36);
3767 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3768 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3769 break;
3770 case 0x04: // Harddrive
3771 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,read_byte(boot_segment,446+6)&0x3f);
3772 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,
3773 (read_byte(boot_segment,446+6)<<2) + read_byte(boot_segment,446+7) + 1);
3774 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,read_byte(boot_segment,446+5) + 1);
3775 break;
3776 }
3777
3778 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0) {
3779 // Increase bios installed hardware number of devices
3780 if(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)==0x00)
3781 write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
3782 else
3783 write_byte(ebda_seg, &EbdaData->ata.hdcount, read_byte(ebda_seg, &EbdaData->ata.hdcount) + 1);
3784 }
3785
3786
3787 // everything is ok, so from now on, the emulation is active
3788 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0)
3789 write_byte(ebda_seg,&EbdaData->cdemu.active,0x01);
3790
3791 // return the boot drive + no error
3792 return (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)*0x100)+0;
3793}
3794
3795// ---------------------------------------------------------------------------
3796// End of El-Torito boot functions
3797// ---------------------------------------------------------------------------
3798#endif // BX_ELTORITO_BOOT
3799
3800#ifdef VBOX_WITH_SCSI
3801# include "scsi.c"
3802#endif
3803
3804 void
3805int14_function(regs, ds, iret_addr)
3806 pusha_regs_t regs; // regs pushed from PUSHA instruction
3807 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
3808 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
3809{
3810 Bit16u addr,timer,val16;
3811 Bit8u timeout;
3812
3813 ASM_START
3814 sti
3815 ASM_END
3816
3817 addr = read_word(0x0040, (regs.u.r16.dx << 1));
3818 timeout = read_byte(0x0040, 0x007C + regs.u.r16.dx);
3819 if ((regs.u.r16.dx < 4) && (addr > 0)) {
3820 switch (regs.u.r8.ah) {
3821 case 0:
3822 outb(addr+3, inb(addr+3) | 0x80);
3823 if (regs.u.r8.al & 0xE0 == 0) {
3824 outb(addr, 0x17);
3825 outb(addr+1, 0x04);
3826 } else {
3827 val16 = 0x600 >> ((regs.u.r8.al & 0xE0) >> 5);
3828 outb(addr, val16 & 0xFF);
3829 outb(addr+1, val16 >> 8);
3830 }
3831 outb(addr+3, regs.u.r8.al & 0x1F);
3832 regs.u.r8.ah = inb(addr+5);
3833 regs.u.r8.al = inb(addr+6);
3834 ClearCF(iret_addr.flags);
3835 break;
3836 case 1:
3837 timer = read_word(0x0040, 0x006C);
3838 while (((inb(addr+5) & 0x60) != 0x60) && (timeout)) {
3839 val16 = read_word(0x0040, 0x006C);
3840 if (val16 != timer) {
3841 timer = val16;
3842 timeout--;
3843 }
3844 }
3845 if (timeout) outb(addr, regs.u.r8.al);
3846 regs.u.r8.ah = inb(addr+5);
3847 if (!timeout) regs.u.r8.ah |= 0x80;
3848 ClearCF(iret_addr.flags);
3849 break;
3850 case 2:
3851 timer = read_word(0x0040, 0x006C);
3852 while (((inb(addr+5) & 0x01) == 0) && (timeout)) {
3853 val16 = read_word(0x0040, 0x006C);
3854 if (val16 != timer) {
3855 timer = val16;
3856 timeout--;
3857 }
3858 }
3859 if (timeout) {
3860 regs.u.r8.ah = 0;
3861 regs.u.r8.al = inb(addr);
3862 } else {
3863 regs.u.r8.ah = inb(addr+5);
3864 }
3865 ClearCF(iret_addr.flags);
3866 break;
3867 case 3:
3868 regs.u.r8.ah = inb(addr+5);
3869 regs.u.r8.al = inb(addr+6);
3870 ClearCF(iret_addr.flags);
3871 break;
3872 default:
3873 SetCF(iret_addr.flags); // Unsupported
3874 }
3875 } else {
3876 SetCF(iret_addr.flags); // Unsupported
3877 }
3878}
3879
3880 void
3881int15_function(regs, ES, DS, FLAGS)
3882 pusha_regs_t regs; // REGS pushed via pusha
3883 Bit16u ES, DS, FLAGS;
3884{
3885 Bit16u ebda_seg=read_word(0x0040,0x000E);
3886 bx_bool prev_a20_enable;
3887 Bit16u base15_00;
3888 Bit8u base23_16;
3889 Bit16u ss;
3890 Bit16u BX,CX,DX;
3891
3892 Bit16u bRegister;
3893 Bit8u irqDisable;
3894
3895BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
3896
3897 switch (regs.u.r8.ah) {
3898#ifdef VBOX
3899 case 0x00: /* assorted functions */
3900 if (regs.u.r8.al != 0xc0)
3901 goto undecoded;
3902 /* GRUB calls int15 with ax=0x00c0 to get the ROM configuration table,
3903 * which we don't support, but logging that event is annoying. In fact
3904 * it is likely that they just misread some specs, because there is a
3905 * int15 BIOS function AH=0xc0 which sounds quite similar to what GRUB
3906 * wants to achieve. */
3907 SET_CF();
3908 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3909 break;
3910#endif
3911 case 0x24: /* A20 Control */
3912 switch (regs.u.r8.al) {
3913 case 0x00:
3914 set_enable_a20(0);
3915 CLEAR_CF();
3916 regs.u.r8.ah = 0;
3917 break;
3918 case 0x01:
3919 set_enable_a20(1);
3920 CLEAR_CF();
3921 regs.u.r8.ah = 0;
3922 break;
3923 case 0x02:
3924 regs.u.r8.al = (inb(0x92) >> 1) & 0x01;
3925 CLEAR_CF();
3926 regs.u.r8.ah = 0;
3927 break;
3928 case 0x03:
3929 CLEAR_CF();
3930 regs.u.r8.ah = 0;
3931 regs.u.r16.bx = 3;
3932 break;
3933 default:
3934 BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs.u.r8.al);
3935 SET_CF();
3936 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3937 }
3938 break;
3939
3940 case 0x41:
3941 SET_CF();
3942 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3943 break;
3944
3945 case 0x4f:
3946 /* keyboard intercept */
3947#if BX_CPU < 2
3948 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3949#else
3950 // nop
3951#endif
3952 SET_CF();
3953 break;
3954
3955 case 0x52: // removable media eject
3956 CLEAR_CF();
3957 regs.u.r8.ah = 0; // "ok ejection may proceed"
3958 break;
3959
3960 case 0x83: {
3961 if( regs.u.r8.al == 0 ) {
3962 // Set Interval requested.
3963 if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
3964 // Interval not already set.
3965 write_byte( 0x40, 0xA0, 1 ); // Set status byte.
3966 write_word( 0x40, 0x98, ES ); // Byte location, segment
3967 write_word( 0x40, 0x9A, regs.u.r16.bx ); // Byte location, offset
3968 write_word( 0x40, 0x9C, regs.u.r16.dx ); // Low word, delay
3969 write_word( 0x40, 0x9E, regs.u.r16.cx ); // High word, delay.
3970 CLEAR_CF( );
3971 irqDisable = inb( 0xA1 );
3972 outb( 0xA1, irqDisable & 0xFE );
3973 bRegister = inb_cmos( 0xB ); // Unmask IRQ8 so INT70 will get through.
3974 outb_cmos( 0xB, bRegister | 0x40 ); // Turn on the Periodic Interrupt timer
3975 } else {
3976 // Interval already set.
3977 BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
3978 SET_CF();
3979 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3980 }
3981 } else if( regs.u.r8.al == 1 ) {
3982 // Clear Interval requested
3983 write_byte( 0x40, 0xA0, 0 ); // Clear status byte
3984 CLEAR_CF( );
3985 bRegister = inb_cmos( 0xB );
3986 outb_cmos( 0xB, bRegister & ~0x40 ); // Turn off the Periodic Interrupt timer
3987 } else {
3988 BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
3989 SET_CF();
3990 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3991 regs.u.r8.al--;
3992 }
3993
3994 break;
3995 }
3996
3997 case 0x87:
3998#if BX_CPU < 3
3999# error "Int15 function 87h not supported on < 80386"
4000#endif
4001 // +++ should probably have descriptor checks
4002 // +++ should have exception handlers
4003
4004 // turn off interrupts
4005ASM_START
4006 cli
4007ASM_END
4008
4009 prev_a20_enable = set_enable_a20(1); // enable A20 line
4010
4011 // 128K max of transfer on 386+ ???
4012 // source == destination ???
4013
4014 // ES:SI points to descriptor table
4015 // offset use initially comments
4016 // ==============================================
4017 // 00..07 Unused zeros Null descriptor
4018 // 08..0f GDT zeros filled in by BIOS
4019 // 10..17 source ssssssss source of data
4020 // 18..1f dest dddddddd destination of data
4021 // 20..27 CS zeros filled in by BIOS
4022 // 28..2f SS zeros filled in by BIOS
4023
4024 //es:si
4025 //eeee0
4026 //0ssss
4027 //-----
4028
4029// check for access rights of source & dest here
4030
4031 // Initialize GDT descriptor
4032 base15_00 = (ES << 4) + regs.u.r16.si;
4033 base23_16 = ES >> 12;
4034 if (base15_00 < (ES<<4))
4035 base23_16++;
4036 write_word(ES, regs.u.r16.si+0x08+0, 47); // limit 15:00 = 6 * 8bytes/descriptor
4037 write_word(ES, regs.u.r16.si+0x08+2, base15_00);// base 15:00
4038 write_byte(ES, regs.u.r16.si+0x08+4, base23_16);// base 23:16
4039 write_byte(ES, regs.u.r16.si+0x08+5, 0x93); // access
4040 write_word(ES, regs.u.r16.si+0x08+6, 0x0000); // base 31:24/reserved/limit 19:16
4041
4042 // Initialize CS descriptor
4043 write_word(ES, regs.u.r16.si+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
4044 write_word(ES, regs.u.r16.si+0x20+2, 0x0000);// base 15:00
4045 write_byte(ES, regs.u.r16.si+0x20+4, 0x000f);// base 23:16
4046 write_byte(ES, regs.u.r16.si+0x20+5, 0x9b); // access
4047 write_word(ES, regs.u.r16.si+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
4048
4049 // Initialize SS descriptor
4050 ss = get_SS();
4051 base15_00 = ss << 4;
4052 base23_16 = ss >> 12;
4053 write_word(ES, regs.u.r16.si+0x28+0, 0xffff); // limit 15:00 = normal 64K limit
4054 write_word(ES, regs.u.r16.si+0x28+2, base15_00);// base 15:00
4055 write_byte(ES, regs.u.r16.si+0x28+4, base23_16);// base 23:16
4056 write_byte(ES, regs.u.r16.si+0x28+5, 0x93); // access
4057 write_word(ES, regs.u.r16.si+0x28+6, 0x0000); // base 31:24/reserved/limit 19:16
4058
4059 CX = regs.u.r16.cx;
4060ASM_START
4061 // Compile generates locals offset info relative to SP.
4062 // Get CX (word count) from stack.
4063 mov bx, sp
4064 SEG SS
4065 mov cx, _int15_function.CX [bx]
4066
4067 // since we need to set SS:SP, save them to the BDA
4068 // for future restore
4069 push eax
4070 xor eax, eax
4071 mov ds, ax
4072 mov 0x0469, ss
4073 mov 0x0467, sp
4074
4075 SEG ES
4076 lgdt [si + 0x08]
4077 SEG CS
4078 lidt [pmode_IDT_info]
4079 ;; perhaps do something with IDT here
4080
4081 ;; set PE bit in CR0
4082 mov eax, cr0
4083 or al, #0x01
4084 mov cr0, eax
4085 ;; far jump to flush CPU queue after transition to protected mode
4086 JMP_AP(0x0020, protected_mode)
4087
4088protected_mode:
4089 ;; GDT points to valid descriptor table, now load SS, DS, ES
4090 mov ax, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
4091 mov ss, ax
4092 mov ax, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
4093 mov ds, ax
4094 mov ax, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
4095 mov es, ax
4096 xor si, si
4097 xor di, di
4098 cld
4099 rep
4100 movsw ;; move CX words from DS:SI to ES:DI
4101
4102 ;; make sure DS and ES limits are 64KB
4103 mov ax, #0x28
4104 mov ds, ax
4105 mov es, ax
4106
4107 ;; reset PG bit in CR0 ???
4108 mov eax, cr0
4109 and al, #0xFE
4110 mov cr0, eax
4111
4112 ;; far jump to flush CPU queue after transition to real mode
4113 JMP_AP(0xf000, real_mode)
4114
4115real_mode:
4116 ;; restore IDT to normal real-mode defaults
4117 SEG CS
4118 lidt [rmode_IDT_info]
4119
4120 // restore SS:SP from the BDA
4121 xor ax, ax
4122 mov ds, ax
4123 mov ss, 0x0469
4124 mov sp, 0x0467
4125 pop eax
4126ASM_END
4127
4128 set_enable_a20(prev_a20_enable);
4129
4130 // turn back on interrupts
4131ASM_START
4132 sti
4133ASM_END
4134
4135 regs.u.r8.ah = 0;
4136 CLEAR_CF();
4137 break;
4138
4139
4140 case 0x88:
4141 // Get the amount of extended memory (above 1M)
4142#if BX_CPU < 2
4143 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4144 SET_CF();
4145#else
4146 regs.u.r8.al = inb_cmos(0x30);
4147 regs.u.r8.ah = inb_cmos(0x31);
4148
4149 // According to Ralf Brown's interrupt the limit should be 15M,
4150 // but real machines mostly return max. 63M.
4151 if(regs.u.r16.ax > 0xffc0)
4152 regs.u.r16.ax = 0xffc0;
4153
4154 CLEAR_CF();
4155#endif
4156 break;
4157
4158#ifdef VBOX
4159 case 0x89:
4160 // Switch to Protected Mode.
4161 // ES:DI points to user-supplied GDT
4162 // BH/BL contains starting interrupt numbers for PIC0/PIC1
4163 // This subfunction does not return!
4164
4165// turn off interrupts
4166ASM_START
4167 cli
4168ASM_END
4169
4170 set_enable_a20(1); // enable A20 line; we're supposed to fail if that fails
4171
4172 // Initialize CS descriptor for BIOS
4173 write_word(ES, regs.u.r16.si+0x38+0, 0xffff);// limit 15:00 = normal 64K limit
4174 write_word(ES, regs.u.r16.si+0x38+2, 0x0000);// base 15:00
4175 write_byte(ES, regs.u.r16.si+0x38+4, 0x000f);// base 23:16 (hardcoded to f000:0000)
4176 write_byte(ES, regs.u.r16.si+0x38+5, 0x9b); // access
4177 write_word(ES, regs.u.r16.si+0x38+6, 0x0000);// base 31:24/reserved/limit 19:16
4178
4179 BX = regs.u.r16.bx;
4180ASM_START
4181 // Compiler generates locals offset info relative to SP.
4182 // Get BX (PIC offsets) from stack.
4183 mov bx, sp
4184 SEG SS
4185 mov bx, _int15_function.BX [bx]
4186
4187 // Program PICs
4188 mov al, #0x11 ; send initialisation commands
4189 out 0x20, al
4190 out 0xa0, al
4191 mov al, bh
4192 out 0x21, al
4193 mov al, bl
4194 out 0xa1, al
4195 mov al, #0x04
4196 out 0x21, al
4197 mov al, #0x02
4198 out 0xa1, al
4199 mov al, #0x01
4200 out 0x21, al
4201 out 0xa1, al
4202 mov al, #0xff ; mask all IRQs, user must re-enable
4203 out 0x21, al
4204 out 0xa1, al
4205
4206 // Load GDT and IDT from supplied data
4207 SEG ES
4208 lgdt [si + 0x08]
4209 SEG ES
4210 lidt [si + 0x10]
4211
4212 // set PE bit in CR0
4213 mov eax, cr0
4214 or al, #0x01
4215 mov cr0, eax
4216 // far jump to flush CPU queue after transition to protected mode
4217 JMP_AP(0x0038, protmode_switch)
4218
4219protmode_switch:
4220 ;; GDT points to valid descriptor table, now load SS, DS, ES
4221 mov ax, #0x28
4222 mov ss, ax
4223 mov ax, #0x18
4224 mov ds, ax
4225 mov ax, #0x20
4226 mov es, ax
4227
4228 // unwind the stack - this will break if calling sequence changes!
4229 mov sp,bp
4230 add sp,#4 ; skip return address
4231 popa ; restore regs
4232 pop ax ; skip saved es
4233 pop ax ; skip saved ds
4234 pop ax ; skip saved flags
4235
4236 // return to caller - note that we do not use IRET because
4237 // we cannot enable interrupts
4238 pop cx ; get return offset
4239 pop ax ; skip return segment
4240 pop ax ; skip flags
4241 mov ax, #0x30 ; ah must be 0 on successful exit
4242 push ax
4243 push cx ; re-create modified ret address on stack
4244 retf
4245
4246ASM_END
4247
4248 break;
4249#endif /* VBOX */
4250
4251 case 0x90:
4252 /* Device busy interrupt. Called by Int 16h when no key available */
4253 break;
4254
4255 case 0x91:
4256 /* Interrupt complete. Called by Int 16h when key becomes available */
4257 break;
4258
4259 case 0xbf:
4260 BX_INFO("*** int 15h function AH=bf not yet supported!\n");
4261 SET_CF();
4262 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4263 break;
4264
4265 case 0xC0:
4266#if 0
4267 SET_CF();
4268 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4269 break;
4270#endif
4271 CLEAR_CF();
4272 regs.u.r8.ah = 0;
4273 regs.u.r16.bx = BIOS_CONFIG_TABLE;
4274 ES = 0xF000;
4275 break;
4276
4277 case 0xc1:
4278 ES = ebda_seg;
4279 CLEAR_CF();
4280 break;
4281
4282 case 0xd8:
4283 bios_printf(BIOS_PRINTF_DEBUG, "EISA BIOS not present\n");
4284 SET_CF();
4285 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4286 break;
4287
4288#ifdef VBOX
4289 /* Make the BIOS warning for pretty much every Linux kernel start
4290 * disappear - it calls with ax=0xe980 to figure out SMI info. */
4291 case 0xe9: /* SMI functions (SpeedStep and similar things) */
4292 SET_CF();
4293 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4294 break;
4295 case 0xec: /* AMD64 target operating mode callback */
4296 if (regs.u.r8.al != 0)
4297 goto undecoded;
4298 regs.u.r8.ah = 0;
4299 if (regs.u.r8.bl >= 1 && regs.u.r8.bl <= 3)
4300 CLEAR_CF(); /* Accepted value. */
4301 else
4302 SET_CF(); /* Reserved, error. */
4303 break;
4304undecoded:
4305#endif /* VBOX */
4306 default:
4307 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4308 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4309 SET_CF();
4310 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4311 break;
4312 }
4313}
4314
4315#if BX_USE_PS2_MOUSE
4316 void
4317int15_function_mouse(regs, ES, DS, FLAGS)
4318 pusha_regs_t regs; // REGS pushed via pusha
4319 Bit16u ES, DS, FLAGS;
4320{
4321 Bit16u ebda_seg=read_word(0x0040,0x000E);
4322 Bit8u mouse_flags_1, mouse_flags_2;
4323 Bit16u mouse_driver_seg;
4324 Bit16u mouse_driver_offset;
4325 Bit8u mouse_cmd;
4326 Bit8u ret, mouse_data1, mouse_data2, mouse_data3;
4327
4328BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4329
4330 switch (regs.u.r8.ah) {
4331 case 0xC2:
4332 // Return Codes status in AH
4333 // =========================
4334 // 00: success
4335 // 01: invalid subfunction (AL > 7)
4336 // 02: invalid input value (out of allowable range)
4337 // 03: interface error
4338 // 04: resend command received from mouse controller,
4339 // device driver should attempt command again
4340 // 05: cannot enable mouse, since no far call has been installed
4341 // 80/86: mouse service not implemented
4342
4343 if (regs.u.r8.al > 7) {
4344BX_DEBUG_INT15("unsupported subfn\n");
4345 // invalid function
4346 SET_CF();
4347 regs.u.r8.ah = 1;
4348 break;
4349 }
4350
4351 // Valid subfn; disable AUX input and IRQ12, assume no error
4352 set_kbd_command_byte(0x65);
4353 CLEAR_CF();
4354 regs.u.r8.ah = 0;
4355
4356 switch (regs.u.r8.al) {
4357 case 0: // Disable/Enable Mouse
4358BX_DEBUG_INT15("case 0: ");
4359 if (regs.u.r8.bh > 1) {
4360 BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs.u.r8.bh);
4361 // invalid subfunction
4362 SET_CF();
4363 regs.u.r8.ah = 1;
4364 break;
4365 }
4366 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4367 if ( (mouse_flags_2 & 0x80) == 0 ) {
4368 BX_DEBUG_INT15("INT 15h C2 Enable/Disable Mouse, no far call handler\n");
4369 SET_CF();
4370 regs.u.r8.ah = 5; // no far call installed
4371 break;
4372 }
4373 if (regs.u.r8.bh == 0) {
4374BX_DEBUG_INT15("Disable Mouse\n");
4375 mouse_cmd = 0xF5; // disable mouse command
4376 } else {
4377BX_DEBUG_INT15("Enable Mouse\n");
4378 mouse_cmd = 0xF4; // enable mouse command
4379 }
4380
4381 ret = send_to_mouse_ctrl(mouse_cmd); // disable mouse command
4382 if (ret == 0) {
4383 ret = get_mouse_data(&mouse_data1);
4384 if ( (ret == 0) || (mouse_data1 == 0xFA) ) {
4385 // success
4386 break;
4387 }
4388 }
4389
4390 // interface error
4391 SET_CF();
4392 regs.u.r8.ah = 3;
4393 break;
4394
4395 case 5: // Initialize Mouse
4396 // Valid package sizes are 1 to 8
4397 if ( (regs.u.r8.bh < 1) || (regs.u.r8.bh > 8) ) {
4398 SET_CF();
4399 regs.u.r8.ah = 2; // invalid input
4400 break;
4401 }
4402 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4403 mouse_flags_2 = (mouse_flags_2 & 0xf8) | (regs.u.r8.bh - 1);
4404 write_byte(ebda_seg, 0x0027, mouse_flags_2);
4405 // fall through!
4406
4407 case 1: // Reset Mouse
4408BX_DEBUG_INT15("case 1 or 5:\n");
4409 // clear current package byte index
4410 mouse_flags_1 = read_byte(ebda_seg, 0x0026);
4411 mouse_flags_1 = mouse_flags_1 & 0xf8;
4412 write_byte(ebda_seg, 0x0026, mouse_flags_1);
4413 ret = send_to_mouse_ctrl(0xFF); // reset mouse command
4414 if (ret == 0) {
4415 ret = get_mouse_data(&mouse_data3);
4416 // if no mouse attached, it will return RESEND
4417 if (mouse_data3 == 0xfe) {
4418 SET_CF();
4419 regs.u.r8.ah = 4; // resend
4420 break;
4421 }
4422 if (mouse_data3 != 0xfa)
4423 BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3);
4424 if ( ret == 0 ) {
4425 ret = get_mouse_data(&mouse_data1);
4426 if ( ret == 0 ) {
4427 ret = get_mouse_data(&mouse_data2);
4428 if ( ret == 0 ) {
4429 // success
4430 regs.u.r8.bl = mouse_data1;
4431 regs.u.r8.bh = mouse_data2;
4432 break;
4433 }
4434 }
4435 }
4436 }
4437
4438 // interface error
4439 SET_CF();
4440 regs.u.r8.ah = 3;
4441 break;
4442
4443 case 2: // Set Sample Rate
4444BX_DEBUG_INT15("case 2:\n");
4445 switch (regs.u.r8.bh) {
4446 case 0: mouse_data1 = 10; break; // 10 reports/sec
4447 case 1: mouse_data1 = 20; break; // 20 reports/sec
4448 case 2: mouse_data1 = 40; break; // 40 reports/sec
4449 case 3: mouse_data1 = 60; break; // 60 reports/sec
4450 case 4: mouse_data1 = 80; break; // 80 reports/sec
4451 case 5: mouse_data1 = 100; break; // 100 reports/sec (default)
4452 case 6: mouse_data1 = 200; break; // 200 reports/sec
4453 default: mouse_data1 = 0;
4454 }
4455 if (mouse_data1 > 0) {
4456 ret = send_to_mouse_ctrl(0xF3); // set sample rate command
4457 if (ret == 0) {
4458 ret = get_mouse_data(&mouse_data2);
4459 ret = send_to_mouse_ctrl(mouse_data1);
4460 ret = get_mouse_data(&mouse_data2);
4461 // success
4462 } else {
4463 // interface error
4464 SET_CF();
4465 regs.u.r8.ah = 3;
4466 }
4467 } else {
4468 // invalid input
4469 SET_CF();
4470 regs.u.r8.ah = 2;
4471 }
4472 break;
4473
4474 case 3: // Set Resolution
4475BX_DEBUG_INT15("case 3:\n");
4476 // BX:
4477 // 0 = 25 dpi, 1 count per millimeter
4478 // 1 = 50 dpi, 2 counts per millimeter
4479 // 2 = 100 dpi, 4 counts per millimeter
4480 // 3 = 200 dpi, 8 counts per millimeter
4481 if (regs.u.r8.bh < 4) {
4482 ret = send_to_mouse_ctrl(0xE8); // set resolution command
4483 if (ret == 0) {
4484 ret = get_mouse_data(&mouse_data1);
4485 if (mouse_data1 != 0xfa)
4486 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4487 ret = send_to_mouse_ctrl(regs.u.r8.bh);
4488 ret = get_mouse_data(&mouse_data1);
4489 if (mouse_data1 != 0xfa)
4490 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4491 // success
4492 } else {
4493 // interface error
4494 SET_CF();
4495 regs.u.r8.ah = 3;
4496 }
4497 } else {
4498 // invalid input
4499 SET_CF();
4500 regs.u.r8.ah = 2;
4501 }
4502 break;
4503
4504 case 4: // Get Device ID
4505BX_DEBUG_INT15("case 4:\n");
4506 ret = send_to_mouse_ctrl(0xF2); // get mouse ID command
4507 if (ret == 0) {
4508 ret = get_mouse_data(&mouse_data1);
4509 ret = get_mouse_data(&mouse_data2);
4510 regs.u.r8.bh = mouse_data2;
4511 // success
4512 } else {
4513 // interface error
4514 SET_CF();
4515 regs.u.r8.ah = 3;
4516 }
4517 break;
4518
4519 case 6: // Return Status & Set Scaling Factor...
4520BX_DEBUG_INT15("case 6:\n");
4521 switch (regs.u.r8.bh) {
4522 case 0: // Return Status
4523 ret = send_to_mouse_ctrl(0xE9); // get mouse info command
4524 if (ret == 0) {
4525 ret = get_mouse_data(&mouse_data1);
4526 if (mouse_data1 != 0xfa)
4527 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4528 if (ret == 0) {
4529 ret = get_mouse_data(&mouse_data1);
4530 if ( ret == 0 ) {
4531 ret = get_mouse_data(&mouse_data2);
4532 if ( ret == 0 ) {
4533 ret = get_mouse_data(&mouse_data3);
4534 if ( ret == 0 ) {
4535 regs.u.r8.bl = mouse_data1;
4536 regs.u.r8.cl = mouse_data2;
4537 regs.u.r8.dl = mouse_data3;
4538 // success
4539 break;
4540 }
4541 }
4542 }
4543 }
4544 }
4545
4546 // interface error
4547 SET_CF();
4548 regs.u.r8.ah = 3;
4549 break;
4550
4551 case 1: // Set Scaling Factor to 1:1
4552 case 2: // Set Scaling Factor to 2:1
4553 if (regs.u.r8.bh == 1) {
4554 ret = send_to_mouse_ctrl(0xE6);
4555 } else {
4556 ret = send_to_mouse_ctrl(0xE7);
4557 }
4558 if (ret == 0) {
4559 get_mouse_data(&mouse_data1);
4560 ret = (mouse_data1 != 0xFA);
4561 }
4562 if (ret != 0) {
4563 // interface error
4564 SET_CF();
4565 regs.u.r8.ah = 3;
4566 }
4567 break;
4568
4569 default:
4570 BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs.u.r8.bh);
4571 // invalid subfunction
4572 SET_CF();
4573 regs.u.r8.ah = 1;
4574 }
4575 break;
4576
4577 case 7: // Set Mouse Handler Address
4578BX_DEBUG_INT15("case 7:\n");
4579 mouse_driver_seg = ES;
4580 mouse_driver_offset = regs.u.r16.bx;
4581 write_word(ebda_seg, 0x0022, mouse_driver_offset);
4582 write_word(ebda_seg, 0x0024, mouse_driver_seg);
4583 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4584 if (mouse_driver_offset == 0 && mouse_driver_seg == 0) {
4585 /* remove handler */
4586 if ( (mouse_flags_2 & 0x80) != 0 ) {
4587 mouse_flags_2 &= ~0x80;
4588 }
4589 }
4590 else {
4591 /* install handler */
4592 mouse_flags_2 |= 0x80;
4593 }
4594 write_byte(ebda_seg, 0x0027, mouse_flags_2);
4595 break;
4596
4597 default:
4598 BX_PANIC("INT 15h C2 default case entered\n");
4599 // invalid subfunction
4600 SET_CF();
4601 regs.u.r8.ah = 1;
4602 }
4603BX_DEBUG_INT15("returning cf = %u, ah = %02x\n", (unsigned)GET_CF(), (unsigned)regs.u.r8.ah);
4604 // Re-enable AUX input and IRQ12
4605 set_kbd_command_byte(0x47);
4606 break;
4607
4608 default:
4609 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4610 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4611 SET_CF();
4612 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4613 break;
4614 }
4615}
4616#endif // BX_USE_PS2_MOUSE
4617
4618
4619void set_e820_range(ES, DI, start, end, extra_start, extra_end, type)
4620 Bit16u ES;
4621 Bit16u DI;
4622 Bit32u start;
4623 Bit32u end;
4624 Bit8u extra_start;
4625 Bit8u extra_end;
4626 Bit16u type;
4627{
4628 write_word(ES, DI, start);
4629 write_word(ES, DI+2, start >> 16);
4630 write_word(ES, DI+4, extra_start);
4631 write_word(ES, DI+6, 0x00);
4632
4633 end -= start;
4634 extra_end -= extra_start;
4635 write_word(ES, DI+8, end);
4636 write_word(ES, DI+10, end >> 16);
4637 write_word(ES, DI+12, extra_end);
4638 write_word(ES, DI+14, 0x0000);
4639
4640 write_word(ES, DI+16, type);
4641 write_word(ES, DI+18, 0x0);
4642}
4643
4644 void
4645int15_function32(regs, ES, DS, FLAGS)
4646 pushad_regs_t regs; // REGS pushed via pushad
4647 Bit16u ES, DS, FLAGS;
4648{
4649 Bit32u extended_memory_size=0; // 64bits long
4650 Bit32u extra_lowbits_memory_size=0;
4651 Bit16u CX,DX;
4652 Bit8u extra_highbits_memory_size=0;
4653
4654BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4655
4656 switch (regs.u.r8.ah) {
4657 case 0x86:
4658 // Wait for CX:DX microseconds. currently using the
4659 // refresh request port 0x61 bit4, toggling every 15usec
4660
4661 CX = regs.u.r16.cx;
4662 DX = regs.u.r16.dx;
4663
4664ASM_START
4665 sti
4666
4667 ;; Get the count in eax
4668 ;; VBOX: corrected _int15_function -> _int15_function32 here.
4669 mov bx, sp
4670 SEG SS
4671 mov ax, _int15_function32.CX [bx]
4672 shl eax, #16
4673 SEG SS
4674 mov ax, _int15_function32.DX [bx]
4675
4676 ;; convert to numbers of 15usec ticks
4677 mov ebx, #15
4678 xor edx, edx
4679 div eax, ebx
4680 mov ecx, eax
4681
4682 ;; wait for ecx number of refresh requests
4683 in al, #0x61
4684 and al,#0x10
4685 mov ah, al
4686
4687 or ecx, ecx
4688 je int1586_tick_end
4689int1586_tick:
4690 in al, #0x61
4691 and al,#0x10
4692 cmp al, ah
4693 je int1586_tick
4694 mov ah, al
4695 dec ecx
4696 jnz int1586_tick
4697int1586_tick_end:
4698ASM_END
4699
4700 break;
4701
4702 case 0xe8:
4703 switch(regs.u.r8.al)
4704 {
4705 case 0x20: // coded by osmaker aka K.J.
4706 if(regs.u.r32.edx == 0x534D4150)
4707 {
4708 extended_memory_size = inb_cmos(0x35);
4709 extended_memory_size <<= 8;
4710 extended_memory_size |= inb_cmos(0x34);
4711 extended_memory_size *= 64;
4712#ifndef VBOX /* The following excludes 0xf0000000 thru 0xffffffff. Trust DevPcBios.cpp to get this right. */
4713 // greater than EFF00000???
4714 if(extended_memory_size > 0x3bc000) {
4715 extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4716 }
4717#endif /* !VBOX */
4718 extended_memory_size *= 1024;
4719 extended_memory_size += (16L * 1024 * 1024);
4720
4721 if(extended_memory_size <= (16L * 1024 * 1024)) {
4722 extended_memory_size = inb_cmos(0x31);
4723 extended_memory_size <<= 8;
4724 extended_memory_size |= inb_cmos(0x30);
4725 extended_memory_size *= 1024;
4726 extended_memory_size += (1L * 1024 * 1024);
4727 }
4728
4729#ifdef VBOX /* We've already used the CMOS entries for SATA.
4730 BTW. This is the amount of memory above 4GB measured in 64KB units. */
4731 extra_lowbits_memory_size = inb_cmos(0x62);
4732 extra_lowbits_memory_size <<= 8;
4733 extra_lowbits_memory_size |= inb_cmos(0x61);
4734 extra_lowbits_memory_size <<= 16;
4735 extra_highbits_memory_size = inb_cmos(0x63);
4736 /* 0x64 and 0x65 can be used if we need to dig 1 TB or more at a later point. */
4737#else
4738 extra_lowbits_memory_size = inb_cmos(0x5c);
4739 extra_lowbits_memory_size <<= 8;
4740 extra_lowbits_memory_size |= inb_cmos(0x5b);
4741 extra_lowbits_memory_size *= 64;
4742 extra_lowbits_memory_size *= 1024;
4743 extra_highbits_memory_size = inb_cmos(0x5d);
4744#endif /* !VBOX */
4745
4746 switch(regs.u.r16.bx)
4747 {
4748 case 0:
4749 set_e820_range(ES, regs.u.r16.di,
4750#ifndef VBOX /** @todo Upstream sugggests the following, needs checking. (see next as well) */
4751 0x0000000L, 0x0009f000L, 0, 0, 1);
4752#else
4753 0x0000000L, 0x0009fc00L, 0, 0, 1);
4754#endif
4755 regs.u.r32.ebx = 1;
4756 break;
4757 case 1:
4758 set_e820_range(ES, regs.u.r16.di,
4759#ifndef VBOX /** @todo Upstream sugggests the following, needs checking. (see next as well) */
4760 0x0009f000L, 0x000a0000L, 0, 0, 2);
4761#else
4762 0x0009fc00L, 0x000a0000L, 0, 0, 2);
4763#endif
4764 regs.u.r32.ebx = 2;
4765 break;
4766 case 2:
4767#ifdef VBOX
4768 /* Mark the BIOS as reserved. VBox doesn't currently
4769 * use the 0xe0000-0xeffff area. It does use the
4770 * 0xd0000-0xdffff area for the BIOS logo, but it's
4771 * not worth marking it as reserved. Note that various
4772 * Windows versions don't accept (read: in debug builds
4773 * they trigger the "Too many similar traps" assertion)
4774 * a single reserved range from 0xd0000 to 0xffffff.
4775 * A 128K area starting from 0xd0000 works. */
4776 set_e820_range(ES, regs.u.r16.di,
4777 0x000f0000L, 0x00100000L, 0, 0, 2);
4778#else /* !VBOX */
4779 set_e820_range(ES, regs.u.r16.di,
4780 0x000e8000L, 0x00100000L, 0, 0, 2);
4781#endif /* !VBOX */
4782 regs.u.r32.ebx = 3;
4783 break;
4784 case 3:
4785#if BX_ROMBIOS32 || defined(VBOX)
4786 set_e820_range(ES, regs.u.r16.di,
4787 0x00100000L,
4788 extended_memory_size - ACPI_DATA_SIZE, 0, 0, 1);
4789 regs.u.r32.ebx = 4;
4790#else
4791 set_e820_range(ES, regs.u.r16.di,
4792 0x00100000L,
4793 extended_memory_size, 1);
4794 regs.u.r32.ebx = 5;
4795#endif
4796 break;
4797 case 4:
4798 set_e820_range(ES, regs.u.r16.di,
4799 extended_memory_size - ACPI_DATA_SIZE,
4800 extended_memory_size, 0, 0, 3); // ACPI RAM
4801 regs.u.r32.ebx = 5;
4802 break;
4803 case 5:
4804 /* 256KB BIOS area at the end of 4 GB */
4805#ifdef VBOX
4806 /* We don't set the end to 1GB here and rely on the 32-bit
4807 unsigned wrap around effect (0-0xfffc0000L). */
4808#endif
4809 set_e820_range(ES, regs.u.r16.di,
4810 0xfffc0000L, 0x00000000L, 0, 0, 2);
4811 if (extra_highbits_memory_size || extra_lowbits_memory_size)
4812 regs.u.r32.ebx = 6;
4813 else
4814 regs.u.r32.ebx = 0;
4815 break;
4816 case 6:
4817#ifdef VBOX /* Don't succeeded if no memory above 4 GB. */
4818 /* Mapping of memory above 4 GB if present.
4819 Note: set_e820_range needs do no borrowing in the
4820 subtraction because of the nice numbers. */
4821 if (extra_highbits_memory_size || extra_lowbits_memory_size)
4822 {
4823 set_e820_range(ES, regs.u.r16.di,
4824 0x00000000L, extra_lowbits_memory_size,
4825 1 /*GB*/, extra_highbits_memory_size + 1 /*GB*/, 1);
4826 regs.u.r32.ebx = 0;
4827 break;
4828 }
4829 /* fall thru */
4830#else /* !VBOX */
4831 /* Maping of memory above 4 GB */
4832 set_e820_range(ES, regs.u.r16.di, 0x00000000L,
4833 extra_lowbits_memory_size, 1, extra_highbits_memory_size
4834 + 1, 1);
4835 regs.u.r32.ebx = 0;
4836 break;
4837#endif /* !VBOX */
4838 default: /* AX=E820, DX=534D4150, BX unrecognized */
4839 goto int15_unimplemented;
4840 break;
4841 }
4842 regs.u.r32.eax = 0x534D4150;
4843 regs.u.r32.ecx = 0x14;
4844 CLEAR_CF();
4845 } else {
4846 // if DX != 0x534D4150)
4847 goto int15_unimplemented;
4848 }
4849 break;
4850
4851 case 0x01:
4852 // do we have any reason to fail here ?
4853 CLEAR_CF();
4854
4855 // my real system sets ax and bx to 0
4856 // this is confirmed by Ralph Brown list
4857 // but syslinux v1.48 is known to behave
4858 // strangely if ax is set to 0
4859 // regs.u.r16.ax = 0;
4860 // regs.u.r16.bx = 0;
4861
4862 // Get the amount of extended memory (above 1M)
4863 regs.u.r8.cl = inb_cmos(0x30);
4864 regs.u.r8.ch = inb_cmos(0x31);
4865
4866 // limit to 15M
4867 if(regs.u.r16.cx > 0x3c00)
4868 {
4869 regs.u.r16.cx = 0x3c00;
4870 }
4871
4872 // Get the amount of extended memory above 16M in 64k blocs
4873 regs.u.r8.dl = inb_cmos(0x34);
4874 regs.u.r8.dh = inb_cmos(0x35);
4875
4876 // Set configured memory equal to extended memory
4877 regs.u.r16.ax = regs.u.r16.cx;
4878 regs.u.r16.bx = regs.u.r16.dx;
4879 break;
4880 default: /* AH=0xE8?? but not implemented */
4881 goto int15_unimplemented;
4882 }
4883 break;
4884 int15_unimplemented:
4885 // fall into the default
4886 default:
4887 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4888 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4889 SET_CF();
4890 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4891 break;
4892 }
4893}
4894
4895 void
4896int16_function(DI, SI, BP, SP, BX, DX, CX, AX, FLAGS)
4897 Bit16u DI, SI, BP, SP, BX, DX, CX, AX, FLAGS;
4898{
4899 Bit8u scan_code, ascii_code, shift_flags, led_flags, count;
4900 Bit16u kbd_code, max;
4901
4902 BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX, BX, CX, DX);
4903
4904 shift_flags = read_byte(0x0040, 0x17);
4905 led_flags = read_byte(0x0040, 0x97);
4906 if ((((shift_flags >> 4) & 0x07) ^ (led_flags & 0x07)) != 0) {
4907ASM_START
4908 cli
4909ASM_END
4910 outb(0x60, 0xed);
4911 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
4912 if ((inb(0x60) == 0xfa)) {
4913 led_flags &= 0xf8;
4914 led_flags |= ((shift_flags >> 4) & 0x07);
4915 outb(0x60, led_flags & 0x07);
4916 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
4917 inb(0x60);
4918 write_byte(0x0040, 0x97, led_flags);
4919 }
4920ASM_START
4921 sti
4922ASM_END
4923 }
4924
4925 switch (GET_AH()) {
4926 case 0x00: /* read keyboard input */
4927
4928 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4929 BX_PANIC("KBD: int16h: out of keyboard input\n");
4930 }
4931 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4932 else if (ascii_code == 0xE0) ascii_code = 0;
4933 AX = (scan_code << 8) | ascii_code;
4934 break;
4935
4936 case 0x01: /* check keyboard status */
4937 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4938 SET_ZF();
4939 return;
4940 }
4941 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4942 else if (ascii_code == 0xE0) ascii_code = 0;
4943 AX = (scan_code << 8) | ascii_code;
4944 CLEAR_ZF();
4945 break;
4946
4947 case 0x02: /* get shift flag status */
4948 shift_flags = read_byte(0x0040, 0x17);
4949 SET_AL(shift_flags);
4950 break;
4951
4952 case 0x05: /* store key-stroke into buffer */
4953 if ( !enqueue_key(GET_CH(), GET_CL()) ) {
4954 SET_AL(1);
4955 }
4956 else {
4957 SET_AL(0);
4958 }
4959 break;
4960
4961 case 0x09: /* GET KEYBOARD FUNCTIONALITY */
4962 // bit Bochs Description
4963 // 7 0 reserved
4964 // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
4965 // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
4966 // 4 1 INT 16/AH=0Ah supported
4967 // 3 0 INT 16/AX=0306h supported
4968 // 2 0 INT 16/AX=0305h supported
4969 // 1 0 INT 16/AX=0304h supported
4970 // 0 0 INT 16/AX=0300h supported
4971 //
4972 SET_AL(0x30);
4973 break;
4974
4975 case 0x0A: /* GET KEYBOARD ID */
4976 count = 2;
4977 kbd_code = 0x0;
4978 outb(0x60, 0xf2);
4979 /* Wait for data */
4980 max=0xffff;
4981 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4982 if (max>0x0) {
4983 if ((inb(0x60) == 0xfa)) {
4984 do {
4985 max=0xffff;
4986 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4987 if (max>0x0) {
4988 kbd_code >>= 8;
4989 kbd_code |= (inb(0x60) << 8);
4990 }
4991 } while (--count>0);
4992 }
4993 }
4994 BX=kbd_code;
4995 break;
4996
4997 case 0x10: /* read MF-II keyboard input */
4998
4999 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
5000 BX_PANIC("KBD: int16h: out of keyboard input\n");
5001 }
5002 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
5003 AX = (scan_code << 8) | ascii_code;
5004 break;
5005
5006 case 0x11: /* check MF-II keyboard status */
5007 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
5008 SET_ZF();
5009 return;
5010 }
5011 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
5012 AX = (scan_code << 8) | ascii_code;
5013 CLEAR_ZF();
5014 break;
5015
5016 case 0x12: /* get extended keyboard status */
5017 shift_flags = read_byte(0x0040, 0x17);
5018 SET_AL(shift_flags);
5019 shift_flags = read_byte(0x0040, 0x18) & 0x73;
5020 shift_flags |= read_byte(0x0040, 0x96) & 0x0c;
5021 SET_AH(shift_flags);
5022 BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX);
5023 break;
5024
5025 case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
5026 SET_AH(0x80); // function int16 ah=0x10-0x12 supported
5027 break;
5028
5029 case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
5030 // don't change AH : function int16 ah=0x20-0x22 NOT supported
5031 break;
5032
5033 case 0x6F:
5034 if (GET_AL() == 0x08)
5035 SET_AH(0x02); // unsupported, aka normal keyboard
5036
5037 default:
5038 BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
5039 }
5040}
5041
5042 unsigned int
5043dequeue_key(scan_code, ascii_code, incr)
5044 Bit8u *scan_code;
5045 Bit8u *ascii_code;
5046 unsigned int incr;
5047{
5048 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail;
5049 Bit16u ss;
5050 Bit8u acode, scode;
5051
5052#if BX_CPU < 2
5053 buffer_start = 0x001E;
5054 buffer_end = 0x003E;
5055#else
5056 buffer_start = read_word(0x0040, 0x0080);
5057 buffer_end = read_word(0x0040, 0x0082);
5058#endif
5059
5060 buffer_head = read_word(0x0040, 0x001a);
5061 buffer_tail = read_word(0x0040, 0x001c);
5062
5063 if (buffer_head != buffer_tail) {
5064 ss = get_SS();
5065 acode = read_byte(0x0040, buffer_head);
5066 scode = read_byte(0x0040, buffer_head+1);
5067 write_byte(ss, ascii_code, acode);
5068 write_byte(ss, scan_code, scode);
5069
5070 if (incr) {
5071 buffer_head += 2;
5072 if (buffer_head >= buffer_end)
5073 buffer_head = buffer_start;
5074 write_word(0x0040, 0x001a, buffer_head);
5075 }
5076 return(1);
5077 }
5078 else {
5079 return(0);
5080 }
5081}
5082
5083static char panic_msg_keyb_buffer_full[] = "%s: keyboard input buffer full\n";
5084
5085 Bit8u
5086send_to_mouse_ctrl(sendbyte)
5087 Bit8u sendbyte;
5088{
5089 Bit8u response;
5090
5091 // wait for chance to write to ctrl
5092 if ( inb(0x64) & 0x02 )
5093 BX_PANIC(panic_msg_keyb_buffer_full,"sendmouse");
5094 outb(0x64, 0xD4);
5095 outb(0x60, sendbyte);
5096 return(0);
5097}
5098
5099
5100 Bit8u
5101get_mouse_data(data)
5102 Bit8u *data;
5103{
5104 Bit8u response;
5105 Bit16u ss;
5106
5107 while ( (inb(0x64) & 0x21) != 0x21 ) {
5108 }
5109
5110 response = inb(0x60);
5111
5112 ss = get_SS();
5113 write_byte(ss, data, response);
5114 return(0);
5115}
5116
5117 void
5118set_kbd_command_byte(command_byte)
5119 Bit8u command_byte;
5120{
5121 if ( inb(0x64) & 0x02 )
5122 BX_PANIC(panic_msg_keyb_buffer_full,"setkbdcomm");
5123
5124 outb(0x64, 0x60); // write command byte
5125 outb(0x60, command_byte);
5126}
5127
5128 void
5129int09_function(DI, SI, BP, SP, BX, DX, CX, AX)
5130 Bit16u DI, SI, BP, SP, BX, DX, CX, AX;
5131{
5132 Bit8u scancode, asciicode, shift_flags;
5133 Bit8u mf2_flags, mf2_state;
5134
5135 //
5136 // DS has been set to F000 before call
5137 //
5138
5139
5140 scancode = GET_AL();
5141
5142 if (scancode == 0) {
5143 BX_INFO("KBD: int09 handler: AL=0\n");
5144 return;
5145 }
5146
5147
5148 shift_flags = read_byte(0x0040, 0x17);
5149 mf2_flags = read_byte(0x0040, 0x18);
5150 mf2_state = read_byte(0x0040, 0x96);
5151 asciicode = 0;
5152
5153 switch (scancode) {
5154 case 0x3a: /* Caps Lock press */
5155 shift_flags ^= 0x40;
5156 write_byte(0x0040, 0x17, shift_flags);
5157 mf2_flags |= 0x40;
5158 write_byte(0x0040, 0x18, mf2_flags);
5159 break;
5160 case 0xba: /* Caps Lock release */
5161 mf2_flags &= ~0x40;
5162 write_byte(0x0040, 0x18, mf2_flags);
5163 break;
5164
5165 case 0x2a: /* L Shift press */
5166 shift_flags |= 0x02;
5167 write_byte(0x0040, 0x17, shift_flags);
5168 break;
5169 case 0xaa: /* L Shift release */
5170 shift_flags &= ~0x02;
5171 write_byte(0x0040, 0x17, shift_flags);
5172 break;
5173
5174 case 0x36: /* R Shift press */
5175 shift_flags |= 0x01;
5176 write_byte(0x0040, 0x17, shift_flags);
5177 break;
5178 case 0xb6: /* R Shift release */
5179 shift_flags &= ~0x01;
5180 write_byte(0x0040, 0x17, shift_flags);
5181 break;
5182
5183 case 0x1d: /* Ctrl press */
5184 if ((mf2_state & 0x01) == 0) {
5185 shift_flags |= 0x04;
5186 write_byte(0x0040, 0x17, shift_flags);
5187 if (mf2_state & 0x02) {
5188 mf2_state |= 0x04;
5189 write_byte(0x0040, 0x96, mf2_state);
5190 } else {
5191 mf2_flags |= 0x01;
5192 write_byte(0x0040, 0x18, mf2_flags);
5193 }
5194 }
5195 break;
5196 case 0x9d: /* Ctrl release */
5197 if ((mf2_state & 0x01) == 0) {
5198 shift_flags &= ~0x04;
5199 write_byte(0x0040, 0x17, shift_flags);
5200 if (mf2_state & 0x02) {
5201 mf2_state &= ~0x04;
5202 write_byte(0x0040, 0x96, mf2_state);
5203 } else {
5204 mf2_flags &= ~0x01;
5205 write_byte(0x0040, 0x18, mf2_flags);
5206 }
5207 }
5208 break;
5209
5210 case 0x38: /* Alt press */
5211 shift_flags |= 0x08;
5212 write_byte(0x0040, 0x17, shift_flags);
5213 if (mf2_state & 0x02) {
5214 mf2_state |= 0x08;
5215 write_byte(0x0040, 0x96, mf2_state);
5216 } else {
5217 mf2_flags |= 0x02;
5218 write_byte(0x0040, 0x18, mf2_flags);
5219 }
5220 break;
5221 case 0xb8: /* Alt release */
5222 shift_flags &= ~0x08;
5223 write_byte(0x0040, 0x17, shift_flags);
5224 if (mf2_state & 0x02) {
5225 mf2_state &= ~0x08;
5226 write_byte(0x0040, 0x96, mf2_state);
5227 } else {
5228 mf2_flags &= ~0x02;
5229 write_byte(0x0040, 0x18, mf2_flags);
5230 }
5231 break;
5232
5233 case 0x45: /* Num Lock press */
5234 if ((mf2_state & 0x03) == 0) {
5235 mf2_flags |= 0x20;
5236 write_byte(0x0040, 0x18, mf2_flags);
5237 shift_flags ^= 0x20;
5238 write_byte(0x0040, 0x17, shift_flags);
5239 }
5240 break;
5241 case 0xc5: /* Num Lock release */
5242 if ((mf2_state & 0x03) == 0) {
5243 mf2_flags &= ~0x20;
5244 write_byte(0x0040, 0x18, mf2_flags);
5245 }
5246 break;
5247
5248 case 0x46: /* Scroll Lock press */
5249 mf2_flags |= 0x10;
5250 write_byte(0x0040, 0x18, mf2_flags);
5251 shift_flags ^= 0x10;
5252 write_byte(0x0040, 0x17, shift_flags);
5253 break;
5254
5255 case 0xc6: /* Scroll Lock release */
5256 mf2_flags &= ~0x10;
5257 write_byte(0x0040, 0x18, mf2_flags);
5258 break;
5259
5260#ifdef VBOX
5261 case 0x53: /* Del press */
5262 if ((shift_flags & 0x0f) == 0x0c)
5263 {
5264ASM_START
5265 /* Ctrl+Alt+Del => Reboot */
5266 jmp 0xf000:post
5267ASM_END
5268 }
5269 /* fall through */
5270#endif
5271
5272 default:
5273 if (scancode & 0x80) {
5274 break; /* toss key releases ... */
5275 }
5276 if (scancode > MAX_SCAN_CODE) {
5277 BX_INFO("KBD: int09h_handler(): unknown scancode read: 0x%02x!\n", scancode);
5278 return;
5279 }
5280 if (shift_flags & 0x08) { /* ALT */
5281 asciicode = scan_to_scanascii[scancode].alt;
5282 scancode = scan_to_scanascii[scancode].alt >> 8;
5283 } else if (shift_flags & 0x04) { /* CONTROL */
5284 asciicode = scan_to_scanascii[scancode].control;
5285 scancode = scan_to_scanascii[scancode].control >> 8;
5286 } else if (((mf2_state & 0x02) > 0) && ((scancode >= 0x47) && (scancode <= 0x53))) {
5287 /* extended keys handling */
5288 asciicode = 0xe0;
5289 scancode = scan_to_scanascii[scancode].normal >> 8;
5290 } else if (shift_flags & 0x03) { /* LSHIFT + RSHIFT */
5291 /* check if lock state should be ignored
5292 * because a SHIFT key are pressed */
5293
5294 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
5295 asciicode = scan_to_scanascii[scancode].normal;
5296 scancode = scan_to_scanascii[scancode].normal >> 8;
5297 } else {
5298 asciicode = scan_to_scanascii[scancode].shift;
5299 scancode = scan_to_scanascii[scancode].shift >> 8;
5300 }
5301 } else {
5302 /* check if lock is on */
5303 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
5304 asciicode = scan_to_scanascii[scancode].shift;
5305 scancode = scan_to_scanascii[scancode].shift >> 8;
5306 } else {
5307 asciicode = scan_to_scanascii[scancode].normal;
5308 scancode = scan_to_scanascii[scancode].normal >> 8;
5309 }
5310 }
5311 if (scancode==0 && asciicode==0) {
5312 BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
5313 }
5314 enqueue_key(scancode, asciicode);
5315 break;
5316 }
5317 if ((scancode & 0x7f) != 0x1d) {
5318 mf2_state &= ~0x01;
5319 }
5320 mf2_state &= ~0x02;
5321 write_byte(0x0040, 0x96, mf2_state);
5322}
5323
5324 unsigned int
5325enqueue_key(scan_code, ascii_code)
5326 Bit8u scan_code, ascii_code;
5327{
5328 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail, temp_tail;
5329
5330#if BX_CPU < 2
5331 buffer_start = 0x001E;
5332 buffer_end = 0x003E;
5333#else
5334 buffer_start = read_word(0x0040, 0x0080);
5335 buffer_end = read_word(0x0040, 0x0082);
5336#endif
5337
5338 buffer_head = read_word(0x0040, 0x001A);
5339 buffer_tail = read_word(0x0040, 0x001C);
5340
5341 temp_tail = buffer_tail;
5342 buffer_tail += 2;
5343 if (buffer_tail >= buffer_end)
5344 buffer_tail = buffer_start;
5345
5346 if (buffer_tail == buffer_head) {
5347 return(0);
5348 }
5349
5350 write_byte(0x0040, temp_tail, ascii_code);
5351 write_byte(0x0040, temp_tail+1, scan_code);
5352 write_word(0x0040, 0x001C, buffer_tail);
5353 return(1);
5354}
5355
5356
5357 void
5358int74_function(make_farcall, Z, Y, X, status)
5359 Bit16u make_farcall, Z, Y, X, status;
5360{
5361 Bit16u ebda_seg=read_word(0x0040,0x000E);
5362 Bit8u in_byte, index, package_count;
5363 Bit8u mouse_flags_1, mouse_flags_2;
5364
5365BX_DEBUG_INT74("entering int74_function\n");
5366 make_farcall = 0;
5367
5368 in_byte = inb(0x64);
5369 if ( (in_byte & 0x21) != 0x21 ) {
5370 return;
5371 }
5372 in_byte = inb(0x60);
5373BX_DEBUG_INT74("int74: read byte %02x\n", in_byte);
5374
5375 mouse_flags_1 = read_byte(ebda_seg, 0x0026);
5376 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
5377
5378 if ( (mouse_flags_2 & 0x80) != 0x80 ) {
5379 return;
5380 }
5381
5382 package_count = mouse_flags_2 & 0x07;
5383 index = mouse_flags_1 & 0x07;
5384 write_byte(ebda_seg, 0x28 + index, in_byte);
5385
5386 if ( index >= package_count ) {
5387BX_DEBUG_INT74("int74_function: make_farcall=1\n");
5388 status = read_byte(ebda_seg, 0x0028 + 0);
5389 X = read_byte(ebda_seg, 0x0028 + 1);
5390 Y = read_byte(ebda_seg, 0x0028 + 2);
5391 Z = 0;
5392 mouse_flags_1 = 0;
5393 // check if far call handler installed
5394 if (mouse_flags_2 & 0x80)
5395 make_farcall = 1;
5396 }
5397 else {
5398 mouse_flags_1++;
5399 }
5400 write_byte(ebda_seg, 0x0026, mouse_flags_1);
5401}
5402
5403#define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
5404
5405#if BX_USE_ATADRV
5406
5407 void
5408int13_harddisk(EHBX, EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5409 Bit16u EHBX, EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5410{
5411 Bit32u lba;
5412 Bit16u ebda_seg=read_word(0x0040,0x000E);
5413 Bit16u cylinder, head, sector;
5414 Bit16u segment, offset;
5415 Bit16u npc, nph, npspt, nlc, nlh, nlspt;
5416 Bit16u size, count;
5417 Bit8u device, status;
5418
5419 BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5420
5421 write_byte(0x0040, 0x008e, 0); // clear completion flag
5422
5423#ifdef VBOX_WITH_SCSI
5424 // basic check : device has to be defined
5425 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_STORAGE_DEVICES) ) {
5426 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5427 goto int13_fail;
5428 }
5429#else
5430 // basic check : device has to be defined
5431 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES) ) {
5432 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5433 goto int13_fail;
5434 }
5435#endif
5436
5437 // Get the ata channel
5438 device=read_byte(ebda_seg,&EbdaData->ata.hdidmap[GET_ELDL()-0x80]);
5439
5440#ifdef VBOX_WITH_SCSI
5441 // basic check : device has to be valid
5442 if (device >= BX_MAX_STORAGE_DEVICES) {
5443 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5444 goto int13_fail;
5445 }
5446#else
5447 // basic check : device has to be valid
5448 if (device >= BX_MAX_ATA_DEVICES) {
5449 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5450 goto int13_fail;
5451 }
5452#endif
5453
5454 switch (GET_AH()) {
5455
5456 case 0x00: /* disk controller reset */
5457#ifdef VBOX_WITH_SCSI
5458 /* SCSI controller does not need a reset. */
5459 if (!VBOX_IS_SCSI_DEVICE(device))
5460#endif
5461 ata_reset (device);
5462 goto int13_success;
5463 break;
5464
5465 case 0x01: /* read disk status */
5466 status = read_byte(0x0040, 0x0074);
5467 SET_AH(status);
5468 SET_DISK_RET_STATUS(0);
5469 /* set CF if error status read */
5470 if (status) goto int13_fail_nostatus;
5471 else goto int13_success_noah;
5472 break;
5473
5474 case 0x02: // read disk sectors
5475 case 0x03: // write disk sectors
5476 case 0x04: // verify disk sectors
5477
5478 count = GET_AL();
5479 cylinder = GET_CH();
5480 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
5481 sector = (GET_CL() & 0x3f);
5482 head = GET_DH();
5483
5484 segment = ES;
5485 offset = BX;
5486
5487 if ( (count > 128) || (count == 0) ) {
5488 BX_INFO("int13_harddisk: function %02x, count out of range!\n",GET_AH());
5489 goto int13_fail;
5490 }
5491
5492#ifdef VBOX_WITH_SCSI
5493 if (!VBOX_IS_SCSI_DEVICE(device))
5494#endif
5495 {
5496 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
5497 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
5498 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
5499 }
5500#ifdef VBOX_WITH_SCSI
5501 else
5502 {
5503 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5504
5505 nlc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.cylinders);
5506 nlh = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.heads);
5507 nlspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.spt);
5508 }
5509#endif
5510
5511 // sanity check on cyl heads, sec
5512 if( (cylinder >= nlc) || (head >= nlh) || (sector > nlspt )) {
5513 BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder, head, sector);
5514 goto int13_fail;
5515 }
5516
5517 // FIXME verify
5518 if ( GET_AH() == 0x04 ) goto int13_success;
5519
5520#ifdef VBOX_WITH_SCSI
5521 if (!VBOX_IS_SCSI_DEVICE(device))
5522#endif
5523 {
5524 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5525 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5526 }
5527#ifdef VBOX_WITH_SCSI
5528 else
5529 {
5530 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5531 nph = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.heads);
5532 npspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.spt);
5533 }
5534#endif
5535
5536 // if needed, translate lchs to lba, and execute command
5537#ifdef VBOX_WITH_SCSI
5538 if (( (nph != nlh) || (npspt != nlspt)) || VBOX_IS_SCSI_DEVICE(device)) {
5539 lba = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
5540 sector = 0; // this forces the command to be lba
5541 }
5542#else
5543 if (( (nph != nlh) || (npspt != nlspt)) ) {
5544 lba = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
5545 sector = 0; // this forces the command to be lba
5546 }
5547#endif
5548
5549 if ( GET_AH() == 0x02 )
5550 {
5551#ifdef VBOX_WITH_SCSI
5552 if (VBOX_IS_SCSI_DEVICE(device))
5553 status=scsi_read_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5554 else
5555#endif
5556 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, cylinder, head, sector, lba, segment, offset);
5557 }
5558 else
5559 {
5560#ifdef VBOX_WITH_SCSI
5561 if (VBOX_IS_SCSI_DEVICE(device))
5562 status=scsi_write_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5563 else
5564#endif
5565 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, cylinder, head, sector, lba, segment, offset);
5566 }
5567
5568 // Set nb of sector transferred
5569 SET_AL(read_word(ebda_seg, &EbdaData->ata.trsfsectors));
5570
5571 if (status != 0) {
5572 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5573 SET_AH(0x0c);
5574 goto int13_fail_noah;
5575 }
5576
5577 goto int13_success;
5578 break;
5579
5580 case 0x05: /* format disk track */
5581 BX_INFO("format disk track called\n");
5582 goto int13_success;
5583 return;
5584 break;
5585
5586 case 0x08: /* read disk drive parameters */
5587
5588 // Get logical geometry from table
5589#ifdef VBOX_WITH_SCSI
5590 if (!VBOX_IS_SCSI_DEVICE(device))
5591#endif
5592 {
5593 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
5594 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
5595 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
5596 }
5597#ifdef VBOX_WITH_SCSI
5598 else
5599 {
5600 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5601 nlc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.cylinders);
5602 nlh = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.heads);
5603 nlspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.spt);
5604 }
5605#endif
5606
5607 count = read_byte(ebda_seg, &EbdaData->ata.hdcount);
5608#ifndef VBOX
5609 nlc = nlc - 2; /* 0 based , last sector not used */
5610#else /* VBOX */
5611 /* Maximum cylinder number is just one less than the number of cylinders. */
5612 nlc = nlc - 1; /* 0 based , last sector not used */
5613#endif /* VBOX */
5614 SET_AL(0);
5615 SET_CH(nlc & 0xff);
5616 SET_CL(((nlc >> 2) & 0xc0) | (nlspt & 0x3f));
5617 SET_DH(nlh - 1);
5618 SET_DL(count); /* FIXME returns 0, 1, or n hard drives */
5619
5620 // FIXME should set ES & DI
5621
5622 goto int13_success;
5623 break;
5624
5625 case 0x10: /* check drive ready */
5626 // should look at 40:8E also???
5627
5628 // Read the status from controller
5629 status = inb(read_word(ebda_seg, &EbdaData->ata.channels[device/2].iobase1) + ATA_CB_STAT);
5630 if ( (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY ) {
5631 goto int13_success;
5632 }
5633 else {
5634 SET_AH(0xAA);
5635 goto int13_fail_noah;
5636 }
5637 break;
5638
5639 case 0x15: /* read disk drive size */
5640
5641 // Get physical geometry from table
5642#ifdef VBOX_WITH_SCSI
5643 if (!VBOX_IS_SCSI_DEVICE(device))
5644#endif
5645 {
5646 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5647 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5648 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5649 }
5650#ifdef VBOX_WITH_SCSI
5651 else
5652 {
5653 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5654 npc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.cylinders);
5655 nph = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.heads);
5656 npspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.spt);
5657 }
5658#endif
5659
5660 // Compute sector count seen by int13
5661#ifndef VBOX
5662 lba = (Bit32u)(npc - 1) * (Bit32u)nph * (Bit32u)npspt;
5663#else /* VBOX */
5664 /* Is it so hard to multiply a couple of counts (without introducing
5665 * arbitrary off by one errors)? */
5666 lba = (Bit32u)npc * (Bit32u)nph * (Bit32u)npspt;
5667#endif /* VBOX */
5668 CX = lba >> 16;
5669 DX = lba & 0xffff;
5670
5671 SET_AH(3); // hard disk accessible
5672 goto int13_success_noah;
5673 break;
5674
5675 case 0x41: // IBM/MS installation check
5676 BX=0xaa55; // install check
5677 SET_AH(0x30); // EDD 3.0
5678 CX=0x0007; // ext disk access and edd, removable supported
5679 goto int13_success_noah;
5680 break;
5681
5682 case 0x42: // IBM/MS extended read
5683 case 0x43: // IBM/MS extended write
5684 case 0x44: // IBM/MS verify
5685 case 0x47: // IBM/MS extended seek
5686
5687 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5688 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5689 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5690
5691 // Can't use 64 bits lba
5692 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5693 if (lba != 0L) {
5694 BX_PANIC("int13_harddisk: function %02x. Can't use 64bits lba\n",GET_AH());
5695 goto int13_fail;
5696 }
5697
5698 // Get 32 bits lba and check
5699 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5700
5701#ifdef VBOX_WITH_SCSI
5702 if (VBOX_IS_SCSI_DEVICE(device))
5703 {
5704 if (lba >= read_dword(ebda_seg, &EbdaData->scsi.devices[VBOX_GET_SCSI_DEVICE(device)].device_info.sectors) ) {
5705 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5706 goto int13_fail;
5707 }
5708 }
5709 else
5710#endif
5711 if (lba >= read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors) ) {
5712 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5713 goto int13_fail;
5714 }
5715
5716
5717 // If verify or seek
5718 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5719 goto int13_success;
5720
5721 // Execute the command
5722 if ( GET_AH() == 0x42 )
5723#ifdef VBOX
5724 {
5725#ifdef VBOX_WITH_SCSI
5726 if (VBOX_IS_SCSI_DEVICE(device))
5727 status=scsi_read_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5728 else
5729#endif
5730 {
5731 if (count >= 256 || lba + count >= 268435456)
5732 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS_EXT, count, 0, 0, 0, lba, segment, offset);
5733 else
5734 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba, segment, offset);
5735 }
5736 }
5737#else /* !VBOX */
5738 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba, segment, offset);
5739#endif /* VBOX */
5740 else
5741#ifdef VBOX
5742 {
5743#ifdef VBOX_WITH_SCSI
5744 if (VBOX_IS_SCSI_DEVICE(device))
5745 status=scsi_write_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5746 else
5747#endif
5748 {
5749 if (count >= 256 || lba + count >= 268435456)
5750 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS_EXT, count, 0, 0, 0, lba, segment, offset);
5751 else
5752 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
5753 }
5754 }
5755#else /* !VBOX */
5756 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
5757#endif /* VBOX */
5758
5759 count=read_word(ebda_seg, &EbdaData->ata.trsfsectors);
5760 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5761
5762 if (status != 0) {
5763 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5764 SET_AH(0x0c);
5765 goto int13_fail_noah;
5766 }
5767
5768 goto int13_success;
5769 break;
5770
5771 case 0x45: // IBM/MS lock/unlock drive
5772 case 0x49: // IBM/MS extended media change
5773 goto int13_success; // Always success for HD
5774 break;
5775
5776 case 0x46: // IBM/MS eject media
5777 SET_AH(0xb2); // Volume Not Removable
5778 goto int13_fail_noah; // Always fail for HD
5779 break;
5780
5781 case 0x48: // IBM/MS get drive parameters
5782 size=read_word(DS,SI+(Bit16u)&Int13DPT->size);
5783
5784 // Buffer is too small
5785 if(size < 0x1a)
5786 goto int13_fail;
5787
5788 // EDD 1.x
5789 if(size >= 0x1a) {
5790 Bit16u blksize;
5791
5792#ifdef VBOX_WITH_SCSI
5793 if (!VBOX_IS_SCSI_DEVICE(device))
5794#endif
5795 {
5796 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5797 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5798 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5799 lba = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors);
5800 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5801 }
5802#ifdef VBOX_WITH_SCSI
5803 else
5804 {
5805 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5806 npc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.cylinders);
5807 nph = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.heads);
5808 npspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.spt);
5809 lba = read_dword(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.sectors);
5810 blksize = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.blksize);
5811 }
5812#endif
5813
5814 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5815 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x02); // geometry is valid
5816 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, (Bit32u)npc);
5817 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, (Bit32u)nph);
5818 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, (Bit32u)npspt);
5819 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, lba); // FIXME should be Bit64
5820 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0L);
5821 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5822 }
5823
5824 // EDD 2.x
5825 if(size >= 0x1e) {
5826 Bit8u channel, dev, irq, mode, checksum, i, translation;
5827 Bit16u iobase1, iobase2, options;
5828
5829 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5830
5831 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5832 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5833
5834 // Fill in dpte
5835 channel = device / 2;
5836 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5837 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5838 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5839 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5840 translation = read_byte(ebda_seg, &EbdaData->ata.devices[device].translation);
5841
5842 options = (translation==ATA_TRANSLATION_NONE?0:1<<3); // chs translation
5843 options |= (1<<4); // lba translation
5844 options |= (mode==ATA_MODE_PIO32?1:0<<7);
5845 options |= (translation==ATA_TRANSLATION_LBA?1:0<<9);
5846 options |= (translation==ATA_TRANSLATION_RECHS?3:0<<9);
5847
5848 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5849 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5850 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5851 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5852 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5853 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5854 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5855 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5856 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5857 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5858 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5859
5860 checksum=0;
5861 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5862 checksum = ~checksum;
5863 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5864 }
5865
5866 // EDD 3.x
5867 if(size >= 0x42) {
5868 Bit8u channel, iface, checksum, i;
5869 Bit16u iobase1;
5870
5871 channel = device / 2;
5872 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5873 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5874
5875 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5876 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5877 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5878 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5879 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5880
5881 if (iface==ATA_IFACE_ISA) {
5882 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5883 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5884 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5885 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5886 }
5887 else {
5888 // FIXME PCI
5889 }
5890 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5891 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5892 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5893 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5894
5895 if (iface==ATA_IFACE_ISA) {
5896 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5897 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5898 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5899 }
5900 else {
5901 // FIXME PCI
5902 }
5903 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5904 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5905 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5906 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5907
5908 checksum=0;
5909 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5910 checksum = ~checksum;
5911 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5912 }
5913
5914 goto int13_success;
5915 break;
5916
5917 case 0x4e: // // IBM/MS set hardware configuration
5918 // DMA, prefetch, PIO maximum not supported
5919 switch (GET_AL()) {
5920 case 0x01:
5921 case 0x03:
5922 case 0x04:
5923 case 0x06:
5924 goto int13_success;
5925 break;
5926 default :
5927 goto int13_fail;
5928 }
5929 break;
5930
5931 case 0x09: /* initialize drive parameters */
5932 case 0x0c: /* seek to specified cylinder */
5933 case 0x0d: /* alternate disk reset */
5934 case 0x11: /* recalibrate */
5935 case 0x14: /* controller internal diagnostic */
5936 BX_INFO("int13_harddisk: function %02xh unimplemented, returns success\n", GET_AH());
5937 goto int13_success;
5938 break;
5939
5940 case 0x0a: /* read disk sectors with ECC */
5941 case 0x0b: /* write disk sectors with ECC */
5942 case 0x18: // set media type for format
5943 case 0x50: // IBM/MS send packet command
5944 default:
5945 BX_INFO("int13_harddisk: function %02xh unsupported, returns fail\n", GET_AH());
5946 goto int13_fail;
5947 break;
5948 }
5949
5950int13_fail:
5951 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5952int13_fail_noah:
5953 SET_DISK_RET_STATUS(GET_AH());
5954int13_fail_nostatus:
5955 SET_CF(); // error occurred
5956 return;
5957
5958int13_success:
5959 SET_AH(0x00); // no error
5960int13_success_noah:
5961 SET_DISK_RET_STATUS(0x00);
5962 CLEAR_CF(); // no error
5963 return;
5964}
5965
5966// ---------------------------------------------------------------------------
5967// Start of int13 for cdrom
5968// ---------------------------------------------------------------------------
5969
5970 void
5971int13_cdrom(EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5972 Bit16u EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5973{
5974 Bit16u ebda_seg=read_word(0x0040,0x000E);
5975 Bit8u device, status, locks;
5976 Bit8u atacmd[12];
5977 Bit32u lba;
5978 Bit16u count, segment, offset, i, size;
5979
5980 BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5981
5982 SET_DISK_RET_STATUS(0x00);
5983
5984 /* basic check : device should be 0xE0+ */
5985 if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES) ) {
5986 BX_INFO("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5987 goto int13_fail;
5988 }
5989
5990 // Get the ata channel
5991 device=read_byte(ebda_seg,&EbdaData->ata.cdidmap[GET_ELDL()-0xE0]);
5992
5993 /* basic check : device has to be valid */
5994 if (device >= BX_MAX_ATA_DEVICES) {
5995 BX_INFO("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5996 goto int13_fail;
5997 }
5998
5999 switch (GET_AH()) {
6000
6001 // all those functions return SUCCESS
6002 case 0x00: /* disk controller reset */
6003 case 0x09: /* initialize drive parameters */
6004 case 0x0c: /* seek to specified cylinder */
6005 case 0x0d: /* alternate disk reset */
6006 case 0x10: /* check drive ready */
6007 case 0x11: /* recalibrate */
6008 case 0x14: /* controller internal diagnostic */
6009 case 0x16: /* detect disk change */
6010 goto int13_success;
6011 break;
6012
6013 // all those functions return disk write-protected
6014 case 0x03: /* write disk sectors */
6015 case 0x05: /* format disk track */
6016 case 0x43: // IBM/MS extended write
6017 SET_AH(0x03);
6018 goto int13_fail_noah;
6019 break;
6020
6021 case 0x01: /* read disk status */
6022 status = read_byte(0x0040, 0x0074);
6023 SET_AH(status);
6024 SET_DISK_RET_STATUS(0);
6025
6026 /* set CF if error status read */
6027 if (status) goto int13_fail_nostatus;
6028 else goto int13_success_noah;
6029 break;
6030
6031 case 0x15: /* read disk drive size */
6032 SET_AH(0x02);
6033 goto int13_fail_noah;
6034 break;
6035
6036 case 0x41: // IBM/MS installation check
6037 BX=0xaa55; // install check
6038 SET_AH(0x30); // EDD 2.1
6039 CX=0x0007; // ext disk access, removable and edd
6040 goto int13_success_noah;
6041 break;
6042
6043 case 0x42: // IBM/MS extended read
6044 case 0x44: // IBM/MS verify sectors
6045 case 0x47: // IBM/MS extended seek
6046
6047 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
6048 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
6049 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
6050
6051 // Can't use 64 bits lba
6052 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
6053 if (lba != 0L) {
6054 BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
6055 goto int13_fail;
6056 }
6057
6058 // Get 32 bits lba
6059 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
6060
6061 // If verify or seek
6062 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
6063 goto int13_success;
6064
6065 memsetb(get_SS(),atacmd,0,12);
6066 atacmd[0]=0x28; // READ command
6067 atacmd[7]=(count & 0xff00) >> 8; // Sectors
6068 atacmd[8]=(count & 0x00ff); // Sectors
6069 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
6070 atacmd[3]=(lba & 0x00ff0000) >> 16;
6071 atacmd[4]=(lba & 0x0000ff00) >> 8;
6072 atacmd[5]=(lba & 0x000000ff);
6073 status = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, count*2048L, ATA_DATA_IN, segment,offset);
6074
6075 count = (Bit16u)(read_dword(ebda_seg, &EbdaData->ata.trsfbytes) >> 11);
6076 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
6077
6078 if (status != 0) {
6079 BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status);
6080 SET_AH(0x0c);
6081 goto int13_fail_noah;
6082 }
6083
6084 goto int13_success;
6085 break;
6086
6087 case 0x45: // IBM/MS lock/unlock drive
6088 if (GET_AL() > 2) goto int13_fail;
6089
6090 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
6091
6092 switch (GET_AL()) {
6093 case 0 : // lock
6094 if (locks == 0xff) {
6095 SET_AH(0xb4);
6096 SET_AL(1);
6097 goto int13_fail_noah;
6098 }
6099 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, ++locks);
6100 SET_AL(1);
6101 break;
6102 case 1 : // unlock
6103 if (locks == 0x00) {
6104 SET_AH(0xb0);
6105 SET_AL(0);
6106 goto int13_fail_noah;
6107 }
6108 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, --locks);
6109 SET_AL(locks==0?0:1);
6110 break;
6111 case 2 : // status
6112 SET_AL(locks==0?0:1);
6113 break;
6114 }
6115 goto int13_success;
6116 break;
6117
6118 case 0x46: // IBM/MS eject media
6119 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
6120
6121 if (locks != 0) {
6122 SET_AH(0xb1); // media locked
6123 goto int13_fail_noah;
6124 }
6125 // FIXME should handle 0x31 no media in device
6126 // FIXME should handle 0xb5 valid request failed
6127
6128 // Call removable media eject
6129 ASM_START
6130 push bp
6131 mov bp, sp
6132
6133 mov ah, #0x52
6134 int #0x15
6135 mov _int13_cdrom.status + 2[bp], ah
6136 jnc int13_cdrom_rme_end
6137 mov _int13_cdrom.status, #1
6138int13_cdrom_rme_end:
6139 pop bp
6140 ASM_END
6141
6142 if (status != 0) {
6143 SET_AH(0xb1); // media locked
6144 goto int13_fail_noah;
6145 }
6146
6147 goto int13_success;
6148 break;
6149
6150 case 0x48: // IBM/MS get drive parameters
6151 size = read_word(DS,SI+(Bit16u)&Int13Ext->size);
6152
6153 // Buffer is too small
6154 if(size < 0x1a)
6155 goto int13_fail;
6156
6157 // EDD 1.x
6158 if(size >= 0x1a) {
6159 Bit16u cylinders, heads, spt, blksize;
6160
6161 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
6162
6163 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
6164 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x74); // removable, media change, lockable, max values
6165 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, 0xffffffff);
6166 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, 0xffffffff);
6167 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, 0xffffffff);
6168 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, 0xffffffff); // FIXME should be Bit64
6169 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0xffffffff);
6170 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
6171 }
6172
6173 // EDD 2.x
6174 if(size >= 0x1e) {
6175 Bit8u channel, dev, irq, mode, checksum, i;
6176 Bit16u iobase1, iobase2, options;
6177
6178 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
6179
6180 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
6181 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
6182
6183 // Fill in dpte
6184 channel = device / 2;
6185 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
6186 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
6187 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
6188 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
6189
6190 // FIXME atapi device
6191 options = (1<<4); // lba translation
6192 options |= (1<<5); // removable device
6193 options |= (1<<6); // atapi device
6194 options |= (mode==ATA_MODE_PIO32?1:0<<7);
6195
6196 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
6197 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
6198 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
6199 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
6200 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
6201 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
6202 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
6203 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
6204 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
6205 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
6206 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
6207
6208 checksum=0;
6209 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
6210 checksum = ~checksum;
6211 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
6212 }
6213
6214 // EDD 3.x
6215 if(size >= 0x42) {
6216 Bit8u channel, iface, checksum, i;
6217 Bit16u iobase1;
6218
6219 channel = device / 2;
6220 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
6221 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
6222
6223 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
6224 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
6225 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
6226 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
6227 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
6228
6229 if (iface==ATA_IFACE_ISA) {
6230 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
6231 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
6232 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
6233 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
6234 }
6235 else {
6236 // FIXME PCI
6237 }
6238 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
6239 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
6240 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
6241 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
6242
6243 if (iface==ATA_IFACE_ISA) {
6244 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
6245 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
6246 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
6247 }
6248 else {
6249 // FIXME PCI
6250 }
6251 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
6252 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
6253 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
6254 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
6255
6256 checksum=0;
6257 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
6258 checksum = ~checksum;
6259 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
6260 }
6261
6262 goto int13_success;
6263 break;
6264
6265 case 0x49: // IBM/MS extended media change
6266 // always send changed ??
6267 SET_AH(06);
6268 goto int13_fail_nostatus;
6269 break;
6270
6271 case 0x4e: // // IBM/MS set hardware configuration
6272 // DMA, prefetch, PIO maximum not supported
6273 switch (GET_AL()) {
6274 case 0x01:
6275 case 0x03:
6276 case 0x04:
6277 case 0x06:
6278 goto int13_success;
6279 break;
6280 default :
6281 goto int13_fail;
6282 }
6283 break;
6284
6285 // all those functions return unimplemented
6286 case 0x02: /* read sectors */
6287 case 0x04: /* verify sectors */
6288 case 0x08: /* read disk drive parameters */
6289 case 0x0a: /* read disk sectors with ECC */
6290 case 0x0b: /* write disk sectors with ECC */
6291 case 0x18: /* set media type for format */
6292 case 0x50: // ? - send packet command
6293 default:
6294 BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
6295 goto int13_fail;
6296 break;
6297 }
6298
6299int13_fail:
6300 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6301int13_fail_noah:
6302 SET_DISK_RET_STATUS(GET_AH());
6303int13_fail_nostatus:
6304 SET_CF(); // error occurred
6305 return;
6306
6307int13_success:
6308 SET_AH(0x00); // no error
6309int13_success_noah:
6310 SET_DISK_RET_STATUS(0x00);
6311 CLEAR_CF(); // no error
6312 return;
6313}
6314
6315// ---------------------------------------------------------------------------
6316// End of int13 for cdrom
6317// ---------------------------------------------------------------------------
6318
6319#if BX_ELTORITO_BOOT
6320// ---------------------------------------------------------------------------
6321// Start of int13 for eltorito functions
6322// ---------------------------------------------------------------------------
6323
6324 void
6325int13_eltorito(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
6326 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
6327{
6328 Bit16u ebda_seg=read_word(0x0040,0x000E);
6329
6330 BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6331 // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
6332
6333 switch (GET_AH()) {
6334
6335 // FIXME ElTorito Various. Should be implemented
6336 case 0x4a: // ElTorito - Initiate disk emu
6337 case 0x4c: // ElTorito - Initiate disk emu and boot
6338 case 0x4d: // ElTorito - Return Boot catalog
6339 BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX);
6340 goto int13_fail;
6341 break;
6342
6343 case 0x4b: // ElTorito - Terminate disk emu
6344 // FIXME ElTorito Hardcoded
6345 write_byte(DS,SI+0x00,0x13);
6346 write_byte(DS,SI+0x01,read_byte(ebda_seg,&EbdaData->cdemu.media));
6347 write_byte(DS,SI+0x02,read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
6348 write_byte(DS,SI+0x03,read_byte(ebda_seg,&EbdaData->cdemu.controller_index));
6349 write_dword(DS,SI+0x04,read_dword(ebda_seg,&EbdaData->cdemu.ilba));
6350 write_word(DS,SI+0x08,read_word(ebda_seg,&EbdaData->cdemu.device_spec));
6351 write_word(DS,SI+0x0a,read_word(ebda_seg,&EbdaData->cdemu.buffer_segment));
6352 write_word(DS,SI+0x0c,read_word(ebda_seg,&EbdaData->cdemu.load_segment));
6353 write_word(DS,SI+0x0e,read_word(ebda_seg,&EbdaData->cdemu.sector_count));
6354 write_byte(DS,SI+0x10,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.cylinders));
6355 write_byte(DS,SI+0x11,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.spt));
6356 write_byte(DS,SI+0x12,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.heads));
6357
6358 // If we have to terminate emulation
6359 if(GET_AL() == 0x00) {
6360 // FIXME ElTorito Various. Should be handled accordingly to spec
6361 write_byte(ebda_seg,&EbdaData->cdemu.active, 0x00); // bye bye
6362 }
6363
6364 goto int13_success;
6365 break;
6366
6367 default:
6368 BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
6369 goto int13_fail;
6370 break;
6371 }
6372
6373int13_fail:
6374 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6375 SET_DISK_RET_STATUS(GET_AH());
6376 SET_CF(); // error occurred
6377 return;
6378
6379int13_success:
6380 SET_AH(0x00); // no error
6381 SET_DISK_RET_STATUS(0x00);
6382 CLEAR_CF(); // no error
6383 return;
6384}
6385
6386// ---------------------------------------------------------------------------
6387// End of int13 for eltorito functions
6388// ---------------------------------------------------------------------------
6389
6390// ---------------------------------------------------------------------------
6391// Start of int13 when emulating a device from the cd
6392// ---------------------------------------------------------------------------
6393
6394 void
6395int13_cdemu(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
6396 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
6397{
6398 Bit16u ebda_seg=read_word(0x0040,0x000E);
6399 Bit8u device, status;
6400 Bit16u vheads, vspt, vcylinders;
6401 Bit16u head, sector, cylinder, nbsectors;
6402 Bit32u vlba, ilba, slba, elba;
6403 Bit16u before, segment, offset;
6404 Bit8u atacmd[12];
6405
6406 BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6407
6408 /* at this point, we are emulating a floppy/harddisk */
6409
6410 // Recompute the device number
6411 device = read_byte(ebda_seg,&EbdaData->cdemu.controller_index) * 2;
6412 device += read_byte(ebda_seg,&EbdaData->cdemu.device_spec);
6413
6414 SET_DISK_RET_STATUS(0x00);
6415
6416 /* basic checks : emulation should be active, dl should equal the emulated drive */
6417 if( (read_byte(ebda_seg,&EbdaData->cdemu.active) ==0 )
6418 || (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive ) != GET_DL())) {
6419 BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
6420 goto int13_fail;
6421 }
6422
6423 switch (GET_AH()) {
6424
6425 // all those functions return SUCCESS
6426 case 0x00: /* disk controller reset */
6427 case 0x09: /* initialize drive parameters */
6428 case 0x0c: /* seek to specified cylinder */
6429 case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
6430 case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
6431 case 0x11: /* recalibrate */
6432 case 0x14: /* controller internal diagnostic */
6433 case 0x16: /* detect disk change */
6434 goto int13_success;
6435 break;
6436
6437 // all those functions return disk write-protected
6438 case 0x03: /* write disk sectors */
6439 case 0x05: /* format disk track */
6440 SET_AH(0x03);
6441 goto int13_fail_noah;
6442 break;
6443
6444 case 0x01: /* read disk status */
6445 status=read_byte(0x0040, 0x0074);
6446 SET_AH(status);
6447 SET_DISK_RET_STATUS(0);
6448
6449 /* set CF if error status read */
6450 if (status) goto int13_fail_nostatus;
6451 else goto int13_success_noah;
6452 break;
6453
6454 case 0x02: // read disk sectors
6455 case 0x04: // verify disk sectors
6456 vspt = read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
6457 vcylinders = read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders);
6458 vheads = read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads);
6459
6460 ilba = read_dword(ebda_seg,&EbdaData->cdemu.ilba);
6461
6462 sector = GET_CL() & 0x003f;
6463 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
6464 head = GET_DH();
6465 nbsectors = GET_AL();
6466 segment = ES;
6467 offset = BX;
6468
6469 // no sector to read ?
6470 if(nbsectors==0) goto int13_success;
6471
6472 // sanity checks sco openserver needs this!
6473 if ((sector > vspt)
6474 || (cylinder >= vcylinders)
6475 || (head >= vheads)) {
6476 goto int13_fail;
6477 }
6478
6479 // After controls, verify do nothing
6480 if (GET_AH() == 0x04) goto int13_success;
6481
6482 segment = ES+(BX / 16);
6483 offset = BX % 16;
6484
6485 // calculate the virtual lba inside the image
6486 vlba=((((Bit32u)cylinder*(Bit32u)vheads)+(Bit32u)head)*(Bit32u)vspt)+((Bit32u)(sector-1));
6487
6488 // In advance so we don't loose the count
6489 SET_AL(nbsectors);
6490
6491 // start lba on cd
6492 slba = (Bit32u)vlba/4;
6493 before= (Bit16u)vlba%4;
6494
6495 // end lba on cd
6496 elba = (Bit32u)(vlba+nbsectors-1)/4;
6497
6498 memsetb(get_SS(),atacmd,0,12);
6499 atacmd[0]=0x28; // READ command
6500 atacmd[7]=((Bit16u)(elba-slba+1) & 0xff00) >> 8; // Sectors
6501 atacmd[8]=((Bit16u)(elba-slba+1) & 0x00ff); // Sectors
6502 atacmd[2]=(ilba+slba & 0xff000000) >> 24; // LBA
6503 atacmd[3]=(ilba+slba & 0x00ff0000) >> 16;
6504 atacmd[4]=(ilba+slba & 0x0000ff00) >> 8;
6505 atacmd[5]=(ilba+slba & 0x000000ff);
6506 if((status = ata_cmd_packet(device, 12, get_SS(), atacmd, before*512, nbsectors*512L, ATA_DATA_IN, segment,offset)) != 0) {
6507 BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status);
6508 SET_AH(0x02);
6509 SET_AL(0);
6510 goto int13_fail_noah;
6511 }
6512
6513 goto int13_success;
6514 break;
6515
6516 case 0x08: /* read disk drive parameters */
6517 vspt=read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
6518 vcylinders=read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders) - 1;
6519 vheads=read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads) - 1;
6520
6521 SET_AL( 0x00 );
6522 SET_BL( 0x00 );
6523 SET_CH( vcylinders & 0xff );
6524 SET_CL((( vcylinders >> 2) & 0xc0) | ( vspt & 0x3f ));
6525 SET_DH( vheads );
6526 SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2
6527 // FIXME ElTorito Harddisk. should send the HD count
6528
6529 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
6530 case 0x01: SET_BL( 0x02 ); break;
6531 case 0x02: SET_BL( 0x04 ); break;
6532 case 0x03: SET_BL( 0x06 ); break;
6533 }
6534
6535ASM_START
6536 push bp
6537 mov bp, sp
6538 mov ax, #diskette_param_table2
6539 mov _int13_cdemu.DI+2[bp], ax
6540 mov _int13_cdemu.ES+2[bp], cs
6541 pop bp
6542ASM_END
6543 goto int13_success;
6544 break;
6545
6546 case 0x15: /* read disk drive size */
6547 // FIXME ElTorito Harddisk. What geometry to send ?
6548 SET_AH(0x03);
6549 goto int13_success_noah;
6550 break;
6551
6552 // all those functions return unimplemented
6553 case 0x0a: /* read disk sectors with ECC */
6554 case 0x0b: /* write disk sectors with ECC */
6555 case 0x18: /* set media type for format */
6556 case 0x41: // IBM/MS installation check
6557 // FIXME ElTorito Harddisk. Darwin would like to use EDD
6558 case 0x42: // IBM/MS extended read
6559 case 0x43: // IBM/MS extended write
6560 case 0x44: // IBM/MS verify sectors
6561 case 0x45: // IBM/MS lock/unlock drive
6562 case 0x46: // IBM/MS eject media
6563 case 0x47: // IBM/MS extended seek
6564 case 0x48: // IBM/MS get drive parameters
6565 case 0x49: // IBM/MS extended media change
6566 case 0x4e: // ? - set hardware configuration
6567 case 0x50: // ? - send packet command
6568 default:
6569 BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
6570 goto int13_fail;
6571 break;
6572 }
6573
6574int13_fail:
6575 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6576int13_fail_noah:
6577 SET_DISK_RET_STATUS(GET_AH());
6578int13_fail_nostatus:
6579 SET_CF(); // error occurred
6580 return;
6581
6582int13_success:
6583 SET_AH(0x00); // no error
6584int13_success_noah:
6585 SET_DISK_RET_STATUS(0x00);
6586 CLEAR_CF(); // no error
6587 return;
6588}
6589
6590// ---------------------------------------------------------------------------
6591// End of int13 when emulating a device from the cd
6592// ---------------------------------------------------------------------------
6593
6594#endif // BX_ELTORITO_BOOT
6595
6596#else //BX_USE_ATADRV
6597
6598 void
6599outLBA(cylinder,hd_heads,head,hd_sectors,sector,dl)
6600 Bit16u cylinder;
6601 Bit16u hd_heads;
6602 Bit16u head;
6603 Bit16u hd_sectors;
6604 Bit16u sector;
6605 Bit16u dl;
6606{
6607ASM_START
6608 push bp
6609 mov bp, sp
6610 push eax
6611 push ebx
6612 push edx
6613 xor eax,eax
6614 mov ax,4[bp] // cylinder
6615 xor ebx,ebx
6616 mov bl,6[bp] // hd_heads
6617 imul ebx
6618
6619 mov bl,8[bp] // head
6620 add eax,ebx
6621 mov bl,10[bp] // hd_sectors
6622 imul ebx
6623 mov bl,12[bp] // sector
6624 add eax,ebx
6625
6626 dec eax
6627 mov dx,#0x1f3
6628 out dx,al
6629 mov dx,#0x1f4
6630 mov al,ah
6631 out dx,al
6632 shr eax,#16
6633 mov dx,#0x1f5
6634 out dx,al
6635 and ah,#0xf
6636 mov bl,14[bp] // dl
6637 and bl,#1
6638 shl bl,#4
6639 or ah,bl
6640 or ah,#0xe0
6641 mov al,ah
6642 mov dx,#0x01f6
6643 out dx,al
6644 pop edx
6645 pop ebx
6646 pop eax
6647 pop bp
6648ASM_END
6649}
6650
6651 void
6652int13_harddisk(EHBX, EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
6653 Bit16u EHBX, EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
6654{
6655 Bit8u drive, num_sectors, sector, head, status, mod;
6656 Bit8u drive_map;
6657 Bit8u n_drives;
6658 Bit16u cyl_mod, ax;
6659 Bit16u max_cylinder, cylinder, total_sectors;
6660 Bit16u hd_cylinders;
6661 Bit8u hd_heads, hd_sectors;
6662 Bit16u val16;
6663 Bit8u sector_count;
6664 unsigned int i;
6665 Bit16u tempbx;
6666 Bit16u dpsize;
6667
6668 Bit16u count, segment, offset;
6669 Bit32u lba;
6670 Bit16u error;
6671
6672 BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6673
6674 write_byte(0x0040, 0x008e, 0); // clear completion flag
6675
6676 /* at this point, DL is >= 0x80 to be passed from the floppy int13h
6677 handler code */
6678 /* check how many disks first (cmos reg 0x12), return an error if
6679 drive not present */
6680 drive_map = inb_cmos(0x12);
6681 drive_map = (((drive_map & 0xf0)==0) ? 0 : 1) |
6682 (((drive_map & 0x0f)==0) ? 0 : 2);
6683 n_drives = (drive_map==0) ? 0 :
6684 ((drive_map==3) ? 2 : 1);
6685
6686 if (!(drive_map & (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
6687 SET_AH(0x01);
6688 SET_DISK_RET_STATUS(0x01);
6689 SET_CF(); /* error occurred */
6690 return;
6691 }
6692
6693 switch (GET_AH()) {
6694
6695 case 0x00: /* disk controller reset */
6696BX_DEBUG_INT13_HD("int13_f00\n");
6697
6698 SET_AH(0);
6699 SET_DISK_RET_STATUS(0);
6700 set_diskette_ret_status(0);
6701 set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
6702 set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
6703 CLEAR_CF(); /* successful */
6704 return;
6705 break;
6706
6707 case 0x01: /* read disk status */
6708BX_DEBUG_INT13_HD("int13_f01\n");
6709 status = read_byte(0x0040, 0x0074);
6710 SET_AH(status);
6711 SET_DISK_RET_STATUS(0);
6712 /* set CF if error status read */
6713 if (status) SET_CF();
6714 else CLEAR_CF();
6715 return;
6716 break;
6717
6718 case 0x04: // verify disk sectors
6719 case 0x02: // read disk sectors
6720 drive = GET_ELDL();
6721 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6722
6723 num_sectors = GET_AL();
6724 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
6725 sector = (GET_CL() & 0x3f);
6726 head = GET_DH();
6727
6728
6729 if (hd_cylinders > 1024) {
6730 if (hd_cylinders <= 2048) {
6731 cylinder <<= 1;
6732 }
6733 else if (hd_cylinders <= 4096) {
6734 cylinder <<= 2;
6735 }
6736 else if (hd_cylinders <= 8192) {
6737 cylinder <<= 3;
6738 }
6739 else { // hd_cylinders <= 16384
6740 cylinder <<= 4;
6741 }
6742
6743 ax = head / hd_heads;
6744 cyl_mod = ax & 0xff;
6745 head = ax >> 8;
6746 cylinder |= cyl_mod;
6747 }
6748
6749 if ( (cylinder >= hd_cylinders) ||
6750 (sector > hd_sectors) ||
6751 (head >= hd_heads) ) {
6752 SET_AH(1);
6753 SET_DISK_RET_STATUS(1);
6754 SET_CF(); /* error occurred */
6755 return;
6756 }
6757
6758 if ( (num_sectors > 128) || (num_sectors == 0) )
6759 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6760
6761 if (head > 15)
6762 BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
6763
6764 if ( GET_AH() == 0x04 ) {
6765 SET_AH(0);
6766 SET_DISK_RET_STATUS(0);
6767 CLEAR_CF();
6768 return;
6769 }
6770
6771 status = inb(0x1f7);
6772 if (status & 0x80) {
6773 BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
6774 }
6775 outb(0x01f2, num_sectors);
6776 /* activate LBA? (tomv) */
6777 if (hd_heads > 16) {
6778BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder, head, sector);
6779 outLBA(cylinder,hd_heads,head,hd_sectors,sector,drive);
6780 }
6781 else {
6782 outb(0x01f3, sector);
6783 outb(0x01f4, cylinder & 0x00ff);
6784 outb(0x01f5, cylinder >> 8);
6785 outb(0x01f6, 0xa0 | ((drive & 0x01)<<4) | (head & 0x0f));
6786 }
6787 outb(0x01f7, 0x20);
6788
6789 while (1) {
6790 status = inb(0x1f7);
6791 if ( !(status & 0x80) ) break;
6792 }
6793
6794 if (status & 0x01) {
6795 BX_PANIC("hard drive BIOS:(read/verify) read error\n");
6796 } else if ( !(status & 0x08) ) {
6797 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6798 BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
6799 }
6800
6801 sector_count = 0;
6802 tempbx = BX;
6803
6804ASM_START
6805 sti ;; enable higher priority interrupts
6806ASM_END
6807
6808 while (1) {
6809ASM_START
6810 ;; store temp bx in real DI register
6811 push bp
6812 mov bp, sp
6813 mov di, _int13_harddisk.tempbx + 2 [bp]
6814 pop bp
6815
6816 ;; adjust if there will be an overrun
6817 cmp di, #0xfe00
6818 jbe i13_f02_no_adjust
6819i13_f02_adjust:
6820 sub di, #0x0200 ; sub 512 bytes from offset
6821 mov ax, es
6822 add ax, #0x0020 ; add 512 to segment
6823 mov es, ax
6824
6825i13_f02_no_adjust:
6826 mov cx, #0x0100 ;; counter (256 words = 512b)
6827 mov dx, #0x01f0 ;; AT data read port
6828
6829 rep
6830 insw ;; CX words transfered from port(DX) to ES:[DI]
6831
6832i13_f02_done:
6833 ;; store real DI register back to temp bx
6834 push bp
6835 mov bp, sp
6836 mov _int13_harddisk.tempbx + 2 [bp], di
6837 pop bp
6838ASM_END
6839
6840 sector_count++;
6841 num_sectors--;
6842 if (num_sectors == 0) {
6843 status = inb(0x1f7);
6844 if ( (status & 0xc9) != 0x40 )
6845 BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status);
6846 break;
6847 }
6848 else {
6849 status = inb(0x1f7);
6850 if ( (status & 0xc9) != 0x48 )
6851 BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status);
6852 continue;
6853 }
6854 }
6855
6856 SET_AH(0);
6857 SET_DISK_RET_STATUS(0);
6858 SET_AL(sector_count);
6859 CLEAR_CF(); /* successful */
6860 return;
6861 break;
6862
6863
6864 case 0x03: /* write disk sectors */
6865BX_DEBUG_INT13_HD("int13_f03\n");
6866 drive = GET_ELDL ();
6867 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6868
6869 num_sectors = GET_AL();
6870 cylinder = GET_CH();
6871 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
6872 sector = (GET_CL() & 0x3f);
6873 head = GET_DH();
6874
6875 if (hd_cylinders > 1024) {
6876 if (hd_cylinders <= 2048) {
6877 cylinder <<= 1;
6878 }
6879 else if (hd_cylinders <= 4096) {
6880 cylinder <<= 2;
6881 }
6882 else if (hd_cylinders <= 8192) {
6883 cylinder <<= 3;
6884 }
6885 else { // hd_cylinders <= 16384
6886 cylinder <<= 4;
6887 }
6888
6889 ax = head / hd_heads;
6890 cyl_mod = ax & 0xff;
6891 head = ax >> 8;
6892 cylinder |= cyl_mod;
6893 }
6894
6895 if ( (cylinder >= hd_cylinders) ||
6896 (sector > hd_sectors) ||
6897 (head >= hd_heads) ) {
6898 SET_AH( 1);
6899 SET_DISK_RET_STATUS(1);
6900 SET_CF(); /* error occurred */
6901 return;
6902 }
6903
6904 if ( (num_sectors > 128) || (num_sectors == 0) )
6905 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6906
6907 if (head > 15)
6908 BX_PANIC("hard drive BIOS:(read) head > 15\n");
6909
6910 status = inb(0x1f7);
6911 if (status & 0x80) {
6912 BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
6913 }
6914// should check for Drive Ready Bit also in status reg
6915 outb(0x01f2, num_sectors);
6916
6917 /* activate LBA? (tomv) */
6918 if (hd_heads > 16) {
6919BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder, head, sector);
6920 outLBA(cylinder,hd_heads,head,hd_sectors,sector,GET_ELDL());
6921 }
6922 else {
6923 outb(0x01f3, sector);
6924 outb(0x01f4, cylinder & 0x00ff);
6925 outb(0x01f5, cylinder >> 8);
6926 outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head & 0x0f));
6927 }
6928 outb(0x01f7, 0x30);
6929
6930 // wait for busy bit to turn off after seeking
6931 while (1) {
6932 status = inb(0x1f7);
6933 if ( !(status & 0x80) ) break;
6934 }
6935
6936 if ( !(status & 0x08) ) {
6937 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6938 BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
6939 }
6940
6941 sector_count = 0;
6942 tempbx = BX;
6943
6944ASM_START
6945 sti ;; enable higher priority interrupts
6946ASM_END
6947
6948 while (1) {
6949ASM_START
6950 ;; store temp bx in real SI register
6951 push bp
6952 mov bp, sp
6953 mov si, _int13_harddisk.tempbx + 2 [bp]
6954 pop bp
6955
6956 ;; adjust if there will be an overrun
6957 cmp si, #0xfe00
6958 jbe i13_f03_no_adjust
6959i13_f03_adjust:
6960 sub si, #0x0200 ; sub 512 bytes from offset
6961 mov ax, es
6962 add ax, #0x0020 ; add 512 to segment
6963 mov es, ax
6964
6965i13_f03_no_adjust:
6966 mov cx, #0x0100 ;; counter (256 words = 512b)
6967 mov dx, #0x01f0 ;; AT data read port
6968
6969 seg ES
6970 rep
6971 outsw ;; CX words tranfered from ES:[SI] to port(DX)
6972
6973 ;; store real SI register back to temp bx
6974 push bp
6975 mov bp, sp
6976 mov _int13_harddisk.tempbx + 2 [bp], si
6977 pop bp
6978ASM_END
6979
6980 sector_count++;
6981 num_sectors--;
6982 if (num_sectors == 0) {
6983 status = inb(0x1f7);
6984 if ( (status & 0xe9) != 0x40 )
6985 BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status);
6986 break;
6987 }
6988 else {
6989 status = inb(0x1f7);
6990 if ( (status & 0xc9) != 0x48 )
6991 BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status);
6992 continue;
6993 }
6994 }
6995
6996 SET_AH(0);
6997 SET_DISK_RET_STATUS(0);
6998 SET_AL(sector_count);
6999 CLEAR_CF(); /* successful */
7000 return;
7001 break;
7002
7003 case 0x05: /* format disk track */
7004BX_DEBUG_INT13_HD("int13_f05\n");
7005 BX_PANIC("format disk track called\n");
7006 /* nop */
7007 SET_AH(0);
7008 SET_DISK_RET_STATUS(0);
7009 CLEAR_CF(); /* successful */
7010 return;
7011 break;
7012
7013 case 0x08: /* read disk drive parameters */
7014BX_DEBUG_INT13_HD("int13_f08\n");
7015
7016 drive = GET_ELDL ();
7017 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
7018
7019 // translate CHS
7020 //
7021 if (hd_cylinders <= 1024) {
7022 // hd_cylinders >>= 0;
7023 // hd_heads <<= 0;
7024 }
7025 else if (hd_cylinders <= 2048) {
7026 hd_cylinders >>= 1;
7027 hd_heads <<= 1;
7028 }
7029 else if (hd_cylinders <= 4096) {
7030 hd_cylinders >>= 2;
7031 hd_heads <<= 2;
7032 }
7033 else if (hd_cylinders <= 8192) {
7034 hd_cylinders >>= 3;
7035 hd_heads <<= 3;
7036 }
7037 else { // hd_cylinders <= 16384
7038 hd_cylinders >>= 4;
7039 hd_heads <<= 4;
7040 }
7041
7042 max_cylinder = hd_cylinders - 2; /* 0 based */
7043 SET_AL(0);
7044 SET_CH(max_cylinder & 0xff);
7045 SET_CL(((max_cylinder >> 2) & 0xc0) | (hd_sectors & 0x3f));
7046 SET_DH(hd_heads - 1);
7047 SET_DL(n_drives); /* returns 0, 1, or 2 hard drives */
7048 SET_AH(0);
7049 SET_DISK_RET_STATUS(0);
7050 CLEAR_CF(); /* successful */
7051
7052 return;
7053 break;
7054
7055 case 0x09: /* initialize drive parameters */
7056BX_DEBUG_INT13_HD("int13_f09\n");
7057 SET_AH(0);
7058 SET_DISK_RET_STATUS(0);
7059 CLEAR_CF(); /* successful */
7060 return;
7061 break;
7062
7063 case 0x0a: /* read disk sectors with ECC */
7064BX_DEBUG_INT13_HD("int13_f0a\n");
7065 case 0x0b: /* write disk sectors with ECC */
7066BX_DEBUG_INT13_HD("int13_f0b\n");
7067 BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
7068 return;
7069 break;
7070
7071 case 0x0c: /* seek to specified cylinder */
7072BX_DEBUG_INT13_HD("int13_f0c\n");
7073 BX_INFO("int13h function 0ch (seek) not implemented!\n");
7074 SET_AH(0);
7075 SET_DISK_RET_STATUS(0);
7076 CLEAR_CF(); /* successful */
7077 return;
7078 break;
7079
7080 case 0x0d: /* alternate disk reset */
7081BX_DEBUG_INT13_HD("int13_f0d\n");
7082 SET_AH(0);
7083 SET_DISK_RET_STATUS(0);
7084 CLEAR_CF(); /* successful */
7085 return;
7086 break;
7087
7088 case 0x10: /* check drive ready */
7089BX_DEBUG_INT13_HD("int13_f10\n");
7090 //SET_AH(0);
7091 //SET_DISK_RET_STATUS(0);
7092 //CLEAR_CF(); /* successful */
7093 //return;
7094 //break;
7095
7096 // should look at 40:8E also???
7097 status = inb(0x01f7);
7098 if ( (status & 0xc0) == 0x40 ) {
7099 SET_AH(0);
7100 SET_DISK_RET_STATUS(0);
7101 CLEAR_CF(); // drive ready
7102 return;
7103 }
7104 else {
7105 SET_AH(0xAA);
7106 SET_DISK_RET_STATUS(0xAA);
7107 SET_CF(); // not ready
7108 return;
7109 }
7110 break;
7111
7112 case 0x11: /* recalibrate */
7113BX_DEBUG_INT13_HD("int13_f11\n");
7114 SET_AH(0);
7115 SET_DISK_RET_STATUS(0);
7116 CLEAR_CF(); /* successful */
7117 return;
7118 break;
7119
7120 case 0x14: /* controller internal diagnostic */
7121BX_DEBUG_INT13_HD("int13_f14\n");
7122 SET_AH(0);
7123 SET_DISK_RET_STATUS(0);
7124 CLEAR_CF(); /* successful */
7125 SET_AL(0);
7126 return;
7127 break;
7128
7129 case 0x15: /* read disk drive size */
7130 drive = GET_ELDL();
7131 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
7132ASM_START
7133 push bp
7134 mov bp, sp
7135 mov al, _int13_harddisk.hd_heads + 2 [bp]
7136 mov ah, _int13_harddisk.hd_sectors + 2 [bp]
7137 mul al, ah ;; ax = heads * sectors
7138 mov bx, _int13_harddisk.hd_cylinders + 2 [bp]
7139 dec bx ;; use (cylinders - 1) ???
7140 mul ax, bx ;; dx:ax = (cylinders -1) * (heads * sectors)
7141 ;; now we need to move the 32bit result dx:ax to what the
7142 ;; BIOS wants which is cx:dx.
7143 ;; and then into CX:DX on the stack
7144 mov _int13_harddisk.CX + 2 [bp], dx
7145 mov _int13_harddisk.DX + 2 [bp], ax
7146 pop bp
7147ASM_END
7148 SET_AH(3); // hard disk accessible
7149 SET_DISK_RET_STATUS(0); // ??? should this be 0
7150 CLEAR_CF(); // successful
7151 return;
7152 break;
7153
7154 case 0x18: // set media type for format
7155 case 0x41: // IBM/MS
7156 case 0x42: // IBM/MS
7157 case 0x43: // IBM/MS
7158 case 0x44: // IBM/MS
7159 case 0x45: // IBM/MS lock/unlock drive
7160 case 0x46: // IBM/MS eject media
7161 case 0x47: // IBM/MS extended seek
7162 case 0x49: // IBM/MS extended media change
7163 case 0x50: // IBM/MS send packet command
7164 default:
7165 BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
7166
7167 SET_AH(1); // code=invalid function in AH or invalid parameter
7168 SET_DISK_RET_STATUS(1);
7169 SET_CF(); /* unsuccessful */
7170 return;
7171 break;
7172 }
7173}
7174
7175static char panic_msg_reg12h[] = "HD%d cmos reg 12h not type F\n";
7176static char panic_msg_reg19h[] = "HD%d cmos reg %02xh not user definable type 47\n";
7177
7178 void
7179get_hd_geometry(drive, hd_cylinders, hd_heads, hd_sectors)
7180 Bit8u drive;
7181 Bit16u *hd_cylinders;
7182 Bit8u *hd_heads;
7183 Bit8u *hd_sectors;
7184{
7185 Bit8u hd_type;
7186 Bit16u ss;
7187 Bit16u cylinders;
7188 Bit8u iobase;
7189
7190 ss = get_SS();
7191 if (drive == 0x80) {
7192 hd_type = inb_cmos(0x12) & 0xf0;
7193 if (hd_type != 0xf0)
7194 BX_INFO(panic_msg_reg12h,0);
7195 hd_type = inb_cmos(0x19); // HD0: extended type
7196 if (hd_type != 47)
7197 BX_INFO(panic_msg_reg19h,0,0x19);
7198 iobase = 0x1b;
7199 } else {
7200 hd_type = inb_cmos(0x12) & 0x0f;
7201 if (hd_type != 0x0f)
7202 BX_INFO(panic_msg_reg12h,1);
7203 hd_type = inb_cmos(0x1a); // HD1: extended type
7204 if (hd_type != 47)
7205 BX_INFO(panic_msg_reg19h,0,0x1a);
7206 iobase = 0x24;
7207 }
7208
7209 // cylinders
7210 cylinders = inb_cmos(iobase) | (inb_cmos(iobase+1) << 8);
7211 write_word(ss, hd_cylinders, cylinders);
7212
7213 // heads
7214 write_byte(ss, hd_heads, inb_cmos(iobase+2));
7215
7216 // sectors per track
7217 write_byte(ss, hd_sectors, inb_cmos(iobase+8));
7218}
7219
7220#endif //else BX_USE_ATADRV
7221
7222#if BX_SUPPORT_FLOPPY
7223
7224//////////////////////
7225// FLOPPY functions //
7226//////////////////////
7227
7228void floppy_reset_controller()
7229{
7230 Bit8u val8;
7231
7232 // Reset controller
7233 val8 = inb(0x03f2);
7234 outb(0x03f2, val8 & ~0x04);
7235 outb(0x03f2, val8 | 0x04);
7236
7237 // Wait for controller to come out of reset
7238 do {
7239 val8 = inb(0x3f4);
7240 } while ( (val8 & 0xc0) != 0x80 );
7241}
7242
7243void floppy_prepare_controller(drive)
7244 Bit16u drive;
7245{
7246 Bit8u val8, dor, prev_reset;
7247
7248 // set 40:3e bit 7 to 0
7249 val8 = read_byte(0x0040, 0x003e);
7250 val8 &= 0x7f;
7251 write_byte(0x0040, 0x003e, val8);
7252
7253 // turn on motor of selected drive, DMA & int enabled, normal operation
7254 prev_reset = inb(0x03f2) & 0x04;
7255 if (drive)
7256 dor = 0x20;
7257 else
7258 dor = 0x10;
7259 dor |= 0x0c;
7260 dor |= drive;
7261 outb(0x03f2, dor);
7262
7263 // reset the disk motor timeout value of INT 08
7264 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
7265
7266#ifdef VBOX
7267 // program data rate
7268 val8 = read_byte(0x0040, 0x008b);
7269 val8 >>= 6;
7270 outb(0x03f7, val8);
7271#endif
7272
7273 // wait for drive readiness
7274 do {
7275 val8 = inb(0x3f4);
7276 } while ( (val8 & 0xc0) != 0x80 );
7277
7278 if (prev_reset == 0) {
7279 // turn on interrupts
7280ASM_START
7281 sti
7282ASM_END
7283 // wait on 40:3e bit 7 to become 1
7284 do {
7285 val8 = read_byte(0x0040, 0x003e);
7286 } while ( (val8 & 0x80) == 0 );
7287 val8 &= 0x7f;
7288ASM_START
7289 cli
7290ASM_END
7291 write_byte(0x0040, 0x003e, val8);
7292 }
7293}
7294
7295 bx_bool
7296floppy_media_known(drive)
7297 Bit16u drive;
7298{
7299 Bit8u val8;
7300 Bit16u media_state_offset;
7301
7302 val8 = read_byte(0x0040, 0x003e); // diskette recal status
7303 if (drive)
7304 val8 >>= 1;
7305 val8 &= 0x01;
7306 if (val8 == 0)
7307 return(0);
7308
7309 media_state_offset = 0x0090;
7310 if (drive)
7311 media_state_offset += 1;
7312
7313 val8 = read_byte(0x0040, media_state_offset);
7314 val8 = (val8 >> 4) & 0x01;
7315 if (val8 == 0)
7316 return(0);
7317
7318 // check pass, return KNOWN
7319 return(1);
7320}
7321
7322 bx_bool
7323floppy_media_sense(drive)
7324 Bit16u drive;
7325{
7326 bx_bool retval;
7327 Bit16u media_state_offset;
7328 Bit8u drive_type, config_data, media_state;
7329
7330 if (floppy_drive_recal(drive) == 0) {
7331 return(0);
7332 }
7333
7334 // for now cheat and get drive type from CMOS,
7335 // assume media is same as drive type
7336
7337 // ** config_data **
7338 // Bitfields for diskette media control:
7339 // Bit(s) Description (Table M0028)
7340 // 7-6 last data rate set by controller
7341 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
7342 // 5-4 last diskette drive step rate selected
7343 // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
7344 // 3-2 {data rate at start of operation}
7345 // 1-0 reserved
7346
7347 // ** media_state **
7348 // Bitfields for diskette drive media state:
7349 // Bit(s) Description (Table M0030)
7350 // 7-6 data rate
7351 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
7352 // 5 double stepping required (e.g. 360kB in 1.2MB)
7353 // 4 media type established
7354 // 3 drive capable of supporting 4MB media
7355 // 2-0 on exit from BIOS, contains
7356 // 000 trying 360kB in 360kB
7357 // 001 trying 360kB in 1.2MB
7358 // 010 trying 1.2MB in 1.2MB
7359 // 011 360kB in 360kB established
7360 // 100 360kB in 1.2MB established
7361 // 101 1.2MB in 1.2MB established
7362 // 110 reserved
7363 // 111 all other formats/drives
7364
7365 drive_type = inb_cmos(0x10);
7366 if (drive == 0)
7367 drive_type >>= 4;
7368 else
7369 drive_type &= 0x0f;
7370 if ( drive_type == 1 ) {
7371 // 360K 5.25" drive
7372 config_data = 0x00; // 0000 0000
7373 media_state = 0x25; // 0010 0101
7374 retval = 1;
7375 }
7376 else if ( drive_type == 2 ) {
7377 // 1.2 MB 5.25" drive
7378 config_data = 0x00; // 0000 0000
7379 media_state = 0x25; // 0010 0101 // need double stepping??? (bit 5)
7380 retval = 1;
7381 }
7382 else if ( drive_type == 3 ) {
7383 // 720K 3.5" drive
7384 config_data = 0x00; // 0000 0000 ???
7385 media_state = 0x17; // 0001 0111
7386 retval = 1;
7387 }
7388 else if ( drive_type == 4 ) {
7389 // 1.44 MB 3.5" drive
7390 config_data = 0x00; // 0000 0000
7391 media_state = 0x17; // 0001 0111
7392 retval = 1;
7393 }
7394 else if ( drive_type == 5 ) {
7395 // 2.88 MB 3.5" drive
7396 config_data = 0xCC; // 1100 1100
7397 media_state = 0xD7; // 1101 0111
7398 retval = 1;
7399 }
7400 //
7401 // Extended floppy size uses special cmos setting
7402 else if ( drive_type == 6 ) {
7403 // 160k 5.25" drive
7404 config_data = 0x00; // 0000 0000
7405 media_state = 0x27; // 0010 0111
7406 retval = 1;
7407 }
7408 else if ( drive_type == 7 ) {
7409 // 180k 5.25" drive
7410 config_data = 0x00; // 0000 0000
7411 media_state = 0x27; // 0010 0111
7412 retval = 1;
7413 }
7414 else if ( drive_type == 8 ) {
7415 // 320k 5.25" drive
7416 config_data = 0x00; // 0000 0000
7417 media_state = 0x27; // 0010 0111
7418 retval = 1;
7419 }
7420
7421 else {
7422 // not recognized
7423 config_data = 0x00; // 0000 0000
7424 media_state = 0x00; // 0000 0000
7425 retval = 0;
7426 }
7427
7428 if (drive == 0)
7429 media_state_offset = 0x90;
7430 else
7431 media_state_offset = 0x91;
7432 write_byte(0x0040, 0x008B, config_data);
7433 write_byte(0x0040, media_state_offset, media_state);
7434
7435 return(retval);
7436}
7437
7438 bx_bool
7439floppy_drive_recal(drive)
7440 Bit16u drive;
7441{
7442 Bit8u val8;
7443 Bit16u curr_cyl_offset;
7444
7445 floppy_prepare_controller(drive);
7446
7447 // send Recalibrate command (2 bytes) to controller
7448 outb(0x03f5, 0x07); // 07: Recalibrate
7449 outb(0x03f5, drive); // 0=drive0, 1=drive1
7450
7451 // turn on interrupts
7452ASM_START
7453 sti
7454ASM_END
7455
7456 // wait on 40:3e bit 7 to become 1
7457 do {
7458 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7459 } while ( val8 == 0 );
7460
7461 val8 = 0; // separate asm from while() loop
7462 // turn off interrupts
7463ASM_START
7464 cli
7465ASM_END
7466
7467 // set 40:3e bit 7 to 0, and calibrated bit
7468 val8 = read_byte(0x0040, 0x003e);
7469 val8 &= 0x7f;
7470 if (drive) {
7471 val8 |= 0x02; // Drive 1 calibrated
7472 curr_cyl_offset = 0x0095;
7473 } else {
7474 val8 |= 0x01; // Drive 0 calibrated
7475 curr_cyl_offset = 0x0094;
7476 }
7477 write_byte(0x0040, 0x003e, val8);
7478 write_byte(0x0040, curr_cyl_offset, 0); // current cylinder is 0
7479
7480 return(1);
7481}
7482
7483
7484
7485 bx_bool
7486floppy_drive_exists(drive)
7487 Bit16u drive;
7488{
7489 Bit8u drive_type;
7490
7491 // check CMOS to see if drive exists
7492 drive_type = inb_cmos(0x10);
7493 if (drive == 0)
7494 drive_type >>= 4;
7495 else
7496 drive_type &= 0x0f;
7497 if ( drive_type == 0 )
7498 return(0);
7499 else
7500 return(1);
7501}
7502
7503 void
7504int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
7505 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
7506{
7507 Bit8u drive, num_sectors, track, sector, head, status;
7508 Bit16u base_address, base_count, base_es;
7509 Bit8u page, mode_register, val8, dor;
7510 Bit8u return_status[7];
7511 Bit8u drive_type, num_floppies, ah;
7512 Bit16u es, last_addr;
7513
7514 BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
7515
7516 ah = GET_AH();
7517
7518 switch ( ah ) {
7519 case 0x00: // diskette controller reset
7520BX_DEBUG_INT13_FL("floppy f00\n");
7521 drive = GET_ELDL();
7522 if (drive > 1) {
7523 SET_AH(1); // invalid param
7524 set_diskette_ret_status(1);
7525 SET_CF();
7526 return;
7527 }
7528 drive_type = inb_cmos(0x10);
7529
7530 if (drive == 0)
7531 drive_type >>= 4;
7532 else
7533 drive_type &= 0x0f;
7534 if (drive_type == 0) {
7535 SET_AH(0x80); // drive not responding
7536 set_diskette_ret_status(0x80);
7537 SET_CF();
7538 return;
7539 }
7540 SET_AH(0);
7541 set_diskette_ret_status(0);
7542 CLEAR_CF(); // successful
7543 set_diskette_current_cyl(drive, 0); // current cylinder
7544 return;
7545
7546 case 0x01: // Read Diskette Status
7547 CLEAR_CF();
7548 val8 = read_byte(0x0000, 0x0441);
7549 SET_AH(val8);
7550 if (val8) {
7551 SET_CF();
7552 }
7553 return;
7554
7555 case 0x02: // Read Diskette Sectors
7556 case 0x03: // Write Diskette Sectors
7557 case 0x04: // Verify Diskette Sectors
7558 num_sectors = GET_AL();
7559 track = GET_CH();
7560 sector = GET_CL();
7561 head = GET_DH();
7562 drive = GET_ELDL();
7563
7564 if ( (drive > 1) || (head > 1) ||
7565 (num_sectors == 0) || (num_sectors > 72) ) {
7566BX_INFO("floppy: drive>1 || head>1 ...\n");
7567 SET_AH(1);
7568 set_diskette_ret_status(1);
7569 SET_AL(0); // no sectors read
7570 SET_CF(); // error occurred
7571 return;
7572 }
7573
7574 // see if drive exists
7575 if (floppy_drive_exists(drive) == 0) {
7576 SET_AH(0x80); // not responding
7577 set_diskette_ret_status(0x80);
7578 SET_AL(0); // no sectors read
7579 SET_CF(); // error occurred
7580 return;
7581 }
7582
7583 // see if media in drive, and type is known
7584 if (floppy_media_known(drive) == 0) {
7585 if (floppy_media_sense(drive) == 0) {
7586 SET_AH(0x0C); // Media type not found
7587 set_diskette_ret_status(0x0C);
7588 SET_AL(0); // no sectors read
7589 SET_CF(); // error occurred
7590 return;
7591 }
7592 }
7593
7594 if (ah == 0x02) {
7595 // Read Diskette Sectors
7596
7597 //-----------------------------------
7598 // set up DMA controller for transfer
7599 //-----------------------------------
7600
7601 // es:bx = pointer to where to place information from diskette
7602 // port 04: DMA-1 base and current address, channel 2
7603 // port 05: DMA-1 base and current count, channel 2
7604 page = (ES >> 12); // upper 4 bits
7605 base_es = (ES << 4); // lower 16bits contributed by ES
7606 base_address = base_es + BX; // lower 16 bits of address
7607 // contributed by ES:BX
7608 if ( base_address < base_es ) {
7609 // in case of carry, adjust page by 1
7610 page++;
7611 }
7612 base_count = (num_sectors * 512) - 1;
7613
7614 // check for 64K boundary overrun
7615 last_addr = base_address + base_count;
7616 if (last_addr < base_address) {
7617 SET_AH(0x09);
7618 set_diskette_ret_status(0x09);
7619 SET_AL(0); // no sectors read
7620 SET_CF(); // error occurred
7621 return;
7622 }
7623
7624 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7625 outb(0x000a, 0x06);
7626
7627 BX_DEBUG_INT13_FL("clear flip-flop\n");
7628 outb(0x000c, 0x00); // clear flip-flop
7629 outb(0x0004, base_address);
7630 outb(0x0004, base_address>>8);
7631 BX_DEBUG_INT13_FL("clear flip-flop\n");
7632 outb(0x000c, 0x00); // clear flip-flop
7633 outb(0x0005, base_count);
7634 outb(0x0005, base_count>>8);
7635
7636 // port 0b: DMA-1 Mode Register
7637 mode_register = 0x46; // single mode, increment, autoinit disable,
7638 // transfer type=write, channel 2
7639 BX_DEBUG_INT13_FL("setting mode register\n");
7640 outb(0x000b, mode_register);
7641
7642 BX_DEBUG_INT13_FL("setting page register\n");
7643 // port 81: DMA-1 Page Register, channel 2
7644 outb(0x0081, page);
7645
7646 BX_DEBUG_INT13_FL("unmask chan 2\n");
7647 outb(0x000a, 0x02); // unmask channel 2
7648
7649 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7650 outb(0x000a, 0x02);
7651
7652 //--------------------------------------
7653 // set up floppy controller for transfer
7654 //--------------------------------------
7655 floppy_prepare_controller(drive);
7656
7657 // send read-normal-data command (9 bytes) to controller
7658 outb(0x03f5, 0xe6); // e6: read normal data
7659 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7660 outb(0x03f5, track);
7661 outb(0x03f5, head);
7662 outb(0x03f5, sector);
7663 outb(0x03f5, 2); // 512 byte sector size
7664 outb(0x03f5, sector + num_sectors - 1); // last sector to read on track
7665 outb(0x03f5, 0); // Gap length
7666 outb(0x03f5, 0xff); // Gap length
7667
7668 // turn on interrupts
7669 ASM_START
7670 sti
7671 ASM_END
7672
7673 // wait on 40:3e bit 7 to become 1
7674 do {
7675 val8 = read_byte(0x0040, 0x0040);
7676 if (val8 == 0) {
7677 floppy_reset_controller();
7678 SET_AH(0x80); // drive not ready (timeout)
7679 set_diskette_ret_status(0x80);
7680 SET_AL(0); // no sectors read
7681 SET_CF(); // error occurred
7682 return;
7683 }
7684 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7685 } while ( val8 == 0 );
7686
7687 val8 = 0; // separate asm from while() loop
7688 // turn off interrupts
7689 ASM_START
7690 cli
7691 ASM_END
7692
7693 // set 40:3e bit 7 to 0
7694 val8 = read_byte(0x0040, 0x003e);
7695 val8 &= 0x7f;
7696 write_byte(0x0040, 0x003e, val8);
7697
7698 // check port 3f4 for accessibility to status bytes
7699 val8 = inb(0x3f4);
7700 if ( (val8 & 0xc0) != 0xc0 )
7701 BX_PANIC("int13_diskette: ctrl not ready\n");
7702
7703 // read 7 return status bytes from controller
7704 // using loop index broken, have to unroll...
7705 return_status[0] = inb(0x3f5);
7706 return_status[1] = inb(0x3f5);
7707 return_status[2] = inb(0x3f5);
7708 return_status[3] = inb(0x3f5);
7709 return_status[4] = inb(0x3f5);
7710 return_status[5] = inb(0x3f5);
7711 return_status[6] = inb(0x3f5);
7712 // record in BIOS Data Area
7713 write_byte(0x0040, 0x0042, return_status[0]);
7714 write_byte(0x0040, 0x0043, return_status[1]);
7715 write_byte(0x0040, 0x0044, return_status[2]);
7716 write_byte(0x0040, 0x0045, return_status[3]);
7717 write_byte(0x0040, 0x0046, return_status[4]);
7718 write_byte(0x0040, 0x0047, return_status[5]);
7719 write_byte(0x0040, 0x0048, return_status[6]);
7720
7721 if ( (return_status[0] & 0xc0) != 0 ) {
7722 SET_AH(0x20);
7723 set_diskette_ret_status(0x20);
7724 SET_AL(0); // no sectors read
7725 SET_CF(); // error occurred
7726 return;
7727 }
7728
7729 // ??? should track be new val from return_status[3] ?
7730 set_diskette_current_cyl(drive, track);
7731 // AL = number of sectors read (same value as passed)
7732 SET_AH(0x00); // success
7733 CLEAR_CF(); // success
7734 return;
7735 } else if (ah == 0x03) {
7736 // Write Diskette Sectors
7737
7738 //-----------------------------------
7739 // set up DMA controller for transfer
7740 //-----------------------------------
7741
7742 // es:bx = pointer to where to place information from diskette
7743 // port 04: DMA-1 base and current address, channel 2
7744 // port 05: DMA-1 base and current count, channel 2
7745 page = (ES >> 12); // upper 4 bits
7746 base_es = (ES << 4); // lower 16bits contributed by ES
7747 base_address = base_es + BX; // lower 16 bits of address
7748 // contributed by ES:BX
7749 if ( base_address < base_es ) {
7750 // in case of carry, adjust page by 1
7751 page++;
7752 }
7753 base_count = (num_sectors * 512) - 1;
7754
7755 // check for 64K boundary overrun
7756 last_addr = base_address + base_count;
7757 if (last_addr < base_address) {
7758 SET_AH(0x09);
7759 set_diskette_ret_status(0x09);
7760 SET_AL(0); // no sectors read
7761 SET_CF(); // error occurred
7762 return;
7763 }
7764
7765 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7766 outb(0x000a, 0x06);
7767
7768 outb(0x000c, 0x00); // clear flip-flop
7769 outb(0x0004, base_address);
7770 outb(0x0004, base_address>>8);
7771 outb(0x000c, 0x00); // clear flip-flop
7772 outb(0x0005, base_count);
7773 outb(0x0005, base_count>>8);
7774
7775 // port 0b: DMA-1 Mode Register
7776 mode_register = 0x4a; // single mode, increment, autoinit disable,
7777 // transfer type=read, channel 2
7778 outb(0x000b, mode_register);
7779
7780 // port 81: DMA-1 Page Register, channel 2
7781 outb(0x0081, page);
7782
7783 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7784 outb(0x000a, 0x02);
7785
7786 //--------------------------------------
7787 // set up floppy controller for transfer
7788 //--------------------------------------
7789 floppy_prepare_controller(drive);
7790
7791 // send write-normal-data command (9 bytes) to controller
7792 outb(0x03f5, 0xc5); // c5: write normal data
7793 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7794 outb(0x03f5, track);
7795 outb(0x03f5, head);
7796 outb(0x03f5, sector);
7797 outb(0x03f5, 2); // 512 byte sector size
7798 outb(0x03f5, sector + num_sectors - 1); // last sector to write on track
7799 outb(0x03f5, 0); // Gap length
7800 outb(0x03f5, 0xff); // Gap length
7801
7802 // turn on interrupts
7803 ASM_START
7804 sti
7805 ASM_END
7806
7807 // wait on 40:3e bit 7 to become 1
7808 do {
7809 val8 = read_byte(0x0040, 0x0040);
7810 if (val8 == 0) {
7811 floppy_reset_controller();
7812 SET_AH(0x80); // drive not ready (timeout)
7813 set_diskette_ret_status(0x80);
7814 SET_AL(0); // no sectors written
7815 SET_CF(); // error occurred
7816 return;
7817 }
7818 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7819 } while ( val8 == 0 );
7820
7821 val8 = 0; // separate asm from while() loop
7822 // turn off interrupts
7823 ASM_START
7824 cli
7825 ASM_END
7826
7827 // set 40:3e bit 7 to 0
7828 val8 = read_byte(0x0040, 0x003e);
7829 val8 &= 0x7f;
7830 write_byte(0x0040, 0x003e, val8);
7831
7832 // check port 3f4 for accessibility to status bytes
7833 val8 = inb(0x3f4);
7834 if ( (val8 & 0xc0) != 0xc0 )
7835 BX_PANIC("int13_diskette: ctrl not ready\n");
7836
7837 // read 7 return status bytes from controller
7838 // using loop index broken, have to unroll...
7839 return_status[0] = inb(0x3f5);
7840 return_status[1] = inb(0x3f5);
7841 return_status[2] = inb(0x3f5);
7842 return_status[3] = inb(0x3f5);
7843 return_status[4] = inb(0x3f5);
7844 return_status[5] = inb(0x3f5);
7845 return_status[6] = inb(0x3f5);
7846 // record in BIOS Data Area
7847 write_byte(0x0040, 0x0042, return_status[0]);
7848 write_byte(0x0040, 0x0043, return_status[1]);
7849 write_byte(0x0040, 0x0044, return_status[2]);
7850 write_byte(0x0040, 0x0045, return_status[3]);
7851 write_byte(0x0040, 0x0046, return_status[4]);
7852 write_byte(0x0040, 0x0047, return_status[5]);
7853 write_byte(0x0040, 0x0048, return_status[6]);
7854
7855 if ( (return_status[0] & 0xc0) != 0 ) {
7856 if ( (return_status[1] & 0x02) != 0 ) {
7857 // diskette not writable.
7858 // AH=status code=0x03 (tried to write on write-protected disk)
7859 // AL=number of sectors written=0
7860 AX = 0x0300;
7861 SET_CF();
7862 return;
7863 } else {
7864 BX_PANIC("int13_diskette_function: read error\n");
7865 }
7866 }
7867
7868 // ??? should track be new val from return_status[3] ?
7869 set_diskette_current_cyl(drive, track);
7870 // AL = number of sectors read (same value as passed)
7871 SET_AH(0x00); // success
7872 CLEAR_CF(); // success
7873 return;
7874 } else { // if (ah == 0x04)
7875 // Verify Diskette Sectors
7876
7877 // ??? should track be new val from return_status[3] ?
7878 set_diskette_current_cyl(drive, track);
7879 // AL = number of sectors verified (same value as passed)
7880 CLEAR_CF(); // success
7881 SET_AH(0x00); // success
7882 return;
7883 }
7884 break;
7885
7886 case 0x05: // format diskette track
7887BX_DEBUG_INT13_FL("floppy f05\n");
7888
7889 num_sectors = GET_AL();
7890 track = GET_CH();
7891 head = GET_DH();
7892 drive = GET_ELDL();
7893
7894 if ((drive > 1) || (head > 1) || (track > 79) ||
7895 (num_sectors == 0) || (num_sectors > 18)) {
7896 SET_AH(1);
7897 set_diskette_ret_status(1);
7898 SET_CF(); // error occurred
7899 }
7900
7901 // see if drive exists
7902 if (floppy_drive_exists(drive) == 0) {
7903 SET_AH(0x80); // drive not responding
7904 set_diskette_ret_status(0x80);
7905 SET_CF(); // error occurred
7906 return;
7907 }
7908
7909 // see if media in drive, and type is known
7910 if (floppy_media_known(drive) == 0) {
7911 if (floppy_media_sense(drive) == 0) {
7912 SET_AH(0x0C); // Media type not found
7913 set_diskette_ret_status(0x0C);
7914 SET_AL(0); // no sectors read
7915 SET_CF(); // error occurred
7916 return;
7917 }
7918 }
7919
7920 // set up DMA controller for transfer
7921 page = (ES >> 12); // upper 4 bits
7922 base_es = (ES << 4); // lower 16bits contributed by ES
7923 base_address = base_es + BX; // lower 16 bits of address
7924 // contributed by ES:BX
7925 if ( base_address < base_es ) {
7926 // in case of carry, adjust page by 1
7927 page++;
7928 }
7929 base_count = (num_sectors * 4) - 1;
7930
7931 // check for 64K boundary overrun
7932 last_addr = base_address + base_count;
7933 if (last_addr < base_address) {
7934 SET_AH(0x09);
7935 set_diskette_ret_status(0x09);
7936 SET_AL(0); // no sectors read
7937 SET_CF(); // error occurred
7938 return;
7939 }
7940
7941 outb(0x000a, 0x06);
7942 outb(0x000c, 0x00); // clear flip-flop
7943 outb(0x0004, base_address);
7944 outb(0x0004, base_address>>8);
7945 outb(0x000c, 0x00); // clear flip-flop
7946 outb(0x0005, base_count);
7947 outb(0x0005, base_count>>8);
7948 mode_register = 0x4a; // single mode, increment, autoinit disable,
7949 // transfer type=read, channel 2
7950 outb(0x000b, mode_register);
7951 // port 81: DMA-1 Page Register, channel 2
7952 outb(0x0081, page);
7953 outb(0x000a, 0x02);
7954
7955 // set up floppy controller for transfer
7956 floppy_prepare_controller(drive);
7957
7958 // send format-track command (6 bytes) to controller
7959 outb(0x03f5, 0x4d); // 4d: format track
7960 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7961 outb(0x03f5, 2); // 512 byte sector size
7962 outb(0x03f5, num_sectors); // number of sectors per track
7963 outb(0x03f5, 0); // Gap length
7964 outb(0x03f5, 0xf6); // Fill byte
7965 // turn on interrupts
7966 ASM_START
7967 sti
7968 ASM_END
7969
7970 // wait on 40:3e bit 7 to become 1
7971 do {
7972 val8 = read_byte(0x0040, 0x0040);
7973 if (val8 == 0) {
7974 floppy_reset_controller();
7975 SET_AH(0x80); // drive not ready (timeout)
7976 set_diskette_ret_status(0x80);
7977 SET_CF(); // error occurred
7978 return;
7979 }
7980 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7981 } while ( val8 == 0 );
7982
7983 val8 = 0; // separate asm from while() loop
7984 // turn off interrupts
7985 ASM_START
7986 cli
7987 ASM_END
7988 // set 40:3e bit 7 to 0
7989 val8 = read_byte(0x0040, 0x003e);
7990 val8 &= 0x7f;
7991 write_byte(0x0040, 0x003e, val8);
7992 // check port 3f4 for accessibility to status bytes
7993 val8 = inb(0x3f4);
7994 if ( (val8 & 0xc0) != 0xc0 )
7995 BX_PANIC("int13_diskette: ctrl not ready\n");
7996
7997 // read 7 return status bytes from controller
7998 // using loop index broken, have to unroll...
7999 return_status[0] = inb(0x3f5);
8000 return_status[1] = inb(0x3f5);
8001 return_status[2] = inb(0x3f5);
8002 return_status[3] = inb(0x3f5);
8003 return_status[4] = inb(0x3f5);
8004 return_status[5] = inb(0x3f5);
8005 return_status[6] = inb(0x3f5);
8006 // record in BIOS Data Area
8007 write_byte(0x0040, 0x0042, return_status[0]);
8008 write_byte(0x0040, 0x0043, return_status[1]);
8009 write_byte(0x0040, 0x0044, return_status[2]);
8010 write_byte(0x0040, 0x0045, return_status[3]);
8011 write_byte(0x0040, 0x0046, return_status[4]);
8012 write_byte(0x0040, 0x0047, return_status[5]);
8013 write_byte(0x0040, 0x0048, return_status[6]);
8014
8015 if ( (return_status[0] & 0xc0) != 0 ) {
8016 if ( (return_status[1] & 0x02) != 0 ) {
8017 // diskette not writable.
8018 // AH=status code=0x03 (tried to write on write-protected disk)
8019 // AL=number of sectors written=0
8020 AX = 0x0300;
8021 SET_CF();
8022 return;
8023 } else {
8024 BX_PANIC("int13_diskette_function: write error\n");
8025 }
8026 }
8027
8028 SET_AH(0);
8029 set_diskette_ret_status(0);
8030 set_diskette_current_cyl(drive, 0);
8031 CLEAR_CF(); // successful
8032 return;
8033
8034
8035 case 0x08: // read diskette drive parameters
8036BX_DEBUG_INT13_FL("floppy f08\n");
8037 drive = GET_ELDL();
8038
8039 if (drive > 1) {
8040 AX = 0;
8041 BX = 0;
8042 CX = 0;
8043 DX = 0;
8044 ES = 0;
8045 DI = 0;
8046 SET_DL(num_floppies);
8047 SET_CF();
8048 return;
8049 }
8050
8051 drive_type = inb_cmos(0x10);
8052 num_floppies = 0;
8053 if (drive_type & 0xf0)
8054 num_floppies++;
8055 if (drive_type & 0x0f)
8056 num_floppies++;
8057
8058 if (drive == 0)
8059 drive_type >>= 4;
8060 else
8061 drive_type &= 0x0f;
8062
8063 SET_BH(0);
8064 SET_BL(drive_type);
8065 SET_AH(0);
8066 SET_AL(0);
8067 SET_DL(num_floppies);
8068
8069 switch (drive_type) {
8070 case 0: // none
8071 CX = 0;
8072 SET_DH(0); // max head #
8073 break;
8074
8075 case 1: // 360KB, 5.25"
8076 CX = 0x2709; // 40 tracks, 9 sectors
8077 SET_DH(1); // max head #
8078 break;
8079
8080 case 2: // 1.2MB, 5.25"
8081 CX = 0x4f0f; // 80 tracks, 15 sectors
8082 SET_DH(1); // max head #
8083 break;
8084
8085 case 3: // 720KB, 3.5"
8086 CX = 0x4f09; // 80 tracks, 9 sectors
8087 SET_DH(1); // max head #
8088 break;
8089
8090 case 4: // 1.44MB, 3.5"
8091 CX = 0x4f12; // 80 tracks, 18 sectors
8092 SET_DH(1); // max head #
8093 break;
8094
8095 case 5: // 2.88MB, 3.5"
8096 CX = 0x4f24; // 80 tracks, 36 sectors
8097 SET_DH(1); // max head #
8098 break;
8099
8100 case 6: // 160k, 5.25"
8101 CX = 0x2708; // 40 tracks, 8 sectors
8102 SET_DH(0); // max head #
8103 break;
8104
8105 case 7: // 180k, 5.25"
8106 CX = 0x2709; // 40 tracks, 9 sectors
8107 SET_DH(0); // max head #
8108 break;
8109
8110 case 8: // 320k, 5.25"
8111 CX = 0x2708; // 40 tracks, 8 sectors
8112 SET_DH(1); // max head #
8113 break;
8114
8115 default: // ?
8116 BX_PANIC("floppy: int13: bad floppy type\n");
8117 }
8118
8119 /* set es & di to point to 11 byte diskette param table in ROM */
8120ASM_START
8121 push bp
8122 mov bp, sp
8123 mov ax, #diskette_param_table2
8124 mov _int13_diskette_function.DI+2[bp], ax
8125 mov _int13_diskette_function.ES+2[bp], cs
8126 pop bp
8127ASM_END
8128 CLEAR_CF(); // success
8129 /* disk status not changed upon success */
8130 return;
8131
8132
8133 case 0x15: // read diskette drive type
8134BX_DEBUG_INT13_FL("floppy f15\n");
8135 drive = GET_ELDL();
8136 if (drive > 1) {
8137 SET_AH(0); // only 2 drives supported
8138 // set_diskette_ret_status here ???
8139 SET_CF();
8140 return;
8141 }
8142 drive_type = inb_cmos(0x10);
8143
8144 if (drive == 0)
8145 drive_type >>= 4;
8146 else
8147 drive_type &= 0x0f;
8148 CLEAR_CF(); // successful, not present
8149 if (drive_type==0) {
8150 SET_AH(0); // drive not present
8151 }
8152 else {
8153 SET_AH(1); // drive present, does not support change line
8154 }
8155
8156 return;
8157
8158 case 0x16: // get diskette change line status
8159BX_DEBUG_INT13_FL("floppy f16\n");
8160 drive = GET_ELDL();
8161 if (drive > 1) {
8162 SET_AH(0x01); // invalid drive
8163 set_diskette_ret_status(0x01);
8164 SET_CF();
8165 return;
8166 }
8167
8168 SET_AH(0x06); // change line not supported
8169 set_diskette_ret_status(0x06);
8170 SET_CF();
8171 return;
8172
8173 case 0x17: // set diskette type for format(old)
8174BX_DEBUG_INT13_FL("floppy f17\n");
8175 /* not used for 1.44M floppies */
8176 SET_AH(0x01); // not supported
8177 set_diskette_ret_status(1); /* not supported */
8178 SET_CF();
8179 return;
8180
8181 case 0x18: // set diskette type for format(new)
8182BX_DEBUG_INT13_FL("floppy f18\n");
8183 SET_AH(0x01); // do later
8184 set_diskette_ret_status(1);
8185 SET_CF();
8186 return;
8187
8188 default:
8189 BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
8190
8191 // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
8192 SET_AH(0x01); // ???
8193 set_diskette_ret_status(1);
8194 SET_CF();
8195 return;
8196 // }
8197 }
8198}
8199#else // #if BX_SUPPORT_FLOPPY
8200 void
8201int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
8202 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
8203{
8204 Bit8u val8;
8205
8206 switch ( GET_AH() ) {
8207
8208 case 0x01: // Read Diskette Status
8209 CLEAR_CF();
8210 val8 = read_byte(0x0000, 0x0441);
8211 SET_AH(val8);
8212 if (val8) {
8213 SET_CF();
8214 }
8215 return;
8216
8217 default:
8218 SET_CF();
8219 write_byte(0x0000, 0x0441, 0x01);
8220 SET_AH(0x01);
8221 }
8222}
8223#endif // #if BX_SUPPORT_FLOPPY
8224
8225 void
8226set_diskette_ret_status(value)
8227 Bit8u value;
8228{
8229 write_byte(0x0040, 0x0041, value);
8230}
8231
8232 void
8233set_diskette_current_cyl(drive, cyl)
8234 Bit8u drive;
8235 Bit8u cyl;
8236{
8237 if (drive > 1)
8238 BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
8239 write_byte(0x0040, 0x0094+drive, cyl);
8240}
8241
8242 void
8243determine_floppy_media(drive)
8244 Bit16u drive;
8245{
8246#if 0
8247 Bit8u val8, DOR, ctrl_info;
8248
8249 ctrl_info = read_byte(0x0040, 0x008F);
8250 if (drive==1)
8251 ctrl_info >>= 4;
8252 else
8253 ctrl_info &= 0x0f;
8254
8255#if 0
8256 if (drive == 0) {
8257 DOR = 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
8258 }
8259 else {
8260 DOR = 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
8261 }
8262#endif
8263
8264 if ( (ctrl_info & 0x04) != 0x04 ) {
8265 // Drive not determined means no drive exists, done.
8266 return;
8267 }
8268
8269#if 0
8270 // check Main Status Register for readiness
8271 val8 = inb(0x03f4) & 0x80; // Main Status Register
8272 if (val8 != 0x80)
8273 BX_PANIC("d_f_m: MRQ bit not set\n");
8274
8275 // change line
8276
8277 // existing BDA values
8278
8279 // turn on drive motor
8280 outb(0x03f2, DOR); // Digital Output Register
8281 //
8282#endif
8283 BX_PANIC("d_f_m: OK so far\n");
8284#endif
8285}
8286
8287 void
8288int17_function(regs, ds, iret_addr)
8289 pusha_regs_t regs; // regs pushed from PUSHA instruction
8290 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8291 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8292{
8293 Bit16u addr,timeout;
8294 Bit8u val8;
8295
8296 ASM_START
8297 sti
8298 ASM_END
8299
8300 addr = read_word(0x0040, (regs.u.r16.dx << 1) + 8);
8301 if ((regs.u.r8.ah < 3) && (regs.u.r16.dx < 3) && (addr > 0)) {
8302 timeout = read_byte(0x0040, 0x0078 + regs.u.r16.dx) << 8;
8303 if (regs.u.r8.ah == 0) {
8304 outb(addr, regs.u.r8.al);
8305 val8 = inb(addr+2);
8306 outb(addr+2, val8 | 0x01); // send strobe
8307 ASM_START
8308 nop
8309 ASM_END
8310 outb(addr+2, val8 & ~0x01);
8311 while (((inb(addr+1) & 0x40) == 0x40) && (timeout)) {
8312 timeout--;
8313 }
8314 }
8315 if (regs.u.r8.ah == 1) {
8316 val8 = inb(addr+2);
8317 outb(addr+2, val8 & ~0x04); // send init
8318 ASM_START
8319 nop
8320 ASM_END
8321 outb(addr+2, val8 | 0x04);
8322 }
8323 val8 = inb(addr+1);
8324 regs.u.r8.ah = (val8 ^ 0x48);
8325 if (!timeout) regs.u.r8.ah |= 0x01;
8326 ClearCF(iret_addr.flags);
8327 } else {
8328 SetCF(iret_addr.flags); // Unsupported
8329 }
8330}
8331
8332// returns bootsegment in ax, drive in bl
8333 Bit32u
8334int19_function(bseqnr)
8335Bit8u bseqnr;
8336{
8337 Bit16u ebda_seg=read_word(0x0040,0x000E);
8338 Bit16u bootseq;
8339 Bit8u bootdrv;
8340 Bit8u bootcd;
8341#ifdef VBOX
8342 Bit8u bootlan;
8343#endif /* VBOX */
8344 Bit8u bootchk;
8345 Bit16u bootseg;
8346 Bit16u status;
8347 Bit8u lastdrive=0;
8348
8349 // if BX_ELTORITO_BOOT is not defined, old behavior
8350 // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
8351 // in preparation for the intial INT 13h (0=floppy A:, 0x80=C:)
8352 // 0: system boot sequence, first drive C: then A:
8353 // 1: system boot sequence, first drive A: then C:
8354 // else BX_ELTORITO_BOOT is defined
8355 // CMOS regs 0x3D and 0x38 contain the boot sequence:
8356 // CMOS reg 0x3D & 0x0f : 1st boot device
8357 // CMOS reg 0x3D & 0xf0 : 2nd boot device
8358 // CMOS reg 0x38 & 0xf0 : 3rd boot device
8359#ifdef VBOX
8360 // CMOS reg 0x3C & 0x0f : 4th boot device
8361#endif /* VBOX */
8362 // boot device codes:
8363 // 0x00 : not defined
8364 // 0x01 : first floppy
8365 // 0x02 : first harddrive
8366 // 0x03 : first cdrom
8367#ifdef VBOX
8368 // 0x04 : local area network
8369#endif /* VBOX */
8370 // else : boot failure
8371
8372 // Get the boot sequence
8373#if BX_ELTORITO_BOOT
8374 bootseq=inb_cmos(0x3d);
8375 bootseq|=((inb_cmos(0x38) & 0xf0) << 4);
8376#ifdef VBOX
8377 bootseq|=((inb_cmos(0x3c) & 0x0f) << 12);
8378 if (read_byte(ebda_seg, &EbdaData->uForceBootDevice))
8379 bootseq = read_byte(ebda_seg, &EbdaData->uForceBootDevice);
8380 /* Boot delay hack. */
8381 if (bseqnr == 1)
8382 delay_boot((inb_cmos(0x3c) & 0xf0) >> 4); /* Implemented in logo.c */
8383#endif /* VBOX */
8384
8385 if (bseqnr==2) bootseq >>= 4;
8386 if (bseqnr==3) bootseq >>= 8;
8387#ifdef VBOX
8388 if (bseqnr==4) bootseq >>= 12;
8389#endif /* VBOX */
8390 if (bootseq<0x10) lastdrive = 1;
8391 bootdrv=0x00; bootcd=0;
8392#ifdef VBOX
8393 bootlan=0;
8394#endif /* VBOX */
8395
8396 switch(bootseq & 0x0f) {
8397 case 0x01:
8398 bootdrv=0x00;
8399 bootcd=0;
8400 break;
8401 case 0x02:
8402 {
8403 // Get the Boot drive.
8404 Bit8u boot_drive = read_byte(ebda_seg, &EbdaData->uForceBootDrive);
8405
8406 bootdrv = boot_drive + 0x80;
8407 bootcd=0;
8408 break;
8409 }
8410 case 0x03:
8411 bootdrv=0x00;
8412 bootcd=1;
8413 break;
8414#ifdef VBOX
8415 case 0x04: bootlan=1; break;
8416#endif /* VBOX */
8417 default: return 0x00000000;
8418 }
8419#else
8420 bootseq=inb_cmos(0x2d);
8421
8422 if (bseqnr==2) {
8423 bootseq ^= 0x20;
8424 lastdrive = 1;
8425 }
8426 bootdrv=0x00; bootcd=0;
8427 if((bootseq&0x20)==0) bootdrv=0x80;
8428#endif // BX_ELTORITO_BOOT
8429
8430#if BX_ELTORITO_BOOT
8431 // We have to boot from cd
8432 if (bootcd != 0) {
8433 status = cdrom_boot();
8434
8435 // If failure
8436 if ( (status & 0x00ff) !=0 ) {
8437 print_cdromboot_failure(status);
8438#ifdef VBOX
8439 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
8440#else /* !VBOX */
8441 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
8442#endif /* !VBOX */
8443 return 0x00000000;
8444 }
8445
8446 bootseg = read_word(ebda_seg,&EbdaData->cdemu.load_segment);
8447 bootdrv = (Bit8u)(status>>8);
8448 }
8449
8450#endif // BX_ELTORITO_BOOT
8451
8452#ifdef VBOX
8453 // Check for boot from LAN first
8454 if (bootlan == 1) {
8455 if (read_word(VBOX_LANBOOT_SEG,0) == 0xaa55) {
8456 Bit16u pnpoff;
8457 Bit32u manuf;
8458 // This is NOT a generic PnP implementation, but an Etherboot-specific hack.
8459 pnpoff = read_word(VBOX_LANBOOT_SEG,0x1a);
8460 if (read_dword(VBOX_LANBOOT_SEG,pnpoff) == 0x506e5024) {
8461 // Found PnP signature
8462 manuf = read_dword(VBOX_LANBOOT_SEG,read_word(VBOX_LANBOOT_SEG,pnpoff+0xe));
8463 if (manuf == 0x65687445) {
8464 // Found Etherboot ROM
8465 print_boot_device(bootcd, bootlan, bootdrv);
8466ASM_START
8467 push ds
8468 push es
8469 pusha
8470 calli 0x0006,VBOX_LANBOOT_SEG
8471 popa
8472 pop es
8473 pop ds
8474ASM_END
8475 } else if (manuf == 0x65746E49) {
8476 // Found Intel PXE ROM
8477 print_boot_device(bootcd, bootlan, bootdrv);
8478ASM_START
8479 push ds
8480 push es
8481 pusha
8482 sti ; Why are interrupts disabled now? Because we were called through an INT!
8483 push #VBOX_LANBOOT_SEG
8484 pop ds
8485 mov bx,#0x1a ; PnP header offset
8486 mov bx,[bx]
8487 add bx,#0x1a ; BEV offset in PnP header
8488 mov ax,[bx]
8489 test ax,ax
8490 jz no_rom
8491bev_jump:
8492 push cs
8493 push #no_rom
8494 push #VBOX_LANBOOT_SEG
8495 push ax
8496 retf ; call Boot Entry Vector
8497no_rom:
8498 popa
8499 pop es
8500 pop ds
8501ASM_END
8502 }
8503 }
8504 }
8505
8506 // boot from LAN will not return if successful.
8507 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
8508 return 0x00000000;
8509 }
8510#endif /* VBOX */
8511 // We have to boot from harddisk or floppy
8512#ifdef VBOX
8513 if (bootcd == 0 && bootlan == 0) {
8514#else /* !VBOX */
8515 if (bootcd == 0) {
8516#endif /* !VBOX */
8517 bootseg=0x07c0;
8518
8519ASM_START
8520 push bp
8521 mov bp, sp
8522
8523 xor ax, ax
8524 mov _int19_function.status + 2[bp], ax
8525 mov dl, _int19_function.bootdrv + 2[bp]
8526 mov ax, _int19_function.bootseg + 2[bp]
8527 mov es, ax ;; segment
8528 xor bx, bx ;; offset
8529 mov ah, #0x02 ;; function 2, read diskette sector
8530 mov al, #0x01 ;; read 1 sector
8531 mov ch, #0x00 ;; track 0
8532 mov cl, #0x01 ;; sector 1
8533 mov dh, #0x00 ;; head 0
8534 int #0x13 ;; read sector
8535 jnc int19_load_done
8536 mov ax, #0x0001
8537 mov _int19_function.status + 2[bp], ax
8538
8539int19_load_done:
8540 pop bp
8541ASM_END
8542
8543 if (status != 0) {
8544#ifdef VBOX
8545 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
8546#else /* !VBOX */
8547 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
8548#endif /* !VBOX */
8549 return 0x00000000;
8550 }
8551 }
8552
8553#ifdef VBOX
8554 // Don't check boot sectors on floppies and don't read CMOS - byte
8555 // 0x38 in CMOS always has the low bit clear.
8556 // There is *no* requirement whatsoever for a valid boot sector to
8557 // have a 55AAh signature. UNIX boot floppies typically have no such
8558 // signature. In general, it is impossible to tell a valid bootsector
8559 // from an invalid one.
8560 // NB: It is somewhat common for failed OS installs to have the
8561 // 0x55AA signature and a valid partition table but zeros in the
8562 // rest of the boot sector. We do a quick check by comparing the first
8563 // two words of boot sector; if identical, the boot sector is
8564 // extremely unlikely to be valid.
8565#endif
8566 // check signature if instructed by cmos reg 0x38, only for floppy
8567 // bootchk = 1 : signature check disabled
8568 // bootchk = 0 : signature check enabled
8569 if (bootdrv != 0) bootchk = 0;
8570#ifdef VBOX
8571 else bootchk = 1; /* disable 0x55AA signature check on drive A: */
8572#else
8573 else bootchk = inb_cmos(0x38) & 0x01;
8574#endif
8575
8576#if BX_ELTORITO_BOOT
8577 // if boot from cd, no signature check
8578 if (bootcd != 0)
8579 bootchk = 1;
8580#endif // BX_ELTORITO_BOOT
8581
8582 if (bootchk == 0) {
8583 if (read_word(bootseg,0x1fe) != 0xaa55 ||
8584 read_word(bootseg,0) == read_word(bootseg,2)) {
8585#ifdef VBOX
8586 print_boot_failure(bootcd, bootlan, bootdrv, 0, lastdrive);
8587#else /* !VBOX */
8588 print_boot_failure(bootcd, bootdrv, 0, lastdrive);
8589#endif /* VBOX */
8590 return 0x00000000;
8591 }
8592 }
8593
8594#if BX_ELTORITO_BOOT
8595 // Print out the boot string
8596#ifdef VBOX
8597 print_boot_device(bootcd, bootlan, bootdrv);
8598#else /* !VBOX */
8599 print_boot_device(bootcd, bootdrv);
8600#endif /* !VBOX */
8601#else // BX_ELTORITO_BOOT
8602#ifdef VBOX
8603 print_boot_device(0, bootlan, bootdrv);
8604#else /* !VBOX */
8605 print_boot_device(0, bootdrv);
8606#endif /* !VBOX */
8607#endif // BX_ELTORITO_BOOT
8608
8609 // return the boot segment
8610 return (((Bit32u)bootdrv) << 16) + bootseg;
8611}
8612
8613 void
8614int1a_function(regs, ds, iret_addr)
8615 pusha_regs_t regs; // regs pushed from PUSHA instruction
8616 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8617 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8618{
8619 Bit8u val8;
8620
8621 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);
8622
8623 ASM_START
8624 sti
8625 ASM_END
8626
8627 switch (regs.u.r8.ah) {
8628 case 0: // get current clock count
8629 ASM_START
8630 cli
8631 ASM_END
8632 regs.u.r16.cx = BiosData->ticks_high;
8633 regs.u.r16.dx = BiosData->ticks_low;
8634 regs.u.r8.al = BiosData->midnight_flag;
8635 BiosData->midnight_flag = 0; // reset flag
8636 ASM_START
8637 sti
8638 ASM_END
8639 // AH already 0
8640 ClearCF(iret_addr.flags); // OK
8641 break;
8642
8643 case 1: // Set Current Clock Count
8644 ASM_START
8645 cli
8646 ASM_END
8647 BiosData->ticks_high = regs.u.r16.cx;
8648 BiosData->ticks_low = regs.u.r16.dx;
8649 BiosData->midnight_flag = 0; // reset flag
8650 ASM_START
8651 sti
8652 ASM_END
8653 regs.u.r8.ah = 0;
8654 ClearCF(iret_addr.flags); // OK
8655 break;
8656
8657
8658 case 2: // Read CMOS Time
8659 if (rtc_updating()) {
8660 SetCF(iret_addr.flags);
8661 break;
8662 }
8663
8664 regs.u.r8.dh = inb_cmos(0x00); // Seconds
8665 regs.u.r8.cl = inb_cmos(0x02); // Minutes
8666 regs.u.r8.ch = inb_cmos(0x04); // Hours
8667 regs.u.r8.dl = inb_cmos(0x0b) & 0x01; // Stat Reg B
8668 regs.u.r8.ah = 0;
8669 regs.u.r8.al = regs.u.r8.ch;
8670 ClearCF(iret_addr.flags); // OK
8671 break;
8672
8673 case 3: // Set CMOS Time
8674 // Using a debugger, I notice the following masking/setting
8675 // of bits in Status Register B, by setting Reg B to
8676 // a few values and getting its value after INT 1A was called.
8677 //
8678 // try#1 try#2 try#3
8679 // before 1111 1101 0111 1101 0000 0000
8680 // after 0110 0010 0110 0010 0000 0010
8681 //
8682 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8683 // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
8684 if (rtc_updating()) {
8685 init_rtc();
8686 // fall through as if an update were not in progress
8687 }
8688 outb_cmos(0x00, regs.u.r8.dh); // Seconds
8689 outb_cmos(0x02, regs.u.r8.cl); // Minutes
8690 outb_cmos(0x04, regs.u.r8.ch); // Hours
8691 // Set Daylight Savings time enabled bit to requested value
8692 val8 = (inb_cmos(0x0b) & 0x60) | 0x02 | (regs.u.r8.dl & 0x01);
8693 // (reg B already selected)
8694 outb_cmos(0x0b, val8);
8695 regs.u.r8.ah = 0;
8696 regs.u.r8.al = val8; // val last written to Reg B
8697 ClearCF(iret_addr.flags); // OK
8698 break;
8699
8700 case 4: // Read CMOS Date
8701 regs.u.r8.ah = 0;
8702 if (rtc_updating()) {
8703 SetCF(iret_addr.flags);
8704 break;
8705 }
8706 regs.u.r8.cl = inb_cmos(0x09); // Year
8707 regs.u.r8.dh = inb_cmos(0x08); // Month
8708 regs.u.r8.dl = inb_cmos(0x07); // Day of Month
8709 regs.u.r8.ch = inb_cmos(0x32); // Century
8710 regs.u.r8.al = regs.u.r8.ch;
8711 ClearCF(iret_addr.flags); // OK
8712 break;
8713
8714 case 5: // Set CMOS Date
8715 // Using a debugger, I notice the following masking/setting
8716 // of bits in Status Register B, by setting Reg B to
8717 // a few values and getting its value after INT 1A was called.
8718 //
8719 // try#1 try#2 try#3 try#4
8720 // before 1111 1101 0111 1101 0000 0010 0000 0000
8721 // after 0110 1101 0111 1101 0000 0010 0000 0000
8722 //
8723 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8724 // My assumption: RegB = (RegB & 01111111b)
8725 if (rtc_updating()) {
8726 init_rtc();
8727 SetCF(iret_addr.flags);
8728 break;
8729 }
8730 outb_cmos(0x09, regs.u.r8.cl); // Year
8731 outb_cmos(0x08, regs.u.r8.dh); // Month
8732 outb_cmos(0x07, regs.u.r8.dl); // Day of Month
8733 outb_cmos(0x32, regs.u.r8.ch); // Century
8734 val8 = inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
8735 outb_cmos(0x0b, val8);
8736 regs.u.r8.ah = 0;
8737 regs.u.r8.al = val8; // AL = val last written to Reg B
8738 ClearCF(iret_addr.flags); // OK
8739 break;
8740
8741 case 6: // Set Alarm Time in CMOS
8742 // Using a debugger, I notice the following masking/setting
8743 // of bits in Status Register B, by setting Reg B to
8744 // a few values and getting its value after INT 1A was called.
8745 //
8746 // try#1 try#2 try#3
8747 // before 1101 1111 0101 1111 0000 0000
8748 // after 0110 1111 0111 1111 0010 0000
8749 //
8750 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8751 // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
8752 val8 = inb_cmos(0x0b); // Get Status Reg B
8753 regs.u.r16.ax = 0;
8754 if (val8 & 0x20) {
8755 // Alarm interrupt enabled already
8756 SetCF(iret_addr.flags); // Error: alarm in use
8757 break;
8758 }
8759 if (rtc_updating()) {
8760 init_rtc();
8761 // fall through as if an update were not in progress
8762 }
8763 outb_cmos(0x01, regs.u.r8.dh); // Seconds alarm
8764 outb_cmos(0x03, regs.u.r8.cl); // Minutes alarm
8765 outb_cmos(0x05, regs.u.r8.ch); // Hours alarm
8766 outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
8767 // enable Status Reg B alarm bit, clear halt clock bit
8768 outb_cmos(0x0b, (val8 & 0x7f) | 0x20);
8769 ClearCF(iret_addr.flags); // OK
8770 break;
8771
8772 case 7: // Turn off Alarm
8773 // Using a debugger, I notice the following masking/setting
8774 // of bits in Status Register B, by setting Reg B to
8775 // a few values and getting its value after INT 1A was called.
8776 //
8777 // try#1 try#2 try#3 try#4
8778 // before 1111 1101 0111 1101 0010 0000 0010 0010
8779 // after 0100 0101 0101 0101 0000 0000 0000 0010
8780 //
8781 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8782 // My assumption: RegB = (RegB & 01010111b)
8783 val8 = inb_cmos(0x0b); // Get Status Reg B
8784 // clear clock-halt bit, disable alarm bit
8785 outb_cmos(0x0b, val8 & 0x57); // disable alarm bit
8786 regs.u.r8.ah = 0;
8787 regs.u.r8.al = val8; // val last written to Reg B
8788 ClearCF(iret_addr.flags); // OK
8789 break;
8790#if BX_PCIBIOS
8791 case 0xb1:
8792 // real mode PCI BIOS functions now handled in assembler code
8793 // this C code handles the error code for information only
8794 if (regs.u.r8.bl == 0xff) {
8795 BX_INFO("PCI BIOS: PCI not present\n");
8796 } else if (regs.u.r8.bl == 0x81) {
8797 BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs.u.r8.al);
8798 } else if (regs.u.r8.bl == 0x83) {
8799 BX_INFO("bad PCI vendor ID %04x\n", regs.u.r16.dx);
8800 } else if (regs.u.r8.bl == 0x86) {
8801 if (regs.u.r8.al == 0x02) {
8802 BX_INFO("PCI device %04x:%04x not found at index %d\n", regs.u.r16.dx, regs.u.r16.cx, regs.u.r16.si);
8803 } else {
8804 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);
8805 }
8806 }
8807 regs.u.r8.ah = regs.u.r8.bl;
8808 SetCF(iret_addr.flags);
8809 break;
8810#endif
8811
8812 default:
8813 SetCF(iret_addr.flags); // Unsupported
8814 }
8815}
8816
8817 void
8818int70_function(regs, ds, iret_addr)
8819 pusha_regs_t regs; // regs pushed from PUSHA instruction
8820 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8821 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8822{
8823 // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
8824 Bit8u registerB = 0, registerC = 0;
8825
8826 // Check which modes are enabled and have occurred.
8827 registerB = inb_cmos( 0xB );
8828 registerC = inb_cmos( 0xC );
8829
8830 if( ( registerB & 0x60 ) != 0 ) {
8831 if( ( registerC & 0x20 ) != 0 ) {
8832 // Handle Alarm Interrupt.
8833ASM_START
8834 sti
8835 int #0x4a
8836 cli
8837ASM_END
8838 }
8839 if( ( registerC & 0x40 ) != 0 ) {
8840 // Handle Periodic Interrupt.
8841
8842 if( read_byte( 0x40, 0xA0 ) != 0 ) {
8843 // Wait Interval (Int 15, AH=83) active.
8844 Bit32u time, toggle;
8845
8846 time = read_dword( 0x40, 0x9C ); // Time left in microseconds.
8847 if( time < 0x3D1 ) {
8848 // Done waiting.
8849 Bit16u segment, offset;
8850
8851 segment = read_word( 0x40, 0x98 );
8852 offset = read_word( 0x40, 0x9A );
8853 write_byte( 0x40, 0xA0, 0 ); // Turn of status byte.
8854 outb_cmos( 0xB, registerB & 0x37 ); // Clear the Periodic Interrupt.
8855 write_byte(segment, offset, read_byte(segment, offset) | 0x80 ); // Write to specified flag byte.
8856 } else {
8857 // Continue waiting.
8858 time -= 0x3D1;
8859 write_dword( 0x40, 0x9C, time );
8860 }
8861 }
8862 }
8863 }
8864
8865ASM_START
8866 call eoi_both_pics
8867ASM_END
8868}
8869
8870 void
8871dummy_isr_function(regs, ds, iret_addr)
8872 pusha_regs_t regs; // regs pushed from PUSHA instruction
8873 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8874 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8875{
8876 // Interrupt handler for unexpected hardware interrupts. We have to clear
8877 // the PIC because if we don't, the next EOI will clear the wrong interrupt
8878 // and all hell will break loose! This routine also masks the unexpected
8879 // interrupt so it will generally be called only once for each unexpected
8880 // interrupt level.
8881 Bit8u isrA, isrB, imr, last_int = 0xFF;
8882
8883 outb( 0x20, 0x0B );
8884 isrA = inb( 0x20 );
8885 if (isrA) {
8886 outb( 0xA0, 0x0B );
8887 isrB = inb( 0xA0 );
8888 if (isrB) {
8889 imr = inb( 0xA1 );
8890 outb( 0xA1, imr | isrB ); // Mask this interrupt
8891 outb( 0xA0, 0x20 ); // Send EOI on slave PIC
8892 } else {
8893 imr = inb( 0x21 );
8894 isrA &= 0xFB; // Never mask the cascade interrupt
8895 outb( 0x21, imr | isrA); // Mask this interrupt
8896 }
8897 outb( 0x20, 0x20 ); // Send EOI on master PIC
8898 last_int = isrA;
8899 }
8900 write_byte( 0x40, 0x6B, last_int ); // Write INTR_FLAG
8901}
8902
8903ASM_START
8904;------------------------------------------
8905;- INT74h : PS/2 mouse hardware interrupt -
8906;------------------------------------------
8907int74_handler:
8908 sti
8909 pusha
8910 push ds ;; save DS
8911 push #0x00 ;; placeholder for status
8912 push #0x00 ;; placeholder for X
8913 push #0x00 ;; placeholder for Y
8914 push #0x00 ;; placeholder for Z
8915 push #0x00 ;; placeholder for make_far_call boolean
8916 call _int74_function
8917 pop cx ;; remove make_far_call from stack
8918 jcxz int74_done
8919
8920 ;; make far call to EBDA:0022
8921 push #0x00
8922 pop ds
8923 push 0x040E ;; push 0000:040E (opcodes 0xff, 0x36, 0x0E, 0x04)
8924 pop ds
8925 //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
8926 call far ptr[0x22]
8927int74_done:
8928 cli
8929 call eoi_both_pics
8930 add sp, #8 ;; pop status, x, y, z
8931
8932 pop ds ;; restore DS
8933 popa
8934 iret
8935
8936
8937;; This will perform an IRET, but will retain value of current CF
8938;; by altering flags on stack. Better than RETF #02.
8939iret_modify_cf:
8940 jc carry_set
8941 push bp
8942 mov bp, sp
8943 and BYTE [bp + 0x06], #0xfe
8944 pop bp
8945 iret
8946carry_set:
8947 push bp
8948 mov bp, sp
8949 or BYTE [bp + 0x06], #0x01
8950 pop bp
8951 iret
8952
8953
8954;----------------------
8955;- INT13h (relocated) -
8956;----------------------
8957;
8958; int13_relocated is a little bit messed up since I played with it
8959; I have to rewrite it:
8960; - call a function that detect which function to call
8961; - make all called C function get the same parameters list
8962;
8963int13_relocated:
8964
8965#if BX_ELTORITO_BOOT
8966 ;; check for an eltorito function
8967 cmp ah,#0x4a
8968 jb int13_not_eltorito
8969 cmp ah,#0x4d
8970 ja int13_not_eltorito
8971
8972 pusha
8973 push es
8974 push ds
8975 push ss
8976 pop ds
8977
8978 push #int13_out
8979 jmp _int13_eltorito ;; ELDX not used
8980
8981int13_not_eltorito:
8982 push ax
8983 push bx
8984 push cx
8985 push dx
8986
8987 ;; check if emulation active
8988 call _cdemu_isactive
8989 cmp al,#0x00
8990 je int13_cdemu_inactive
8991
8992 ;; check if access to the emulated drive
8993 call _cdemu_emulated_drive
8994 pop dx
8995 push dx
8996 cmp al,dl ;; int13 on emulated drive
8997 jne int13_nocdemu
8998
8999 pop dx
9000 pop cx
9001 pop bx
9002 pop ax
9003
9004 pusha
9005 push es
9006 push ds
9007 push ss
9008 pop ds
9009
9010 push #int13_out
9011 jmp _int13_cdemu ;; ELDX not used
9012
9013int13_nocdemu:
9014 and dl,#0xE0 ;; mask to get device class, including cdroms
9015 cmp al,dl ;; al is 0x00 or 0x80
9016 jne int13_cdemu_inactive ;; inactive for device class
9017
9018 pop dx
9019 pop cx
9020 pop bx
9021 pop ax
9022
9023 push ax
9024 push cx
9025 push dx
9026 push bx
9027
9028 dec dl ;; real drive is dl - 1
9029 jmp int13_legacy
9030
9031int13_cdemu_inactive:
9032 pop dx
9033 pop cx
9034 pop bx
9035 pop ax
9036
9037#endif // BX_ELTORITO_BOOT
9038
9039int13_noeltorito:
9040
9041 push ax
9042 push cx
9043 push dx
9044 push bx
9045
9046int13_legacy:
9047
9048 push dx ;; push eltorito value of dx instead of sp
9049
9050 push bp
9051 push si
9052 push di
9053
9054 push es
9055 push ds
9056 push ss
9057 pop ds
9058
9059 ;; now the 16-bit registers can be restored with:
9060 ;; pop ds; pop es; popa; iret
9061 ;; arguments passed to functions should be
9062 ;; DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS
9063
9064 test dl, #0x80
9065 jnz int13_notfloppy
9066
9067 push #int13_out
9068 jmp _int13_diskette_function
9069
9070int13_notfloppy:
9071
9072#if BX_USE_ATADRV
9073
9074 cmp dl, #0xE0
9075 jb int13_notcdrom
9076
9077 // ebx is modified: BSD 5.2.1 boot loader problem
9078 // someone should figure out which 32 bit register that actually are used
9079
9080 shr ebx, #16
9081 push bx
9082
9083 call _int13_cdrom
9084
9085 pop bx
9086 shl ebx, #16
9087
9088 jmp int13_out
9089
9090int13_notcdrom:
9091
9092#endif
9093
9094int13_disk:
9095 ;; int13_harddisk modifies high word of EAX and EBX
9096 shr eax, #16
9097 push ax
9098 shr ebx, #16
9099 push bx
9100 call _int13_harddisk
9101 pop bx
9102 shl ebx, #16
9103 pop ax
9104 shl eax, #16
9105
9106int13_out:
9107 pop ds
9108 pop es
9109 popa
9110 iret
9111
9112;----------
9113;- INT18h -
9114;----------
9115int18_handler: ;; Boot Failure routing
9116 call _int18_panic_msg
9117 hlt
9118 iret
9119
9120;----------
9121;- INT19h -
9122;----------
9123int19_relocated: ;; Boot function, relocated
9124
9125#ifdef VBOX
9126 // If an already booted OS calls int 0x19 to reboot, it is not sufficient
9127 // just to try booting from the configured drives. All BIOS variables and
9128 // interrupt vectors need to be reset, otherwise strange things may happen.
9129 // The approach used is faking a warm reboot (which just skips showing the
9130 // logo), which is a bit more than what we need, but hey, it's fast.
9131 mov bp, sp
9132 mov ax, 2[bp]
9133 cmp ax, #0xf000
9134 jz bios_initiated_boot
9135 xor ax, ax
9136 mov ds, ax
9137 mov ax, #0x1234
9138 mov 0x472, ax
9139 jmp post
9140bios_initiated_boot:
9141#endif /* VBOX */
9142
9143 ;; int19 was beginning to be really complex, so now it
9144 ;; just calls a C function that does the work
9145 ;; it returns in BL the boot drive, and in AX the boot segment
9146 ;; the boot segment will be 0x0000 if something has failed
9147
9148 push bp
9149 mov bp, sp
9150
9151 ;; drop ds
9152 xor ax, ax
9153 mov ds, ax
9154
9155 ;; 1st boot device
9156 mov ax, #0x0001
9157 push ax
9158 call _int19_function
9159 inc sp
9160 inc sp
9161 ;; bl contains the boot drive
9162 ;; ax contains the boot segment or 0 if failure
9163
9164 test ax, ax ;; if ax is 0 try next boot device
9165 jnz boot_setup
9166
9167 ;; 2nd boot device
9168 mov ax, #0x0002
9169 push ax
9170 call _int19_function
9171 inc sp
9172 inc sp
9173 test ax, ax ;; if ax is 0 try next boot device
9174 jnz boot_setup
9175
9176 ;; 3rd boot device
9177 mov ax, #0x0003
9178 push ax
9179 call _int19_function
9180 inc sp
9181 inc sp
9182#ifdef VBOX
9183 test ax, ax ;; if ax is 0 try next boot device
9184 jnz boot_setup
9185
9186 ;; 4th boot device
9187 mov ax, #0x0004
9188 push ax
9189 call _int19_function
9190 inc sp
9191 inc sp
9192#endif /* VBOX */
9193 test ax, ax ;; if ax is 0 call int18
9194 jz int18_handler
9195
9196boot_setup:
9197 mov dl, bl ;; set drive so guest os find it
9198 shl eax, #0x04 ;; convert seg to ip
9199 mov 2[bp], ax ;; set ip
9200
9201 shr eax, #0x04 ;; get cs back
9202 and ax, #0xF000 ;; remove what went in ip
9203 mov 4[bp], ax ;; set cs
9204 xor ax, ax
9205 mov es, ax ;; set es to zero fixes [ 549815 ]
9206 mov [bp], ax ;; set bp to zero
9207 mov ax, #0xaa55 ;; set ok flag
9208
9209 pop bp
9210 iret ;; Beam me up Scotty
9211
9212;----------
9213;- INT1Ch -
9214;----------
9215int1c_handler: ;; User Timer Tick
9216 iret
9217
9218
9219;----------------------
9220;- POST: Floppy Drive -
9221;----------------------
9222floppy_drive_post:
9223 xor ax, ax
9224 mov ds, ax
9225
9226 mov al, #0x00
9227 mov 0x043e, al ;; drive 0 & 1 uncalibrated, no interrupt has occurred
9228
9229 mov 0x043f, al ;; diskette motor status: read op, drive0, motors off
9230
9231 mov 0x0440, al ;; diskette motor timeout counter: not active
9232 mov 0x0441, al ;; diskette controller status return code
9233
9234 mov 0x0442, al ;; disk & diskette controller status register 0
9235 mov 0x0443, al ;; diskette controller status register 1
9236 mov 0x0444, al ;; diskette controller status register 2
9237 mov 0x0445, al ;; diskette controller cylinder number
9238 mov 0x0446, al ;; diskette controller head number
9239 mov 0x0447, al ;; diskette controller sector number
9240 mov 0x0448, al ;; diskette controller bytes written
9241
9242 mov 0x048b, al ;; diskette configuration data
9243
9244 ;; -----------------------------------------------------------------
9245 ;; (048F) diskette controller information
9246 ;;
9247 mov al, #0x10 ;; get CMOS diskette drive type
9248 out 0x70, AL
9249 in AL, 0x71
9250 mov ah, al ;; save byte to AH
9251
9252look_drive0:
9253 shr al, #4 ;; look at top 4 bits for drive 0
9254 jz f0_missing ;; jump if no drive0
9255 mov bl, #0x07 ;; drive0 determined, multi-rate, has changed line
9256 jmp look_drive1
9257f0_missing:
9258 mov bl, #0x00 ;; no drive0
9259
9260look_drive1:
9261 mov al, ah ;; restore from AH
9262 and al, #0x0f ;; look at bottom 4 bits for drive 1
9263 jz f1_missing ;; jump if no drive1
9264 or bl, #0x70 ;; drive1 determined, multi-rate, has changed line
9265f1_missing:
9266 ;; leave high bits in BL zerod
9267 mov 0x048f, bl ;; put new val in BDA (diskette controller information)
9268 ;; -----------------------------------------------------------------
9269
9270 mov al, #0x00
9271 mov 0x0490, al ;; diskette 0 media state
9272 mov 0x0491, al ;; diskette 1 media state
9273
9274 ;; diskette 0,1 operational starting state
9275 ;; drive type has not been determined,
9276 ;; has no changed detection line
9277 mov 0x0492, al
9278 mov 0x0493, al
9279
9280 mov 0x0494, al ;; diskette 0 current cylinder
9281 mov 0x0495, al ;; diskette 1 current cylinder
9282
9283 mov al, #0x02
9284 out #0x0a, al ;; clear DMA-1 channel 2 mask bit
9285
9286 SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
9287 SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
9288 SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
9289
9290 ret
9291
9292
9293;--------------------
9294;- POST: HARD DRIVE -
9295;--------------------
9296; relocated here because the primary POST area isnt big enough.
9297hard_drive_post:
9298 // IRQ 14 = INT 76h
9299 // INT 76h calls INT 15h function ax=9100
9300
9301 mov al, #0x0a ; 0000 1010 = reserved, disable IRQ 14
9302 mov dx, #0x03f6
9303 out dx, al
9304
9305 xor ax, ax
9306 mov ds, ax
9307 mov 0x0474, al /* hard disk status of last operation */
9308 mov 0x0477, al /* hard disk port offset (XT only ???) */
9309 mov 0x048c, al /* hard disk status register */
9310 mov 0x048d, al /* hard disk error register */
9311 mov 0x048e, al /* hard disk task complete flag */
9312 mov al, #0x01
9313 mov 0x0475, al /* hard disk number attached */
9314 mov al, #0xc0
9315 mov 0x0476, al /* hard disk control byte */
9316 SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
9317 SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
9318 ;; INT 41h: hard disk 0 configuration pointer
9319 ;; INT 46h: hard disk 1 configuration pointer
9320 SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D)
9321 SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D)
9322
9323#ifndef VBOX /* This is done later (and the CMOS format is now different). */
9324 ;; move disk geometry data from CMOS to EBDA disk parameter table(s)
9325 mov al, #0x12
9326 out #0x70, al
9327 in al, #0x71
9328 and al, #0xf0
9329 cmp al, #0xf0
9330 je post_d0_extended
9331 jmp check_for_hd1
9332post_d0_extended:
9333 mov al, #0x19
9334 out #0x70, al
9335 in al, #0x71
9336 cmp al, #47 ;; decimal 47 - user definable
9337 je post_d0_type47
9338 HALT(__LINE__)
9339post_d0_type47:
9340 ;; CMOS purpose param table offset
9341 ;; 1b cylinders low 0
9342 ;; 1c cylinders high 1
9343 ;; 1d heads 2
9344 ;; 1e write pre-comp low 5
9345 ;; 1f write pre-comp high 6
9346 ;; 20 retries/bad map/heads>8 8
9347 ;; 21 landing zone low C
9348 ;; 22 landing zone high D
9349 ;; 23 sectors/track E
9350
9351 mov ax, #EBDA_SEG
9352 mov ds, ax
9353
9354 ;;; Filling EBDA table for hard disk 0.
9355 mov al, #0x1f
9356 out #0x70, al
9357 in al, #0x71
9358 mov ah, al
9359 mov al, #0x1e
9360 out #0x70, al
9361 in al, #0x71
9362 mov (0x003d + 0x05), ax ;; write precomp word
9363
9364 mov al, #0x20
9365 out #0x70, al
9366 in al, #0x71
9367 mov (0x003d + 0x08), al ;; drive control byte
9368
9369 mov al, #0x22
9370 out #0x70, al
9371 in al, #0x71
9372 mov ah, al
9373 mov al, #0x21
9374 out #0x70, al
9375 in al, #0x71
9376 mov (0x003d + 0x0C), ax ;; landing zone word
9377
9378 mov al, #0x1c ;; get cylinders word in AX
9379 out #0x70, al
9380 in al, #0x71 ;; high byte
9381 mov ah, al
9382 mov al, #0x1b
9383 out #0x70, al
9384 in al, #0x71 ;; low byte
9385 mov bx, ax ;; BX = cylinders
9386
9387 mov al, #0x1d
9388 out #0x70, al
9389 in al, #0x71
9390 mov cl, al ;; CL = heads
9391
9392 mov al, #0x23
9393 out #0x70, al
9394 in al, #0x71
9395 mov dl, al ;; DL = sectors
9396
9397 cmp bx, #1024
9398 jnbe hd0_post_logical_chs ;; if cylinders > 1024, use translated style CHS
9399
9400hd0_post_physical_chs:
9401 ;; no logical CHS mapping used, just physical CHS
9402 ;; use Standard Fixed Disk Parameter Table (FDPT)
9403 mov (0x003d + 0x00), bx ;; number of physical cylinders
9404 mov (0x003d + 0x02), cl ;; number of physical heads
9405 mov (0x003d + 0x0E), dl ;; number of physical sectors
9406 jmp check_for_hd1
9407
9408hd0_post_logical_chs:
9409 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
9410 mov (0x003d + 0x09), bx ;; number of physical cylinders
9411 mov (0x003d + 0x0b), cl ;; number of physical heads
9412 mov (0x003d + 0x04), dl ;; number of physical sectors
9413 mov (0x003d + 0x0e), dl ;; number of logical sectors (same)
9414 mov al, #0xa0
9415 mov (0x003d + 0x03), al ;; A0h signature, indicates translated table
9416
9417 cmp bx, #2048
9418 jnbe hd0_post_above_2048
9419 ;; 1024 < c <= 2048 cylinders
9420 shr bx, #0x01
9421 shl cl, #0x01
9422 jmp hd0_post_store_logical
9423
9424hd0_post_above_2048:
9425 cmp bx, #4096
9426 jnbe hd0_post_above_4096
9427 ;; 2048 < c <= 4096 cylinders
9428 shr bx, #0x02
9429 shl cl, #0x02
9430 jmp hd0_post_store_logical
9431
9432hd0_post_above_4096:
9433 cmp bx, #8192
9434 jnbe hd0_post_above_8192
9435 ;; 4096 < c <= 8192 cylinders
9436 shr bx, #0x03
9437 shl cl, #0x03
9438 jmp hd0_post_store_logical
9439
9440hd0_post_above_8192:
9441 ;; 8192 < c <= 16384 cylinders
9442 shr bx, #0x04
9443 shl cl, #0x04
9444
9445hd0_post_store_logical:
9446 mov (0x003d + 0x00), bx ;; number of physical cylinders
9447 mov (0x003d + 0x02), cl ;; number of physical heads
9448 ;; checksum
9449 mov cl, #0x0f ;; repeat count
9450 mov si, #0x003d ;; offset to disk0 FDPT
9451 mov al, #0x00 ;; sum
9452hd0_post_checksum_loop:
9453 add al, [si]
9454 inc si
9455 dec cl
9456 jnz hd0_post_checksum_loop
9457 not al ;; now take 2s complement
9458 inc al
9459 mov [si], al
9460;;; Done filling EBDA table for hard disk 0.
9461
9462
9463check_for_hd1:
9464 ;; is there really a second hard disk? if not, return now
9465 mov al, #0x12
9466 out #0x70, al
9467 in al, #0x71
9468 and al, #0x0f
9469 jnz post_d1_exists
9470 ret
9471post_d1_exists:
9472 ;; check that the hd type is really 0x0f.
9473 cmp al, #0x0f
9474 jz post_d1_extended
9475 HALT(__LINE__)
9476post_d1_extended:
9477 ;; check that the extended type is 47 - user definable
9478 mov al, #0x1a
9479 out #0x70, al
9480 in al, #0x71
9481 cmp al, #47 ;; decimal 47 - user definable
9482 je post_d1_type47
9483 HALT(__LINE__)
9484post_d1_type47:
9485 ;; Table for disk1.
9486 ;; CMOS purpose param table offset
9487 ;; 0x24 cylinders low 0
9488 ;; 0x25 cylinders high 1
9489 ;; 0x26 heads 2
9490 ;; 0x27 write pre-comp low 5
9491 ;; 0x28 write pre-comp high 6
9492 ;; 0x29 heads>8 8
9493 ;; 0x2a landing zone low C
9494 ;; 0x2b landing zone high D
9495 ;; 0x2c sectors/track E
9496;;; Fill EBDA table for hard disk 1.
9497 mov ax, #EBDA_SEG
9498 mov ds, ax
9499 mov al, #0x28
9500 out #0x70, al
9501 in al, #0x71
9502 mov ah, al
9503 mov al, #0x27
9504 out #0x70, al
9505 in al, #0x71
9506 mov (0x004d + 0x05), ax ;; write precomp word
9507
9508 mov al, #0x29
9509 out #0x70, al
9510 in al, #0x71
9511 mov (0x004d + 0x08), al ;; drive control byte
9512
9513 mov al, #0x2b
9514 out #0x70, al
9515 in al, #0x71
9516 mov ah, al
9517 mov al, #0x2a
9518 out #0x70, al
9519 in al, #0x71
9520 mov (0x004d + 0x0C), ax ;; landing zone word
9521
9522 mov al, #0x25 ;; get cylinders word in AX
9523 out #0x70, al
9524 in al, #0x71 ;; high byte
9525 mov ah, al
9526 mov al, #0x24
9527 out #0x70, al
9528 in al, #0x71 ;; low byte
9529 mov bx, ax ;; BX = cylinders
9530
9531 mov al, #0x26
9532 out #0x70, al
9533 in al, #0x71
9534 mov cl, al ;; CL = heads
9535
9536 mov al, #0x2c
9537 out #0x70, al
9538 in al, #0x71
9539 mov dl, al ;; DL = sectors
9540
9541 cmp bx, #1024
9542 jnbe hd1_post_logical_chs ;; if cylinders > 1024, use translated style CHS
9543
9544hd1_post_physical_chs:
9545 ;; no logical CHS mapping used, just physical CHS
9546 ;; use Standard Fixed Disk Parameter Table (FDPT)
9547 mov (0x004d + 0x00), bx ;; number of physical cylinders
9548 mov (0x004d + 0x02), cl ;; number of physical heads
9549 mov (0x004d + 0x0E), dl ;; number of physical sectors
9550 ret
9551
9552hd1_post_logical_chs:
9553 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
9554 mov (0x004d + 0x09), bx ;; number of physical cylinders
9555 mov (0x004d + 0x0b), cl ;; number of physical heads
9556 mov (0x004d + 0x04), dl ;; number of physical sectors
9557 mov (0x004d + 0x0e), dl ;; number of logical sectors (same)
9558 mov al, #0xa0
9559 mov (0x004d + 0x03), al ;; A0h signature, indicates translated table
9560
9561 cmp bx, #2048
9562 jnbe hd1_post_above_2048
9563 ;; 1024 < c <= 2048 cylinders
9564 shr bx, #0x01
9565 shl cl, #0x01
9566 jmp hd1_post_store_logical
9567
9568hd1_post_above_2048:
9569 cmp bx, #4096
9570 jnbe hd1_post_above_4096
9571 ;; 2048 < c <= 4096 cylinders
9572 shr bx, #0x02
9573 shl cl, #0x02
9574 jmp hd1_post_store_logical
9575
9576hd1_post_above_4096:
9577 cmp bx, #8192
9578 jnbe hd1_post_above_8192
9579 ;; 4096 < c <= 8192 cylinders
9580 shr bx, #0x03
9581 shl cl, #0x03
9582 jmp hd1_post_store_logical
9583
9584hd1_post_above_8192:
9585 ;; 8192 < c <= 16384 cylinders
9586 shr bx, #0x04
9587 shl cl, #0x04
9588
9589hd1_post_store_logical:
9590 mov (0x004d + 0x00), bx ;; number of physical cylinders
9591 mov (0x004d + 0x02), cl ;; number of physical heads
9592 ;; checksum
9593 mov cl, #0x0f ;; repeat count
9594 mov si, #0x004d ;; offset to disk0 FDPT
9595 mov al, #0x00 ;; sum
9596hd1_post_checksum_loop:
9597 add al, [si]
9598 inc si
9599 dec cl
9600 jnz hd1_post_checksum_loop
9601 not al ;; now take 2s complement
9602 inc al
9603 mov [si], al
9604;;; Done filling EBDA table for hard disk 1.
9605#endif /* !VBOX */
9606
9607 ret
9608
9609;--------------------
9610;- POST: EBDA segment
9611;--------------------
9612; relocated here because the primary POST area isnt big enough.
9613; the SET_INT_VECTORs have nothing to do with EBDA but do not
9614; fit into the primary POST area either
9615ebda_post:
9616 SET_INT_VECTOR(0x0D, #0xF000, #dummy_isr); IRQ 5
9617 SET_INT_VECTOR(0x0F, #0xF000, #dummy_isr); IRQ 7
9618 SET_INT_VECTOR(0x72, #0xF000, #dummy_isr); IRQ 11
9619 SET_INT_VECTOR(0x77, #0xF000, #dummy_isr); IRQ 15
9620
9621#if BX_USE_EBDA
9622 mov ax, #EBDA_SEG
9623 mov ds, ax
9624 mov byte ptr [0x0], #EBDA_SIZE
9625#endif
9626 xor ax, ax ; mov EBDA seg into 40E
9627 mov ds, ax
9628 mov word ptr [0x40E], #EBDA_SEG
9629 ret;;
9630
9631;--------------------
9632;- POST: EOI + jmp via [0x40:67)
9633;--------------------
9634; relocated here because the primary POST area isnt big enough.
9635eoi_jmp_post:
9636 call eoi_both_pics
9637
9638 xor ax, ax
9639 mov ds, ax
9640
9641 jmp far ptr [0x467]
9642
9643
9644;--------------------
9645eoi_both_pics:
9646 mov al, #0x20
9647 out #0xA0, al ;; slave PIC EOI
9648eoi_master_pic:
9649 mov al, #0x20
9650 out #0x20, al ;; master PIC EOI
9651 ret
9652
9653;--------------------
9654BcdToBin:
9655 ;; in: AL in BCD format
9656 ;; out: AL in binary format, AH will always be 0
9657 ;; trashes BX
9658 mov bl, al
9659 and bl, #0x0f ;; bl has low digit
9660 shr al, #4 ;; al has high digit
9661 mov bh, #10
9662 mul al, bh ;; multiply high digit by 10 (result in AX)
9663 add al, bl ;; then add low digit
9664 ret
9665
9666;--------------------
9667timer_tick_post:
9668 ;; Setup the Timer Ticks Count (0x46C:dword) and
9669 ;; Timer Ticks Roller Flag (0x470:byte)
9670 ;; The Timer Ticks Count needs to be set according to
9671 ;; the current CMOS time, as if ticks have been occurring
9672 ;; at 18.2hz since midnight up to this point. Calculating
9673 ;; this is a little complicated. Here are the factors I gather
9674 ;; regarding this. 14,318,180 hz was the original clock speed,
9675 ;; chosen so it could be divided by either 3 to drive the 5Mhz CPU
9676 ;; at the time, or 4 to drive the CGA video adapter. The div3
9677 ;; source was divided again by 4 to feed a 1.193Mhz signal to
9678 ;; the timer. With a maximum 16bit timer count, this is again
9679 ;; divided down by 65536 to 18.2hz.
9680 ;;
9681 ;; 14,318,180 Hz clock
9682 ;; /3 = 4,772,726 Hz fed to orginal 5Mhz CPU
9683 ;; /4 = 1,193,181 Hz fed to timer
9684 ;; /65536 (maximum timer count) = 18.20650736 ticks/second
9685 ;; 1 second = 18.20650736 ticks
9686 ;; 1 minute = 1092.390442 ticks
9687 ;; 1 hour = 65543.42651 ticks
9688 ;;
9689 ;; Given the values in the CMOS clock, one could calculate
9690 ;; the number of ticks by the following:
9691 ;; ticks = (BcdToBin(seconds) * 18.206507) +
9692 ;; (BcdToBin(minutes) * 1092.3904)
9693 ;; (BcdToBin(hours) * 65543.427)
9694 ;; To get a little more accuracy, since Im using integer
9695 ;; arithmatic, I use:
9696 ;; ticks = (BcdToBin(seconds) * 18206507) / 1000000 +
9697 ;; (BcdToBin(minutes) * 10923904) / 10000 +
9698 ;; (BcdToBin(hours) * 65543427) / 1000
9699
9700 ;; assuming DS=0000
9701
9702 ;; get CMOS seconds
9703 xor eax, eax ;; clear EAX
9704 mov al, #0x00
9705 out #0x70, al
9706 in al, #0x71 ;; AL has CMOS seconds in BCD
9707 call BcdToBin ;; EAX now has seconds in binary
9708 mov edx, #18206507
9709 mul eax, edx
9710 mov ebx, #1000000
9711 xor edx, edx
9712 div eax, ebx
9713 mov ecx, eax ;; ECX will accumulate total ticks
9714
9715 ;; get CMOS minutes
9716 xor eax, eax ;; clear EAX
9717 mov al, #0x02
9718 out #0x70, al
9719 in al, #0x71 ;; AL has CMOS minutes in BCD
9720 call BcdToBin ;; EAX now has minutes in binary
9721 mov edx, #10923904
9722 mul eax, edx
9723 mov ebx, #10000
9724 xor edx, edx
9725 div eax, ebx
9726 add ecx, eax ;; add to total ticks
9727
9728 ;; get CMOS hours
9729 xor eax, eax ;; clear EAX
9730 mov al, #0x04
9731 out #0x70, al
9732 in al, #0x71 ;; AL has CMOS hours in BCD
9733 call BcdToBin ;; EAX now has hours in binary
9734 mov edx, #65543427
9735 mul eax, edx
9736 mov ebx, #1000
9737 xor edx, edx
9738 div eax, ebx
9739 add ecx, eax ;; add to total ticks
9740
9741 mov 0x46C, ecx ;; Timer Ticks Count
9742 xor al, al
9743 mov 0x470, al ;; Timer Ticks Rollover Flag
9744 ret
9745
9746;--------------------
9747int76_handler:
9748 ;; record completion in BIOS task complete flag
9749 push ax
9750 push ds
9751 mov ax, #0x0040
9752 mov ds, ax
9753 mov 0x008E, #0xff
9754 call eoi_both_pics
9755 pop ds
9756 pop ax
9757 iret
9758
9759
9760;--------------------
9761#ifdef VBOX
9762init_pic:
9763 ;; init PIC
9764 mov al, #0x11 ; send initialisation commands
9765 out 0x20, al
9766 out 0xa0, al
9767 mov al, #0x08
9768 out 0x21, al
9769 mov al, #0x70
9770 out 0xa1, al
9771 mov al, #0x04
9772 out 0x21, al
9773 mov al, #0x02
9774 out 0xa1, al
9775 mov al, #0x01
9776 out 0x21, al
9777 out 0xa1, al
9778 mov al, #0xb8
9779 out 0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6
9780#if BX_USE_PS2_MOUSE
9781 mov al, #0x8f
9782#else
9783 mov al, #0x9f
9784#endif
9785 out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14
9786 ret
9787#endif /* VBOX */
9788
9789;--------------------
9790#if BX_APM
9791
9792use32 386
9793#define APM_PROT32
9794#include "apmbios.S"
9795
9796use16 386
9797#define APM_PROT16
9798#include "apmbios.S"
9799
9800#define APM_REAL
9801#include "apmbios.S"
9802
9803#endif
9804
9805;--------------------
9806#if BX_PCIBIOS
9807use32 386
9808.align 16
9809bios32_structure:
9810 db 0x5f, 0x33, 0x32, 0x5f ;; "_32_" signature
9811 dw bios32_entry_point, 0xf ;; 32 bit physical address
9812 db 0 ;; revision level
9813 ;; length in paragraphs and checksum stored in a word to prevent errors
9814 dw (~(((bios32_entry_point >> 8) + (bios32_entry_point & 0xff) + 0x32) \
9815 & 0xff) << 8) + 0x01
9816 db 0,0,0,0,0 ;; reserved
9817
9818.align 16
9819bios32_entry_point:
9820 pushfd
9821 cmp eax, #0x49435024 ;; "$PCI"
9822 jne unknown_service
9823
9824#ifdef PCI_FIXED_HOST_BRIDGE_1
9825 mov eax, #0x80000000
9826 mov dx, #0x0cf8
9827 out dx, eax
9828 mov dx, #0x0cfc
9829 in eax, dx
9830 cmp eax, #PCI_FIXED_HOST_BRIDGE_1
9831 je device_ok
9832#endif
9833
9834#ifdef PCI_FIXED_HOST_BRIDGE_2
9835 /* 0x1e << 11 */
9836 mov eax, #0x8000f000
9837 mov dx, #0x0cf8
9838 out dx, eax
9839 mov dx, #0x0cfc
9840 in eax, dx
9841 cmp eax, #PCI_FIXED_HOST_BRIDGE_2
9842 je device_ok
9843#endif
9844 jmp unknown_service
9845device_ok:
9846 mov ebx, #0x000f0000
9847 mov ecx, #0
9848 mov edx, #pcibios_protected
9849 xor al, al
9850 jmp bios32_end
9851unknown_service:
9852 mov al, #0x80
9853bios32_end:
9854#ifdef BX_QEMU
9855 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
9856#endif
9857 popfd
9858 retf
9859
9860.align 16
9861pcibios_protected:
9862 pushfd
9863 cli
9864 push esi
9865 push edi
9866 cmp al, #0x01 ;; installation check
9867 jne pci_pro_f02
9868 mov bx, #0x0210
9869 mov cx, #0
9870 mov edx, #0x20494350 ;; "PCI "
9871 mov al, #0x01
9872 jmp pci_pro_ok
9873pci_pro_f02: ;; find pci device
9874 cmp al, #0x02
9875 jne pci_pro_f03
9876 shl ecx, #16
9877 mov cx, dx
9878 xor ebx, ebx
9879 mov di, #0x00
9880pci_pro_devloop:
9881 call pci_pro_select_reg
9882 mov dx, #0x0cfc
9883 in eax, dx
9884 cmp eax, ecx
9885 jne pci_pro_nextdev
9886 cmp si, #0
9887 je pci_pro_ok
9888 dec si
9889pci_pro_nextdev:
9890 inc ebx
9891 cmp ebx, #0x10000
9892 jne pci_pro_devloop
9893 mov ah, #0x86
9894 jmp pci_pro_fail
9895pci_pro_f03: ;; find class code
9896 cmp al, #0x03
9897 jne pci_pro_f08
9898 xor ebx, ebx
9899 mov di, #0x08
9900pci_pro_devloop2:
9901 call pci_pro_select_reg
9902 mov dx, #0x0cfc
9903 in eax, dx
9904 shr eax, #8
9905 cmp eax, ecx
9906 jne pci_pro_nextdev2
9907 cmp si, #0
9908 je pci_pro_ok
9909 dec si
9910pci_pro_nextdev2:
9911 inc ebx
9912 cmp ebx, #0x10000
9913 jne pci_pro_devloop2
9914 mov ah, #0x86
9915 jmp pci_pro_fail
9916pci_pro_f08: ;; read configuration byte
9917 cmp al, #0x08
9918 jne pci_pro_f09
9919 call pci_pro_select_reg
9920 push edx
9921 mov dx, di
9922 and dx, #0x03
9923 add dx, #0x0cfc
9924 in al, dx
9925 pop edx
9926 mov cl, al
9927 jmp pci_pro_ok
9928pci_pro_f09: ;; read configuration word
9929 cmp al, #0x09
9930 jne pci_pro_f0a
9931 call pci_pro_select_reg
9932 push edx
9933 mov dx, di
9934 and dx, #0x02
9935 add dx, #0x0cfc
9936 in ax, dx
9937 pop edx
9938 mov cx, ax
9939 jmp pci_pro_ok
9940pci_pro_f0a: ;; read configuration dword
9941 cmp al, #0x0a
9942 jne pci_pro_f0b
9943 call pci_pro_select_reg
9944 push edx
9945 mov dx, #0x0cfc
9946 in eax, dx
9947 pop edx
9948 mov ecx, eax
9949 jmp pci_pro_ok
9950pci_pro_f0b: ;; write configuration byte
9951 cmp al, #0x0b
9952 jne pci_pro_f0c
9953 call pci_pro_select_reg
9954 push edx
9955 mov dx, di
9956 and dx, #0x03
9957 add dx, #0x0cfc
9958 mov al, cl
9959 out dx, al
9960 pop edx
9961 jmp pci_pro_ok
9962pci_pro_f0c: ;; write configuration word
9963 cmp al, #0x0c
9964 jne pci_pro_f0d
9965 call pci_pro_select_reg
9966 push edx
9967 mov dx, di
9968 and dx, #0x02
9969 add dx, #0x0cfc
9970 mov ax, cx
9971 out dx, ax
9972 pop edx
9973 jmp pci_pro_ok
9974pci_pro_f0d: ;; write configuration dword
9975 cmp al, #0x0d
9976 jne pci_pro_unknown
9977 call pci_pro_select_reg
9978 push edx
9979 mov dx, #0x0cfc
9980 mov eax, ecx
9981 out dx, eax
9982 pop edx
9983 jmp pci_pro_ok
9984pci_pro_unknown:
9985 mov ah, #0x81
9986pci_pro_fail:
9987 pop edi
9988 pop esi
9989#ifdef BX_QEMU
9990 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
9991#endif
9992 popfd
9993 stc
9994 retf
9995pci_pro_ok:
9996 xor ah, ah
9997 pop edi
9998 pop esi
9999#ifdef BX_QEMU
10000 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
10001#endif
10002 popfd
10003 clc
10004 retf
10005
10006pci_pro_select_reg:
10007 push edx
10008 mov eax, #0x800000
10009 mov ax, bx
10010 shl eax, #8
10011 and di, #0xff
10012 or ax, di
10013 and al, #0xfc
10014 mov dx, #0x0cf8
10015 out dx, eax
10016 pop edx
10017 ret
10018
10019use16 386
10020
10021pcibios_real:
10022 push eax
10023 push dx
10024#ifdef PCI_FIXED_HOST_BRIDGE_1
10025 mov eax, #0x80000000
10026 mov dx, #0x0cf8
10027 out dx, eax
10028 mov dx, #0x0cfc
10029 in eax, dx
10030 cmp eax, #PCI_FIXED_HOST_BRIDGE_1
10031 je pci_present
10032#endif
10033
10034#ifdef PCI_FIXED_HOST_BRIDGE_2
10035 /* 0x1e << 11 */
10036 mov eax, #0x8000f000
10037 mov dx, #0x0cf8
10038 out dx, eax
10039 mov dx, #0x0cfc
10040 in eax, dx
10041 cmp eax, #PCI_FIXED_HOST_BRIDGE_2
10042 je pci_present
10043#endif
10044 pop dx
10045 pop eax
10046 mov ah, #0xff
10047 stc
10048 ret
10049pci_present:
10050 pop dx
10051 pop eax
10052 cmp al, #0x01 ;; installation check
10053 jne pci_real_f02
10054 mov ax, #0x0001
10055 mov bx, #0x0210
10056 mov cx, #0
10057 mov edx, #0x20494350 ;; "PCI "
10058 mov edi, #0xf0000
10059 mov di, #pcibios_protected
10060 clc
10061 ret
10062pci_real_f02: ;; find pci device
10063 push esi
10064 push edi
10065 push edx
10066 cmp al, #0x02
10067 jne pci_real_f03
10068 shl ecx, #16
10069 mov cx, dx
10070 xor ebx, ebx
10071 mov di, #0x00
10072pci_real_devloop:
10073 call pci_real_select_reg
10074 mov dx, #0x0cfc
10075 in eax, dx
10076 cmp eax, ecx
10077 jne pci_real_nextdev
10078 cmp si, #0
10079 je pci_real_ok
10080 dec si
10081pci_real_nextdev:
10082 inc ebx
10083 cmp ebx, #0x10000
10084 jne pci_real_devloop
10085 mov dx, cx
10086 shr ecx, #16
10087 mov ax, #0x8602
10088 jmp pci_real_fail
10089pci_real_f03: ;; find class code
10090 cmp al, #0x03
10091 jne pci_real_f08
10092 xor ebx, ebx
10093 mov di, #0x08
10094pci_real_devloop2:
10095 call pci_real_select_reg
10096 mov dx, #0x0cfc
10097 in eax, dx
10098 shr eax, #8
10099 cmp eax, ecx
10100 jne pci_real_nextdev2
10101 cmp si, #0
10102 je pci_real_ok
10103 dec si
10104pci_real_nextdev2:
10105 inc ebx
10106 cmp ebx, #0x10000
10107 jne pci_real_devloop2
10108 mov ax, #0x8603
10109 jmp pci_real_fail
10110pci_real_f08: ;; read configuration byte
10111 cmp al, #0x08
10112 jne pci_real_f09
10113 call pci_real_select_reg
10114 push dx
10115 mov dx, di
10116 and dx, #0x03
10117 add dx, #0x0cfc
10118 in al, dx
10119 pop dx
10120 mov cl, al
10121 jmp pci_real_ok
10122pci_real_f09: ;; read configuration word
10123 cmp al, #0x09
10124 jne pci_real_f0a
10125 call pci_real_select_reg
10126 push dx
10127 mov dx, di
10128 and dx, #0x02
10129 add dx, #0x0cfc
10130 in ax, dx
10131 pop dx
10132 mov cx, ax
10133 jmp pci_real_ok
10134pci_real_f0a: ;; read configuration dword
10135 cmp al, #0x0a
10136 jne pci_real_f0b
10137 call pci_real_select_reg
10138 push dx
10139 mov dx, #0x0cfc
10140 in eax, dx
10141 pop dx
10142 mov ecx, eax
10143 jmp pci_real_ok
10144pci_real_f0b: ;; write configuration byte
10145 cmp al, #0x0b
10146 jne pci_real_f0c
10147 call pci_real_select_reg
10148 push dx
10149 mov dx, di
10150 and dx, #0x03
10151 add dx, #0x0cfc
10152 mov al, cl
10153 out dx, al
10154 pop dx
10155 jmp pci_real_ok
10156pci_real_f0c: ;; write configuration word
10157 cmp al, #0x0c
10158 jne pci_real_f0d
10159 call pci_real_select_reg
10160 push dx
10161 mov dx, di
10162 and dx, #0x02
10163 add dx, #0x0cfc
10164 mov ax, cx
10165 out dx, ax
10166 pop dx
10167 jmp pci_real_ok
10168pci_real_f0d: ;; write configuration dword
10169 cmp al, #0x0d
10170 jne pci_real_f0e
10171 call pci_real_select_reg
10172 push dx
10173 mov dx, #0x0cfc
10174 mov eax, ecx
10175 out dx, eax
10176 pop dx
10177 jmp pci_real_ok
10178pci_real_f0e: ;; get irq routing options
10179 cmp al, #0x0e
10180 jne pci_real_unknown
10181 SEG ES
10182 cmp word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
10183 jb pci_real_too_small
10184 SEG ES
10185 mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
10186 pushf
10187 push ds
10188 push es
10189 push cx
10190 push si
10191 push di
10192 cld
10193 mov si, #pci_routing_table_structure_start
10194 push cs
10195 pop ds
10196 SEG ES
10197 mov cx, [di+2]
10198 SEG ES
10199 mov es, [di+4]
10200 mov di, cx
10201 mov cx, #pci_routing_table_structure_end - pci_routing_table_structure_start
10202 rep
10203 movsb
10204 pop di
10205 pop si
10206 pop cx
10207 pop es
10208 pop ds
10209 popf
10210 mov bx, #(1 << 9) | (1 << 11) ;; irq 9 and 11 are used
10211 jmp pci_real_ok
10212pci_real_too_small:
10213 SEG ES
10214 mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
10215 mov ah, #0x89
10216 jmp pci_real_fail
10217
10218pci_real_unknown:
10219 mov ah, #0x81
10220pci_real_fail:
10221 pop edx
10222 pop edi
10223 pop esi
10224 stc
10225 ret
10226pci_real_ok:
10227 xor ah, ah
10228 pop edx
10229 pop edi
10230 pop esi
10231 clc
10232 ret
10233
10234;; prepare from reading the PCI config space; on input:
10235;; bx = bus/dev/fn
10236;; di = offset into config space header
10237;; destroys eax and may modify di
10238pci_real_select_reg:
10239 push dx
10240 mov eax, #0x800000
10241 mov ax, bx
10242 shl eax, #8
10243 and di, #0xff
10244 or ax, di
10245 and al, #0xfc
10246 mov dx, #0x0cf8
10247 out dx, eax
10248 pop dx
10249 ret
10250
10251.align 16
10252pci_routing_table_structure:
10253 db 0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature
10254 db 0, 1 ;; version
10255#ifdef VBOX
10256 dw 32 + (30 * 16) ;; table size
10257#else /* !VBOX */
10258 dw 32 + (6 * 16) ;; table size
10259#endif /* !VBOX */
10260 db 0 ;; PCI interrupt router bus
10261 db 0x08 ;; PCI interrupt router DevFunc
10262 dw 0x0000 ;; PCI exclusive IRQs
10263 dw 0x8086 ;; compatible PCI interrupt router vendor ID
10264 dw 0x7000 ;; compatible PCI interrupt router device ID
10265 dw 0,0 ;; Miniport data
10266 db 0,0,0,0,0,0,0,0,0,0,0 ;; reserved
10267#ifdef VBOX
10268 db 0x00 ;; checksum (set by biossums)
10269#else /* !VBOX */
10270 db 0x07 ;; checksum
10271#endif /* !VBOX */
10272pci_routing_table_structure_start:
10273 ;; first slot entry PCI-to-ISA (embedded)
10274 db 0 ;; pci bus number
10275 db 0x08 ;; pci device number (bit 7-3)
10276 db 0x60 ;; link value INTA#: pointer into PCI2ISA config space
10277 dw 0xdef8 ;; IRQ bitmap INTA#
10278 db 0x61 ;; link value INTB#
10279 dw 0xdef8 ;; IRQ bitmap INTB#
10280 db 0x62 ;; link value INTC#
10281 dw 0xdef8 ;; IRQ bitmap INTC#
10282 db 0x63 ;; link value INTD#
10283 dw 0xdef8 ;; IRQ bitmap INTD#
10284 db 0 ;; physical slot (0 = embedded)
10285 db 0 ;; reserved
10286 ;; second slot entry: 1st PCI slot
10287 db 0 ;; pci bus number
10288 db 0x10 ;; pci device number (bit 7-3)
10289 db 0x61 ;; link value INTA#
10290 dw 0xdef8 ;; IRQ bitmap INTA#
10291 db 0x62 ;; link value INTB#
10292 dw 0xdef8 ;; IRQ bitmap INTB#
10293 db 0x63 ;; link value INTC#
10294 dw 0xdef8 ;; IRQ bitmap INTC#
10295 db 0x60 ;; link value INTD#
10296 dw 0xdef8 ;; IRQ bitmap INTD#
10297 db 1 ;; physical slot (0 = embedded)
10298 db 0 ;; reserved
10299 ;; third slot entry: 2nd PCI slot
10300 db 0 ;; pci bus number
10301 db 0x18 ;; pci device number (bit 7-3)
10302 db 0x62 ;; link value INTA#
10303 dw 0xdef8 ;; IRQ bitmap INTA#
10304 db 0x63 ;; link value INTB#
10305 dw 0xdef8 ;; IRQ bitmap INTB#
10306 db 0x60 ;; link value INTC#
10307 dw 0xdef8 ;; IRQ bitmap INTC#
10308 db 0x61 ;; link value INTD#
10309 dw 0xdef8 ;; IRQ bitmap INTD#
10310 db 2 ;; physical slot (0 = embedded)
10311 db 0 ;; reserved
10312 ;; 4th slot entry: 3rd PCI slot
10313 db 0 ;; pci bus number
10314 db 0x20 ;; pci device number (bit 7-3)
10315 db 0x63 ;; link value INTA#
10316 dw 0xdef8 ;; IRQ bitmap INTA#
10317 db 0x60 ;; link value INTB#
10318 dw 0xdef8 ;; IRQ bitmap INTB#
10319 db 0x61 ;; link value INTC#
10320 dw 0xdef8 ;; IRQ bitmap INTC#
10321 db 0x62 ;; link value INTD#
10322 dw 0xdef8 ;; IRQ bitmap INTD#
10323 db 3 ;; physical slot (0 = embedded)
10324 db 0 ;; reserved
10325 ;; 5th slot entry: 4rd PCI slot
10326 db 0 ;; pci bus number
10327 db 0x28 ;; pci device number (bit 7-3)
10328 db 0x60 ;; link value INTA#
10329 dw 0xdef8 ;; IRQ bitmap INTA#
10330 db 0x61 ;; link value INTB#
10331 dw 0xdef8 ;; IRQ bitmap INTB#
10332 db 0x62 ;; link value INTC#
10333 dw 0xdef8 ;; IRQ bitmap INTC#
10334 db 0x63 ;; link value INTD#
10335 dw 0xdef8 ;; IRQ bitmap INTD#
10336 db 4 ;; physical slot (0 = embedded)
10337 db 0 ;; reserved
10338 ;; 6th slot entry: 5rd PCI slot
10339 db 0 ;; pci bus number
10340 db 0x30 ;; pci device number (bit 7-3)
10341 db 0x61 ;; link value INTA#
10342 dw 0xdef8 ;; IRQ bitmap INTA#
10343 db 0x62 ;; link value INTB#
10344 dw 0xdef8 ;; IRQ bitmap INTB#
10345 db 0x63 ;; link value INTC#
10346 dw 0xdef8 ;; IRQ bitmap INTC#
10347 db 0x60 ;; link value INTD#
10348 dw 0xdef8 ;; IRQ bitmap INTD#
10349 db 5 ;; physical slot (0 = embedded)
10350 db 0 ;; reserved
10351#ifdef VBOX
10352 ;; 7th slot entry: 6th PCI slot
10353 db 0 ;; pci bus number
10354 db 0x38 ;; pci device number (bit 7-3)
10355 db 0x62 ;; link value INTA#
10356 dw 0xdef8 ;; IRQ bitmap INTA#
10357 db 0x63 ;; link value INTB#
10358 dw 0xdef8 ;; IRQ bitmap INTB#
10359 db 0x60 ;; link value INTC#
10360 dw 0xdef8 ;; IRQ bitmap INTC#
10361 db 0x61 ;; link value INTD#
10362 dw 0xdef8 ;; IRQ bitmap INTD#
10363 db 6 ;; physical slot (0 = embedded)
10364 db 0 ;; reserved
10365 ;; 8th slot entry: 7th PCI slot
10366 db 0 ;; pci bus number
10367 db 0x40 ;; pci device number (bit 7-3)
10368 db 0x63 ;; link value INTA#
10369 dw 0xdef8 ;; IRQ bitmap INTA#
10370 db 0x60 ;; link value INTB#
10371 dw 0xdef8 ;; IRQ bitmap INTB#
10372 db 0x61 ;; link value INTC#
10373 dw 0xdef8 ;; IRQ bitmap INTC#
10374 db 0x62 ;; link value INTD#
10375 dw 0xdef8 ;; IRQ bitmap INTD#
10376 db 7 ;; physical slot (0 = embedded)
10377 db 0 ;; reserved
10378 ;; 9th slot entry: 8th PCI slot
10379 db 0 ;; pci bus number
10380 db 0x48 ;; pci device number (bit 7-3)
10381 db 0x60 ;; link value INTA#
10382 dw 0xdef8 ;; IRQ bitmap INTA#
10383 db 0x61 ;; link value INTB#
10384 dw 0xdef8 ;; IRQ bitmap INTB#
10385 db 0x62 ;; link value INTC#
10386 dw 0xdef8 ;; IRQ bitmap INTC#
10387 db 0x63 ;; link value INTD#
10388 dw 0xdef8 ;; IRQ bitmap INTD#
10389 db 8 ;; physical slot (0 = embedded)
10390 db 0 ;; reserved
10391 ;; 10th slot entry: 9th PCI slot
10392 db 0 ;; pci bus number
10393 db 0x50 ;; pci device number (bit 7-3)
10394 db 0x61 ;; link value INTA#
10395 dw 0xdef8 ;; IRQ bitmap INTA#
10396 db 0x62 ;; link value INTB#
10397 dw 0xdef8 ;; IRQ bitmap INTB#
10398 db 0x63 ;; link value INTC#
10399 dw 0xdef8 ;; IRQ bitmap INTC#
10400 db 0x60 ;; link value INTD#
10401 dw 0xdef8 ;; IRQ bitmap INTD#
10402 db 9 ;; physical slot (0 = embedded)
10403 db 0 ;; reserved
10404 ;; 11th slot entry: 10th PCI slot
10405 db 0 ;; pci bus number
10406 db 0x58 ;; pci device number (bit 7-3)
10407 db 0x62 ;; link value INTA#
10408 dw 0xdef8 ;; IRQ bitmap INTA#
10409 db 0x63 ;; link value INTB#
10410 dw 0xdef8 ;; IRQ bitmap INTB#
10411 db 0x60 ;; link value INTC#
10412 dw 0xdef8 ;; IRQ bitmap INTC#
10413 db 0x61 ;; link value INTD#
10414 dw 0xdef8 ;; IRQ bitmap INTD#
10415 db 10 ;; physical slot (0 = embedded)
10416 db 0 ;; reserved
10417 ;; 12th slot entry: 11th PCI slot
10418 db 0 ;; pci bus number
10419 db 0x60 ;; pci device number (bit 7-3)
10420 db 0x63 ;; link value INTA#
10421 dw 0xdef8 ;; IRQ bitmap INTA#
10422 db 0x60 ;; link value INTB#
10423 dw 0xdef8 ;; IRQ bitmap INTB#
10424 db 0x61 ;; link value INTC#
10425 dw 0xdef8 ;; IRQ bitmap INTC#
10426 db 0x62 ;; link value INTD#
10427 dw 0xdef8 ;; IRQ bitmap INTD#
10428 db 11 ;; physical slot (0 = embedded)
10429 db 0 ;; reserved
10430 ;; 13th slot entry: 12th PCI slot
10431 db 0 ;; pci bus number
10432 db 0x68 ;; pci device number (bit 7-3)
10433 db 0x60 ;; link value INTA#
10434 dw 0xdef8 ;; IRQ bitmap INTA#
10435 db 0x61 ;; link value INTB#
10436 dw 0xdef8 ;; IRQ bitmap INTB#
10437 db 0x62 ;; link value INTC#
10438 dw 0xdef8 ;; IRQ bitmap INTC#
10439 db 0x63 ;; link value INTD#
10440 dw 0xdef8 ;; IRQ bitmap INTD#
10441 db 12 ;; physical slot (0 = embedded)
10442 db 0 ;; reserved
10443 ;; 14th slot entry: 13th PCI slot
10444 db 0 ;; pci bus number
10445 db 0x70 ;; pci device number (bit 7-3)
10446 db 0x61 ;; link value INTA#
10447 dw 0xdef8 ;; IRQ bitmap INTA#
10448 db 0x62 ;; link value INTB#
10449 dw 0xdef8 ;; IRQ bitmap INTB#
10450 db 0x63 ;; link value INTC#
10451 dw 0xdef8 ;; IRQ bitmap INTC#
10452 db 0x60 ;; link value INTD#
10453 dw 0xdef8 ;; IRQ bitmap INTD#
10454 db 13 ;; physical slot (0 = embedded)
10455 db 0 ;; reserved
10456 ;; 15th slot entry: 14th PCI slot
10457 db 0 ;; pci bus number
10458 db 0x78 ;; pci device number (bit 7-3)
10459 db 0x62 ;; link value INTA#
10460 dw 0xdef8 ;; IRQ bitmap INTA#
10461 db 0x63 ;; link value INTB#
10462 dw 0xdef8 ;; IRQ bitmap INTB#
10463 db 0x60 ;; link value INTC#
10464 dw 0xdef8 ;; IRQ bitmap INTC#
10465 db 0x61 ;; link value INTD#
10466 dw 0xdef8 ;; IRQ bitmap INTD#
10467 db 14 ;; physical slot (0 = embedded)
10468 db 0 ;; reserved
10469 ;; 16th slot entry: 15th PCI slot
10470 db 0 ;; pci bus number
10471 db 0x80 ;; pci device number (bit 7-3)
10472 db 0x63 ;; link value INTA#
10473 dw 0xdef8 ;; IRQ bitmap INTA#
10474 db 0x60 ;; link value INTB#
10475 dw 0xdef8 ;; IRQ bitmap INTB#
10476 db 0x61 ;; link value INTC#
10477 dw 0xdef8 ;; IRQ bitmap INTC#
10478 db 0x62 ;; link value INTD#
10479 dw 0xdef8 ;; IRQ bitmap INTD#
10480 db 15 ;; physical slot (0 = embedded)
10481 db 0 ;; reserved
10482 ;; 17th slot entry: 16th PCI slot
10483 db 0 ;; pci bus number
10484 db 0x88 ;; pci device number (bit 7-3)
10485 db 0x60 ;; link value INTA#
10486 dw 0xdef8 ;; IRQ bitmap INTA#
10487 db 0x61 ;; link value INTB#
10488 dw 0xdef8 ;; IRQ bitmap INTB#
10489 db 0x62 ;; link value INTC#
10490 dw 0xdef8 ;; IRQ bitmap INTC#
10491 db 0x63 ;; link value INTD#
10492 dw 0xdef8 ;; IRQ bitmap INTD#
10493 db 16 ;; physical slot (0 = embedded)
10494 db 0 ;; reserved
10495 ;; 18th slot entry: 17th PCI slot
10496 db 0 ;; pci bus number
10497 db 0x90 ;; pci device number (bit 7-3)
10498 db 0x61 ;; link value INTA#
10499 dw 0xdef8 ;; IRQ bitmap INTA#
10500 db 0x62 ;; link value INTB#
10501 dw 0xdef8 ;; IRQ bitmap INTB#
10502 db 0x63 ;; link value INTC#
10503 dw 0xdef8 ;; IRQ bitmap INTC#
10504 db 0x60 ;; link value INTD#
10505 dw 0xdef8 ;; IRQ bitmap INTD#
10506 db 17 ;; physical slot (0 = embedded)
10507 db 0 ;; reserved
10508 ;; 19th slot entry: 18th PCI slot
10509 db 0 ;; pci bus number
10510 db 0x98 ;; pci device number (bit 7-3)
10511 db 0x62 ;; link value INTA#
10512 dw 0xdef8 ;; IRQ bitmap INTA#
10513 db 0x63 ;; link value INTB#
10514 dw 0xdef8 ;; IRQ bitmap INTB#
10515 db 0x60 ;; link value INTC#
10516 dw 0xdef8 ;; IRQ bitmap INTC#
10517 db 0x61 ;; link value INTD#
10518 dw 0xdef8 ;; IRQ bitmap INTD#
10519 db 18 ;; physical slot (0 = embedded)
10520 db 0 ;; reserved
10521 ;; 20th slot entry: 19th PCI slot
10522 db 0 ;; pci bus number
10523 db 0xa0 ;; pci device number (bit 7-3)
10524 db 0x63 ;; link value INTA#
10525 dw 0xdef8 ;; IRQ bitmap INTA#
10526 db 0x60 ;; link value INTB#
10527 dw 0xdef8 ;; IRQ bitmap INTB#
10528 db 0x61 ;; link value INTC#
10529 dw 0xdef8 ;; IRQ bitmap INTC#
10530 db 0x62 ;; link value INTD#
10531 dw 0xdef8 ;; IRQ bitmap INTD#
10532 db 19 ;; physical slot (0 = embedded)
10533 db 0 ;; reserved
10534 ;; 21st slot entry: 20th PCI slot
10535 db 0 ;; pci bus number
10536 db 0xa8 ;; pci device number (bit 7-3)
10537 db 0x60 ;; link value INTA#
10538 dw 0xdef8 ;; IRQ bitmap INTA#
10539 db 0x61 ;; link value INTB#
10540 dw 0xdef8 ;; IRQ bitmap INTB#
10541 db 0x62 ;; link value INTC#
10542 dw 0xdef8 ;; IRQ bitmap INTC#
10543 db 0x63 ;; link value INTD#
10544 dw 0xdef8 ;; IRQ bitmap INTD#
10545 db 20 ;; physical slot (0 = embedded)
10546 db 0 ;; reserved
10547 ;; 22nd slot entry: 21st PCI slot
10548 db 0 ;; pci bus number
10549 db 0xb0 ;; pci device number (bit 7-3)
10550 db 0x61 ;; link value INTA#
10551 dw 0xdef8 ;; IRQ bitmap INTA#
10552 db 0x62 ;; link value INTB#
10553 dw 0xdef8 ;; IRQ bitmap INTB#
10554 db 0x63 ;; link value INTC#
10555 dw 0xdef8 ;; IRQ bitmap INTC#
10556 db 0x60 ;; link value INTD#
10557 dw 0xdef8 ;; IRQ bitmap INTD#
10558 db 21 ;; physical slot (0 = embedded)
10559 db 0 ;; reserved
10560 ;; 23rd slot entry: 22nd PCI slot
10561 db 0 ;; pci bus number
10562 db 0xb8 ;; pci device number (bit 7-3)
10563 db 0x62 ;; link value INTA#
10564 dw 0xdef8 ;; IRQ bitmap INTA#
10565 db 0x63 ;; link value INTB#
10566 dw 0xdef8 ;; IRQ bitmap INTB#
10567 db 0x60 ;; link value INTC#
10568 dw 0xdef8 ;; IRQ bitmap INTC#
10569 db 0x61 ;; link value INTD#
10570 dw 0xdef8 ;; IRQ bitmap INTD#
10571 db 22 ;; physical slot (0 = embedded)
10572 db 0 ;; reserved
10573 ;; 24th slot entry: 23rd PCI slot
10574 db 0 ;; pci bus number
10575 db 0xc0 ;; pci device number (bit 7-3)
10576 db 0x63 ;; link value INTA#
10577 dw 0xdef8 ;; IRQ bitmap INTA#
10578 db 0x60 ;; link value INTB#
10579 dw 0xdef8 ;; IRQ bitmap INTB#
10580 db 0x61 ;; link value INTC#
10581 dw 0xdef8 ;; IRQ bitmap INTC#
10582 db 0x62 ;; link value INTD#
10583 dw 0xdef8 ;; IRQ bitmap INTD#
10584 db 23 ;; physical slot (0 = embedded)
10585 db 0 ;; reserved
10586 ;; 25th slot entry: 24th PCI slot
10587 db 0 ;; pci bus number
10588 db 0xc8 ;; pci device number (bit 7-3)
10589 db 0x60 ;; link value INTA#
10590 dw 0xdef8 ;; IRQ bitmap INTA#
10591 db 0x61 ;; link value INTB#
10592 dw 0xdef8 ;; IRQ bitmap INTB#
10593 db 0x62 ;; link value INTC#
10594 dw 0xdef8 ;; IRQ bitmap INTC#
10595 db 0x63 ;; link value INTD#
10596 dw 0xdef8 ;; IRQ bitmap INTD#
10597 db 24 ;; physical slot (0 = embedded)
10598 db 0 ;; reserved
10599 ;; 26th slot entry: 25th PCI slot
10600 db 0 ;; pci bus number
10601 db 0xd0 ;; pci device number (bit 7-3)
10602 db 0x61 ;; link value INTA#
10603 dw 0xdef8 ;; IRQ bitmap INTA#
10604 db 0x62 ;; link value INTB#
10605 dw 0xdef8 ;; IRQ bitmap INTB#
10606 db 0x63 ;; link value INTC#
10607 dw 0xdef8 ;; IRQ bitmap INTC#
10608 db 0x60 ;; link value INTD#
10609 dw 0xdef8 ;; IRQ bitmap INTD#
10610 db 25 ;; physical slot (0 = embedded)
10611 db 0 ;; reserved
10612 ;; 27th slot entry: 26th PCI slot
10613 db 0 ;; pci bus number
10614 db 0xd8 ;; pci device number (bit 7-3)
10615 db 0x62 ;; link value INTA#
10616 dw 0xdef8 ;; IRQ bitmap INTA#
10617 db 0x63 ;; link value INTB#
10618 dw 0xdef8 ;; IRQ bitmap INTB#
10619 db 0x60 ;; link value INTC#
10620 dw 0xdef8 ;; IRQ bitmap INTC#
10621 db 0x61 ;; link value INTD#
10622 dw 0xdef8 ;; IRQ bitmap INTD#
10623 db 26 ;; physical slot (0 = embedded)
10624 db 0 ;; reserved
10625 ;; 28th slot entry: 27th PCI slot
10626 db 0 ;; pci bus number
10627 db 0xe0 ;; pci device number (bit 7-3)
10628 db 0x63 ;; link value INTA#
10629 dw 0xdef8 ;; IRQ bitmap INTA#
10630 db 0x60 ;; link value INTB#
10631 dw 0xdef8 ;; IRQ bitmap INTB#
10632 db 0x61 ;; link value INTC#
10633 dw 0xdef8 ;; IRQ bitmap INTC#
10634 db 0x62 ;; link value INTD#
10635 dw 0xdef8 ;; IRQ bitmap INTD#
10636 db 27 ;; physical slot (0 = embedded)
10637 db 0 ;; reserved
10638 ;; 29th slot entry: 28th PCI slot
10639 db 0 ;; pci bus number
10640 db 0xe8 ;; pci device number (bit 7-3)
10641 db 0x60 ;; link value INTA#
10642 dw 0xdef8 ;; IRQ bitmap INTA#
10643 db 0x61 ;; link value INTB#
10644 dw 0xdef8 ;; IRQ bitmap INTB#
10645 db 0x62 ;; link value INTC#
10646 dw 0xdef8 ;; IRQ bitmap INTC#
10647 db 0x63 ;; link value INTD#
10648 dw 0xdef8 ;; IRQ bitmap INTD#
10649 db 28 ;; physical slot (0 = embedded)
10650 db 0 ;; reserved
10651 ;; 30th slot entry: 29th PCI slot
10652 db 0 ;; pci bus number
10653 db 0xf0 ;; pci device number (bit 7-3)
10654 db 0x61 ;; link value INTA#
10655 dw 0xdef8 ;; IRQ bitmap INTA#
10656 db 0x62 ;; link value INTB#
10657 dw 0xdef8 ;; IRQ bitmap INTB#
10658 db 0x63 ;; link value INTC#
10659 dw 0xdef8 ;; IRQ bitmap INTC#
10660 db 0x60 ;; link value INTD#
10661 dw 0xdef8 ;; IRQ bitmap INTD#
10662 db 29 ;; physical slot (0 = embedded)
10663 db 0 ;; reserved
10664#endif /* VBOX */
10665pci_routing_table_structure_end:
10666
10667#if !BX_ROMBIOS32
10668pci_irq_list:
10669 db 11, 10, 9, 5;
10670
10671pcibios_init_sel_reg:
10672 push eax
10673 mov eax, #0x800000
10674 mov ax, bx
10675 shl eax, #8
10676 and dl, #0xfc
10677 or al, dl
10678 mov dx, #0x0cf8
10679 out dx, eax
10680 pop eax
10681 ret
10682
10683pcibios_init_iomem_bases:
10684 push bp
10685 mov bp, sp
10686 mov eax, #0xe0000000 ;; base for memory init
10687 push eax
10688 mov ax, #0xc000 ;; base for i/o init
10689 push ax
10690 mov ax, #0x0010 ;; start at base address #0
10691 push ax
10692 mov bx, #0x0008
10693pci_init_io_loop1:
10694 mov dl, #0x00
10695 call pcibios_init_sel_reg
10696 mov dx, #0x0cfc
10697 in ax, dx
10698 cmp ax, #0xffff
10699 jz next_pci_dev
10700#ifndef VBOX /* This currently breaks restoring a previously saved state. */
10701 mov dl, #0x04 ;; disable i/o and memory space access
10702 call pcibios_init_sel_reg
10703 mov dx, #0x0cfc
10704 in al, dx
10705 and al, #0xfc
10706 out dx, al
10707pci_init_io_loop2:
10708 mov dl, [bp-8]
10709 call pcibios_init_sel_reg
10710 mov dx, #0x0cfc
10711 in eax, dx
10712 test al, #0x01
10713 jnz init_io_base
10714 mov ecx, eax
10715 mov eax, #0xffffffff
10716 out dx, eax
10717 in eax, dx
10718 cmp eax, ecx
10719 je next_pci_base
10720 xor eax, #0xffffffff
10721 mov ecx, eax
10722 mov eax, [bp-4]
10723 out dx, eax
10724 add eax, ecx ;; calculate next free mem base
10725 add eax, #0x01000000
10726 and eax, #0xff000000
10727 mov [bp-4], eax
10728 jmp next_pci_base
10729init_io_base:
10730 mov cx, ax
10731 mov ax, #0xffff
10732 out dx, ax
10733 in ax, dx
10734 cmp ax, cx
10735 je next_pci_base
10736 xor ax, #0xfffe
10737 mov cx, ax
10738 mov ax, [bp-6]
10739 out dx, ax
10740 add ax, cx ;; calculate next free i/o base
10741 add ax, #0x0100
10742 and ax, #0xff00
10743 mov [bp-6], ax
10744next_pci_base:
10745 mov al, [bp-8]
10746 add al, #0x04
10747 cmp al, #0x28
10748 je enable_iomem_space
10749 mov byte ptr[bp-8], al
10750 jmp pci_init_io_loop2
10751#endif /* !VBOX */
10752enable_iomem_space:
10753 mov dl, #0x04 ;; enable i/o and memory space access if available
10754 call pcibios_init_sel_reg
10755 mov dx, #0x0cfc
10756 in al, dx
10757 or al, #0x07
10758 out dx, al
10759#ifdef VBOX
10760 mov dl, #0x00 ;; check if PCI device is AMD PCNet
10761 call pcibios_init_sel_reg
10762 mov dx, #0x0cfc
10763 in eax, dx
10764 cmp eax, #0x20001022
10765 jne next_pci_dev
10766 mov dl, #0x10 ;; get I/O address
10767 call pcibios_init_sel_reg
10768 mov dx, #0x0cfc
10769 in ax, dx
10770 and ax, #0xfffc
10771 mov cx, ax
10772 mov dx, cx
10773 add dx, #0x14 ;; reset register if PCNet is in word I/O mode
10774 in ax, dx ;; reset is performed by reading the reset register
10775 mov dx, cx
10776 add dx, #0x18 ;; reset register if PCNet is in word I/O mode
10777 in eax, dx ;; reset is performed by reading the reset register
10778#endif /* VBOX */
10779next_pci_dev:
10780 mov byte ptr[bp-8], #0x10
10781 inc bx
10782 cmp bx, #0x0100
10783 jne pci_init_io_loop1
10784 mov sp, bp
10785 pop bp
10786 ret
10787
10788pcibios_init_set_elcr:
10789 push ax
10790 push cx
10791 mov dx, #0x04d0
10792 test al, #0x08
10793 jz is_master_pic
10794 inc dx
10795 and al, #0x07
10796is_master_pic:
10797 mov cl, al
10798 mov bl, #0x01
10799 shl bl, cl
10800 in al, dx
10801 or al, bl
10802 out dx, al
10803 pop cx
10804 pop ax
10805 ret
10806
10807pcibios_init_irqs:
10808 push ds
10809 push bp
10810 mov ax, #0xf000
10811 mov ds, ax
10812 mov dx, #0x04d0 ;; reset ELCR1 + ELCR2
10813 mov al, #0x00
10814 out dx, al
10815 inc dx
10816 out dx, al
10817 mov si, #pci_routing_table_structure
10818 mov bh, [si+8]
10819 mov bl, [si+9]
10820 mov dl, #0x00
10821 call pcibios_init_sel_reg
10822 mov dx, #0x0cfc
10823 in eax, dx
10824 cmp eax, [si+12] ;; check irq router
10825 jne pci_init_end
10826 mov dl, [si+34]
10827 call pcibios_init_sel_reg
10828 push bx ;; save irq router bus + devfunc
10829 mov dx, #0x0cfc
10830 mov ax, #0x8080
10831 out dx, ax ;; reset PIRQ route control
10832 add dx, #2
10833 out dx, ax
10834 mov ax, [si+6]
10835 sub ax, #0x20
10836 shr ax, #4
10837 mov cx, ax
10838 add si, #0x20 ;; set pointer to 1st entry
10839 mov bp, sp
10840 mov ax, #pci_irq_list
10841 push ax
10842 xor ax, ax
10843 push ax
10844pci_init_irq_loop1:
10845 mov bh, [si]
10846 mov bl, [si+1]
10847pci_init_irq_loop2:
10848 mov dl, #0x00
10849 call pcibios_init_sel_reg
10850 mov dx, #0x0cfc
10851 in ax, dx
10852 cmp ax, #0xffff
10853 jnz pci_test_int_pin
10854 test bl, #0x07
10855 jz next_pir_entry
10856 jmp next_pci_func
10857pci_test_int_pin:
10858 mov dl, #0x3c
10859 call pcibios_init_sel_reg
10860 mov dx, #0x0cfd
10861 in al, dx
10862 and al, #0x07
10863 jz next_pci_func
10864 dec al ;; determine pirq reg
10865 mov dl, #0x03
10866 mul al, dl
10867 add al, #0x02
10868 xor ah, ah
10869 mov bx, ax
10870 mov al, [si+bx]
10871 mov dl, al
10872 mov bx, [bp]
10873 call pcibios_init_sel_reg
10874 mov dx, #0x0cfc
10875 and al, #0x03
10876 add dl, al
10877 in al, dx
10878 cmp al, #0x80
10879 jb pirq_found
10880 mov bx, [bp-2] ;; pci irq list pointer
10881 mov al, [bx]
10882 out dx, al
10883 inc bx
10884 mov [bp-2], bx
10885 call pcibios_init_set_elcr
10886pirq_found:
10887 mov bh, [si]
10888 mov bl, [si+1]
10889 add bl, [bp-3] ;; pci function number
10890 mov dl, #0x3c
10891 call pcibios_init_sel_reg
10892 mov dx, #0x0cfc
10893 out dx, al
10894next_pci_func:
10895 inc byte ptr[bp-3]
10896 inc bl
10897 test bl, #0x07
10898 jnz pci_init_irq_loop2
10899next_pir_entry:
10900 add si, #0x10
10901 mov byte ptr[bp-3], #0x00
10902 loop pci_init_irq_loop1
10903 mov sp, bp
10904 pop bx
10905pci_init_end:
10906 pop bp
10907 pop ds
10908 ret
10909#endif // !BX_ROMBIOS32
10910#endif // BX_PCIBIOS
10911
10912#if BX_ROMBIOS32
10913rombios32_init:
10914 ;; save a20 and enable it
10915 in al, 0x92
10916 push ax
10917 or al, #0x02
10918 out 0x92, al
10919
10920 ;; save SS:SP to the BDA
10921 xor ax, ax
10922 mov ds, ax
10923 mov 0x0469, ss
10924 mov 0x0467, sp
10925
10926 SEG CS
10927 lidt [pmode_IDT_info]
10928 SEG CS
10929 lgdt [rombios32_gdt_48]
10930 ;; set PE bit in CR0
10931 mov eax, cr0
10932 or al, #0x01
10933 mov cr0, eax
10934 ;; start protected mode code: ljmpl 0x10:rombios32_init1
10935 db 0x66, 0xea
10936 dw rombios32_05
10937 dw 0x000f ;; high 16 bit address
10938 dw 0x0010
10939
10940use32 386
10941rombios32_05:
10942 ;; init data segments
10943 mov eax, #0x18
10944 mov ds, ax
10945 mov es, ax
10946 mov ss, ax
10947 xor eax, eax
10948 mov fs, ax
10949 mov gs, ax
10950 cld
10951
10952 ;; copy rombios32 code to ram (ram offset = 1MB)
10953 mov esi, #0xfffe0000
10954 mov edi, #0x00040000
10955 mov ecx, #0x10000 / 4
10956 rep
10957 movsd
10958
10959 ;; init the stack pointer
10960 mov esp, #0x00080000
10961
10962 ;; call rombios32 code
10963 mov eax, #0x00040000
10964 call eax
10965
10966 ;; return to 16 bit protected mode first
10967 db 0xea
10968 dd rombios32_10
10969 dw 0x20
10970
10971use16 386
10972rombios32_10:
10973 ;; restore data segment limits to 0xffff
10974 mov ax, #0x28
10975 mov ds, ax
10976 mov es, ax
10977 mov ss, ax
10978 mov fs, ax
10979 mov gs, ax
10980
10981 ;; reset PE bit in CR0
10982 mov eax, cr0
10983 and al, #0xFE
10984 mov cr0, eax
10985
10986 ;; far jump to flush CPU queue after transition to real mode
10987 JMP_AP(0xf000, rombios32_real_mode)
10988
10989rombios32_real_mode:
10990 ;; restore IDT to normal real-mode defaults
10991 SEG CS
10992 lidt [rmode_IDT_info]
10993
10994 xor ax, ax
10995 mov ds, ax
10996 mov es, ax
10997 mov fs, ax
10998 mov gs, ax
10999
11000 ;; restore SS:SP from the BDA
11001 mov ss, 0x0469
11002 xor esp, esp
11003 mov sp, 0x0467
11004 ;; restore a20
11005 pop ax
11006 out 0x92, al
11007 ret
11008
11009rombios32_gdt_48:
11010 dw 0x30
11011 dw rombios32_gdt
11012 dw 0x000f
11013
11014rombios32_gdt:
11015 dw 0, 0, 0, 0
11016 dw 0, 0, 0, 0
11017 dw 0xffff, 0, 0x9b00, 0x00cf ; 32 bit flat code segment (0x10)
11018 dw 0xffff, 0, 0x9300, 0x00cf ; 32 bit flat data segment (0x18)
11019 dw 0xffff, 0, 0x9b0f, 0x0000 ; 16 bit code segment base=0xf0000 limit=0xffff
11020 dw 0xffff, 0, 0x9300, 0x0000 ; 16 bit data segment base=0x0 limit=0xffff
11021#endif // BX_ROMBIOS32
11022
11023
11024; parallel port detection: base address in DX, index in BX, timeout in CL
11025detect_parport:
11026 push dx
11027 add dx, #2
11028 in al, dx
11029 and al, #0xdf ; clear input mode
11030 out dx, al
11031 pop dx
11032 mov al, #0xaa
11033 out dx, al
11034 in al, dx
11035 cmp al, #0xaa
11036 jne no_parport
11037 push bx
11038 shl bx, #1
11039 mov [bx+0x408], dx ; Parallel I/O address
11040 pop bx
11041 mov [bx+0x478], cl ; Parallel printer timeout
11042 inc bx
11043no_parport:
11044 ret
11045
11046; serial port detection: base address in DX, index in BX, timeout in CL
11047detect_serial:
11048 push dx
11049 inc dx
11050 mov al, #0x02
11051 out dx, al
11052 in al, dx
11053 cmp al, #0x02
11054 jne no_serial
11055 inc dx
11056 in al, dx
11057 cmp al, #0x02
11058 jne no_serial
11059 dec dx
11060 xor al, al
11061 out dx, al
11062 pop dx
11063 push bx
11064 shl bx, #1
11065 mov [bx+0x400], dx ; Serial I/O address
11066 pop bx
11067 mov [bx+0x47c], cl ; Serial timeout
11068 inc bx
11069 ret
11070no_serial:
11071 pop dx
11072 ret
11073
11074rom_checksum:
11075 push ax
11076 push bx
11077 push cx
11078 xor ax, ax
11079 xor bx, bx
11080 xor cx, cx
11081 mov ch, [2]
11082 shl cx, #1
11083checksum_loop:
11084 add al, [bx]
11085 inc bx
11086 loop checksum_loop
11087 and al, #0xff
11088 pop cx
11089 pop bx
11090 pop ax
11091 ret
11092
11093rom_scan:
11094 ;; Scan for existence of valid expansion ROMS.
11095 ;; Video ROM: from 0xC0000..0xC7FFF in 2k increments
11096 ;; General ROM: from 0xC8000..0xDFFFF in 2k increments
11097 ;; System ROM: only 0xE0000
11098 ;;
11099 ;; Header:
11100 ;; Offset Value
11101 ;; 0 0x55
11102 ;; 1 0xAA
11103 ;; 2 ROM length in 512-byte blocks
11104 ;; 3 ROM initialization entry point (FAR CALL)
11105
11106 mov cx, #0xc000
11107rom_scan_loop:
11108 mov ds, cx
11109 mov ax, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
11110 cmp [0], #0xAA55 ;; look for signature
11111 jne rom_scan_increment
11112 call rom_checksum
11113 jnz rom_scan_increment
11114 mov al, [2] ;; change increment to ROM length in 512-byte blocks
11115
11116 ;; We want our increment in 512-byte quantities, rounded to
11117 ;; the nearest 2k quantity, since we only scan at 2k intervals.
11118 test al, #0x03
11119 jz block_count_rounded
11120 and al, #0xfc ;; needs rounding up
11121 add al, #0x04
11122block_count_rounded:
11123
11124 xor bx, bx ;; Restore DS back to 0000:
11125 mov ds, bx
11126 push ax ;; Save AX
11127 ;; Push addr of ROM entry point
11128 push cx ;; Push seg
11129 push #0x0003 ;; Push offset
11130 mov bp, sp ;; Call ROM init routine using seg:off on stack
11131 db 0xff ;; call_far ss:[bp+0]
11132 db 0x5e
11133 db 0
11134 cli ;; In case expansion ROM BIOS turns IF on
11135 add sp, #2 ;; Pop offset value
11136 pop cx ;; Pop seg value (restore CX)
11137 pop ax ;; Restore AX
11138rom_scan_increment:
11139 shl ax, #5 ;; convert 512-bytes blocks to 16-byte increments
11140 ;; because the segment selector is shifted left 4 bits.
11141 add cx, ax
11142 cmp cx, #0xe800 ;; Must encompass VBOX_LANBOOT_SEG!
11143 jbe rom_scan_loop
11144
11145 xor ax, ax ;; Restore DS back to 0000:
11146 mov ds, ax
11147 ret
11148
11149#define LVT0 0xFEE00350
11150#define LVT1 0xFEE00360
11151
11152;; Program LVT0/LVT1 entries in the local APIC. Some Linux kernels (e.g., RHEL4
11153;; SMP 32-bit) expect the entries to be unmasked in virtual wire mode.
11154
11155setup_lapic:
11156 pushf
11157 cli ;; Interrupts would kill us!
11158 call pmode_enter
11159 mov esi, #LVT0 ;; Program LVT0 to ExtINT and unmask
11160 mov eax, [esi]
11161 and eax, #0xfffe00ff
11162 or ah, #0x07
11163 mov [esi], eax
11164 mov esi, #LVT1 ;; Program LVT1 to NMI and unmask
11165 mov eax, [esi]
11166 and eax, #0xfffe00ff
11167 or ah, #0x04
11168 mov [esi], eax
11169 call pmode_exit
11170 popf
11171 ret
11172
11173;; Enter and exit minimal protected-mode environment. May only be called from
11174;; the F000 segment (16-bit). Does not switch stacks. Must be run with disabled
11175;; interrupts(!). On return from pmode_enter, DS contains a selector which can
11176;; address the entire 4GB address space.
11177
11178pmode_enter:
11179 push cs
11180 pop ds
11181 lgdt [pmbios_gdt_desc]
11182 mov eax, cr0
11183 or al, #0x1
11184 mov cr0, eax
11185 JMP_AP(0x20, really_enter_pm)
11186really_enter_pm:
11187 mov ax, #0x18
11188 mov ds, ax
11189 ret
11190
11191pmode_exit:
11192 mov eax, cr0
11193 and al, #0xfe
11194 mov cr0, eax
11195 JMP_AP(0xF000, really_exit_pm)
11196really_exit_pm:
11197 ret
11198
11199pmbios_gdt_desc:
11200 dw 0x30
11201 dw pmbios_gdt
11202 dw 0x000f
11203
11204pmbios_gdt:
11205 dw 0, 0, 0, 0
11206 dw 0, 0, 0, 0
11207 dw 0xffff, 0, 0x9b00, 0x00cf ; 32 bit flat code segment (0x10)
11208 dw 0xffff, 0, 0x9300, 0x00cf ; 32 bit flat data segment (0x18)
11209 dw 0xffff, 0, 0x9b0f, 0x0000 ; 16 bit code segment base=0xf0000 limit=0xffff
11210 dw 0xffff, 0, 0x9300, 0x0000 ; 16 bit data segment base=0x0 limit=0xffff
11211
11212;; for 'C' strings and other data, insert them here with
11213;; a the following hack:
11214;; DATA_SEG_DEFS_HERE
11215
11216
11217;; the following area can be used to write dynamically generated tables
11218 .align 16
11219bios_table_area_start:
11220 dd 0xaafb4442
11221 dd bios_table_area_end - bios_table_area_start - 8;
11222
11223;--------
11224;- POST -
11225;--------
11226.org 0xe05b ; POST Entry Point
11227bios_table_area_end:
11228post:
11229
11230 xor ax, ax
11231
11232 ;; first reset the DMA controllers
11233 out 0x0d,al
11234 out 0xda,al
11235
11236 ;; then initialize the DMA controllers
11237 mov al, #0xC0
11238 out 0xD6, al ; cascade mode of channel 4 enabled
11239 mov al, #0x00
11240 out 0xD4, al ; unmask channel 4
11241
11242 ;; Examine CMOS shutdown status.
11243 mov AL, #0x0f
11244 out 0x70, AL
11245 in AL, 0x71
11246
11247 ;; backup status
11248 mov bl, al
11249
11250 ;; Reset CMOS shutdown status.
11251 mov AL, #0x0f
11252 out 0x70, AL ; select CMOS register Fh
11253 mov AL, #0x00
11254 out 0x71, AL ; set shutdown action to normal
11255
11256 ;; Examine CMOS shutdown status.
11257 mov al, bl
11258
11259 ;; 0x00, 0x09, 0x0D+ = normal startup
11260 cmp AL, #0x00
11261 jz normal_post
11262 cmp AL, #0x0d
11263 jae normal_post
11264 cmp AL, #0x09
11265 je normal_post
11266
11267 ;; 0x05 = eoi + jmp via [0x40:0x67] jump
11268 cmp al, #0x05
11269 je eoi_jmp_post
11270
11271#ifdef VBOX
11272 ;; just ignore all other CMOS shutdown status values (OpenSolaris sets it to 0xA for some reason in certain cases)
11273 ;; (shutdown_status_panic just crashes the VM as it calls int 0x10 before the IDT table has been initialized)
11274 jmp normal_post
11275#else
11276 ;; Examine CMOS shutdown status.
11277 ;; 0x01,0x02,0x03,0x04,0x06,0x07,0x08, 0x0a, 0x0b, 0x0c = Unimplemented shutdown status.
11278 push bx
11279 call _shutdown_status_panic
11280#endif
11281
11282#if 0
11283 HALT(__LINE__)
11284 ;
11285 ;#if 0
11286 ; 0xb0, 0x20, /* mov al, #0x20 */
11287 ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */
11288 ;#endif
11289 ;
11290 pop es
11291 pop ds
11292 popa
11293 iret
11294#endif
11295
11296normal_post:
11297 ; case 0: normal startup
11298
11299 cli
11300 mov ax, #0xfffe
11301 mov sp, ax
11302 xor ax, ax
11303 mov ds, ax
11304 mov ss, ax
11305
11306#ifndef VBOX
11307 ;; zero out BIOS data area (40:00..40:ff)
11308 mov es, ax
11309 mov cx, #0x0080 ;; 128 words
11310 mov di, #0x0400
11311 cld
11312 rep
11313 stosw
11314#else /* VBOX */
11315 ;; zero out segment 0 (includes BIOS data area) except word at 40:72
11316 mov es, ax
11317 xor di, di
11318 cld
11319 mov cx, #0x0239 ;; 569 words
11320 rep
11321 stosw
11322 inc di
11323 inc di
11324 mov cx, #0x7dc6 ;; 32198 words
11325 rep
11326 stosw
11327 ;; zero out remaining base memory except the last 16 bytes of the EBDA
11328 ;; because we store the MP table there
11329 xor eax, eax
11330 xor bx, bx
11331memory_zero_loop:
11332 add bx, #0x1000
11333 cmp bx, #0x9000
11334 jae memory_cleared
11335 mov es, bx
11336 xor di, di
11337 mov cx, #0x4000
11338 rep
11339 stosd
11340 jmp memory_zero_loop
11341memory_cleared:
11342 mov es, bx
11343 xor di, di
11344 mov cx, #0x3f00
11345 rep
11346 stosd
11347 xor bx, bx
11348#endif
11349
11350 call _log_bios_start
11351
11352 ;; set all interrupts to default handler
11353 xor bx, bx ;; offset index
11354 mov cx, #0x0100 ;; counter (256 interrupts)
11355 mov ax, #dummy_iret_handler
11356 mov dx, #0xF000
11357
11358post_default_ints:
11359 mov [bx], ax
11360 add bx, #2
11361 mov [bx], dx
11362 add bx, #2
11363 loop post_default_ints
11364
11365 ;; set vector 0x79 to zero
11366 ;; this is used by 'gardian angel' protection system
11367 SET_INT_VECTOR(0x79, #0, #0)
11368
11369 ;; base memory in K 40:13 (word)
11370 mov ax, #BASE_MEM_IN_K
11371 mov 0x0413, ax
11372
11373
11374 ;; Manufacturing Test 40:12
11375 ;; zerod out above
11376
11377#ifndef VBOX
11378 ;; Warm Boot Flag 0040:0072
11379 ;; value of 1234h = skip memory checks
11380 ;; zerod out above
11381#endif /* !VBOX */
11382
11383
11384 ;; Printer Services vector
11385 SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
11386
11387 ;; Bootstrap failure vector
11388 SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
11389
11390 ;; Bootstrap Loader vector
11391 SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
11392
11393 ;; User Timer Tick vector
11394 SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
11395
11396 ;; Memory Size Check vector
11397 SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
11398
11399 ;; Equipment Configuration Check vector
11400 SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
11401
11402 ;; System Services
11403 SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
11404
11405 ;; EBDA setup
11406 call ebda_post
11407
11408 ;; PIT setup
11409 SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
11410 ;; int 1C already points at dummy_iret_handler (above)
11411 mov al, #0x34 ; timer0: binary count, 16bit count, mode 2
11412 out 0x43, al
11413 mov al, #0x00 ; maximum count of 0000H = 18.2Hz
11414 out 0x40, al
11415 out 0x40, al
11416
11417 ;; Keyboard
11418 SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
11419 SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
11420
11421 xor ax, ax
11422 mov ds, ax
11423 mov 0x0417, al /* keyboard shift flags, set 1 */
11424 mov 0x0418, al /* keyboard shift flags, set 2 */
11425 mov 0x0419, al /* keyboard alt-numpad work area */
11426 mov 0x0471, al /* keyboard ctrl-break flag */
11427 mov 0x0497, al /* keyboard status flags 4 */
11428 mov al, #0x10
11429 mov 0x0496, al /* keyboard status flags 3 */
11430
11431
11432 /* keyboard head of buffer pointer */
11433 mov bx, #0x001E
11434 mov 0x041A, bx
11435
11436 /* keyboard end of buffer pointer */
11437 mov 0x041C, bx
11438
11439 /* keyboard pointer to start of buffer */
11440 mov bx, #0x001E
11441 mov 0x0480, bx
11442
11443 /* keyboard pointer to end of buffer */
11444 mov bx, #0x003E
11445 mov 0x0482, bx
11446
11447 /* init the keyboard */
11448 call _keyboard_init
11449
11450 ;; mov CMOS Equipment Byte to BDA Equipment Word
11451 mov ax, 0x0410
11452 mov al, #0x14
11453 out 0x70, al
11454 in al, 0x71
11455 mov 0x0410, ax
11456
11457
11458 ;; Parallel setup
11459 SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
11460 xor ax, ax
11461 mov ds, ax
11462 xor bx, bx
11463 mov cl, #0x14 ; timeout value
11464 mov dx, #0x378 ; Parallel I/O address, port 1
11465 call detect_parport
11466 mov dx, #0x278 ; Parallel I/O address, port 2
11467 call detect_parport
11468 shl bx, #0x0e
11469 mov ax, 0x410 ; Equipment word bits 14..15 determing # parallel ports
11470 and ax, #0x3fff
11471 or ax, bx ; set number of parallel ports
11472 mov 0x410, ax
11473
11474 ;; Serial setup
11475 SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
11476 SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
11477 xor bx, bx
11478 mov cl, #0x0a ; timeout value
11479 mov dx, #0x03f8 ; Serial I/O address, port 1
11480 call detect_serial
11481 mov dx, #0x02f8 ; Serial I/O address, port 2
11482 call detect_serial
11483 mov dx, #0x03e8 ; Serial I/O address, port 3
11484 call detect_serial
11485 mov dx, #0x02e8 ; Serial I/O address, port 4
11486 call detect_serial
11487 shl bx, #0x09
11488 mov ax, 0x410 ; Equipment word bits 9..11 determing # serial ports
11489 and ax, #0xf1ff
11490 or ax, bx ; set number of serial port
11491 mov 0x410, ax
11492
11493 ;; CMOS RTC
11494 SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
11495 SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
11496 SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
11497 ;; BIOS DATA AREA 0x4CE ???
11498 call timer_tick_post
11499
11500 ;; PS/2 mouse setup
11501 SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
11502
11503 ;; IRQ13 (FPU exception) setup
11504 SET_INT_VECTOR(0x75, #0xF000, #int75_handler)
11505
11506 ;; Video setup
11507 SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
11508
11509#ifdef VBOX
11510 ;; moved the PIC initialization to another place as we need
11511 ;; some space for additions init calls. Otherwise this code
11512 ;; overlaps with the NMI handler at 0xe2c3 (fixed BIOS entry)
11513 call init_pic
11514#else /* !VBOX */
11515 ;; PIC
11516 mov al, #0x11 ; send initialisation commands
11517 out 0x20, al
11518 out 0xa0, al
11519 mov al, #0x08
11520 out 0x21, al
11521 mov al, #0x70
11522 out 0xa1, al
11523 mov al, #0x04
11524 out 0x21, al
11525 mov al, #0x02
11526 out 0xa1, al
11527 mov al, #0x01
11528 out 0x21, al
11529 out 0xa1, al
11530 mov al, #0xb8
11531 out 0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6
11532#if BX_USE_PS2_MOUSE
11533 mov al, #0x8f
11534#else
11535 mov al, #0x9f
11536#endif
11537 out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14
11538#endif /* !VBOX */
11539
11540#if BX_ROMBIOS32
11541 call rombios32_init
11542#else
11543 call pcibios_init_iomem_bases
11544 call pcibios_init_irqs
11545#endif
11546 call setup_lapic
11547 call rom_scan
11548
11549#if BX_USE_ATADRV
11550 ;;
11551 ;; ATA/ATAPI driver setup
11552 ;;
11553 call _ata_init
11554 call _ata_detect
11555 ;;
11556#endif
11557
11558#ifdef VBOX_WITH_SCSI
11559 ;;
11560 ;; SCSI driver setup
11561 ;;
11562 call _scsi_init
11563 ;;
11564#endif
11565
11566 call _print_bios_banner
11567
11568 ;;
11569 ;; Floppy setup
11570 ;;
11571 call floppy_drive_post
11572
11573 ;;
11574 ;; Hard Drive setup
11575 ;;
11576 call hard_drive_post
11577
11578#if BX_ELTORITO_BOOT
11579 ;;
11580 ;; eltorito floppy/harddisk emulation from cd
11581 ;;
11582 call _cdemu_init
11583 ;;
11584#endif // BX_ELTORITO_BOOT
11585
11586 sti ;; enable interrupts
11587 int #0x19
11588
11589.org 0xe2c3 ; NMI Handler Entry Point
11590nmi:
11591 ;; FIXME the NMI handler should not panic
11592 ;; but iret when called from int75 (fpu exception)
11593 call _nmi_handler_msg
11594 iret
11595
11596int75_handler:
11597 out 0xf0, al // clear irq13
11598 call eoi_both_pics // clear interrupt
11599 int 2 // legacy nmi call
11600 iret
11601
11602;-------------------------------------------
11603;- INT 13h Fixed Disk Services Entry Point -
11604;-------------------------------------------
11605.org 0xe3fe ; INT 13h Fixed Disk Services Entry Point
11606int13_handler:
11607 //JMPL(int13_relocated)
11608 jmp int13_relocated
11609
11610.org 0xe401 ; Fixed Disk Parameter Table
11611
11612;----------
11613;- INT19h -
11614;----------
11615.org 0xe6f2 ; INT 19h Boot Load Service Entry Point
11616int19_handler:
11617
11618 jmp int19_relocated
11619;-------------------------------------------
11620;- System BIOS Configuration Data Table
11621;-------------------------------------------
11622.org BIOS_CONFIG_TABLE
11623db 0x08 ; Table size (bytes) -Lo
11624db 0x00 ; Table size (bytes) -Hi
11625db SYS_MODEL_ID
11626db SYS_SUBMODEL_ID
11627db BIOS_REVISION
11628; Feature byte 1
11629; b7: 1=DMA channel 3 used by hard disk
11630; b6: 1=2 interrupt controllers present
11631; b5: 1=RTC present
11632; b4: 1=BIOS calls int 15h/4Fh every key
11633; b3: 1=wait for extern event supported (Int 15h/41h)
11634; b2: 1=extended BIOS data area used
11635; b1: 0=AT or ESDI bus, 1=MicroChannel
11636; b0: 1=Dual bus (MicroChannel + ISA)
11637db (0 << 7) | \
11638 (1 << 6) | \
11639 (1 << 5) | \
11640 (BX_CALL_INT15_4F << 4) | \
11641 (0 << 3) | \
11642 (BX_USE_EBDA << 2) | \
11643 (0 << 1) | \
11644 (0 << 0)
11645; Feature byte 2
11646; b7: 1=32-bit DMA supported
11647; b6: 1=int16h, function 9 supported
11648; b5: 1=int15h/C6h (get POS data) supported
11649; b4: 1=int15h/C7h (get mem map info) supported
11650; b3: 1=int15h/C8h (en/dis CPU) supported
11651; b2: 1=non-8042 kb controller
11652; b1: 1=data streaming supported
11653; b0: reserved
11654db (0 << 7) | \
11655 (1 << 6) | \
11656 (0 << 5) | \
11657 (0 << 4) | \
11658 (0 << 3) | \
11659 (0 << 2) | \
11660 (0 << 1) | \
11661 (0 << 0)
11662; Feature byte 3
11663; b7: not used
11664; b6: reserved
11665; b5: reserved
11666; b4: POST supports ROM-to-RAM enable/disable
11667; b3: SCSI on system board
11668; b2: info panel installed
11669; b1: Initial Machine Load (IML) system - BIOS on disk
11670; b0: SCSI supported in IML
11671db 0x00
11672; Feature byte 4
11673; b7: IBM private
11674; b6: EEPROM present
11675; b5-3: ABIOS presence (011 = not supported)
11676; b2: private
11677; b1: memory split above 16Mb supported
11678; b0: POSTEXT directly supported by POST
11679db 0x00
11680; Feature byte 5 (IBM)
11681; b1: enhanced mouse
11682; b0: flash EPROM
11683db 0x00
11684
11685
11686
11687.org 0xe729 ; Baud Rate Generator Table
11688
11689;----------
11690;- INT14h -
11691;----------
11692.org 0xe739 ; INT 14h Serial Communications Service Entry Point
11693int14_handler:
11694 push ds
11695 pusha
11696 xor ax, ax
11697 mov ds, ax
11698 call _int14_function
11699 popa
11700 pop ds
11701 iret
11702
11703
11704;----------------------------------------
11705;- INT 16h Keyboard Service Entry Point -
11706;----------------------------------------
11707.org 0xe82e
11708int16_handler:
11709
11710 sti
11711 push ds
11712 pushf
11713 pusha
11714
11715 cmp ah, #0x00
11716 je int16_F00
11717 cmp ah, #0x10
11718 je int16_F00
11719
11720 mov bx, #0xf000
11721 mov ds, bx
11722 call _int16_function
11723 popa
11724 popf
11725 pop ds
11726 jz int16_zero_set
11727
11728int16_zero_clear:
11729 push bp
11730 mov bp, sp
11731 //SEG SS
11732 and BYTE [bp + 0x06], #0xbf
11733 pop bp
11734 iret
11735
11736int16_zero_set:
11737 push bp
11738 mov bp, sp
11739 //SEG SS
11740 or BYTE [bp + 0x06], #0x40
11741 pop bp
11742 iret
11743
11744int16_F00:
11745 mov bx, #0x0040
11746 mov ds, bx
11747
11748int16_wait_for_key:
11749 cli
11750 mov bx, 0x001a
11751 cmp bx, 0x001c
11752 jne int16_key_found
11753 sti
11754 nop
11755#if 0
11756 /* no key yet, call int 15h, function AX=9002 */
11757 0x50, /* push AX */
11758 0xb8, 0x02, 0x90, /* mov AX, #0x9002 */
11759 0xcd, 0x15, /* int 15h */
11760 0x58, /* pop AX */
11761 0xeb, 0xea, /* jmp WAIT_FOR_KEY */
11762#endif
11763 jmp int16_wait_for_key
11764
11765int16_key_found:
11766 mov bx, #0xf000
11767 mov ds, bx
11768 call _int16_function
11769 popa
11770 popf
11771 pop ds
11772#if 0
11773 /* notify int16 complete w/ int 15h, function AX=9102 */
11774 0x50, /* push AX */
11775 0xb8, 0x02, 0x91, /* mov AX, #0x9102 */
11776 0xcd, 0x15, /* int 15h */
11777 0x58, /* pop AX */
11778#endif
11779 iret
11780
11781
11782
11783;-------------------------------------------------
11784;- INT09h : Keyboard Hardware Service Entry Point -
11785;-------------------------------------------------
11786.org 0xe987
11787int09_handler:
11788 cli
11789 push ax
11790
11791 mov al, #0xAD ;;disable keyboard
11792 out #0x64, al
11793
11794 mov al, #0x0B
11795 out #0x20, al
11796 in al, #0x20
11797 and al, #0x02
11798 jz int09_finish
11799
11800 in al, #0x60 ;;read key from keyboard controller
11801 sti
11802 push ds
11803 pusha
11804#ifdef BX_CALL_INT15_4F
11805 mov ah, #0x4f ;; allow for keyboard intercept
11806 stc
11807 int #0x15
11808 jnc int09_done
11809#endif
11810
11811 ;; check for extended key
11812 cmp al, #0xe0
11813 jne int09_check_pause
11814 xor ax, ax
11815 mov ds, ax
11816 mov al, BYTE [0x496] ;; mf2_state |= 0x02
11817 or al, #0x02
11818 mov BYTE [0x496], al
11819 jmp int09_done
11820
11821int09_check_pause: ;; check for pause key
11822 cmp al, #0xe1
11823 jne int09_process_key
11824 xor ax, ax
11825 mov ds, ax
11826 mov al, BYTE [0x496] ;; mf2_state |= 0x01
11827 or al, #0x01
11828 mov BYTE [0x496], al
11829 jmp int09_done
11830
11831int09_process_key:
11832 mov bx, #0xf000
11833 mov ds, bx
11834 call _int09_function
11835
11836int09_done:
11837 popa
11838 pop ds
11839 cli
11840 call eoi_master_pic
11841
11842int09_finish:
11843 mov al, #0xAE ;;enable keyboard
11844 out #0x64, al
11845 pop ax
11846 iret
11847
11848
11849;----------------------------------------
11850;- INT 13h Diskette Service Entry Point -
11851;----------------------------------------
11852.org 0xec59
11853int13_diskette:
11854 jmp int13_noeltorito
11855
11856;---------------------------------------------
11857;- INT 0Eh Diskette Hardware ISR Entry Point -
11858;---------------------------------------------
11859.org 0xef57 ; INT 0Eh Diskette Hardware ISR Entry Point
11860int0e_handler:
11861 push ax
11862 push dx
11863 mov dx, #0x03f4
11864 in al, dx
11865 and al, #0xc0
11866 cmp al, #0xc0
11867 je int0e_normal
11868 mov dx, #0x03f5
11869 mov al, #0x08 ; sense interrupt status
11870 out dx, al
11871int0e_loop1:
11872 mov dx, #0x03f4
11873 in al, dx
11874 and al, #0xc0
11875 cmp al, #0xc0
11876 jne int0e_loop1
11877int0e_loop2:
11878 mov dx, #0x03f5
11879 in al, dx
11880 mov dx, #0x03f4
11881 in al, dx
11882 and al, #0xc0
11883 cmp al, #0xc0
11884 je int0e_loop2
11885int0e_normal:
11886 push ds
11887 xor ax, ax ;; segment 0000
11888 mov ds, ax
11889 call eoi_master_pic
11890 mov al, 0x043e
11891 or al, #0x80 ;; diskette interrupt has occurred
11892 mov 0x043e, al
11893 pop ds
11894 pop dx
11895 pop ax
11896 iret
11897
11898
11899.org 0xefc7 ; Diskette Controller Parameter Table
11900diskette_param_table:
11901;; Since no provisions are made for multiple drive types, most
11902;; values in this table are ignored. I set parameters for 1.44M
11903;; floppy here
11904db 0xAF
11905db 0x02 ;; head load time 0000001, DMA used
11906db 0x25
11907db 0x02
11908db 18
11909db 0x1B
11910db 0xFF
11911db 0x6C
11912db 0xF6
11913db 0x0F
11914db 0x08
11915
11916
11917;----------------------------------------
11918;- INT17h : Printer Service Entry Point -
11919;----------------------------------------
11920.org 0xefd2
11921int17_handler:
11922 push ds
11923 pusha
11924 xor ax, ax
11925 mov ds, ax
11926 call _int17_function
11927 popa
11928 pop ds
11929 iret
11930
11931diskette_param_table2:
11932;; New diskette parameter table adding 3 parameters from IBM
11933;; Since no provisions are made for multiple drive types, most
11934;; values in this table are ignored. I set parameters for 1.44M
11935;; floppy here
11936db 0xAF
11937db 0x02 ;; head load time 0000001, DMA used
11938db 0x25
11939db 0x02
11940db 18
11941db 0x1B
11942db 0xFF
11943db 0x6C
11944db 0xF6
11945db 0x0F
11946db 0x08
11947db 79 ;; maximum track
11948db 0 ;; data transfer rate
11949db 4 ;; drive type in cmos
11950
11951.org 0xf045 ; INT 10 Functions 0-Fh Entry Point
11952 HALT(__LINE__)
11953 iret
11954
11955;----------
11956;- INT10h -
11957;----------
11958.org 0xf065 ; INT 10h Video Support Service Entry Point
11959int10_handler:
11960 ;; dont do anything, since the VGA BIOS handles int10h requests
11961 iret
11962
11963.org 0xf0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
11964
11965;----------
11966;- INT12h -
11967;----------
11968.org 0xf841 ; INT 12h Memory Size Service Entry Point
11969; ??? different for Pentium (machine check)?
11970int12_handler:
11971 push ds
11972 mov ax, #0x0040
11973 mov ds, ax
11974 mov ax, 0x0013
11975 pop ds
11976 iret
11977
11978;----------
11979;- INT11h -
11980;----------
11981.org 0xf84d ; INT 11h Equipment List Service Entry Point
11982int11_handler:
11983 push ds
11984 mov ax, #0x0040
11985 mov ds, ax
11986 mov ax, 0x0010
11987 pop ds
11988 iret
11989
11990;----------
11991;- INT15h -
11992;----------
11993.org 0xf859 ; INT 15h System Services Entry Point
11994int15_handler:
11995 pushf
11996#if BX_APM
11997 cmp ah, #0x53
11998 je apm_call
11999#endif
12000 push ds
12001 push es
12002 cmp ah, #0x86
12003 je int15_handler32
12004 cmp ah, #0xE8
12005 je int15_handler32
12006 pusha
12007#if BX_USE_PS2_MOUSE
12008 cmp ah, #0xC2
12009 je int15_handler_mouse
12010#endif
12011 call _int15_function
12012int15_handler_mouse_ret:
12013 popa
12014int15_handler32_ret:
12015 pop es
12016 pop ds
12017 popf
12018 jmp iret_modify_cf
12019#if BX_APM
12020apm_call:
12021 jmp _apmreal_entry
12022#endif
12023
12024#if BX_USE_PS2_MOUSE
12025int15_handler_mouse:
12026 call _int15_function_mouse
12027 jmp int15_handler_mouse_ret
12028#endif
12029
12030int15_handler32:
12031 pushad
12032 call _int15_function32
12033 popad
12034 jmp int15_handler32_ret
12035
12036;; Protected mode IDT descriptor
12037;;
12038;; I just make the limit 0, so the machine will shutdown
12039;; if an exception occurs during protected mode memory
12040;; transfers.
12041;;
12042;; Set base to f0000 to correspond to beginning of BIOS,
12043;; in case I actually define an IDT later
12044;; Set limit to 0
12045
12046pmode_IDT_info:
12047dw 0x0000 ;; limit 15:00
12048dw 0x0000 ;; base 15:00
12049db 0x0f ;; base 23:16
12050
12051;; Real mode IDT descriptor
12052;;
12053;; Set to typical real-mode values.
12054;; base = 000000
12055;; limit = 03ff
12056
12057rmode_IDT_info:
12058dw 0x03ff ;; limit 15:00
12059dw 0x0000 ;; base 15:00
12060db 0x00 ;; base 23:16
12061
12062;;
12063;; Handler for unexpected hardware interrupts
12064;;
12065dummy_isr:
12066 push ds
12067 pushad
12068 xor ax, ax
12069 mov ds, ax
12070 call _dummy_isr_function
12071 popad
12072 pop ds
12073 iret
12074
12075;----------
12076;- INT1Ah -
12077;----------
12078.org 0xfe6e ; INT 1Ah Time-of-day Service Entry Point
12079int1a_handler:
12080#if BX_PCIBIOS
12081 cmp ah, #0xb1
12082 jne int1a_normal
12083 call pcibios_real
12084 jc pcibios_error
12085 retf 2
12086pcibios_error:
12087 mov bl, ah
12088 mov ah, #0xb1
12089 push ds
12090 pusha
12091 mov ax, ss ; set readable descriptor to ds, for calling pcibios
12092 mov ds, ax ; on 16bit protected mode.
12093 jmp int1a_callfunction
12094int1a_normal:
12095#endif
12096 push ds
12097 pusha
12098 xor ax, ax
12099 mov ds, ax
12100int1a_callfunction:
12101 call _int1a_function
12102 popa
12103 pop ds
12104 iret
12105
12106;;
12107;; int70h: IRQ8 - CMOS RTC
12108;;
12109int70_handler:
12110 push ds
12111 pushad
12112 xor ax, ax
12113 mov ds, ax
12114 call _int70_function
12115 popad
12116 pop ds
12117 iret
12118
12119;---------
12120;- INT08 -
12121;---------
12122.org 0xfea5 ; INT 08h System Timer ISR Entry Point
12123int08_handler:
12124 sti
12125 push eax
12126 push ds
12127 xor ax, ax
12128 mov ds, ax
12129
12130 ;; time to turn off drive(s)?
12131 mov al,0x0440
12132 or al,al
12133 jz int08_floppy_off
12134 dec al
12135 mov 0x0440,al
12136 jnz int08_floppy_off
12137 ;; turn motor(s) off
12138 push dx
12139 mov dx,#0x03f2
12140 in al,dx
12141 and al,#0xcf
12142 out dx,al
12143 pop dx
12144int08_floppy_off:
12145
12146 mov eax, 0x046c ;; get ticks dword
12147 inc eax
12148
12149 ;; compare eax to one days worth of timer ticks at 18.2 hz
12150 cmp eax, #0x001800B0
12151 jb int08_store_ticks
12152 ;; there has been a midnight rollover at this point
12153 xor eax, eax ;; zero out counter
12154 inc BYTE 0x0470 ;; increment rollover flag
12155
12156int08_store_ticks:
12157 mov 0x046c, eax ;; store new ticks dword
12158 ;; chain to user timer tick INT #0x1c
12159 //pushf
12160 //;; call_ep [ds:loc]
12161 //CALL_EP( 0x1c << 2 )
12162 int #0x1c
12163 cli
12164 call eoi_master_pic
12165 pop ds
12166 pop eax
12167 iret
12168
12169.org 0xfef3 ; Initial Interrupt Vector Offsets Loaded by POST
12170
12171
12172.org 0xff00
12173.ascii BIOS_COPYRIGHT_STRING
12174
12175#ifdef VBOX
12176// The SMBIOS header
12177.org 0xff30
12178.align 16
12179 db 0x5f, 0x53, 0x4d, 0x5f ; "_SM_" signature
12180 db 0x00 ; checksum (set by biossums)
12181 db 0x1f ; EPS length, defined by standard
12182 db VBOX_SMBIOS_MAJOR_VER ; SMBIOS major version
12183 db VBOX_SMBIOS_MINOR_VER ; SMBIOS minor version
12184 dw VBOX_SMBIOS_MAXSS ; Maximum structure size
12185 db 0x00 ; Entry point revision
12186 db 0x00, 0x00, 0x00, 0x00, 0x00
12187
12188// The DMI header
12189 db 0x5f, 0x44, 0x4d, 0x49, 0x5f ; "_DMI_" signature
12190 db 0x00 ; checksum (set by biossums)
12191 dw VBOX_DMI_TABLE_SIZE ; DMI tables length
12192 dd VBOX_DMI_TABLE_BASE ; DMI tables base
12193 dw VBOX_DMI_TABLE_ENTR ; DMI tables entries
12194 db VBOX_DMI_TABLE_VER ; DMI version
12195 db 0x00 ; Just for alignment
12196#endif
12197
12198;------------------------------------------------
12199;- IRET Instruction for Dummy Interrupt Handler -
12200;------------------------------------------------
12201.org 0xff53 ; IRET Instruction for Dummy Interrupt Handler
12202dummy_iret_handler:
12203 iret
12204
12205.org 0xff54 ; INT 05h Print Screen Service Entry Point
12206 HALT(__LINE__)
12207 iret
12208
12209.org 0xfff0 ; Power-up Entry Point
12210 jmp 0xf000:post
12211
12212.org 0xfff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
12213.ascii BIOS_BUILD_DATE
12214
12215.org 0xfffe ; System Model ID
12216db SYS_MODEL_ID
12217db 0x00 ; filler
12218
12219.org 0xfa6e ;; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
12220ASM_END
12221/*
12222 * This font comes from the fntcol16.zip package (c) by Joseph Gil
12223 * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
12224 * This font is public domain
12225 */
12226static Bit8u vgafont8[128*8]=
12227{
12228 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
12229 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
12230 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
12231 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
12232 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
12233 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
12234 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
12235 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
12236 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
12237 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
12238 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
12239 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
12240 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
12241 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
12242 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
12243 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
12244 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
12245 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
12246 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
12247 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
12248 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
12249 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
12250 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
12251 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
12252 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
12253 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
12254 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
12255 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
12256 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
12257 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
12258 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
12259 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
12260 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
12261 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
12262 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
12263 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
12264 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
12265 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
12266 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
12267 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
12268 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
12269 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
12270 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
12271 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
12272 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
12273 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
12274 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
12275 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
12276 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
12277 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
12278 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
12279 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
12280 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
12281 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
12282 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
12283 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
12284 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
12285 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
12286 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
12287 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
12288 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
12289 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
12290 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
12291 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
12292 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
12293 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
12294 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
12295 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
12296 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
12297 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
12298 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
12299 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
12300 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
12301 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
12302 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
12303 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
12304 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
12305 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
12306 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
12307 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
12308 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
12309 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
12310 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
12311 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
12312 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
12313 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
12314 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
12315 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
12316 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
12317 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
12318 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
12319 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
12320 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
12321 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
12322 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
12323 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
12324 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
12325 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
12326 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
12327 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
12328 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
12329 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
12330 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
12331 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
12332 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
12333 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
12334 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
12335 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
12336 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
12337 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
12338 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
12339 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
12340 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
12341 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
12342 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
12343 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
12344 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
12345 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
12346 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
12347 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
12348 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
12349 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
12350 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
12351 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
12352 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
12353 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
12354 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
12355 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
12356};
12357
12358ASM_START
12359.org 0xcc00
12360// bcc-generated data will be placed here
12361ASM_END
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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