VirtualBox

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

Last change on this file since 33656 was 33656, checked in by vboxsync, 14 years ago

*: rebrand Sun (L)GPL disclaimers

  • Property svn:eol-style set to native
File size: 335.2 KB
Line 
1/////////////////////////////////////////////////////////////////////////
2// $Id: rombios.c,v 1.176 2006/12/30 17:13:17 vruppert Exp $
3/////////////////////////////////////////////////////////////////////////
4//
5// Copyright (C) 2002 MandrakeSoft S.A.
6//
7// MandrakeSoft S.A.
8// 43, rue d'Aboukir
9// 75002 Paris - France
10// http://www.linux-mandrake.com/
11// http://www.mandrakesoft.com/
12//
13// This library is free software; you can redistribute it and/or
14// modify it under the terms of the GNU Lesser General Public
15// License as published by the Free Software Foundation; either
16// version 2 of the License, or (at your option) any later version.
17//
18// This library is distributed in the hope that it will be useful,
19// but WITHOUT ANY WARRANTY; without even the implied warranty of
20// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21// Lesser General Public License for more details.
22//
23// You should have received a copy of the GNU Lesser General Public
24// License along with this library; if not, write to the Free Software
25// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
26
27
28/*
29 * Oracle 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, Oracle 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
37// ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
38
39
40// ROM BIOS compatibility entry points:
41// ===================================
42// $e05b ; POST Entry Point
43// $e2c3 ; NMI Handler Entry Point
44// $e3fe ; INT 13h Fixed Disk Services Entry Point
45// $e401 ; Fixed Disk Parameter Table
46// $e6f2 ; INT 19h Boot Load Service Entry Point
47// $e6f5 ; Configuration Data Table
48// $e729 ; Baud Rate Generator Table
49// $e739 ; INT 14h Serial Communications Service Entry Point
50// $e82e ; INT 16h Keyboard Service Entry Point
51// $e987 ; INT 09h Keyboard Service Entry Point
52// $ec59 ; INT 13h Diskette Service Entry Point
53// $ef57 ; INT 0Eh Diskette Hardware ISR Entry Point
54// $efc7 ; Diskette Controller Parameter Table
55// $efd2 ; INT 17h Printer Service Entry Point
56// $f045 ; INT 10 Functions 0-Fh Entry Point
57// $f065 ; INT 10h Video Support Service Entry Point
58// $f0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
59// $f841 ; INT 12h Memory Size Service Entry Point
60// $f84d ; INT 11h Equipment List Service Entry Point
61// $f859 ; INT 15h System Services Entry Point
62// $fa6e ; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
63// $fe6e ; INT 1Ah Time-of-day Service Entry Point
64// $fea5 ; INT 08h System Timer ISR Entry Point
65// $fef3 ; Initial Interrupt Vector Offsets Loaded by POST
66// $ff53 ; IRET Instruction for Dummy Interrupt Handler
67// $ff54 ; INT 05h Print Screen Service Entry Point
68// $fff0 ; Power-up Entry Point
69// $fff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
70// $fffe ; System Model ID
71
72// NOTES for ATA/ATAPI driver ([email protected])
73// Features
74// - supports up to 4 ATA interfaces
75// - device/geometry detection
76// - 16bits/32bits device access
77// - pchs/lba access
78// - datain/dataout/packet command support
79//
80// NOTES for El-Torito Boot ([email protected])
81// - CD-ROM booting is only available if ATA/ATAPI Driver is available
82// - Current code is only able to boot mono-session cds
83// - Current code can not boot and emulate a hard-disk
84// the bios will panic otherwise
85// - Current code also use memory in EBDA segment.
86// - I used cmos byte 0x3D to store extended information on boot-device
87// - Code has to be modified modified to handle multiple cdrom drives
88// - Here are the cdrom boot failure codes:
89// 1 : no atapi device found
90// 2 : no atapi cdrom found
91// 3 : can not read cd - BRVD
92// 4 : cd is not eltorito (BRVD)
93// 5 : cd is not eltorito (ISO TAG)
94// 6 : cd is not eltorito (ELTORITO TAG)
95// 7 : can not read cd - boot catalog
96// 8 : boot catalog : bad header
97// 9 : boot catalog : bad platform
98// 10 : boot catalog : bad signature
99// 11 : boot catalog : bootable flag not set
100// 12 : can not read cd - boot image
101//
102// ATA driver
103// - EBDA segment.
104// I used memory starting at 0x121 in the segment
105#ifndef VBOX
106// - the translation policy is defined in cmos regs 0x39 & 0x3a
107#endif /* !VBOX */
108//
109// TODO :
110//
111// int74
112// - needs to be reworked. Uses direct [bp] offsets. (?)
113//
114// int13:
115// - f04 (verify sectors) isn't complete (?)
116// - f02/03/04 should set current cyl,etc in BDA (?)
117// - rewrite int13_relocated & clean up int13 entry code
118//
119// NOTES:
120// - NMI access (bit7 of addr written to 70h)
121//
122// ATA driver
123// - should handle the "don't detect" bit (cmos regs 0x3b & 0x3c)
124// - could send the multiple-sector read/write commands
125//
126// El-Torito
127// - Emulate a Hard-disk (currently only diskette can be emulated) see "FIXME ElTorito Harddisk"
128// - Implement remaining int13_cdemu functions (as defined by El-Torito specs)
129// - cdrom drive is hardcoded to ide 0 device 1 in several places. see "FIXME ElTorito Hardcoded"
130// - int13 Fix DL when emulating a cd. In that case DL is decremented before calling real int13.
131// This is ok. But DL should be reincremented afterwards.
132// - Fix all "FIXME ElTorito Various"
133// - should be able to boot any cdrom instead of the first one
134//
135// BCC Bug: find a generic way to handle the bug of #asm after an "if" (fixed in 0.16.7)
136
137#ifdef VBOX
138#include "DevPcBios.h"
139#include <VBox/version.h>
140#endif
141
142#define BX_ROMBIOS32 0
143#define DEBUG_ROMBIOS 0
144
145#define DEBUG_ATA 0
146#define DEBUG_INT13_HD 0
147#define DEBUG_INT13_CD 0
148#define DEBUG_INT13_ET 0
149#define DEBUG_INT13_FL 0
150#define DEBUG_INT15 0
151#define DEBUG_INT16 0
152#define DEBUG_INT1A 0
153#define DEBUG_INT74 0
154#define DEBUG_APM 0
155
156#define BX_CPU 3
157#define BX_USE_PS2_MOUSE 1
158#define BX_CALL_INT15_4F 1
159#define BX_USE_EBDA 1
160#define BX_SUPPORT_FLOPPY 1
161#define BX_FLOPPY_ON_CNT 37 /* 2 seconds */
162#define BX_PCIBIOS 1
163#define BX_APM 1
164
165#define BX_USE_ATADRV 1
166#define BX_ELTORITO_BOOT 1
167
168#define BX_MAX_ATA_INTERFACES 4
169#define BX_MAX_ATA_DEVICES (BX_MAX_ATA_INTERFACES*2)
170
171#define BX_VIRTUAL_PORTS 1 /* normal output to Bochs ports */
172#define BX_DEBUG_SERIAL 0 /* output to COM1 */
173
174 /* model byte 0xFC = AT */
175#define SYS_MODEL_ID 0xFC
176#define SYS_SUBMODEL_ID 0x00
177#define BIOS_REVISION 1
178#define BIOS_CONFIG_TABLE 0xe6f5
179
180#ifndef BIOS_BUILD_DATE
181# define BIOS_BUILD_DATE "06/23/99"
182#endif
183
184 // 1K of base memory used for Extended Bios Data Area (EBDA)
185 // EBDA is used for PS/2 mouse support, and IDE BIOS, etc.
186#define EBDA_SEG 0x9FC0
187#define EBDA_SIZE 1 // In KiB
188#define BASE_MEM_IN_K (640 - EBDA_SIZE)
189
190#define ACPI_DATA_SIZE 0x00010000L
191
192 // Define the application NAME
193#if defined(BX_QEMU)
194# define BX_APPNAME "QEMU"
195#elif defined(PLEX86)
196# define BX_APPNAME "Plex86"
197#else
198# define BX_APPNAME "Bochs"
199#endif
200
201 // Sanity Checks
202#if BX_USE_ATADRV && BX_CPU<3
203# error The ATA/ATAPI Driver can only to be used with a 386+ cpu
204#endif
205#if BX_USE_ATADRV && !BX_USE_EBDA
206# error ATA/ATAPI Driver can only be used if EBDA is available
207#endif
208#if BX_ELTORITO_BOOT && !BX_USE_ATADRV
209# error El-Torito Boot can only be use if ATA/ATAPI Driver is available
210#endif
211#if BX_PCIBIOS && BX_CPU<3
212# error PCI BIOS can only be used with 386+ cpu
213#endif
214#if BX_APM && BX_CPU<3
215# error APM BIOS can only be used with 386+ cpu
216#endif
217
218#if defined(VBOX) && !BX_USE_ATADRV
219# error VBOX requires enabling the ATA/ATAPI driver
220#endif
221
222#ifdef VBOX_WITH_SCSI
223/* Enough for now */
224# define BX_MAX_SCSI_DEVICES 4
225# define BX_MAX_STORAGE_DEVICES (BX_MAX_ATA_DEVICES + BX_MAX_SCSI_DEVICES)
226
227/* A SCSI device starts always at BX_MAX_ATA_DEVICES. */
228# define VBOX_IS_SCSI_DEVICE(device_id) (device_id >= BX_MAX_ATA_DEVICES)
229# define VBOX_GET_SCSI_DEVICE(device_id) (device_id - BX_MAX_ATA_DEVICES)
230#endif
231
232#ifndef VBOX
233#define PANIC_PORT 0x400
234#define PANIC_PORT2 0x401
235#define INFO_PORT 0x402
236#define DEBUG_PORT 0x403
237#else /* VBOX */
238/* Redirect INFO output to backdoor logging port. */
239#define PANIC_PORT 0x400
240#define PANIC_PORT2 0x401
241#define INFO_PORT 0x504
242#define DEBUG_PORT 0x403
243#endif /* VBOX */
244
245// define this if you want to make PCIBIOS working on a specific bridge only
246// undef enables PCIBIOS when at least one PCI device is found
247// i440FX is emulated by Bochs and QEMU
248#define PCI_FIXED_HOST_BRIDGE_1 0x12378086 ;; i440FX PCI bridge
249#define PCI_FIXED_HOST_BRIDGE_2 0x244e8086 ;; ICH9 PCI bridge
250
251// #20 is dec 20
252// #$20 is hex 20 = 32
253// #0x20 is hex 20 = 32
254// LDA #$20
255// JSR $E820
256// LDD .i,S
257// JSR $C682
258// mov al, #$20
259
260// all hex literals should be prefixed with '0x'
261// grep "#[0-9a-fA-F][0-9a-fA-F]" rombios.c
262// no mov SEG-REG, #value, must mov register into seg-reg
263// grep -i "mov[ ]*.s" rombios.c
264
265// This is for compiling with gcc2 and gcc3
266#define ASM_START #asm
267#define ASM_END #endasm
268
269ASM_START
270.rom
271
272.org 0x0000
273
274#if BX_CPU >= 3
275use16 386
276#else
277use16 286
278#endif
279
280MACRO HALT
281 ;; the HALT macro is called with the line number of the HALT call.
282 ;; The line number is then sent to the PANIC_PORT, causing Bochs/Plex
283 ;; to print a BX_PANIC message. This will normally halt the simulation
284 ;; with a message such as "BIOS panic at rombios.c, line 4091".
285 ;; However, users can choose to make panics non-fatal and continue.
286#if BX_VIRTUAL_PORTS
287 mov dx,#PANIC_PORT
288 mov ax,#?1
289 out dx,ax
290#else
291 mov dx,#0x80
292 mov ax,#?1
293 out dx,al
294#endif
295MEND
296
297MACRO JMP_AP
298 db 0xea
299 dw ?2
300 dw ?1
301MEND
302
303MACRO SET_INT_VECTOR
304 mov ax, ?3
305 mov ?1*4, ax
306 mov ax, ?2
307 mov ?1*4+2, ax
308MEND
309
310ASM_END
311
312typedef unsigned char Bit8u;
313typedef unsigned short Bit16u;
314typedef unsigned short bx_bool;
315typedef unsigned long Bit32u;
316
317#if BX_USE_ATADRV
318
319 void memsetb(seg,offset,value,count);
320 void memcpyb(dseg,doffset,sseg,soffset,count);
321 void memcpyd(dseg,doffset,sseg,soffset,count);
322
323 // memset of count bytes
324 void
325 memsetb(seg,offset,value,count)
326 Bit16u seg;
327 Bit16u offset;
328 Bit16u value;
329 Bit16u count;
330 {
331 ASM_START
332 push bp
333 mov bp, sp
334
335 push ax
336 push cx
337 push es
338 push di
339
340 mov cx, 10[bp] ; count
341 test cx, cx
342 je memsetb_end
343 mov ax, 4[bp] ; segment
344 mov es, ax
345 mov ax, 6[bp] ; offset
346 mov di, ax
347 mov al, 8[bp] ; value
348 cld
349 rep
350 stosb
351
352 memsetb_end:
353 pop di
354 pop es
355 pop cx
356 pop ax
357
358 pop bp
359 ASM_END
360 }
361
362#if 0
363 // memcpy of count bytes
364 void
365 memcpyb(dseg,doffset,sseg,soffset,count)
366 Bit16u dseg;
367 Bit16u doffset;
368 Bit16u sseg;
369 Bit16u soffset;
370 Bit16u count;
371 {
372 ASM_START
373 push bp
374 mov bp, sp
375
376 push ax
377 push cx
378 push es
379 push di
380 push ds
381 push si
382
383 mov cx, 12[bp] ; count
384 cmp cx, #0x0000
385 je memcpyb_end
386 mov ax, 4[bp] ; dsegment
387 mov es, ax
388 mov ax, 6[bp] ; doffset
389 mov di, ax
390 mov ax, 8[bp] ; ssegment
391 mov ds, ax
392 mov ax, 10[bp] ; soffset
393 mov si, ax
394 cld
395 rep
396 movsb
397
398 memcpyb_end:
399 pop si
400 pop ds
401 pop di
402 pop es
403 pop cx
404 pop ax
405
406 pop bp
407 ASM_END
408 }
409
410 // memcpy of count dword
411 void
412 memcpyd(dseg,doffset,sseg,soffset,count)
413 Bit16u dseg;
414 Bit16u doffset;
415 Bit16u sseg;
416 Bit16u soffset;
417 Bit16u count;
418 {
419 ASM_START
420 push bp
421 mov bp, sp
422
423 push ax
424 push cx
425 push es
426 push di
427 push ds
428 push si
429
430 mov cx, 12[bp] ; count
431 test cx, cx
432 je memcpyd_end
433 mov ax, 4[bp] ; dsegment
434 mov es, ax
435 mov ax, 6[bp] ; doffset
436 mov di, ax
437 mov ax, 8[bp] ; ssegment
438 mov ds, ax
439 mov ax, 10[bp] ; soffset
440 mov si, ax
441 cld
442 rep
443 movsd
444
445 memcpyd_end:
446 pop si
447 pop ds
448 pop di
449 pop es
450 pop cx
451 pop ax
452
453 pop bp
454 ASM_END
455 }
456#endif
457#endif //BX_USE_ATADRV
458
459 // read_dword and write_dword functions
460 static Bit32u read_dword();
461 static void write_dword();
462
463 Bit32u
464 read_dword(seg, offset)
465 Bit16u seg;
466 Bit16u offset;
467 {
468 ASM_START
469 push bp
470 mov bp, sp
471
472 push bx
473 push ds
474 mov ax, 4[bp] ; segment
475 mov ds, ax
476 mov bx, 6[bp] ; offset
477 mov ax, [bx]
478 add bx, #2
479 mov dx, [bx]
480 ;; ax = return value (word)
481 ;; dx = return value (word)
482 pop ds
483 pop bx
484
485 pop bp
486 ASM_END
487 }
488
489 void
490 write_dword(seg, offset, data)
491 Bit16u seg;
492 Bit16u offset;
493 Bit32u data;
494 {
495 ASM_START
496 push bp
497 mov bp, sp
498
499 push ax
500 push bx
501 push ds
502 mov ax, 4[bp] ; segment
503 mov ds, ax
504 mov bx, 6[bp] ; offset
505 mov ax, 8[bp] ; data word
506 mov [bx], ax ; write data word
507 add bx, #2
508 mov ax, 10[bp] ; data word
509 mov [bx], ax ; write data word
510 pop ds
511 pop bx
512 pop ax
513
514 pop bp
515 ASM_END
516 }
517
518 // Bit32u (unsigned long) and long helper functions
519 ASM_START
520
521 ;; and function
522 landl:
523 landul:
524 SEG SS
525 and ax,[di]
526 SEG SS
527 and bx,2[di]
528 ret
529
530 ;; add function
531 laddl:
532 laddul:
533 SEG SS
534 add ax,[di]
535 SEG SS
536 adc bx,2[di]
537 ret
538
539 ;; cmp function
540 lcmpl:
541 lcmpul:
542 and eax, #0x0000FFFF
543 shl ebx, #16
544 or eax, ebx
545 shr ebx, #16
546 SEG SS
547 cmp eax, dword ptr [di]
548 ret
549
550 ;; sub function
551 lsubl:
552 lsubul:
553 SEG SS
554 sub ax,[di]
555 SEG SS
556 sbb bx,2[di]
557 ret
558
559 ;; mul function
560 lmull:
561 lmulul:
562 and eax, #0x0000FFFF
563 shl ebx, #16
564 or eax, ebx
565 SEG SS
566 mul eax, dword ptr [di]
567 mov ebx, eax
568 shr ebx, #16
569 ret
570
571 ;; dec function
572 ldecl:
573 ldecul:
574 SEG SS
575 dec dword ptr [bx]
576 ret
577
578 ;; or function
579 lorl:
580 lorul:
581 SEG SS
582 or ax,[di]
583 SEG SS
584 or bx,2[di]
585 ret
586
587 ;; inc function
588 lincl:
589 lincul:
590 SEG SS
591 inc dword ptr [bx]
592 ret
593
594 ;; tst function
595 ltstl:
596 ltstul:
597 and eax, #0x0000FFFF
598 shl ebx, #16
599 or eax, ebx
600 shr ebx, #16
601 test eax, eax
602 ret
603
604 ;; sr function
605 lsrul:
606 mov cx,di
607 jcxz lsr_exit
608 and eax, #0x0000FFFF
609 shl ebx, #16
610 or eax, ebx
611 lsr_loop:
612 shr eax, #1
613 loop lsr_loop
614 mov ebx, eax
615 shr ebx, #16
616 lsr_exit:
617 ret
618
619 ;; sl function
620 lsll:
621 lslul:
622 mov cx,di
623 jcxz lsl_exit
624 and eax, #0x0000FFFF
625 shl ebx, #16
626 or eax, ebx
627 lsl_loop:
628 shl eax, #1
629 loop lsl_loop
630 mov ebx, eax
631 shr ebx, #16
632 lsl_exit:
633 ret
634
635 idiv_:
636 cwd
637 idiv bx
638 ret
639
640 idiv_u:
641 xor dx,dx
642 div bx
643 ret
644
645 ldivul:
646 and eax, #0x0000FFFF
647 shl ebx, #16
648 or eax, ebx
649 xor edx, edx
650 SEG SS
651 mov bx, 2[di]
652 shl ebx, #16
653 SEG SS
654 mov bx, [di]
655 div ebx
656 mov ebx, eax
657 shr ebx, #16
658 ret
659
660 ASM_END
661
662// for access to RAM area which is used by interrupt vectors
663// and BIOS Data Area
664
665typedef struct {
666 unsigned char filler1[0x400];
667 unsigned char filler2[0x6c];
668 Bit16u ticks_low;
669 Bit16u ticks_high;
670 Bit8u midnight_flag;
671 } bios_data_t;
672
673#define BiosData ((bios_data_t *) 0)
674
675#if BX_USE_ATADRV
676 typedef struct {
677 Bit16u heads; // # heads
678 Bit16u cylinders; // # cylinders
679 Bit16u spt; // # sectors / track
680 } chs_t;
681
682 // DPTE definition
683 typedef struct {
684 Bit16u iobase1;
685 Bit16u iobase2;
686 Bit8u prefix;
687 Bit8u unused;
688 Bit8u irq;
689 Bit8u blkcount;
690 Bit8u dma;
691 Bit8u pio;
692 Bit16u options;
693 Bit16u reserved;
694 Bit8u revision;
695 Bit8u checksum;
696 } dpte_t;
697
698 typedef struct {
699 Bit8u iface; // ISA or PCI
700 Bit16u iobase1; // IO Base 1
701 Bit16u iobase2; // IO Base 2
702 Bit8u irq; // IRQ
703 } ata_channel_t;
704
705 typedef struct {
706 Bit8u type; // Detected type of ata (ata/atapi/none/unknown/scsi)
707 Bit8u device; // Detected type of attached devices (hd/cd/none)
708 Bit8u removable; // Removable device flag
709 Bit8u lock; // Locks for removable devices
710 Bit8u mode; // transfer mode : PIO 16/32 bits - IRQ - ISADMA - PCIDMA
711 Bit16u blksize; // block size
712
713 Bit8u translation; // type of translation
714 chs_t lchs; // Logical CHS
715 chs_t pchs; // Physical CHS
716
717 Bit32u sectors; // Total sectors count
718 } ata_device_t;
719
720 typedef struct {
721 // ATA channels info
722 ata_channel_t channels[BX_MAX_ATA_INTERFACES];
723
724 // ATA devices info
725 ata_device_t devices[BX_MAX_ATA_DEVICES];
726 //
727 // map between (bios hd id - 0x80) and ata channels and scsi disks.
728#ifdef VBOX_WITH_SCSI
729 Bit8u hdcount, hdidmap[BX_MAX_ATA_DEVICES+BX_MAX_SCSI_DEVICES];
730#else
731 Bit8u hdcount, hdidmap[BX_MAX_ATA_DEVICES];
732#endif
733
734 // map between (bios cd id - 0xE0) and ata channels
735 Bit8u cdcount, cdidmap[BX_MAX_ATA_DEVICES];
736
737 // Buffer for DPTE table
738 dpte_t dpte;
739
740 // Count of transferred sectors and bytes
741 Bit16u trsfsectors;
742 Bit32u trsfbytes;
743
744 } ata_t;
745
746#if BX_ELTORITO_BOOT
747 // ElTorito Device Emulation data
748 typedef struct {
749 Bit8u active;
750 Bit8u media;
751 Bit8u emulated_drive;
752 Bit8u controller_index;
753 Bit16u device_spec;
754 Bit32u ilba;
755 Bit16u buffer_segment;
756 Bit16u load_segment;
757 Bit16u sector_count;
758
759 // Virtual device
760 chs_t vdevice;
761 } cdemu_t;
762#endif // BX_ELTORITO_BOOT
763
764#ifdef VBOX_WITH_SCSI
765 typedef struct {
766 // I/O port this device is attached to.
767 Bit16u io_base;
768 // Target Id.
769 Bit8u target_id;
770 // SCSI devices info
771 ata_device_t device_info;
772 } scsi_device_t;
773
774 typedef struct {
775 // SCSi device info
776 scsi_device_t devices[BX_MAX_SCSI_DEVICES];
777 // Number of scsi disks.
778 Bit8u hdcount;
779 } scsi_t;
780#endif
781
782 // for access to EBDA area
783 // The EBDA structure should conform to
784 // http://www.frontiernet.net/~fys/rombios.htm document
785 // I made the ata and cdemu structs begin at 0x121 in the EBDA seg
786 typedef struct {
787 unsigned char filler1[0x3D];
788
789 // FDPT - Can be split into data members if needed
790 unsigned char fdpt0[0x10];
791 unsigned char fdpt1[0x10];
792
793 unsigned char filler2[0xC4];
794
795 // ATA Driver data
796 ata_t ata;
797
798#if BX_ELTORITO_BOOT
799 // El Torito Emulation data
800 cdemu_t cdemu;
801#endif // BX_ELTORITO_BOOT
802
803#ifdef VBOX
804
805#ifdef VBOX_WITH_SCSI
806 // SCSI Driver data
807 scsi_t scsi;
808# endif
809
810 unsigned char uForceBootDrive;
811 unsigned char uForceBootDevice;
812#endif /* VBOX */
813
814 } ebda_data_t;
815
816#ifdef VBOX
817 // the last 16 bytes of the EBDA segment are used for the MPS floating
818 // pointer structure (only if an IOAPIC is present)
819#endif
820
821 #define EbdaData ((ebda_data_t *) 0)
822
823 // for access to the int13ext structure
824 typedef struct {
825 Bit8u size;
826 Bit8u reserved;
827 Bit16u count;
828 Bit16u offset;
829 Bit16u segment;
830 Bit32u lba1;
831 Bit32u lba2;
832 } int13ext_t;
833
834 #define Int13Ext ((int13ext_t *) 0)
835
836 // Disk Physical Table definition
837 typedef struct {
838 Bit16u size;
839 Bit16u infos;
840 Bit32u cylinders;
841 Bit32u heads;
842 Bit32u spt;
843 Bit32u sector_count1;
844 Bit32u sector_count2;
845 Bit16u blksize;
846 Bit16u dpte_offset;
847 Bit16u dpte_segment;
848 Bit16u key;
849 Bit8u dpi_length;
850 Bit8u reserved1;
851 Bit16u reserved2;
852 Bit8u host_bus[4];
853 Bit8u iface_type[8];
854 Bit8u iface_path[8];
855 Bit8u device_path[8];
856 Bit8u reserved3;
857 Bit8u checksum;
858 } dpt_t;
859
860 #define Int13DPT ((dpt_t *) 0)
861
862#endif // BX_USE_ATADRV
863
864typedef struct {
865 union {
866 struct {
867 Bit16u di, si, bp, sp;
868 Bit16u bx, dx, cx, ax;
869 } r16;
870 struct {
871 Bit16u filler[4];
872 Bit8u bl, bh, dl, dh, cl, ch, al, ah;
873 } r8;
874 } u;
875 } pusha_regs_t;
876
877typedef struct {
878 union {
879 struct {
880 Bit32u edi, esi, ebp, esp;
881 Bit32u ebx, edx, ecx, eax;
882 } r32;
883 struct {
884 Bit16u di, filler1, si, filler2, bp, filler3, sp, filler4;
885 Bit16u bx, filler5, dx, filler6, cx, filler7, ax, filler8;
886 } r16;
887 struct {
888 Bit32u filler[4];
889 Bit8u bl, bh;
890 Bit16u filler1;
891 Bit8u dl, dh;
892 Bit16u filler2;
893 Bit8u cl, ch;
894 Bit16u filler3;
895 Bit8u al, ah;
896 Bit16u filler4;
897 } r8;
898 } u;
899} pushad_regs_t;
900
901typedef struct {
902 union {
903 struct {
904 Bit16u flags;
905 } r16;
906 struct {
907 Bit8u flagsl;
908 Bit8u flagsh;
909 } r8;
910 } u;
911 } flags_t;
912
913#define SetCF(x) x.u.r8.flagsl |= 0x01
914#define SetZF(x) x.u.r8.flagsl |= 0x40
915#define ClearCF(x) x.u.r8.flagsl &= 0xfe
916#define ClearZF(x) x.u.r8.flagsl &= 0xbf
917#define GetCF(x) (x.u.r8.flagsl & 0x01)
918
919typedef struct {
920 Bit16u ip;
921 Bit16u cs;
922 flags_t flags;
923 } iret_addr_t;
924
925
926
927static Bit8u inb();
928static Bit8u inb_cmos();
929static void outb();
930static void outb_cmos();
931static Bit16u inw();
932static void outw();
933static void init_rtc();
934static bx_bool rtc_updating();
935
936static Bit8u read_byte();
937static Bit16u read_word();
938static void write_byte();
939static void write_word();
940static void bios_printf();
941
942static Bit8u send_to_mouse_ctrl();
943static Bit8u get_mouse_data();
944static void set_kbd_command_byte();
945
946static void int09_function();
947static void int13_harddisk();
948static void int13_cdrom();
949static void int13_cdemu();
950static void int13_eltorito();
951static void int13_diskette_function();
952static void int14_function();
953static void int15_function();
954static void int16_function();
955static void int17_function();
956static Bit32u int19_function();
957static void int1a_function();
958static void int70_function();
959static void int74_function();
960static void dummy_isr_function();
961static Bit16u get_CS();
962static Bit16u get_SS();
963static unsigned int enqueue_key();
964static unsigned int dequeue_key();
965static void get_hd_geometry();
966static void set_diskette_ret_status();
967static void set_diskette_current_cyl();
968static void determine_floppy_media();
969static bx_bool floppy_drive_exists();
970static bx_bool floppy_drive_recal();
971static bx_bool floppy_media_known();
972static bx_bool floppy_media_sense();
973static bx_bool set_enable_a20();
974static void debugger_on();
975static void debugger_off();
976static void keyboard_init();
977static void keyboard_panic();
978static void shutdown_status_panic();
979static void nmi_handler_msg();
980
981static void print_bios_banner();
982static void print_boot_device();
983static void print_boot_failure();
984static void print_cdromboot_failure();
985
986# if BX_USE_ATADRV
987
988// ATA / ATAPI driver
989void ata_init();
990void ata_detect();
991void ata_reset();
992
993Bit16u ata_cmd_non_data();
994Bit16u ata_cmd_data_in();
995Bit16u ata_cmd_data_out();
996Bit16u ata_cmd_packet();
997
998Bit16u atapi_get_sense();
999Bit16u atapi_is_ready();
1000Bit16u atapi_is_cdrom();
1001
1002#endif // BX_USE_ATADRV
1003
1004#if BX_ELTORITO_BOOT
1005
1006void cdemu_init();
1007Bit8u cdemu_isactive();
1008Bit8u cdemu_emulated_drive();
1009
1010Bit16u cdrom_boot();
1011
1012#endif // BX_ELTORITO_BOOT
1013
1014#ifdef VBOX
1015static char bios_prefix_string[] = "BIOS: ";
1016/* Do not use build timestamps in this string. Otherwise even rebuilding the
1017 * very same code will lead to compare errors when restoring saved state. */
1018static char bios_cvs_version_string[] = "VirtualBox " VBOX_VERSION_STRING;
1019#define BIOS_COPYRIGHT_STRING "Oracle VM VirtualBox BIOS"
1020#else /* !VBOX */
1021static char bios_cvs_version_string[] = "$Revision: 1.176 $ $Date: 2006/12/30 17:13:17 $";
1022
1023#define BIOS_COPYRIGHT_STRING "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team."
1024#endif /* !VBOX */
1025
1026#define BIOS_PRINTF_HALT 1
1027#define BIOS_PRINTF_SCREEN 2
1028#define BIOS_PRINTF_INFO 4
1029#define BIOS_PRINTF_DEBUG 8
1030#define BIOS_PRINTF_ALL (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO)
1031#define BIOS_PRINTF_DEBHALT (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO | BIOS_PRINTF_HALT)
1032
1033#define printf(format, p...) bios_printf(BIOS_PRINTF_SCREEN, format, ##p)
1034
1035// Defines the output macros.
1036// BX_DEBUG goes to INFO port until we can easily choose debug info on a
1037// per-device basis. Debug info are sent only in debug mode
1038#if DEBUG_ROMBIOS
1039# define BX_DEBUG(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
1040#else
1041# define BX_DEBUG(format, p...)
1042#endif
1043#ifdef VBOX
1044#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)
1045#else /* !VBOX */
1046#define BX_INFO(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
1047#endif /* !VBOX */
1048#define BX_PANIC(format, p...) bios_printf(BIOS_PRINTF_DEBHALT, format, ##p)
1049
1050#if DEBUG_ATA
1051# define BX_DEBUG_ATA(a...) BX_DEBUG(a)
1052#else
1053# define BX_DEBUG_ATA(a...)
1054#endif
1055#if DEBUG_INT13_HD
1056# define BX_DEBUG_INT13_HD(a...) BX_DEBUG(a)
1057#else
1058# define BX_DEBUG_INT13_HD(a...)
1059#endif
1060#if DEBUG_INT13_CD
1061# define BX_DEBUG_INT13_CD(a...) BX_DEBUG(a)
1062#else
1063# define BX_DEBUG_INT13_CD(a...)
1064#endif
1065#if DEBUG_INT13_ET
1066# define BX_DEBUG_INT13_ET(a...) BX_DEBUG(a)
1067#else
1068# define BX_DEBUG_INT13_ET(a...)
1069#endif
1070#if DEBUG_INT13_FL
1071# define BX_DEBUG_INT13_FL(a...) BX_DEBUG(a)
1072#else
1073# define BX_DEBUG_INT13_FL(a...)
1074#endif
1075#if DEBUG_INT15
1076# define BX_DEBUG_INT15(a...) BX_DEBUG(a)
1077#else
1078# define BX_DEBUG_INT15(a...)
1079#endif
1080#if DEBUG_INT16
1081# define BX_DEBUG_INT16(a...) BX_DEBUG(a)
1082#else
1083# define BX_DEBUG_INT16(a...)
1084#endif
1085#if DEBUG_INT1A
1086# define BX_DEBUG_INT1A(a...) BX_DEBUG(a)
1087#else
1088# define BX_DEBUG_INT1A(a...)
1089#endif
1090#if DEBUG_INT74
1091# define BX_DEBUG_INT74(a...) BX_DEBUG(a)
1092#else
1093# define BX_DEBUG_INT74(a...)
1094#endif
1095
1096#define SET_AL(val8) AX = ((AX & 0xff00) | (val8))
1097#define SET_BL(val8) BX = ((BX & 0xff00) | (val8))
1098#define SET_CL(val8) CX = ((CX & 0xff00) | (val8))
1099#define SET_DL(val8) DX = ((DX & 0xff00) | (val8))
1100#define SET_AH(val8) AX = ((AX & 0x00ff) | ((val8) << 8))
1101#define SET_BH(val8) BX = ((BX & 0x00ff) | ((val8) << 8))
1102#define SET_CH(val8) CX = ((CX & 0x00ff) | ((val8) << 8))
1103#define SET_DH(val8) DX = ((DX & 0x00ff) | ((val8) << 8))
1104
1105#define GET_AL() ( AX & 0x00ff )
1106#define GET_BL() ( BX & 0x00ff )
1107#define GET_CL() ( CX & 0x00ff )
1108#define GET_DL() ( DX & 0x00ff )
1109#define GET_AH() ( AX >> 8 )
1110#define GET_BH() ( BX >> 8 )
1111#define GET_CH() ( CX >> 8 )
1112#define GET_DH() ( DX >> 8 )
1113
1114#define GET_ELDL() ( ELDX & 0x00ff )
1115#define GET_ELDH() ( ELDX >> 8 )
1116
1117#define SET_CF() FLAGS |= 0x0001
1118#define CLEAR_CF() FLAGS &= 0xfffe
1119#define GET_CF() (FLAGS & 0x0001)
1120
1121#define SET_ZF() FLAGS |= 0x0040
1122#define CLEAR_ZF() FLAGS &= 0xffbf
1123#define GET_ZF() (FLAGS & 0x0040)
1124
1125#define UNSUPPORTED_FUNCTION 0x86
1126
1127#define none 0
1128#define MAX_SCAN_CODE 0x58
1129
1130static struct {
1131 Bit16u normal;
1132 Bit16u shift;
1133 Bit16u control;
1134 Bit16u alt;
1135 Bit8u lock_flags;
1136 } scan_to_scanascii[MAX_SCAN_CODE + 1] = {
1137 { none, none, none, none, none },
1138 { 0x011b, 0x011b, 0x011b, 0x0100, none }, /* escape */
1139 { 0x0231, 0x0221, none, 0x7800, none }, /* 1! */
1140 { 0x0332, 0x0340, 0x0300, 0x7900, none }, /* 2@ */
1141 { 0x0433, 0x0423, none, 0x7a00, none }, /* 3# */
1142 { 0x0534, 0x0524, none, 0x7b00, none }, /* 4$ */
1143 { 0x0635, 0x0625, none, 0x7c00, none }, /* 5% */
1144 { 0x0736, 0x075e, 0x071e, 0x7d00, none }, /* 6^ */
1145 { 0x0837, 0x0826, none, 0x7e00, none }, /* 7& */
1146 { 0x0938, 0x092a, none, 0x7f00, none }, /* 8* */
1147 { 0x0a39, 0x0a28, none, 0x8000, none }, /* 9( */
1148 { 0x0b30, 0x0b29, none, 0x8100, none }, /* 0) */
1149 { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200, none }, /* -_ */
1150 { 0x0d3d, 0x0d2b, none, 0x8300, none }, /* =+ */
1151 { 0x0e08, 0x0e08, 0x0e7f, none, none }, /* backspace */
1152 { 0x0f09, 0x0f00, none, none, none }, /* tab */
1153 { 0x1071, 0x1051, 0x1011, 0x1000, 0x40 }, /* Q */
1154 { 0x1177, 0x1157, 0x1117, 0x1100, 0x40 }, /* W */
1155 { 0x1265, 0x1245, 0x1205, 0x1200, 0x40 }, /* E */
1156 { 0x1372, 0x1352, 0x1312, 0x1300, 0x40 }, /* R */
1157 { 0x1474, 0x1454, 0x1414, 0x1400, 0x40 }, /* T */
1158 { 0x1579, 0x1559, 0x1519, 0x1500, 0x40 }, /* Y */
1159 { 0x1675, 0x1655, 0x1615, 0x1600, 0x40 }, /* U */
1160 { 0x1769, 0x1749, 0x1709, 0x1700, 0x40 }, /* I */
1161 { 0x186f, 0x184f, 0x180f, 0x1800, 0x40 }, /* O */
1162 { 0x1970, 0x1950, 0x1910, 0x1900, 0x40 }, /* P */
1163 { 0x1a5b, 0x1a7b, 0x1a1b, none, none }, /* [{ */
1164 { 0x1b5d, 0x1b7d, 0x1b1d, none, none }, /* ]} */
1165 { 0x1c0d, 0x1c0d, 0x1c0a, none, none }, /* Enter */
1166 { none, none, none, none, none }, /* L Ctrl */
1167 { 0x1e61, 0x1e41, 0x1e01, 0x1e00, 0x40 }, /* A */
1168 { 0x1f73, 0x1f53, 0x1f13, 0x1f00, 0x40 }, /* S */
1169 { 0x2064, 0x2044, 0x2004, 0x2000, 0x40 }, /* D */
1170 { 0x2166, 0x2146, 0x2106, 0x2100, 0x40 }, /* F */
1171 { 0x2267, 0x2247, 0x2207, 0x2200, 0x40 }, /* G */
1172 { 0x2368, 0x2348, 0x2308, 0x2300, 0x40 }, /* H */
1173 { 0x246a, 0x244a, 0x240a, 0x2400, 0x40 }, /* J */
1174 { 0x256b, 0x254b, 0x250b, 0x2500, 0x40 }, /* K */
1175 { 0x266c, 0x264c, 0x260c, 0x2600, 0x40 }, /* L */
1176 { 0x273b, 0x273a, none, none, none }, /* ;: */
1177 { 0x2827, 0x2822, none, none, none }, /* '" */
1178 { 0x2960, 0x297e, none, none, none }, /* `~ */
1179 { none, none, none, none, none }, /* L shift */
1180 { 0x2b5c, 0x2b7c, 0x2b1c, none, none }, /* |\ */
1181 { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, 0x40 }, /* Z */
1182 { 0x2d78, 0x2d58, 0x2d18, 0x2d00, 0x40 }, /* X */
1183 { 0x2e63, 0x2e43, 0x2e03, 0x2e00, 0x40 }, /* C */
1184 { 0x2f76, 0x2f56, 0x2f16, 0x2f00, 0x40 }, /* V */
1185 { 0x3062, 0x3042, 0x3002, 0x3000, 0x40 }, /* B */
1186 { 0x316e, 0x314e, 0x310e, 0x3100, 0x40 }, /* N */
1187 { 0x326d, 0x324d, 0x320d, 0x3200, 0x40 }, /* M */
1188 { 0x332c, 0x333c, none, none, none }, /* ,< */
1189 { 0x342e, 0x343e, none, none, none }, /* .> */
1190 { 0x352f, 0x353f, none, none, none }, /* /? */
1191 { none, none, none, none, none }, /* R Shift */
1192 { 0x372a, 0x372a, none, none, none }, /* * */
1193 { none, none, none, none, none }, /* L Alt */
1194 { 0x3920, 0x3920, 0x3920, 0x3920, none }, /* space */
1195 { none, none, none, none, none }, /* caps lock */
1196 { 0x3b00, 0x5400, 0x5e00, 0x6800, none }, /* F1 */
1197 { 0x3c00, 0x5500, 0x5f00, 0x6900, none }, /* F2 */
1198 { 0x3d00, 0x5600, 0x6000, 0x6a00, none }, /* F3 */
1199 { 0x3e00, 0x5700, 0x6100, 0x6b00, none }, /* F4 */
1200 { 0x3f00, 0x5800, 0x6200, 0x6c00, none }, /* F5 */
1201 { 0x4000, 0x5900, 0x6300, 0x6d00, none }, /* F6 */
1202 { 0x4100, 0x5a00, 0x6400, 0x6e00, none }, /* F7 */
1203 { 0x4200, 0x5b00, 0x6500, 0x6f00, none }, /* F8 */
1204 { 0x4300, 0x5c00, 0x6600, 0x7000, none }, /* F9 */
1205 { 0x4400, 0x5d00, 0x6700, 0x7100, none }, /* F10 */
1206 { none, none, none, none, none }, /* Num Lock */
1207 { none, none, none, none, none }, /* Scroll Lock */
1208 { 0x4700, 0x4737, 0x7700, none, 0x20 }, /* 7 Home */
1209 { 0x4800, 0x4838, none, none, 0x20 }, /* 8 UP */
1210 { 0x4900, 0x4939, 0x8400, none, 0x20 }, /* 9 PgUp */
1211 { 0x4a2d, 0x4a2d, none, none, none }, /* - */
1212 { 0x4b00, 0x4b34, 0x7300, none, 0x20 }, /* 4 Left */
1213 { 0x4c00, 0x4c35, none, none, 0x20 }, /* 5 */
1214 { 0x4d00, 0x4d36, 0x7400, none, 0x20 }, /* 6 Right */
1215 { 0x4e2b, 0x4e2b, none, none, none }, /* + */
1216 { 0x4f00, 0x4f31, 0x7500, none, 0x20 }, /* 1 End */
1217 { 0x5000, 0x5032, none, none, 0x20 }, /* 2 Down */
1218 { 0x5100, 0x5133, 0x7600, none, 0x20 }, /* 3 PgDn */
1219 { 0x5200, 0x5230, none, none, 0x20 }, /* 0 Ins */
1220 { 0x5300, 0x532e, none, none, 0x20 }, /* Del */
1221 { none, none, none, none, none },
1222 { none, none, none, none, none },
1223 { 0x565c, 0x567c, none, none, none }, /* \| */
1224#ifndef VBOX
1225 { 0x5700, 0x5700, none, none, none }, /* F11 */
1226 { 0x5800, 0x5800, none, none, none } /* F12 */
1227#else
1228 { 0x8500, 0x8700, 0x8900, 0x8b00, none }, /* F11 */
1229 { 0x8600, 0x8800, 0x8a00, 0x8c00, none } /* F12 */
1230#endif
1231 };
1232
1233 Bit8u
1234inb(port)
1235 Bit16u port;
1236{
1237ASM_START
1238 push bp
1239 mov bp, sp
1240
1241 push dx
1242 mov dx, 4[bp]
1243 in al, dx
1244 pop dx
1245
1246 pop bp
1247ASM_END
1248}
1249
1250#if BX_USE_ATADRV
1251 Bit16u
1252inw(port)
1253 Bit16u port;
1254{
1255ASM_START
1256 push bp
1257 mov bp, sp
1258
1259 push dx
1260 mov dx, 4[bp]
1261 in ax, dx
1262 pop dx
1263
1264 pop bp
1265ASM_END
1266}
1267#endif
1268
1269 void
1270outb(port, val)
1271 Bit16u port;
1272 Bit8u val;
1273{
1274ASM_START
1275 push bp
1276 mov bp, sp
1277
1278 push ax
1279 push dx
1280 mov dx, 4[bp]
1281 mov al, 6[bp]
1282 out dx, al
1283 pop dx
1284 pop ax
1285
1286 pop bp
1287ASM_END
1288}
1289
1290#if BX_USE_ATADRV
1291 void
1292outw(port, val)
1293 Bit16u port;
1294 Bit16u val;
1295{
1296ASM_START
1297 push bp
1298 mov bp, sp
1299
1300 push ax
1301 push dx
1302 mov dx, 4[bp]
1303 mov ax, 6[bp]
1304 out dx, ax
1305 pop dx
1306 pop ax
1307
1308 pop bp
1309ASM_END
1310}
1311#endif
1312
1313 void
1314outb_cmos(cmos_reg, val)
1315 Bit8u cmos_reg;
1316 Bit8u val;
1317{
1318ASM_START
1319 push bp
1320 mov bp, sp
1321
1322 mov al, 4[bp] ;; cmos_reg
1323 out 0x70, al
1324 mov al, 6[bp] ;; val
1325 out 0x71, al
1326
1327 pop bp
1328ASM_END
1329}
1330
1331 Bit8u
1332inb_cmos(cmos_reg)
1333 Bit8u cmos_reg;
1334{
1335ASM_START
1336 push bp
1337 mov bp, sp
1338
1339 mov al, 4[bp] ;; cmos_reg
1340 out 0x70, al
1341 in al, 0x71
1342
1343 pop bp
1344ASM_END
1345}
1346
1347 void
1348init_rtc()
1349{
1350 outb_cmos(0x0a, 0x26);
1351 outb_cmos(0x0b, 0x02);
1352 inb_cmos(0x0c);
1353 inb_cmos(0x0d);
1354}
1355
1356 bx_bool
1357rtc_updating()
1358{
1359 // This function checks to see if the update-in-progress bit
1360 // is set in CMOS Status Register A. If not, it returns 0.
1361 // If it is set, it tries to wait until there is a transition
1362 // to 0, and will return 0 if such a transition occurs. A 1
1363 // is returned only after timing out. The maximum period
1364 // that this bit should be set is constrained to 244useconds.
1365 // The count I use below guarantees coverage or more than
1366 // this time, with any reasonable IPS setting.
1367
1368 Bit16u count;
1369
1370 count = 25000;
1371 while (--count != 0) {
1372 if ( (inb_cmos(0x0a) & 0x80) == 0 )
1373 return(0);
1374 }
1375 return(1); // update-in-progress never transitioned to 0
1376}
1377
1378
1379 Bit8u
1380read_byte(seg, offset)
1381 Bit16u seg;
1382 Bit16u offset;
1383{
1384ASM_START
1385 push bp
1386 mov bp, sp
1387
1388 push bx
1389 push ds
1390 mov ax, 4[bp] ; segment
1391 mov ds, ax
1392 mov bx, 6[bp] ; offset
1393 mov al, [bx]
1394 ;; al = return value (byte)
1395 pop ds
1396 pop bx
1397
1398 pop bp
1399ASM_END
1400}
1401
1402 Bit16u
1403read_word(seg, offset)
1404 Bit16u seg;
1405 Bit16u offset;
1406{
1407ASM_START
1408 push bp
1409 mov bp, sp
1410
1411 push bx
1412 push ds
1413 mov ax, 4[bp] ; segment
1414 mov ds, ax
1415 mov bx, 6[bp] ; offset
1416 mov ax, [bx]
1417 ;; ax = return value (word)
1418 pop ds
1419 pop bx
1420
1421 pop bp
1422ASM_END
1423}
1424
1425 void
1426write_byte(seg, offset, data)
1427 Bit16u seg;
1428 Bit16u offset;
1429 Bit8u data;
1430{
1431ASM_START
1432 push bp
1433 mov bp, sp
1434
1435 push ax
1436 push bx
1437 push ds
1438 mov ax, 4[bp] ; segment
1439 mov ds, ax
1440 mov bx, 6[bp] ; offset
1441 mov al, 8[bp] ; data byte
1442 mov [bx], al ; write data byte
1443 pop ds
1444 pop bx
1445 pop ax
1446
1447 pop bp
1448ASM_END
1449}
1450
1451 void
1452write_word(seg, offset, data)
1453 Bit16u seg;
1454 Bit16u offset;
1455 Bit16u data;
1456{
1457ASM_START
1458 push bp
1459 mov bp, sp
1460
1461 push ax
1462 push bx
1463 push ds
1464 mov ax, 4[bp] ; segment
1465 mov ds, ax
1466 mov bx, 6[bp] ; offset
1467 mov ax, 8[bp] ; data word
1468 mov [bx], ax ; write data word
1469 pop ds
1470 pop bx
1471 pop ax
1472
1473 pop bp
1474ASM_END
1475}
1476
1477 Bit16u
1478get_CS()
1479{
1480ASM_START
1481 mov ax, cs
1482ASM_END
1483}
1484
1485 Bit16u
1486get_SS()
1487{
1488ASM_START
1489 mov ax, ss
1490ASM_END
1491}
1492
1493#if BX_DEBUG_SERIAL
1494/* serial debug port*/
1495#define BX_DEBUG_PORT 0x03f8
1496
1497/* data */
1498#define UART_RBR 0x00
1499#define UART_THR 0x00
1500
1501/* control */
1502#define UART_IER 0x01
1503#define UART_IIR 0x02
1504#define UART_FCR 0x02
1505#define UART_LCR 0x03
1506#define UART_MCR 0x04
1507#define UART_DLL 0x00
1508#define UART_DLM 0x01
1509
1510/* status */
1511#define UART_LSR 0x05
1512#define UART_MSR 0x06
1513#define UART_SCR 0x07
1514
1515int uart_can_tx_byte(base_port)
1516 Bit16u base_port;
1517{
1518 return inb(base_port + UART_LSR) & 0x20;
1519}
1520
1521void uart_wait_to_tx_byte(base_port)
1522 Bit16u base_port;
1523{
1524 while (!uart_can_tx_byte(base_port));
1525}
1526
1527void uart_wait_until_sent(base_port)
1528 Bit16u base_port;
1529{
1530 while (!(inb(base_port + UART_LSR) & 0x40));
1531}
1532
1533void uart_tx_byte(base_port, data)
1534 Bit16u base_port;
1535 Bit8u data;
1536{
1537 uart_wait_to_tx_byte(base_port);
1538 outb(base_port + UART_THR, data);
1539 uart_wait_until_sent(base_port);
1540}
1541#endif
1542
1543 void
1544wrch(c)
1545 Bit8u c;
1546{
1547 ASM_START
1548 push bp
1549 mov bp, sp
1550
1551 push bx
1552 mov ah, #0x0e
1553 mov al, 4[bp]
1554 xor bx,bx
1555 int #0x10
1556 pop bx
1557
1558 pop bp
1559 ASM_END
1560}
1561
1562 void
1563send(action, c)
1564 Bit16u action;
1565 Bit8u c;
1566{
1567#if BX_DEBUG_SERIAL
1568 if (c == '\n') uart_tx_byte(BX_DEBUG_PORT, '\r');
1569 uart_tx_byte(BX_DEBUG_PORT, c);
1570#endif
1571#if BX_VIRTUAL_PORTS
1572 if (action & BIOS_PRINTF_DEBUG) outb(DEBUG_PORT, c);
1573 if (action & BIOS_PRINTF_INFO) outb(INFO_PORT, c);
1574#endif
1575 if (action & BIOS_PRINTF_SCREEN) {
1576 if (c == '\n') wrch('\r');
1577 wrch(c);
1578 }
1579}
1580
1581 void
1582put_int(action, val, width, neg)
1583 Bit16u action;
1584 short val, width;
1585 bx_bool neg;
1586{
1587 short nval = val / 10;
1588 if (nval)
1589 put_int(action, nval, width - 1, neg);
1590 else {
1591 while (--width > 0) send(action, ' ');
1592 if (neg) send(action, '-');
1593 }
1594 send(action, val - (nval * 10) + '0');
1595}
1596
1597 void
1598put_uint(action, val, width, neg)
1599 Bit16u action;
1600 unsigned short val;
1601 short width;
1602 bx_bool neg;
1603{
1604 unsigned short nval = val / 10;
1605 if (nval)
1606 put_uint(action, nval, width - 1, neg);
1607 else {
1608 while (--width > 0) send(action, ' ');
1609 if (neg) send(action, '-');
1610 }
1611 send(action, val - (nval * 10) + '0');
1612}
1613
1614 void
1615put_luint(action, val, width, neg)
1616 Bit16u action;
1617 unsigned long val;
1618 short width;
1619 bx_bool neg;
1620{
1621 unsigned long nval = val / 10;
1622 if (nval)
1623 put_luint(action, nval, width - 1, neg);
1624 else {
1625 while (--width > 0) send(action, ' ');
1626 if (neg) send(action, '-');
1627 }
1628 send(action, val - (nval * 10) + '0');
1629}
1630
1631void put_str(action, segment, offset)
1632 Bit16u action;
1633 Bit16u segment;
1634 Bit16u offset;
1635{
1636 Bit8u c;
1637
1638 while (c = read_byte(segment, offset)) {
1639 send(action, c);
1640 offset++;
1641 }
1642}
1643
1644
1645//--------------------------------------------------------------------------
1646// bios_printf()
1647// A compact variable argument printf function.
1648//
1649// Supports %[format_width][length]format
1650// where format can be x,X,u,d,s,S,c
1651// and the optional length modifier is l (ell)
1652//--------------------------------------------------------------------------
1653 void
1654bios_printf(action, s)
1655 Bit16u action;
1656 Bit8u *s;
1657{
1658 Bit8u c, format_char;
1659 bx_bool in_format;
1660 short i;
1661 Bit16u *arg_ptr;
1662 Bit16u arg_seg, arg, nibble, hibyte, shift_count, format_width, hexadd;
1663
1664 arg_ptr = &s;
1665 arg_seg = get_SS();
1666
1667 in_format = 0;
1668 format_width = 0;
1669
1670 if ((action & BIOS_PRINTF_DEBHALT) == BIOS_PRINTF_DEBHALT) {
1671#if BX_VIRTUAL_PORTS
1672 outb(PANIC_PORT2, 0x00);
1673#endif
1674 bios_printf (BIOS_PRINTF_SCREEN, "FATAL: ");
1675 }
1676
1677 while (c = read_byte(get_CS(), s)) {
1678 if ( c == '%' ) {
1679 in_format = 1;
1680 format_width = 0;
1681 }
1682 else if (in_format) {
1683 if ( (c>='0') && (c<='9') ) {
1684 format_width = (format_width * 10) + (c - '0');
1685 }
1686 else {
1687 arg_ptr++; // increment to next arg
1688 arg = read_word(arg_seg, arg_ptr);
1689 if (c == 'x' || c == 'X') {
1690 if (format_width == 0)
1691 format_width = 4;
1692 if (c == 'x')
1693 hexadd = 'a';
1694 else
1695 hexadd = 'A';
1696 for (i=format_width-1; i>=0; i--) {
1697 nibble = (arg >> (4 * i)) & 0x000f;
1698 send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd));
1699 }
1700 }
1701 else if (c == 'u') {
1702 put_uint(action, arg, format_width, 0);
1703 }
1704 else if (c == 'l') {
1705 s++;
1706 c = read_byte(get_CS(), s); /* is it ld,lx,lu? */
1707 arg_ptr++; /* increment to next arg */
1708 hibyte = read_word(arg_seg, arg_ptr);
1709 if (c == 'd') {
1710 if (hibyte & 0x8000)
1711 put_luint(action, 0L-(((Bit32u) hibyte << 16) | arg), format_width-1, 1);
1712 else
1713 put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
1714 }
1715 else if (c == 'u') {
1716 put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
1717 }
1718 else if (c == 'x' || c == 'X')
1719 {
1720 if (format_width == 0)
1721 format_width = 8;
1722 if (c == 'x')
1723 hexadd = 'a';
1724 else
1725 hexadd = 'A';
1726 for (i=format_width-1; i>=0; i--) {
1727 nibble = ((((Bit32u) hibyte <<16) | arg) >> (4 * i)) & 0x000f;
1728 send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd));
1729 }
1730 }
1731 }
1732 else if (c == 'd') {
1733 if (arg & 0x8000)
1734 put_int(action, -arg, format_width - 1, 1);
1735 else
1736 put_int(action, arg, format_width, 0);
1737 }
1738 else if (c == 's') {
1739 put_str(action, get_CS(), arg);
1740 }
1741 else if (c == 'S') {
1742 hibyte = arg;
1743 arg_ptr++;
1744 arg = read_word(arg_seg, arg_ptr);
1745 put_str(action, hibyte, arg);
1746 }
1747 else if (c == 'c') {
1748 send(action, arg);
1749 }
1750 else
1751 BX_PANIC("bios_printf: unknown format\n");
1752 in_format = 0;
1753 }
1754 }
1755 else {
1756 send(action, c);
1757 }
1758 s ++;
1759 }
1760
1761 if (action & BIOS_PRINTF_HALT) {
1762 // freeze in a busy loop.
1763ASM_START
1764 cli
1765 halt2_loop:
1766 hlt
1767 jmp halt2_loop
1768ASM_END
1769 }
1770}
1771
1772//--------------------------------------------------------------------------
1773// keyboard_init
1774//--------------------------------------------------------------------------
1775// this file is based on LinuxBIOS implementation of keyboard.c
1776// could convert to #asm to gain space
1777 void
1778keyboard_init()
1779{
1780 Bit16u max;
1781
1782 /* ------------------- Flush buffers ------------------------*/
1783 /* Wait until buffer is empty */
1784 max=0xffff;
1785 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
1786
1787 /* flush incoming keys */
1788 max=0x2000;
1789 while (--max > 0) {
1790 outb(0x80, 0x00);
1791 if (inb(0x64) & 0x01) {
1792 inb(0x60);
1793 max = 0x2000;
1794 }
1795 }
1796
1797 // Due to timer issues, and if the IPS setting is > 15000000,
1798 // the incoming keys might not be flushed here. That will
1799 // cause a panic a few lines below. See sourceforge bug report :
1800 // [ 642031 ] FATAL: Keyboard RESET error:993
1801
1802 /* ------------------- controller side ----------------------*/
1803 /* send cmd = 0xAA, self test 8042 */
1804 outb(0x64, 0xaa);
1805
1806 /* Wait until buffer is empty */
1807 max=0xffff;
1808 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
1809 if (max==0x0) keyboard_panic(00);
1810
1811 /* Wait for data */
1812 max=0xffff;
1813 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x01);
1814 if (max==0x0) keyboard_panic(01);
1815
1816 /* read self-test result, 0x55 should be returned from 0x60 */
1817 if ((inb(0x60) != 0x55)){
1818 keyboard_panic(991);
1819 }
1820
1821 /* send cmd = 0xAB, keyboard interface test */
1822 outb(0x64,0xab);
1823
1824 /* Wait until buffer is empty */
1825 max=0xffff;
1826 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x10);
1827 if (max==0x0) keyboard_panic(10);
1828
1829 /* Wait for data */
1830 max=0xffff;
1831 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x11);
1832 if (max==0x0) keyboard_panic(11);
1833
1834 /* read keyboard interface test result, */
1835 /* 0x00 should be returned form 0x60 */
1836 if ((inb(0x60) != 0x00)) {
1837 keyboard_panic(992);
1838 }
1839
1840 /* Enable Keyboard clock */
1841 outb(0x64,0xae);
1842 outb(0x64,0xa8);
1843
1844 /* ------------------- keyboard side ------------------------*/
1845 /* reset keyboard and self test (keyboard side) */
1846 outb(0x60, 0xff);
1847
1848 /* Wait until buffer is empty */
1849 max=0xffff;
1850 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x20);
1851 if (max==0x0) keyboard_panic(20);
1852
1853 /* Wait for data */
1854 max=0xffff;
1855 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x21);
1856 if (max==0x0) keyboard_panic(21);
1857
1858 /* keyboard should return ACK */
1859 if ((inb(0x60) != 0xfa)) {
1860 keyboard_panic(993);
1861 }
1862
1863 /* Wait for data */
1864 max=0xffff;
1865 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x31);
1866 if (max==0x0) keyboard_panic(31);
1867
1868 if ((inb(0x60) != 0xaa)) {
1869 keyboard_panic(994);
1870 }
1871
1872 /* Disable keyboard */
1873 outb(0x60, 0xf5);
1874
1875 /* Wait until buffer is empty */
1876 max=0xffff;
1877 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x40);
1878 if (max==0x0) keyboard_panic(40);
1879
1880 /* Wait for data */
1881 max=0xffff;
1882 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x41);
1883 if (max==0x0) keyboard_panic(41);
1884
1885 /* keyboard should return ACK */
1886 if ((inb(0x60) != 0xfa)) {
1887 keyboard_panic(995);
1888 }
1889
1890 /* Write Keyboard Mode */
1891 outb(0x64, 0x60);
1892
1893 /* Wait until buffer is empty */
1894 max=0xffff;
1895 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x50);
1896 if (max==0x0) keyboard_panic(50);
1897
1898 /* send cmd: scan code convert, disable mouse, enable IRQ 1 */
1899 outb(0x60, 0x65);
1900
1901 /* Wait until buffer is empty */
1902 max=0xffff;
1903 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x60);
1904 if (max==0x0) keyboard_panic(60);
1905
1906 /* Enable keyboard */
1907 outb(0x60, 0xf4);
1908
1909 /* Wait until buffer is empty */
1910 max=0xffff;
1911 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x70);
1912 if (max==0x0) keyboard_panic(70);
1913
1914 /* Wait for data */
1915 max=0xffff;
1916 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x71);
1917 if (max==0x0) keyboard_panic(70);
1918
1919 /* keyboard should return ACK */
1920 if ((inb(0x60) != 0xfa)) {
1921 keyboard_panic(996);
1922 }
1923
1924 outb(0x80, 0x77);
1925}
1926
1927//--------------------------------------------------------------------------
1928// keyboard_panic
1929//--------------------------------------------------------------------------
1930 void
1931keyboard_panic(status)
1932 Bit16u status;
1933{
1934 // If you're getting a 993 keyboard panic here,
1935 // please see the comment in keyboard_init
1936
1937 BX_PANIC("Keyboard error:%u\n",status);
1938}
1939
1940//--------------------------------------------------------------------------
1941// shutdown_status_panic
1942// called when the shutdown status is not implemented, displays the status
1943//--------------------------------------------------------------------------
1944 void
1945shutdown_status_panic(status)
1946 Bit16u status;
1947{
1948 BX_PANIC("Unimplemented shutdown status: %02x\n",(Bit8u)status);
1949}
1950
1951#ifdef VBOX
1952#include "logo.c"
1953#endif /* VBOX */
1954
1955//--------------------------------------------------------------------------
1956// print_bios_banner
1957// displays a the bios version
1958//--------------------------------------------------------------------------
1959void
1960print_bios_banner()
1961{
1962#ifdef VBOX
1963 // Skip the logo if a warm boot is requested.
1964 Bit16u warm_boot = read_word(0x0040,0x0072);
1965 write_word(0x0040,0x0072, 0);
1966 if (warm_boot == 0x1234)
1967 return;
1968 /* show graphical logo */
1969 show_logo();
1970#else /* !VBOX */
1971 printf(BX_APPNAME" BIOS - build: %s\n%s\nOptions: ",
1972 BIOS_BUILD_DATE, bios_cvs_version_string);
1973 printf(
1974#if BX_APM
1975 "apmbios "
1976#endif
1977#if BX_PCIBIOS
1978 "pcibios "
1979#endif
1980#if BX_ELTORITO_BOOT
1981 "eltorito "
1982#endif
1983#if BX_ROMBIOS32
1984 "rombios32 "
1985#endif
1986 "\n\n");
1987#endif /* VBOX */
1988}
1989
1990//--------------------------------------------------------------------------
1991// print_boot_device
1992// displays the boot device
1993//--------------------------------------------------------------------------
1994
1995#ifdef VBOX
1996static char drivetypes[][10]={"Floppy","Hard Disk","CD-ROM","LAN"};
1997#else /* !VBOX */
1998static char drivetypes[][10]={"Floppy","Hard Disk","CD-Rom"};
1999#endif /* !VBOX */
2000
2001#ifdef VBOX
2002void
2003print_boot_device(cdboot, lanboot, drive)
2004 Bit8u cdboot; Bit8u lanboot; Bit16u drive;
2005#else /* !VBOX */
2006void
2007print_boot_device(cdboot, drive)
2008 Bit8u cdboot; Bit16u drive;
2009#endif /* !VBOX */
2010{
2011 Bit8u i;
2012
2013#ifdef VBOX
2014 // cdboot contains 0 if lan/floppy/harddisk, 1 otherwise
2015 // lanboot contains 0 if floppy/harddisk, 1 otherwise
2016#else /* !VBOX */
2017 // cdboot contains 0 if floppy/harddisk, 1 otherwise
2018#endif /* !VBOX */
2019 // drive contains real/emulated boot drive
2020
2021 if(cdboot)i=2; // CD-Rom
2022#ifdef VBOX
2023 else if(lanboot)i=3; // LAN
2024#endif /* VBOX */
2025 else if((drive&0x0080)==0x00)i=0; // Floppy
2026 else if((drive&0x0080)==0x80)i=1; // Hard drive
2027 else return;
2028
2029#ifdef VBOX
2030 BX_INFO("Booting from %s...\n",drivetypes[i]);
2031#else /* !VBOX */
2032 printf("Booting from %s...\n",drivetypes[i]);
2033#endif /* !VBOX */
2034}
2035
2036//--------------------------------------------------------------------------
2037// print_boot_failure
2038// displays the reason why boot failed
2039//--------------------------------------------------------------------------
2040#ifdef VBOX
2041 void
2042print_boot_failure(cdboot, lanboot, drive, reason, lastdrive)
2043 Bit8u cdboot; Bit8u lanboot; Bit8u drive; Bit8u reason; Bit8u lastdrive;
2044#else /* !VBOX */
2045 void
2046print_boot_failure(cdboot, drive, reason, lastdrive)
2047 Bit8u cdboot; Bit8u drive; Bit8u lastdrive;
2048#endif /* !VBOX */
2049{
2050 Bit16u drivenum = drive&0x7f;
2051
2052 // cdboot: 1 if boot from cd, 0 otherwise
2053#ifdef VBOX
2054 // lanboot: 1 if boot from lan, 0 otherwise
2055#endif /* VBOX */
2056 // drive : drive number
2057 // reason: 0 signature check failed, 1 read error
2058 // lastdrive: 1 boot drive is the last one in boot sequence
2059
2060 if (cdboot)
2061#ifndef VBOX
2062 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s failed\n",drivetypes[2]);
2063#else /* VBOX */
2064 BX_INFO("Boot from %s failed\n",drivetypes[2]);
2065 else if (lanboot)
2066 BX_INFO("Boot from %s failed\n",drivetypes[3]);
2067#endif /* VBOX */
2068 else if (drive & 0x80)
2069#ifndef VBOX
2070 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[1],drivenum);
2071#else /* VBOX */
2072 BX_INFO("Boot from %s %d failed\n", drivetypes[1],drivenum);
2073#endif /* VBOX */
2074 else
2075#ifndef VBOX
2076 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[0],drivenum);
2077#else /* VBOX */
2078 BX_INFO("Boot from %s %d failed\n", drivetypes[0],drivenum);
2079#endif /* VBOX */
2080
2081 if (lastdrive==1) {
2082 if (reason==0)
2083#ifndef VBOX
2084 BX_PANIC("Not a bootable disk\n");
2085#else /* VBOX */
2086 BX_PANIC("No bootable medium found! System halted.\n");
2087#endif /* VBOX */
2088 else
2089#ifndef VBOX
2090 BX_PANIC("Could not read the boot disk\n");
2091#else /* VBOX */
2092 BX_PANIC("Could not read from the boot medium! System halted.\n");
2093#endif /* VBOX */
2094 }
2095}
2096
2097//--------------------------------------------------------------------------
2098// print_cdromboot_failure
2099// displays the reason why boot failed
2100//--------------------------------------------------------------------------
2101 void
2102print_cdromboot_failure( code )
2103 Bit16u code;
2104{
2105#ifndef VBOX
2106 bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "CDROM boot failure code : %04x\n",code);
2107#else /* VBOX */
2108 BX_INFO("CDROM boot failure code : %04x\n",code);
2109#endif /* VBOX */
2110
2111 return;
2112}
2113
2114void
2115nmi_handler_msg()
2116{
2117 BX_PANIC("NMI Handler called\n");
2118}
2119
2120void
2121int18_panic_msg()
2122{
2123 BX_PANIC("INT18: BOOT FAILURE\n");
2124}
2125
2126void
2127log_bios_start()
2128{
2129#if BX_DEBUG_SERIAL
2130 outb(BX_DEBUG_PORT+UART_LCR, 0x03); /* setup for serial logging: 8N1 */
2131#endif
2132 BX_INFO("%s\n", bios_cvs_version_string);
2133}
2134
2135 bx_bool
2136set_enable_a20(val)
2137 bx_bool val;
2138{
2139 Bit8u oldval;
2140
2141 // Use PS2 System Control port A to set A20 enable
2142
2143 // get current setting first
2144 oldval = inb(0x92);
2145
2146 // change A20 status
2147 if (val)
2148 outb(0x92, oldval | 0x02);
2149 else
2150 outb(0x92, oldval & 0xfd);
2151
2152 return((oldval & 0x02) != 0);
2153}
2154
2155 void
2156debugger_on()
2157{
2158 outb(0xfedc, 0x01);
2159}
2160
2161 void
2162debugger_off()
2163{
2164 outb(0xfedc, 0x00);
2165}
2166
2167#if BX_USE_ATADRV
2168
2169// ---------------------------------------------------------------------------
2170// Start of ATA/ATAPI Driver
2171// ---------------------------------------------------------------------------
2172
2173// Global defines -- ATA register and register bits.
2174// command block & control block regs
2175#define ATA_CB_DATA 0 // data reg in/out pio_base_addr1+0
2176#define ATA_CB_ERR 1 // error in pio_base_addr1+1
2177#define ATA_CB_FR 1 // feature reg out pio_base_addr1+1
2178#define ATA_CB_SC 2 // sector count in/out pio_base_addr1+2
2179#define ATA_CB_SN 3 // sector number in/out pio_base_addr1+3
2180#define ATA_CB_CL 4 // cylinder low in/out pio_base_addr1+4
2181#define ATA_CB_CH 5 // cylinder high in/out pio_base_addr1+5
2182#define ATA_CB_DH 6 // device head in/out pio_base_addr1+6
2183#define ATA_CB_STAT 7 // primary status in pio_base_addr1+7
2184#define ATA_CB_CMD 7 // command out pio_base_addr1+7
2185#define ATA_CB_ASTAT 6 // alternate status in pio_base_addr2+6
2186#define ATA_CB_DC 6 // device control out pio_base_addr2+6
2187#define ATA_CB_DA 7 // device address in pio_base_addr2+7
2188
2189#define ATA_CB_ER_ICRC 0x80 // ATA Ultra DMA bad CRC
2190#define ATA_CB_ER_BBK 0x80 // ATA bad block
2191#define ATA_CB_ER_UNC 0x40 // ATA uncorrected error
2192#define ATA_CB_ER_MC 0x20 // ATA media change
2193#define ATA_CB_ER_IDNF 0x10 // ATA id not found
2194#define ATA_CB_ER_MCR 0x08 // ATA media change request
2195#define ATA_CB_ER_ABRT 0x04 // ATA command aborted
2196#define ATA_CB_ER_NTK0 0x02 // ATA track 0 not found
2197#define ATA_CB_ER_NDAM 0x01 // ATA address mark not found
2198
2199#define ATA_CB_ER_P_SNSKEY 0xf0 // ATAPI sense key (mask)
2200#define ATA_CB_ER_P_MCR 0x08 // ATAPI Media Change Request
2201#define ATA_CB_ER_P_ABRT 0x04 // ATAPI command abort
2202#define ATA_CB_ER_P_EOM 0x02 // ATAPI End of Media
2203#define ATA_CB_ER_P_ILI 0x01 // ATAPI Illegal Length Indication
2204
2205// ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC)
2206#define ATA_CB_SC_P_TAG 0xf8 // ATAPI tag (mask)
2207#define ATA_CB_SC_P_REL 0x04 // ATAPI release
2208#define ATA_CB_SC_P_IO 0x02 // ATAPI I/O
2209#define ATA_CB_SC_P_CD 0x01 // ATAPI C/D
2210
2211// bits 7-4 of the device/head (CB_DH) reg
2212#define ATA_CB_DH_DEV0 0xa0 // select device 0
2213#define ATA_CB_DH_DEV1 0xb0 // select device 1
2214
2215// status reg (CB_STAT and CB_ASTAT) bits
2216#define ATA_CB_STAT_BSY 0x80 // busy
2217#define ATA_CB_STAT_RDY 0x40 // ready
2218#define ATA_CB_STAT_DF 0x20 // device fault
2219#define ATA_CB_STAT_WFT 0x20 // write fault (old name)
2220#define ATA_CB_STAT_SKC 0x10 // seek complete
2221#define ATA_CB_STAT_SERV 0x10 // service
2222#define ATA_CB_STAT_DRQ 0x08 // data request
2223#define ATA_CB_STAT_CORR 0x04 // corrected
2224#define ATA_CB_STAT_IDX 0x02 // index
2225#define ATA_CB_STAT_ERR 0x01 // error (ATA)
2226#define ATA_CB_STAT_CHK 0x01 // check (ATAPI)
2227
2228// device control reg (CB_DC) bits
2229#define ATA_CB_DC_HD15 0x08 // bit should always be set to one
2230#define ATA_CB_DC_SRST 0x04 // soft reset
2231#define ATA_CB_DC_NIEN 0x02 // disable interrupts
2232
2233// Most mandatory and optional ATA commands (from ATA-3),
2234#define ATA_CMD_CFA_ERASE_SECTORS 0xC0
2235#define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03
2236#define ATA_CMD_CFA_TRANSLATE_SECTOR 0x87
2237#define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD
2238#define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38
2239#define ATA_CMD_CHECK_POWER_MODE1 0xE5
2240#define ATA_CMD_CHECK_POWER_MODE2 0x98
2241#define ATA_CMD_DEVICE_RESET 0x08
2242#define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90
2243#define ATA_CMD_FLUSH_CACHE 0xE7
2244#define ATA_CMD_FORMAT_TRACK 0x50
2245#define ATA_CMD_IDENTIFY_DEVICE 0xEC
2246#define ATA_CMD_IDENTIFY_DEVICE_PACKET 0xA1
2247#define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xA1
2248#define ATA_CMD_IDLE1 0xE3
2249#define ATA_CMD_IDLE2 0x97
2250#define ATA_CMD_IDLE_IMMEDIATE1 0xE1
2251#define ATA_CMD_IDLE_IMMEDIATE2 0x95
2252#define ATA_CMD_INITIALIZE_DRIVE_PARAMETERS 0x91
2253#define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
2254#define ATA_CMD_NOP 0x00
2255#define ATA_CMD_PACKET 0xA0
2256#define ATA_CMD_READ_BUFFER 0xE4
2257#define ATA_CMD_READ_DMA 0xC8
2258#define ATA_CMD_READ_DMA_QUEUED 0xC7
2259#define ATA_CMD_READ_MULTIPLE 0xC4
2260#define ATA_CMD_READ_SECTORS 0x20
2261#ifdef VBOX
2262#define ATA_CMD_READ_SECTORS_EXT 0x24
2263#endif /* VBOX */
2264#define ATA_CMD_READ_VERIFY_SECTORS 0x40
2265#define ATA_CMD_RECALIBRATE 0x10
2266#define ATA_CMD_SEEK 0x70
2267#define ATA_CMD_SET_FEATURES 0xEF
2268#define ATA_CMD_SET_MULTIPLE_MODE 0xC6
2269#define ATA_CMD_SLEEP1 0xE6
2270#define ATA_CMD_SLEEP2 0x99
2271#define ATA_CMD_STANDBY1 0xE2
2272#define ATA_CMD_STANDBY2 0x96
2273#define ATA_CMD_STANDBY_IMMEDIATE1 0xE0
2274#define ATA_CMD_STANDBY_IMMEDIATE2 0x94
2275#define ATA_CMD_WRITE_BUFFER 0xE8
2276#define ATA_CMD_WRITE_DMA 0xCA
2277#define ATA_CMD_WRITE_DMA_QUEUED 0xCC
2278#define ATA_CMD_WRITE_MULTIPLE 0xC5
2279#define ATA_CMD_WRITE_SECTORS 0x30
2280#ifdef VBOX
2281#define ATA_CMD_WRITE_SECTORS_EXT 0x34
2282#endif /* VBOX */
2283#define ATA_CMD_WRITE_VERIFY 0x3C
2284
2285#define ATA_IFACE_NONE 0x00
2286#define ATA_IFACE_ISA 0x00
2287#define ATA_IFACE_PCI 0x01
2288
2289#define ATA_TYPE_NONE 0x00
2290#define ATA_TYPE_UNKNOWN 0x01
2291#define ATA_TYPE_ATA 0x02
2292#define ATA_TYPE_ATAPI 0x03
2293#ifdef VBOX
2294#define ATA_TYPE_SCSI 0x04 // SCSI disk
2295#endif
2296
2297#define ATA_DEVICE_NONE 0x00
2298#define ATA_DEVICE_HD 0xFF
2299#define ATA_DEVICE_CDROM 0x05
2300
2301#define ATA_MODE_NONE 0x00
2302#define ATA_MODE_PIO16 0x00
2303#define ATA_MODE_PIO32 0x01
2304#define ATA_MODE_ISADMA 0x02
2305#define ATA_MODE_PCIDMA 0x03
2306#define ATA_MODE_USEIRQ 0x10
2307
2308#define ATA_TRANSLATION_NONE 0
2309#define ATA_TRANSLATION_LBA 1
2310#define ATA_TRANSLATION_LARGE 2
2311#define ATA_TRANSLATION_RECHS 3
2312
2313#define ATA_DATA_NO 0x00
2314#define ATA_DATA_IN 0x01
2315#define ATA_DATA_OUT 0x02
2316
2317// ---------------------------------------------------------------------------
2318// ATA/ATAPI driver : initialization
2319// ---------------------------------------------------------------------------
2320void ata_init( )
2321{
2322 Bit16u ebda_seg=read_word(0x0040,0x000E);
2323 Bit8u channel, device;
2324
2325 // Channels info init.
2326 for (channel=0; channel<BX_MAX_ATA_INTERFACES; channel++) {
2327 write_byte(ebda_seg,&EbdaData->ata.channels[channel].iface,ATA_IFACE_NONE);
2328 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1,0x0);
2329 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2,0x0);
2330 write_byte(ebda_seg,&EbdaData->ata.channels[channel].irq,0);
2331 }
2332
2333 // Devices info init.
2334 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2335 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
2336 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_NONE);
2337 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable,0);
2338 write_byte(ebda_seg,&EbdaData->ata.devices[device].lock,0);
2339 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode,ATA_MODE_NONE);
2340 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,0);
2341 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation,ATA_TRANSLATION_NONE);
2342 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads,0);
2343 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders,0);
2344 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt,0);
2345 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads,0);
2346 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders,0);
2347 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt,0);
2348
2349 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors,0L);
2350 }
2351
2352 // hdidmap and cdidmap init.
2353 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2354 write_byte(ebda_seg,&EbdaData->ata.hdidmap[device],BX_MAX_STORAGE_DEVICES);
2355 write_byte(ebda_seg,&EbdaData->ata.cdidmap[device],BX_MAX_STORAGE_DEVICES);
2356 }
2357
2358 write_byte(ebda_seg,&EbdaData->ata.hdcount,0);
2359 write_byte(ebda_seg,&EbdaData->ata.cdcount,0);
2360}
2361
2362// ---------------------------------------------------------------------------
2363// ATA/ATAPI driver : device detection
2364// ---------------------------------------------------------------------------
2365
2366void ata_detect( )
2367{
2368 Bit16u ebda_seg=read_word(0x0040,0x000E);
2369 Bit8u hdcount, cdcount, device, type;
2370 Bit8u buffer[0x0200];
2371
2372#if BX_MAX_ATA_INTERFACES > 0
2373 write_byte(ebda_seg,&EbdaData->ata.channels[0].iface,ATA_IFACE_ISA);
2374 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase1,0x1f0);
2375 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase2,0x3f0);
2376 write_byte(ebda_seg,&EbdaData->ata.channels[0].irq,14);
2377#endif
2378#if BX_MAX_ATA_INTERFACES > 1
2379 write_byte(ebda_seg,&EbdaData->ata.channels[1].iface,ATA_IFACE_ISA);
2380 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase1,0x170);
2381 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase2,0x370);
2382 write_byte(ebda_seg,&EbdaData->ata.channels[1].irq,15);
2383#endif
2384#if BX_MAX_ATA_INTERFACES > 2
2385 write_byte(ebda_seg,&EbdaData->ata.channels[2].iface,ATA_IFACE_ISA);
2386 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase1,0x1e8);
2387 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase2,0x3e0);
2388 write_byte(ebda_seg,&EbdaData->ata.channels[2].irq,12);
2389#endif
2390#if BX_MAX_ATA_INTERFACES > 3
2391 write_byte(ebda_seg,&EbdaData->ata.channels[3].iface,ATA_IFACE_ISA);
2392 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase1,0x168);
2393 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase2,0x360);
2394 write_byte(ebda_seg,&EbdaData->ata.channels[3].irq,11);
2395#endif
2396#if BX_MAX_ATA_INTERFACES > 4
2397#error Please fill the ATA interface informations
2398#endif
2399
2400 // Device detection
2401 hdcount=cdcount=0;
2402
2403 for(device=0; device<BX_MAX_ATA_DEVICES; device++) {
2404 Bit16u iobase1, iobase2;
2405 Bit8u channel, slave, shift;
2406 Bit8u sc, sn, cl, ch, st;
2407
2408 channel = device / 2;
2409 slave = device % 2;
2410
2411 iobase1 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1);
2412 iobase2 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2);
2413
2414 // Disable interrupts
2415 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2416
2417 // Look for device
2418 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2419 outb(iobase1+ATA_CB_SC, 0x55);
2420 outb(iobase1+ATA_CB_SN, 0xaa);
2421 outb(iobase1+ATA_CB_SC, 0xaa);
2422 outb(iobase1+ATA_CB_SN, 0x55);
2423 outb(iobase1+ATA_CB_SC, 0x55);
2424 outb(iobase1+ATA_CB_SN, 0xaa);
2425
2426 // If we found something
2427 sc = inb(iobase1+ATA_CB_SC);
2428 sn = inb(iobase1+ATA_CB_SN);
2429
2430 if ( (sc == 0x55) && (sn == 0xaa) ) {
2431 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_UNKNOWN);
2432
2433 // reset the channel
2434 ata_reset(device);
2435
2436 // check for ATA or ATAPI
2437 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2438 sc = inb(iobase1+ATA_CB_SC);
2439 sn = inb(iobase1+ATA_CB_SN);
2440 if ((sc==0x01) && (sn==0x01)) {
2441 cl = inb(iobase1+ATA_CB_CL);
2442 ch = inb(iobase1+ATA_CB_CH);
2443 st = inb(iobase1+ATA_CB_STAT);
2444
2445 if ((cl==0x14) && (ch==0xeb)) {
2446 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATAPI);
2447 } else if ((cl==0x00) && (ch==0x00) && (st!=0x00)) {
2448 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATA);
2449 } else if ((cl==0xff) && (ch==0xff)) {
2450 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
2451 }
2452 }
2453 }
2454
2455#ifdef VBOX
2456 // Enable interrupts
2457 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2458#endif /* VBOX */
2459
2460 type=read_byte(ebda_seg,&EbdaData->ata.devices[device].type);
2461
2462 // Now we send a IDENTIFY command to ATA device
2463 if(type == ATA_TYPE_ATA) {
2464 Bit32u sectors;
2465 Bit16u cylinders, heads, spt, blksize;
2466#ifdef VBOX
2467 Bit16u lcylinders, lheads, lspt;
2468 Bit8u chsgeo_base;
2469#endif /* VBOX */
2470 Bit8u translation, removable, mode;
2471
2472 //Temporary values to do the transfer
2473 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2474 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2475
2476 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE, 1, 0, 0, 0, 0L, get_SS(),buffer) !=0 )
2477 BX_PANIC("ata-detect: Failed to detect ATA device\n");
2478
2479 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2480 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2481#ifdef VBOX
2482 blksize = 512; /* There is no sector size field any more. */
2483#else /* !VBOX */
2484 blksize = read_word(get_SS(),buffer+10);
2485#endif /* !VBOX */
2486
2487 cylinders = read_word(get_SS(),buffer+(1*2)); // word 1
2488 heads = read_word(get_SS(),buffer+(3*2)); // word 3
2489 spt = read_word(get_SS(),buffer+(6*2)); // word 6
2490
2491 sectors = read_dword(get_SS(),buffer+(60*2)); // word 60 and word 61
2492#ifdef VBOX
2493 /** @todo update sectors to be a 64 bit number (also lba...). */
2494 if (sectors == 268435455)
2495 sectors = read_dword(get_SS(),buffer+(100*2)); // words 100 to 103 (someday)
2496 switch (device)
2497 {
2498 case 0:
2499 chsgeo_base = 0x1e;
2500 break;
2501 case 1:
2502 chsgeo_base = 0x26;
2503 break;
2504 case 2:
2505 chsgeo_base = 0x67;
2506 break;
2507 case 3:
2508 chsgeo_base = 0x70;
2509 break;
2510 case 4:
2511 chsgeo_base = 0x40;
2512 break;
2513 case 5:
2514 chsgeo_base = 0x48;
2515 break;
2516 case 6:
2517 chsgeo_base = 0x50;
2518 break;
2519 case 7:
2520 chsgeo_base = 0x58;
2521 break;
2522 default:
2523 chsgeo_base = 0;
2524 }
2525 if (chsgeo_base != 0)
2526 {
2527 lcylinders = inb_cmos(chsgeo_base) + (inb_cmos(chsgeo_base+1) << 8);
2528 lheads = inb_cmos(chsgeo_base+2);
2529 lspt = inb_cmos(chsgeo_base+7);
2530 }
2531 else
2532 {
2533 lcylinders = 0;
2534 lheads = 0;
2535 lspt = 0;
2536 }
2537 BX_INFO("ata%d-%d: PCHS=%u/%d/%d LCHS=%u/%u/%u\n", channel, slave, cylinders, heads, spt, lcylinders, lheads, lspt);
2538#endif /* VBOX */
2539
2540 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2541 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2542 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2543 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2544 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads, heads);
2545 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders, cylinders);
2546 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt, spt);
2547 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors, sectors);
2548#ifdef VBOX
2549 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, lheads);
2550 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, lcylinders);
2551 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, lspt);
2552 if (device < 2)
2553 {
2554 Bit8u sum, i;
2555 unsigned char *fdpt;
2556 if (device == 0)
2557 fdpt = &EbdaData->fdpt0;
2558 else
2559 fdpt = &EbdaData->fdpt1;
2560
2561 /* Update the DPT for drive 0/1 pointed to by Int41/46. This used
2562 * to be done at POST time with lots of ugly assembler code, which
2563 * isn't worth the effort of converting from AMI to Award CMOS
2564 * format. Just do it here. */
2565 write_word(ebda_seg, fdpt + 0x00, lcylinders);
2566 write_byte(ebda_seg, fdpt + 0x02, lheads);
2567 write_byte(ebda_seg, fdpt + 0x0e, lspt);
2568 write_word(ebda_seg, fdpt + 0x09, cylinders);
2569 write_byte(ebda_seg, fdpt + 0x0b, heads);
2570 write_byte(ebda_seg, fdpt + 0x04, spt);
2571 write_byte(ebda_seg, fdpt + 0x03, 0xa0);
2572 sum = 0;
2573 for (i = 0; i < 0xf; i++)
2574 sum += read_byte(ebda_seg, fdpt + i);
2575 sum = 1 - sum;
2576 write_byte(ebda_seg, fdpt + 0x0f, sum);
2577 }
2578#else /* !VBOX */
2579 BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel, slave,cylinders, heads, spt);
2580
2581 translation = inb_cmos(0x39 + channel/2);
2582 for (shift=device%4; shift>0; shift--) translation >>= 2;
2583 translation &= 0x03;
2584
2585 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation, translation);
2586
2587 switch (translation) {
2588 case ATA_TRANSLATION_NONE:
2589 BX_INFO("none");
2590 break;
2591 case ATA_TRANSLATION_LBA:
2592 BX_INFO("lba");
2593 break;
2594 case ATA_TRANSLATION_LARGE:
2595 BX_INFO("large");
2596 break;
2597 case ATA_TRANSLATION_RECHS:
2598 BX_INFO("r-echs");
2599 break;
2600 }
2601 switch (translation) {
2602 case ATA_TRANSLATION_NONE:
2603 break;
2604 case ATA_TRANSLATION_LBA:
2605 spt = 63;
2606 sectors /= 63;
2607 heads = sectors / 1024;
2608 if (heads>128) heads = 255;
2609 else if (heads>64) heads = 128;
2610 else if (heads>32) heads = 64;
2611 else if (heads>16) heads = 32;
2612 else heads=16;
2613 cylinders = sectors / heads;
2614 break;
2615 case ATA_TRANSLATION_RECHS:
2616 // Take care not to overflow
2617 if (heads==16) {
2618 if(cylinders>61439) cylinders=61439;
2619 heads=15;
2620 cylinders = (Bit16u)((Bit32u)(cylinders)*16/15);
2621 }
2622 // then go through the large bitshift process
2623 case ATA_TRANSLATION_LARGE:
2624 while(cylinders > 1024) {
2625 cylinders >>= 1;
2626 heads <<= 1;
2627
2628 // If we max out the head count
2629 if (heads > 127) break;
2630 }
2631 break;
2632 }
2633 // clip to 1024 cylinders in lchs
2634 if (cylinders > 1024) cylinders=1024;
2635 BX_INFO(" LCHS=%d/%d/%d\n", cylinders, heads, spt);
2636
2637 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, heads);
2638 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, cylinders);
2639 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, spt);
2640#endif /* VBOX */
2641
2642 // fill hdidmap
2643 write_byte(ebda_seg,&EbdaData->ata.hdidmap[hdcount], device);
2644 hdcount++;
2645 }
2646
2647 // Now we send a IDENTIFY command to ATAPI device
2648 if(type == ATA_TYPE_ATAPI) {
2649
2650 Bit8u type, removable, mode;
2651 Bit16u blksize;
2652
2653 //Temporary values to do the transfer
2654 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_CDROM);
2655 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2656
2657 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE_PACKET, 1, 0, 0, 0, 0L, get_SS(),buffer) != 0)
2658 BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
2659
2660 type = read_byte(get_SS(),buffer+1) & 0x1f;
2661 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2662 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2663 blksize = 2048;
2664
2665 write_byte(ebda_seg,&EbdaData->ata.devices[device].device, type);
2666 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2667 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2668 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2669
2670 // fill cdidmap
2671 write_byte(ebda_seg,&EbdaData->ata.cdidmap[cdcount], device);
2672 cdcount++;
2673 }
2674
2675 {
2676 Bit32u sizeinmb;
2677 Bit16u ataversion;
2678 Bit8u c, i, version, model[41];
2679
2680 switch (type) {
2681 case ATA_TYPE_ATA:
2682 sizeinmb = read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors);
2683 sizeinmb >>= 11;
2684 case ATA_TYPE_ATAPI:
2685 // Read ATA/ATAPI version
2686 ataversion=((Bit16u)(read_byte(get_SS(),buffer+161))<<8)|read_byte(get_SS(),buffer+160);
2687 for(version=15;version>0;version--) {
2688 if((ataversion&(1<<version))!=0)
2689 break;
2690 }
2691
2692 // Read model name
2693 for(i=0;i<20;i++){
2694 write_byte(get_SS(),model+(i*2),read_byte(get_SS(),buffer+(i*2)+54+1));
2695 write_byte(get_SS(),model+(i*2)+1,read_byte(get_SS(),buffer+(i*2)+54));
2696 }
2697
2698 // Reformat
2699 write_byte(get_SS(),model+40,0x00);
2700 for(i=39;i>0;i--){
2701 if(read_byte(get_SS(),model+i)==0x20)
2702 write_byte(get_SS(),model+i,0x00);
2703 else break;
2704 }
2705 break;
2706 }
2707
2708#ifdef VBOX
2709 // we don't want any noisy output for now
2710#else /* !VBOX */
2711 switch (type) {
2712 case ATA_TYPE_ATA:
2713 printf("ata%d %s: ",channel,slave?" slave":"master");
2714 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2715 printf(" ATA-%d Hard-Disk (%lu MBytes)\n", version, sizeinmb);
2716 break;
2717 case ATA_TYPE_ATAPI:
2718 printf("ata%d %s: ",channel,slave?" slave":"master");
2719 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2720 if(read_byte(ebda_seg,&EbdaData->ata.devices[device].device)==ATA_DEVICE_CDROM)
2721 printf(" ATAPI-%d CD-Rom/DVD-Rom\n",version);
2722 else
2723 printf(" ATAPI-%d Device\n",version);
2724 break;
2725 case ATA_TYPE_UNKNOWN:
2726 printf("ata%d %s: Unknown device\n",channel,slave?" slave":"master");
2727 break;
2728 }
2729#endif /* !VBOX */
2730 }
2731 }
2732
2733 // Store the devices counts
2734 write_byte(ebda_seg,&EbdaData->ata.hdcount, hdcount);
2735 write_byte(ebda_seg,&EbdaData->ata.cdcount, cdcount);
2736 write_byte(0x40,0x75, hdcount);
2737
2738#ifdef VBOX
2739 // we don't want any noisy output for now
2740#else /* !VBOX */
2741 printf("\n");
2742#endif /* !VBOX */
2743
2744 // FIXME : should use bios=cmos|auto|disable bits
2745 // FIXME : should know about translation bits
2746 // FIXME : move hard_drive_post here
2747
2748}
2749
2750// ---------------------------------------------------------------------------
2751// ATA/ATAPI driver : software reset
2752// ---------------------------------------------------------------------------
2753// ATA-3
2754// 8.2.1 Software reset - Device 0
2755
2756void ata_reset(device)
2757Bit16u device;
2758{
2759 Bit16u ebda_seg=read_word(0x0040,0x000E);
2760 Bit16u iobase1, iobase2;
2761 Bit8u channel, slave, sn, sc;
2762 Bit16u max;
2763#ifdef VBOX
2764 Bit16u pdelay;
2765#endif /* VBOX */
2766
2767 channel = device / 2;
2768 slave = device % 2;
2769
2770 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2771 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2772
2773 // Reset
2774
2775// 8.2.1 (a) -- set SRST in DC
2776 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN | ATA_CB_DC_SRST);
2777
2778// 8.2.1 (b) -- wait for BSY
2779 max=0xff;
2780 while(--max>0) {
2781 Bit8u status = inb(iobase1+ATA_CB_STAT);
2782 if ((status & ATA_CB_STAT_BSY) != 0) break;
2783 }
2784
2785// 8.2.1 (f) -- clear SRST
2786 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2787
2788 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_NONE) {
2789
2790// 8.2.1 (g) -- check for sc==sn==0x01
2791 // select device
2792 outb(iobase1+ATA_CB_DH, slave?ATA_CB_DH_DEV1:ATA_CB_DH_DEV0);
2793 sc = inb(iobase1+ATA_CB_SC);
2794 sn = inb(iobase1+ATA_CB_SN);
2795
2796 if ( (sc==0x01) && (sn==0x01) ) {
2797
2798// 8.2.1 (h) -- wait for not BSY
2799#ifdef VBOX
2800 max=0xffff; /* The ATA specification says that the drive may be busy for up to 30 seconds. */
2801#else /* !VBOX */
2802 max=0xff;
2803#endif /* !VBOX */
2804 while(--max>0) {
2805 Bit8u status = inb(iobase1+ATA_CB_STAT);
2806 if ((status & ATA_CB_STAT_BSY) == 0) break;
2807#ifdef VBOX
2808 pdelay=0xffff;
2809 while (--pdelay>0) {
2810 /* nothing */
2811 }
2812#endif /* VBOX */
2813 }
2814 }
2815 }
2816
2817// 8.2.1 (i) -- wait for DRDY
2818#ifdef VBOX
2819 max=0x10; /* Speed up for virtual drives. Disks are immediately ready, CDs never */
2820#else /* !VBOX */
2821 max=0xfff;
2822#endif /* !VBOX */
2823 while(--max>0) {
2824 Bit8u status = inb(iobase1+ATA_CB_STAT);
2825 if ((status & ATA_CB_STAT_RDY) != 0) break;
2826 }
2827
2828 // Enable interrupts
2829 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2830}
2831
2832// ---------------------------------------------------------------------------
2833// ATA/ATAPI driver : execute a non data command
2834// ---------------------------------------------------------------------------
2835
2836Bit16u ata_cmd_non_data()
2837{return 0;}
2838
2839// ---------------------------------------------------------------------------
2840// ATA/ATAPI driver : execute a data-in command
2841// ---------------------------------------------------------------------------
2842 // returns
2843 // 0 : no error
2844 // 1 : BUSY bit set
2845 // 2 : read error
2846 // 3 : expected DRQ=1
2847 // 4 : no sectors left to read/verify
2848 // 5 : more sectors to read/verify
2849 // 6 : no sectors left to write
2850 // 7 : more sectors to write
2851Bit16u ata_cmd_data_in(device, command, count, cylinder, head, sector, lba, segment, offset)
2852Bit16u device, command, count, cylinder, head, sector, segment, offset;
2853Bit32u lba;
2854{
2855 Bit16u ebda_seg=read_word(0x0040,0x000E);
2856 Bit16u iobase1, iobase2, blksize;
2857 Bit8u channel, slave;
2858 Bit8u status, current, mode;
2859
2860 channel = device / 2;
2861 slave = device % 2;
2862
2863 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2864 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2865 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2866 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2867 if (mode == ATA_MODE_PIO32) blksize>>=2;
2868 else blksize>>=1;
2869
2870#ifdef VBOX
2871 status = inb(iobase1 + ATA_CB_STAT);
2872 if (status & ATA_CB_STAT_BSY)
2873 {
2874 // Enable interrupts
2875 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2876 return 1;
2877 }
2878#endif /* VBOX */
2879
2880 // sector will be 0 only on lba access. Convert to lba-chs
2881 if (sector == 0) {
2882#ifdef VBOX
2883 if (count >= 256 || lba + count >= 268435456)
2884 {
2885 sector = (lba & 0xff000000L) >> 24;
2886 cylinder = 0; /* The parameter lba is just a 32 bit value. */
2887 outb(iobase1 + ATA_CB_SC, (count & 0xff00) >> 8);
2888 outb(iobase1 + ATA_CB_SN, sector);
2889 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2890 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2891 /* Leave the bottom 24 bits as is, they are treated correctly by the
2892 * LBA28 code path. */
2893 lba &= 0xffffff;
2894 }
2895#endif /* VBOX */
2896 sector = (Bit16u) (lba & 0x000000ffL);
2897 lba >>= 8;
2898 cylinder = (Bit16u) (lba & 0x0000ffffL);
2899 lba >>= 16;
2900 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
2901 }
2902
2903 // Reset count of transferred data
2904 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2905 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2906 current = 0;
2907
2908#ifndef VBOX
2909 status = inb(iobase1 + ATA_CB_STAT);
2910 if (status & ATA_CB_STAT_BSY) return 1;
2911#endif /* !VBOX */
2912
2913 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2914 outb(iobase1 + ATA_CB_FR, 0x00);
2915 outb(iobase1 + ATA_CB_SC, count);
2916 outb(iobase1 + ATA_CB_SN, sector);
2917 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2918 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2919 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
2920 outb(iobase1 + ATA_CB_CMD, command);
2921
2922 while (1) {
2923 status = inb(iobase1 + ATA_CB_STAT);
2924 if ( !(status & ATA_CB_STAT_BSY) ) break;
2925 }
2926
2927 if (status & ATA_CB_STAT_ERR) {
2928 BX_DEBUG_ATA("ata_cmd_data_in : read error\n");
2929#ifdef VBOX
2930 // Enable interrupts
2931 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2932#endif /* VBOX */
2933 return 2;
2934 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2935 BX_DEBUG_ATA("ata_cmd_data_in : DRQ not set (status %02x)\n", (unsigned) status);
2936#ifdef VBOX
2937 // Enable interrupts
2938 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2939#endif /* VBOX */
2940 return 3;
2941 }
2942
2943 // FIXME : move seg/off translation here
2944
2945ASM_START
2946 sti ;; enable higher priority interrupts
2947ASM_END
2948
2949 while (1) {
2950
2951ASM_START
2952 push bp
2953 mov bp, sp
2954 mov di, _ata_cmd_data_in.offset + 2[bp]
2955 mov ax, _ata_cmd_data_in.segment + 2[bp]
2956 mov cx, _ata_cmd_data_in.blksize + 2[bp]
2957
2958 ;; adjust if there will be an overrun. 2K max sector size
2959 cmp di, #0xf800 ;;
2960 jbe ata_in_no_adjust
2961
2962ata_in_adjust:
2963 sub di, #0x0800 ;; sub 2 kbytes from offset
2964 add ax, #0x0080 ;; add 2 Kbytes to segment
2965
2966ata_in_no_adjust:
2967 mov es, ax ;; segment in es
2968
2969 mov dx, _ata_cmd_data_in.iobase1 + 2[bp] ;; ATA data read port
2970
2971 mov ah, _ata_cmd_data_in.mode + 2[bp]
2972 cmp ah, #ATA_MODE_PIO32
2973 je ata_in_32
2974
2975ata_in_16:
2976 rep
2977 insw ;; CX words transferred from port(DX) to ES:[DI]
2978 jmp ata_in_done
2979
2980ata_in_32:
2981 rep
2982 insd ;; CX dwords transferred from port(DX) to ES:[DI]
2983
2984ata_in_done:
2985 mov _ata_cmd_data_in.offset + 2[bp], di
2986 mov _ata_cmd_data_in.segment + 2[bp], es
2987 pop bp
2988ASM_END
2989
2990 current++;
2991 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
2992 count--;
2993#ifdef VBOX
2994 while (1) {
2995 status = inb(iobase1 + ATA_CB_STAT);
2996 if ( !(status & ATA_CB_STAT_BSY) ) break;
2997 }
2998#else /* !VBOX */
2999 status = inb(iobase1 + ATA_CB_STAT);
3000#endif /* !VBOX */
3001 if (count == 0) {
3002 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3003 != ATA_CB_STAT_RDY ) {
3004 BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n", (unsigned) status);
3005#ifdef VBOX
3006 // Enable interrupts
3007 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3008#endif /* VBOX */
3009 return 4;
3010 }
3011 break;
3012 }
3013 else {
3014 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3015 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3016 BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n", (unsigned) status);
3017#ifdef VBOX
3018 // Enable interrupts
3019 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3020#endif /* VBOX */
3021 return 5;
3022 }
3023 continue;
3024 }
3025 }
3026 // Enable interrupts
3027 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3028 return 0;
3029}
3030
3031// ---------------------------------------------------------------------------
3032// ATA/ATAPI driver : execute a data-out command
3033// ---------------------------------------------------------------------------
3034 // returns
3035 // 0 : no error
3036 // 1 : BUSY bit set
3037 // 2 : read error
3038 // 3 : expected DRQ=1
3039 // 4 : no sectors left to read/verify
3040 // 5 : more sectors to read/verify
3041 // 6 : no sectors left to write
3042 // 7 : more sectors to write
3043Bit16u ata_cmd_data_out(device, command, count, cylinder, head, sector, lba, segment, offset)
3044Bit16u device, command, count, cylinder, head, sector, segment, offset;
3045Bit32u lba;
3046{
3047 Bit16u ebda_seg=read_word(0x0040,0x000E);
3048 Bit16u iobase1, iobase2, blksize;
3049 Bit8u channel, slave;
3050 Bit8u status, current, mode;
3051
3052 channel = device / 2;
3053 slave = device % 2;
3054
3055 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
3056 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
3057 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
3058 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
3059 if (mode == ATA_MODE_PIO32) blksize>>=2;
3060 else blksize>>=1;
3061
3062#ifdef VBOX
3063 status = inb(iobase1 + ATA_CB_STAT);
3064 if (status & ATA_CB_STAT_BSY)
3065 {
3066 // Enable interrupts
3067 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3068 return 1;
3069 }
3070#endif /* VBOX */
3071
3072 // sector will be 0 only on lba access. Convert to lba-chs
3073 if (sector == 0) {
3074#ifdef VBOX
3075 if (count >= 256 || lba + count >= 268435456)
3076 {
3077 sector = (lba & 0xff000000L) >> 24;
3078 cylinder = 0; /* The parameter lba is just a 32 bit value. */
3079 outb(iobase1 + ATA_CB_SC, (count & 0xff00) >> 8);
3080 outb(iobase1 + ATA_CB_SN, sector);
3081 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
3082 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
3083 /* Leave the bottom 24 bits as is, they are treated correctly by the
3084 * LBA28 code path. */
3085 lba &= 0xffffff;
3086 }
3087#endif /* VBOX */
3088 sector = (Bit16u) (lba & 0x000000ffL);
3089 lba >>= 8;
3090 cylinder = (Bit16u) (lba & 0x0000ffffL);
3091 lba >>= 16;
3092 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
3093 }
3094
3095 // Reset count of transferred data
3096 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
3097 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
3098 current = 0;
3099
3100#ifndef VBOX
3101 status = inb(iobase1 + ATA_CB_STAT);
3102 if (status & ATA_CB_STAT_BSY) return 1;
3103#endif /* !VBOX */
3104
3105 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
3106 outb(iobase1 + ATA_CB_FR, 0x00);
3107 outb(iobase1 + ATA_CB_SC, count);
3108 outb(iobase1 + ATA_CB_SN, sector);
3109 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
3110 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
3111 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
3112 outb(iobase1 + ATA_CB_CMD, command);
3113
3114 while (1) {
3115 status = inb(iobase1 + ATA_CB_STAT);
3116 if ( !(status & ATA_CB_STAT_BSY) ) break;
3117 }
3118
3119 if (status & ATA_CB_STAT_ERR) {
3120 BX_DEBUG_ATA("ata_cmd_data_out : read error\n");
3121#ifdef VBOX
3122 // Enable interrupts
3123 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3124#endif /* VBOX */
3125 return 2;
3126 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
3127 BX_DEBUG_ATA("ata_cmd_data_out : DRQ not set (status %02x)\n", (unsigned) status);
3128#ifdef VBOX
3129 // Enable interrupts
3130 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3131#endif /* VBOX */
3132 return 3;
3133 }
3134
3135 // FIXME : move seg/off translation here
3136
3137ASM_START
3138 sti ;; enable higher priority interrupts
3139ASM_END
3140
3141 while (1) {
3142
3143ASM_START
3144 push bp
3145 mov bp, sp
3146 mov si, _ata_cmd_data_out.offset + 2[bp]
3147 mov ax, _ata_cmd_data_out.segment + 2[bp]
3148 mov cx, _ata_cmd_data_out.blksize + 2[bp]
3149
3150 ;; adjust if there will be an overrun. 2K max sector size
3151 cmp si, #0xf800 ;;
3152 jbe ata_out_no_adjust
3153
3154ata_out_adjust:
3155 sub si, #0x0800 ;; sub 2 kbytes from offset
3156 add ax, #0x0080 ;; add 2 Kbytes to segment
3157
3158ata_out_no_adjust:
3159 mov es, ax ;; segment in es
3160
3161 mov dx, _ata_cmd_data_out.iobase1 + 2[bp] ;; ATA data write port
3162
3163 mov ah, _ata_cmd_data_out.mode + 2[bp]
3164 cmp ah, #ATA_MODE_PIO32
3165 je ata_out_32
3166
3167ata_out_16:
3168 seg ES
3169 rep
3170 outsw ;; CX words transferred from port(DX) to ES:[SI]
3171 jmp ata_out_done
3172
3173ata_out_32:
3174 seg ES
3175 rep
3176 outsd ;; CX dwords transferred from port(DX) to ES:[SI]
3177
3178ata_out_done:
3179 mov _ata_cmd_data_out.offset + 2[bp], si
3180 mov _ata_cmd_data_out.segment + 2[bp], es
3181 pop bp
3182ASM_END
3183
3184 current++;
3185 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
3186 count--;
3187#ifdef VBOX
3188 while (1) {
3189 status = inb(iobase1 + ATA_CB_STAT);
3190 if ( !(status & ATA_CB_STAT_BSY) ) break;
3191 }
3192#else /* !VBOX */
3193 status = inb(iobase1 + ATA_CB_STAT);
3194#endif /* VBOX */
3195 if (count == 0) {
3196 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3197 != ATA_CB_STAT_RDY ) {
3198 BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n", (unsigned) status);
3199#ifdef VBOX
3200 // Enable interrupts
3201 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3202#endif /* VBOX */
3203 return 6;
3204 }
3205 break;
3206 }
3207 else {
3208 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3209 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3210 BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n", (unsigned) status);
3211#ifdef VBOX
3212 // Enable interrupts
3213 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3214#endif /* VBOX */
3215 return 7;
3216 }
3217 continue;
3218 }
3219 }
3220 // Enable interrupts
3221 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3222 return 0;
3223}
3224
3225// ---------------------------------------------------------------------------
3226// ATA/ATAPI driver : execute a packet command
3227// ---------------------------------------------------------------------------
3228 // returns
3229 // 0 : no error
3230 // 1 : error in parameters
3231 // 2 : BUSY bit set
3232 // 3 : error
3233 // 4 : not ready
3234Bit16u ata_cmd_packet(device, cmdlen, cmdseg, cmdoff, header, length, inout, bufseg, bufoff)
3235Bit8u cmdlen,inout;
3236Bit16u device,cmdseg, cmdoff, bufseg, bufoff;
3237Bit16u header;
3238Bit32u length;
3239{
3240 Bit16u ebda_seg=read_word(0x0040,0x000E);
3241 Bit16u iobase1, iobase2;
3242 Bit16u lcount, lbefore, lafter, count;
3243 Bit8u channel, slave;
3244 Bit8u status, mode, lmode;
3245 Bit32u total, transfer;
3246
3247 channel = device / 2;
3248 slave = device % 2;
3249
3250 // Data out is not supported yet
3251 if (inout == ATA_DATA_OUT) {
3252 BX_INFO("ata_cmd_packet: DATA_OUT not supported yet\n");
3253 return 1;
3254 }
3255
3256 // The header length must be even
3257 if (header & 1) {
3258 BX_DEBUG_ATA("ata_cmd_packet : header must be even (%04x)\n",header);
3259 return 1;
3260 }
3261
3262 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
3263 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
3264 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
3265 transfer= 0L;
3266
3267 if (cmdlen < 12) cmdlen=12;
3268 if (cmdlen > 12) cmdlen=16;
3269 cmdlen>>=1;
3270
3271 // Reset count of transferred data
3272 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
3273 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
3274
3275 status = inb(iobase1 + ATA_CB_STAT);
3276 if (status & ATA_CB_STAT_BSY) return 2;
3277
3278 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
3279 // outb(iobase1 + ATA_CB_FR, 0x00);
3280 // outb(iobase1 + ATA_CB_SC, 0x00);
3281 // outb(iobase1 + ATA_CB_SN, 0x00);
3282 outb(iobase1 + ATA_CB_CL, 0xfff0 & 0x00ff);
3283 outb(iobase1 + ATA_CB_CH, 0xfff0 >> 8);
3284 outb(iobase1 + ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
3285 outb(iobase1 + ATA_CB_CMD, ATA_CMD_PACKET);
3286
3287 // Device should ok to receive command
3288 while (1) {
3289 status = inb(iobase1 + ATA_CB_STAT);
3290 if ( !(status & ATA_CB_STAT_BSY) ) break;
3291 }
3292
3293 if (status & ATA_CB_STAT_ERR) {
3294 BX_DEBUG_ATA("ata_cmd_packet : error, status is %02x\n",status);
3295#ifdef VBOX
3296 // Enable interrupts
3297 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3298#endif /* VBOX */
3299 return 3;
3300 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
3301 BX_DEBUG_ATA("ata_cmd_packet : DRQ not set (status %02x)\n", (unsigned) status);
3302#ifdef VBOX
3303 // Enable interrupts
3304 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3305#endif /* VBOX */
3306 return 4;
3307 }
3308
3309 // Normalize address
3310 cmdseg += (cmdoff / 16);
3311 cmdoff %= 16;
3312
3313 // Send command to device
3314ASM_START
3315 sti ;; enable higher priority interrupts
3316
3317 push bp
3318 mov bp, sp
3319
3320 mov si, _ata_cmd_packet.cmdoff + 2[bp]
3321 mov ax, _ata_cmd_packet.cmdseg + 2[bp]
3322 mov cx, _ata_cmd_packet.cmdlen + 2[bp]
3323 mov es, ax ;; segment in es
3324
3325 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data write port
3326
3327 seg ES
3328 rep
3329 outsw ;; CX words transferred from port(DX) to ES:[SI]
3330
3331 pop bp
3332ASM_END
3333
3334 if (inout == ATA_DATA_NO) {
3335 status = inb(iobase1 + ATA_CB_STAT);
3336 }
3337 else {
3338 while (1) {
3339
3340#ifdef VBOX
3341 while (1) {
3342 status = inb(iobase1 + ATA_CB_STAT);
3343 if ( !(status & ATA_CB_STAT_BSY) ) break;
3344 }
3345#else /* VBOX */
3346 status = inb(iobase1 + ATA_CB_STAT);
3347#endif /* VBOX */
3348
3349 // Check if command completed
3350 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_DRQ) ) ==0 ) break;
3351
3352 if (status & ATA_CB_STAT_ERR) {
3353 BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status);
3354#ifdef VBOX
3355 // Enable interrupts
3356 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3357#endif /* VBOX */
3358 return 3;
3359 }
3360
3361 // Device must be ready to send data
3362 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3363 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3364 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", status);
3365#ifdef VBOX
3366 // Enable interrupts
3367 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3368#endif /* VBOX */
3369 return 4;
3370 }
3371
3372 // Normalize address
3373 bufseg += (bufoff / 16);
3374 bufoff %= 16;
3375
3376 // Get the byte count
3377 lcount = ((Bit16u)(inb(iobase1 + ATA_CB_CH))<<8)+inb(iobase1 + ATA_CB_CL);
3378
3379 // adjust to read what we want
3380 if(header>lcount) {
3381 lbefore=lcount;
3382 header-=lcount;
3383 lcount=0;
3384 }
3385 else {
3386 lbefore=header;
3387 header=0;
3388 lcount-=lbefore;
3389 }
3390
3391 if(lcount>length) {
3392 lafter=lcount-length;
3393 lcount=length;
3394 length=0;
3395 }
3396 else {
3397 lafter=0;
3398 length-=lcount;
3399 }
3400
3401 // Save byte count
3402 count = lcount;
3403
3404 BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore+lcount+lafter,lbefore,lcount,lafter);
3405 BX_DEBUG_ATA("to 0x%04x:0x%04x\n",bufseg,bufoff);
3406
3407 // If counts not dividable by 4, use 16bits mode
3408 lmode = mode;
3409 if (lbefore & 0x03) lmode=ATA_MODE_PIO16;
3410 if (lcount & 0x03) lmode=ATA_MODE_PIO16;
3411 if (lafter & 0x03) lmode=ATA_MODE_PIO16;
3412
3413 // adds an extra byte if count are odd. before is always even
3414 if (lcount & 0x01) {
3415 lcount+=1;
3416 if ((lafter > 0) && (lafter & 0x01)) {
3417 lafter-=1;
3418 }
3419 }
3420
3421 if (lmode == ATA_MODE_PIO32) {
3422 lcount>>=2; lbefore>>=2; lafter>>=2;
3423 }
3424 else {
3425 lcount>>=1; lbefore>>=1; lafter>>=1;
3426 }
3427
3428 ; // FIXME bcc bug
3429
3430ASM_START
3431 push bp
3432 mov bp, sp
3433
3434 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data read port
3435
3436 mov cx, _ata_cmd_packet.lbefore + 2[bp]
3437 jcxz ata_packet_no_before
3438
3439 mov ah, _ata_cmd_packet.lmode + 2[bp]
3440 cmp ah, #ATA_MODE_PIO32
3441 je ata_packet_in_before_32
3442
3443ata_packet_in_before_16:
3444 in ax, dx
3445 loop ata_packet_in_before_16
3446 jmp ata_packet_no_before
3447
3448ata_packet_in_before_32:
3449 push eax
3450ata_packet_in_before_32_loop:
3451 in eax, dx
3452 loop ata_packet_in_before_32_loop
3453 pop eax
3454
3455ata_packet_no_before:
3456 mov cx, _ata_cmd_packet.lcount + 2[bp]
3457 jcxz ata_packet_after
3458
3459 mov di, _ata_cmd_packet.bufoff + 2[bp]
3460 mov ax, _ata_cmd_packet.bufseg + 2[bp]
3461 mov es, ax
3462
3463 mov ah, _ata_cmd_packet.lmode + 2[bp]
3464 cmp ah, #ATA_MODE_PIO32
3465 je ata_packet_in_32
3466
3467ata_packet_in_16:
3468 rep
3469 insw ;; CX words transferred tp port(DX) to ES:[DI]
3470 jmp ata_packet_after
3471
3472ata_packet_in_32:
3473 rep
3474 insd ;; CX dwords transferred to port(DX) to ES:[DI]
3475
3476ata_packet_after:
3477 mov cx, _ata_cmd_packet.lafter + 2[bp]
3478 jcxz ata_packet_done
3479
3480 mov ah, _ata_cmd_packet.lmode + 2[bp]
3481 cmp ah, #ATA_MODE_PIO32
3482 je ata_packet_in_after_32
3483
3484ata_packet_in_after_16:
3485 in ax, dx
3486 loop ata_packet_in_after_16
3487 jmp ata_packet_done
3488
3489ata_packet_in_after_32:
3490 push eax
3491ata_packet_in_after_32_loop:
3492 in eax, dx
3493 loop ata_packet_in_after_32_loop
3494 pop eax
3495
3496ata_packet_done:
3497 pop bp
3498ASM_END
3499
3500 // Compute new buffer address
3501 bufoff += count;
3502
3503 // Save transferred bytes count
3504 transfer += count;
3505 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,transfer);
3506 }
3507 }
3508
3509 // Final check, device must be ready
3510 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3511 != ATA_CB_STAT_RDY ) {
3512 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", (unsigned) status);
3513#ifdef VBOX
3514 // Enable interrupts
3515 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3516#endif /* VBOX */
3517 return 4;
3518 }
3519
3520 // Enable interrupts
3521 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3522 return 0;
3523}
3524
3525// ---------------------------------------------------------------------------
3526// End of ATA/ATAPI Driver
3527// ---------------------------------------------------------------------------
3528
3529// ---------------------------------------------------------------------------
3530// Start of ATA/ATAPI generic functions
3531// ---------------------------------------------------------------------------
3532
3533#if 0 // currently unused
3534 Bit16u
3535atapi_get_sense(device)
3536 Bit16u device;
3537{
3538 Bit8u atacmd[12];
3539 Bit8u buffer[16];
3540 Bit8u i;
3541
3542 memsetb(get_SS(),atacmd,0,12);
3543
3544 // Request SENSE
3545 atacmd[0]=0x03;
3546 atacmd[4]=0x20;
3547 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 16L, ATA_DATA_IN, get_SS(), buffer) != 0)
3548 return 0x0002;
3549
3550 if ((buffer[0] & 0x7e) == 0x70) {
3551 return (((Bit16u)buffer[2]&0x0f)*0x100)+buffer[12];
3552 }
3553
3554 return 0;
3555}
3556
3557 Bit16u
3558atapi_is_ready(device)
3559 Bit16u device;
3560{
3561 Bit8u atacmd[12];
3562 Bit8u buffer[];
3563
3564 memsetb(get_SS(),atacmd,0,12);
3565
3566 // Test Unit Ready
3567 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3568 return 0x000f;
3569
3570 if (atapi_get_sense(device) !=0 ) {
3571 memsetb(get_SS(),atacmd,0,12);
3572
3573 // try to send Test Unit Ready again
3574 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3575 return 0x000f;
3576
3577 return atapi_get_sense(device);
3578 }
3579 return 0;
3580}
3581#endif
3582
3583 Bit16u
3584atapi_is_cdrom(device)
3585 Bit8u device;
3586{
3587 Bit16u ebda_seg=read_word(0x0040,0x000E);
3588
3589 if (device >= BX_MAX_ATA_DEVICES)
3590 return 0;
3591
3592 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_ATAPI)
3593 return 0;
3594
3595 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].device) != ATA_DEVICE_CDROM)
3596 return 0;
3597
3598 return 1;
3599}
3600
3601// ---------------------------------------------------------------------------
3602// End of ATA/ATAPI generic functions
3603// ---------------------------------------------------------------------------
3604
3605#endif // BX_USE_ATADRV
3606
3607#if BX_ELTORITO_BOOT
3608
3609// ---------------------------------------------------------------------------
3610// Start of El-Torito boot functions
3611// ---------------------------------------------------------------------------
3612
3613 void
3614cdemu_init()
3615{
3616 Bit16u ebda_seg=read_word(0x0040,0x000E);
3617
3618 // the only important data is this one for now
3619 write_byte(ebda_seg,&EbdaData->cdemu.active,0x00);
3620}
3621
3622 Bit8u
3623cdemu_isactive()
3624{
3625 Bit16u ebda_seg=read_word(0x0040,0x000E);
3626
3627 return(read_byte(ebda_seg,&EbdaData->cdemu.active));
3628}
3629
3630 Bit8u
3631cdemu_emulated_drive()
3632{
3633 Bit16u ebda_seg=read_word(0x0040,0x000E);
3634
3635 return(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
3636}
3637
3638static char isotag[6]="CD001";
3639static char eltorito[24]="EL TORITO SPECIFICATION";
3640//
3641// Returns ah: emulated drive, al: error code
3642//
3643 Bit16u
3644cdrom_boot()
3645{
3646 Bit16u ebda_seg=read_word(0x0040,0x000E);
3647 Bit8u atacmd[12], buffer[2048];
3648 Bit32u lba;
3649 Bit16u boot_segment, nbsectors, i, error;
3650 Bit8u device;
3651#ifdef VBOX
3652 Bit8u read_try;
3653#endif /* VBOX */
3654
3655 // Find out the first cdrom
3656 for (device=0; device<BX_MAX_ATA_DEVICES;device++) {
3657 if (atapi_is_cdrom(device)) break;
3658 }
3659
3660 // if not found
3661 if(device >= BX_MAX_ATA_DEVICES) return 2;
3662
3663 // Read the Boot Record Volume Descriptor
3664 memsetb(get_SS(),atacmd,0,12);
3665 atacmd[0]=0x28; // READ command
3666 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3667 atacmd[8]=(0x01 & 0x00ff); // Sectors
3668 atacmd[2]=(0x11 & 0xff000000) >> 24; // LBA
3669 atacmd[3]=(0x11 & 0x00ff0000) >> 16;
3670 atacmd[4]=(0x11 & 0x0000ff00) >> 8;
3671 atacmd[5]=(0x11 & 0x000000ff);
3672#ifdef VBOX
3673 for (read_try = 0; read_try <= 4; read_try++)
3674 {
3675 error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer);
3676 if (!error)
3677 break;
3678 }
3679 if (error)
3680 return 3;
3681#else /* !VBOX */
3682 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3683 return 3;
3684#endif /* !VBOX */
3685
3686 // Validity checks
3687 if(buffer[0]!=0)return 4;
3688 for(i=0;i<5;i++){
3689 if(buffer[1+i]!=read_byte(0xf000,&isotag[i]))return 5;
3690 }
3691 for(i=0;i<23;i++)
3692 if(buffer[7+i]!=read_byte(0xf000,&eltorito[i]))return 6;
3693
3694 // ok, now we calculate the Boot catalog address
3695 lba=buffer[0x4A]*0x1000000+buffer[0x49]*0x10000+buffer[0x48]*0x100+buffer[0x47];
3696
3697 // And we read the Boot Catalog
3698 memsetb(get_SS(),atacmd,0,12);
3699 atacmd[0]=0x28; // READ command
3700 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3701 atacmd[8]=(0x01 & 0x00ff); // Sectors
3702 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3703 atacmd[3]=(lba & 0x00ff0000) >> 16;
3704 atacmd[4]=(lba & 0x0000ff00) >> 8;
3705 atacmd[5]=(lba & 0x000000ff);
3706 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3707 return 7;
3708
3709 // Validation entry
3710 if(buffer[0x00]!=0x01)return 8; // Header
3711 if(buffer[0x01]!=0x00)return 9; // Platform
3712 if(buffer[0x1E]!=0x55)return 10; // key 1
3713 if(buffer[0x1F]!=0xAA)return 10; // key 2
3714
3715 // Initial/Default Entry
3716 if(buffer[0x20]!=0x88)return 11; // Bootable
3717
3718 write_byte(ebda_seg,&EbdaData->cdemu.media,buffer[0x21]);
3719 if(buffer[0x21]==0){
3720 // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
3721 // Win2000 cd boot needs to know it booted from cd
3722 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0xE0);
3723 }
3724 else if(buffer[0x21]<4)
3725 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x00);
3726 else
3727 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x80);
3728
3729 write_byte(ebda_seg,&EbdaData->cdemu.controller_index,device/2);
3730 write_byte(ebda_seg,&EbdaData->cdemu.device_spec,device%2);
3731
3732 boot_segment=buffer[0x23]*0x100+buffer[0x22];
3733 if(boot_segment==0x0000)boot_segment=0x07C0;
3734
3735 write_word(ebda_seg,&EbdaData->cdemu.load_segment,boot_segment);
3736 write_word(ebda_seg,&EbdaData->cdemu.buffer_segment,0x0000);
3737
3738 nbsectors=buffer[0x27]*0x100+buffer[0x26];
3739 write_word(ebda_seg,&EbdaData->cdemu.sector_count,nbsectors);
3740
3741 lba=buffer[0x2B]*0x1000000+buffer[0x2A]*0x10000+buffer[0x29]*0x100+buffer[0x28];
3742 write_dword(ebda_seg,&EbdaData->cdemu.ilba,lba);
3743
3744 // And we read the image in memory
3745 memsetb(get_SS(),atacmd,0,12);
3746 atacmd[0]=0x28; // READ command
3747 atacmd[7]=((1+(nbsectors-1)/4) & 0xff00) >> 8; // Sectors
3748 atacmd[8]=((1+(nbsectors-1)/4) & 0x00ff); // Sectors
3749 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3750 atacmd[3]=(lba & 0x00ff0000) >> 16;
3751 atacmd[4]=(lba & 0x0000ff00) >> 8;
3752 atacmd[5]=(lba & 0x000000ff);
3753 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, nbsectors*512L, ATA_DATA_IN, boot_segment,0)) != 0)
3754 return 12;
3755
3756 // Remember the media type
3757 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
3758 case 0x01: // 1.2M floppy
3759 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,15);
3760 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3761 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3762 break;
3763 case 0x02: // 1.44M floppy
3764 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,18);
3765 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3766 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3767 break;
3768 case 0x03: // 2.88M floppy
3769 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,36);
3770 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3771 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3772 break;
3773 case 0x04: // Harddrive
3774 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,read_byte(boot_segment,446+6)&0x3f);
3775 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,
3776 (read_byte(boot_segment,446+6)<<2) + read_byte(boot_segment,446+7) + 1);
3777 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,read_byte(boot_segment,446+5) + 1);
3778 break;
3779 }
3780
3781 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0) {
3782 // Increase bios installed hardware number of devices
3783 if(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)==0x00)
3784 write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
3785 else
3786 write_byte(ebda_seg, &EbdaData->ata.hdcount, read_byte(ebda_seg, &EbdaData->ata.hdcount) + 1);
3787 }
3788
3789
3790 // everything is ok, so from now on, the emulation is active
3791 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0)
3792 write_byte(ebda_seg,&EbdaData->cdemu.active,0x01);
3793
3794 // return the boot drive + no error
3795 return (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)*0x100)+0;
3796}
3797
3798// ---------------------------------------------------------------------------
3799// End of El-Torito boot functions
3800// ---------------------------------------------------------------------------
3801#endif // BX_ELTORITO_BOOT
3802
3803#ifdef VBOX_WITH_SCSI
3804# include "scsi.c"
3805#endif
3806
3807 void
3808int14_function(regs, ds, iret_addr)
3809 pusha_regs_t regs; // regs pushed from PUSHA instruction
3810 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
3811 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
3812{
3813 Bit16u addr,timer,val16;
3814 Bit8u timeout;
3815
3816 ASM_START
3817 sti
3818 ASM_END
3819
3820 addr = read_word(0x0040, (regs.u.r16.dx << 1));
3821 timeout = read_byte(0x0040, 0x007C + regs.u.r16.dx);
3822 if ((regs.u.r16.dx < 4) && (addr > 0)) {
3823 switch (regs.u.r8.ah) {
3824 case 0:
3825 outb(addr+3, inb(addr+3) | 0x80);
3826 if (regs.u.r8.al & 0xE0 == 0) {
3827 outb(addr, 0x17);
3828 outb(addr+1, 0x04);
3829 } else {
3830 val16 = 0x600 >> ((regs.u.r8.al & 0xE0) >> 5);
3831 outb(addr, val16 & 0xFF);
3832 outb(addr+1, val16 >> 8);
3833 }
3834 outb(addr+3, regs.u.r8.al & 0x1F);
3835 regs.u.r8.ah = inb(addr+5);
3836 regs.u.r8.al = inb(addr+6);
3837 ClearCF(iret_addr.flags);
3838 break;
3839 case 1:
3840 timer = read_word(0x0040, 0x006C);
3841 while (((inb(addr+5) & 0x60) != 0x60) && (timeout)) {
3842 val16 = read_word(0x0040, 0x006C);
3843 if (val16 != timer) {
3844 timer = val16;
3845 timeout--;
3846 }
3847 }
3848 if (timeout) outb(addr, regs.u.r8.al);
3849 regs.u.r8.ah = inb(addr+5);
3850 if (!timeout) regs.u.r8.ah |= 0x80;
3851 ClearCF(iret_addr.flags);
3852 break;
3853 case 2:
3854 timer = read_word(0x0040, 0x006C);
3855 while (((inb(addr+5) & 0x01) == 0) && (timeout)) {
3856 val16 = read_word(0x0040, 0x006C);
3857 if (val16 != timer) {
3858 timer = val16;
3859 timeout--;
3860 }
3861 }
3862 if (timeout) {
3863 regs.u.r8.ah = 0;
3864 regs.u.r8.al = inb(addr);
3865 } else {
3866 regs.u.r8.ah = inb(addr+5);
3867 }
3868 ClearCF(iret_addr.flags);
3869 break;
3870 case 3:
3871 regs.u.r8.ah = inb(addr+5);
3872 regs.u.r8.al = inb(addr+6);
3873 ClearCF(iret_addr.flags);
3874 break;
3875 default:
3876 SetCF(iret_addr.flags); // Unsupported
3877 }
3878 } else {
3879 SetCF(iret_addr.flags); // Unsupported
3880 }
3881}
3882
3883 void
3884int15_function(regs, ES, DS, FLAGS)
3885 pusha_regs_t regs; // REGS pushed via pusha
3886 Bit16u ES, DS, FLAGS;
3887{
3888 Bit16u ebda_seg=read_word(0x0040,0x000E);
3889 bx_bool prev_a20_enable;
3890 Bit16u base15_00;
3891 Bit8u base23_16;
3892 Bit16u ss;
3893 Bit16u BX,CX,DX;
3894
3895 Bit16u bRegister;
3896 Bit8u irqDisable;
3897
3898BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
3899
3900 switch (regs.u.r8.ah) {
3901#ifdef VBOX
3902 case 0x00: /* assorted functions */
3903 if (regs.u.r8.al != 0xc0)
3904 goto undecoded;
3905 /* GRUB calls int15 with ax=0x00c0 to get the ROM configuration table,
3906 * which we don't support, but logging that event is annoying. In fact
3907 * it is likely that they just misread some specs, because there is a
3908 * int15 BIOS function AH=0xc0 which sounds quite similar to what GRUB
3909 * wants to achieve. */
3910 SET_CF();
3911 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3912 break;
3913#endif
3914 case 0x24: /* A20 Control */
3915 switch (regs.u.r8.al) {
3916 case 0x00:
3917 set_enable_a20(0);
3918 CLEAR_CF();
3919 regs.u.r8.ah = 0;
3920 break;
3921 case 0x01:
3922 set_enable_a20(1);
3923 CLEAR_CF();
3924 regs.u.r8.ah = 0;
3925 break;
3926 case 0x02:
3927 regs.u.r8.al = (inb(0x92) >> 1) & 0x01;
3928 CLEAR_CF();
3929 regs.u.r8.ah = 0;
3930 break;
3931 case 0x03:
3932 CLEAR_CF();
3933 regs.u.r8.ah = 0;
3934 regs.u.r16.bx = 3;
3935 break;
3936 default:
3937 BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs.u.r8.al);
3938 SET_CF();
3939 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3940 }
3941 break;
3942
3943 case 0x41:
3944 SET_CF();
3945 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3946 break;
3947
3948 case 0x4f:
3949 /* keyboard intercept */
3950#if BX_CPU < 2
3951 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3952#else
3953 // nop
3954#endif
3955 SET_CF();
3956 break;
3957
3958 case 0x52: // removable media eject
3959 CLEAR_CF();
3960 regs.u.r8.ah = 0; // "ok ejection may proceed"
3961 break;
3962
3963 case 0x83: {
3964 if( regs.u.r8.al == 0 ) {
3965 // Set Interval requested.
3966 if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
3967 // Interval not already set.
3968 write_byte( 0x40, 0xA0, 1 ); // Set status byte.
3969 write_word( 0x40, 0x98, ES ); // Byte location, segment
3970 write_word( 0x40, 0x9A, regs.u.r16.bx ); // Byte location, offset
3971 write_word( 0x40, 0x9C, regs.u.r16.dx ); // Low word, delay
3972 write_word( 0x40, 0x9E, regs.u.r16.cx ); // High word, delay.
3973 CLEAR_CF( );
3974 irqDisable = inb( 0xA1 );
3975 outb( 0xA1, irqDisable & 0xFE );
3976 bRegister = inb_cmos( 0xB ); // Unmask IRQ8 so INT70 will get through.
3977 outb_cmos( 0xB, bRegister | 0x40 ); // Turn on the Periodic Interrupt timer
3978 } else {
3979 // Interval already set.
3980 BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
3981 SET_CF();
3982 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3983 }
3984 } else if( regs.u.r8.al == 1 ) {
3985 // Clear Interval requested
3986 write_byte( 0x40, 0xA0, 0 ); // Clear status byte
3987 CLEAR_CF( );
3988 bRegister = inb_cmos( 0xB );
3989 outb_cmos( 0xB, bRegister & ~0x40 ); // Turn off the Periodic Interrupt timer
3990 } else {
3991 BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
3992 SET_CF();
3993 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3994 regs.u.r8.al--;
3995 }
3996
3997 break;
3998 }
3999
4000 case 0x87:
4001#if BX_CPU < 3
4002# error "Int15 function 87h not supported on < 80386"
4003#endif
4004 // +++ should probably have descriptor checks
4005 // +++ should have exception handlers
4006
4007 // turn off interrupts
4008ASM_START
4009 cli
4010ASM_END
4011
4012 prev_a20_enable = set_enable_a20(1); // enable A20 line
4013
4014 // 128K max of transfer on 386+ ???
4015 // source == destination ???
4016
4017 // ES:SI points to descriptor table
4018 // offset use initially comments
4019 // ==============================================
4020 // 00..07 Unused zeros Null descriptor
4021 // 08..0f GDT zeros filled in by BIOS
4022 // 10..17 source ssssssss source of data
4023 // 18..1f dest dddddddd destination of data
4024 // 20..27 CS zeros filled in by BIOS
4025 // 28..2f SS zeros filled in by BIOS
4026
4027 //es:si
4028 //eeee0
4029 //0ssss
4030 //-----
4031
4032// check for access rights of source & dest here
4033
4034 // Initialize GDT descriptor
4035 base15_00 = (ES << 4) + regs.u.r16.si;
4036 base23_16 = ES >> 12;
4037 if (base15_00 < (ES<<4))
4038 base23_16++;
4039 write_word(ES, regs.u.r16.si+0x08+0, 47); // limit 15:00 = 6 * 8bytes/descriptor
4040 write_word(ES, regs.u.r16.si+0x08+2, base15_00);// base 15:00
4041 write_byte(ES, regs.u.r16.si+0x08+4, base23_16);// base 23:16
4042 write_byte(ES, regs.u.r16.si+0x08+5, 0x93); // access
4043 write_word(ES, regs.u.r16.si+0x08+6, 0x0000); // base 31:24/reserved/limit 19:16
4044
4045 // Initialize CS descriptor
4046 write_word(ES, regs.u.r16.si+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
4047 write_word(ES, regs.u.r16.si+0x20+2, 0x0000);// base 15:00
4048 write_byte(ES, regs.u.r16.si+0x20+4, 0x000f);// base 23:16
4049 write_byte(ES, regs.u.r16.si+0x20+5, 0x9b); // access
4050 write_word(ES, regs.u.r16.si+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
4051
4052 // Initialize SS descriptor
4053 ss = get_SS();
4054 base15_00 = ss << 4;
4055 base23_16 = ss >> 12;
4056 write_word(ES, regs.u.r16.si+0x28+0, 0xffff); // limit 15:00 = normal 64K limit
4057 write_word(ES, regs.u.r16.si+0x28+2, base15_00);// base 15:00
4058 write_byte(ES, regs.u.r16.si+0x28+4, base23_16);// base 23:16
4059 write_byte(ES, regs.u.r16.si+0x28+5, 0x93); // access
4060 write_word(ES, regs.u.r16.si+0x28+6, 0x0000); // base 31:24/reserved/limit 19:16
4061
4062 CX = regs.u.r16.cx;
4063ASM_START
4064 // Compile generates locals offset info relative to SP.
4065 // Get CX (word count) from stack.
4066 mov bx, sp
4067 SEG SS
4068 mov cx, _int15_function.CX [bx]
4069
4070 // since we need to set SS:SP, save them to the BDA
4071 // for future restore
4072 push eax
4073 xor eax, eax
4074 mov ds, ax
4075 mov 0x0469, ss
4076 mov 0x0467, sp
4077
4078 SEG ES
4079 lgdt [si + 0x08]
4080 SEG CS
4081 lidt [pmode_IDT_info]
4082 ;; perhaps do something with IDT here
4083
4084 ;; set PE bit in CR0
4085 mov eax, cr0
4086 or al, #0x01
4087 mov cr0, eax
4088 ;; far jump to flush CPU queue after transition to protected mode
4089 JMP_AP(0x0020, protected_mode)
4090
4091protected_mode:
4092 ;; GDT points to valid descriptor table, now load SS, DS, ES
4093 mov ax, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
4094 mov ss, ax
4095 mov ax, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
4096 mov ds, ax
4097 mov ax, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
4098 mov es, ax
4099 xor si, si
4100 xor di, di
4101 cld
4102 rep
4103 movsw ;; move CX words from DS:SI to ES:DI
4104
4105 ;; make sure DS and ES limits are 64KB
4106 mov ax, #0x28
4107 mov ds, ax
4108 mov es, ax
4109
4110 ;; reset PG bit in CR0 ???
4111 mov eax, cr0
4112 and al, #0xFE
4113 mov cr0, eax
4114
4115 ;; far jump to flush CPU queue after transition to real mode
4116 JMP_AP(0xf000, real_mode)
4117
4118real_mode:
4119 ;; restore IDT to normal real-mode defaults
4120 SEG CS
4121 lidt [rmode_IDT_info]
4122
4123 // restore SS:SP from the BDA
4124 xor ax, ax
4125 mov ds, ax
4126 mov ss, 0x0469
4127 mov sp, 0x0467
4128 pop eax
4129ASM_END
4130
4131 set_enable_a20(prev_a20_enable);
4132
4133 // turn back on interrupts
4134ASM_START
4135 sti
4136ASM_END
4137
4138 regs.u.r8.ah = 0;
4139 CLEAR_CF();
4140 break;
4141
4142
4143 case 0x88:
4144 // Get the amount of extended memory (above 1M)
4145#if BX_CPU < 2
4146 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4147 SET_CF();
4148#else
4149 regs.u.r8.al = inb_cmos(0x30);
4150 regs.u.r8.ah = inb_cmos(0x31);
4151
4152 // According to Ralf Brown's interrupt the limit should be 15M,
4153 // but real machines mostly return max. 63M.
4154 if(regs.u.r16.ax > 0xffc0)
4155 regs.u.r16.ax = 0xffc0;
4156
4157 CLEAR_CF();
4158#endif
4159 break;
4160
4161#ifdef VBOX
4162 case 0x89:
4163 // Switch to Protected Mode.
4164 // ES:DI points to user-supplied GDT
4165 // BH/BL contains starting interrupt numbers for PIC0/PIC1
4166 // This subfunction does not return!
4167
4168// turn off interrupts
4169ASM_START
4170 cli
4171ASM_END
4172
4173 set_enable_a20(1); // enable A20 line; we're supposed to fail if that fails
4174
4175 // Initialize CS descriptor for BIOS
4176 write_word(ES, regs.u.r16.si+0x38+0, 0xffff);// limit 15:00 = normal 64K limit
4177 write_word(ES, regs.u.r16.si+0x38+2, 0x0000);// base 15:00
4178 write_byte(ES, regs.u.r16.si+0x38+4, 0x000f);// base 23:16 (hardcoded to f000:0000)
4179 write_byte(ES, regs.u.r16.si+0x38+5, 0x9b); // access
4180 write_word(ES, regs.u.r16.si+0x38+6, 0x0000);// base 31:24/reserved/limit 19:16
4181
4182 BX = regs.u.r16.bx;
4183ASM_START
4184 // Compiler generates locals offset info relative to SP.
4185 // Get BX (PIC offsets) from stack.
4186 mov bx, sp
4187 SEG SS
4188 mov bx, _int15_function.BX [bx]
4189
4190 // Program PICs
4191 mov al, #0x11 ; send initialisation commands
4192 out 0x20, al
4193 out 0xa0, al
4194 mov al, bh
4195 out 0x21, al
4196 mov al, bl
4197 out 0xa1, al
4198 mov al, #0x04
4199 out 0x21, al
4200 mov al, #0x02
4201 out 0xa1, al
4202 mov al, #0x01
4203 out 0x21, al
4204 out 0xa1, al
4205 mov al, #0xff ; mask all IRQs, user must re-enable
4206 out 0x21, al
4207 out 0xa1, al
4208
4209 // Load GDT and IDT from supplied data
4210 SEG ES
4211 lgdt [si + 0x08]
4212 SEG ES
4213 lidt [si + 0x10]
4214
4215 // set PE bit in CR0
4216 mov eax, cr0
4217 or al, #0x01
4218 mov cr0, eax
4219 // far jump to flush CPU queue after transition to protected mode
4220 JMP_AP(0x0038, protmode_switch)
4221
4222protmode_switch:
4223 ;; GDT points to valid descriptor table, now load SS, DS, ES
4224 mov ax, #0x28
4225 mov ss, ax
4226 mov ax, #0x18
4227 mov ds, ax
4228 mov ax, #0x20
4229 mov es, ax
4230
4231 // unwind the stack - this will break if calling sequence changes!
4232 mov sp,bp
4233 add sp,#4 ; skip return address
4234 popa ; restore regs
4235 pop ax ; skip saved es
4236 pop ax ; skip saved ds
4237 pop ax ; skip saved flags
4238
4239 // return to caller - note that we do not use IRET because
4240 // we cannot enable interrupts
4241 pop cx ; get return offset
4242 pop ax ; skip return segment
4243 pop ax ; skip flags
4244 mov ax, #0x30 ; ah must be 0 on successful exit
4245 push ax
4246 push cx ; re-create modified ret address on stack
4247 retf
4248
4249ASM_END
4250
4251 break;
4252#endif /* VBOX */
4253
4254 case 0x90:
4255 /* Device busy interrupt. Called by Int 16h when no key available */
4256 break;
4257
4258 case 0x91:
4259 /* Interrupt complete. Called by Int 16h when key becomes available */
4260 break;
4261
4262 case 0xbf:
4263 BX_INFO("*** int 15h function AH=bf not yet supported!\n");
4264 SET_CF();
4265 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4266 break;
4267
4268 case 0xC0:
4269#if 0
4270 SET_CF();
4271 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4272 break;
4273#endif
4274 CLEAR_CF();
4275 regs.u.r8.ah = 0;
4276 regs.u.r16.bx = BIOS_CONFIG_TABLE;
4277 ES = 0xF000;
4278 break;
4279
4280 case 0xc1:
4281 ES = ebda_seg;
4282 CLEAR_CF();
4283 break;
4284
4285 case 0xd8:
4286 bios_printf(BIOS_PRINTF_DEBUG, "EISA BIOS not present\n");
4287 SET_CF();
4288 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4289 break;
4290
4291#ifdef VBOX
4292 /* Make the BIOS warning for pretty much every Linux kernel start
4293 * disappear - it calls with ax=0xe980 to figure out SMI info. */
4294 case 0xe9: /* SMI functions (SpeedStep and similar things) */
4295 SET_CF();
4296 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4297 break;
4298 case 0xec: /* AMD64 target operating mode callback */
4299 if (regs.u.r8.al != 0)
4300 goto undecoded;
4301 regs.u.r8.ah = 0;
4302 if (regs.u.r8.bl >= 1 && regs.u.r8.bl <= 3)
4303 CLEAR_CF(); /* Accepted value. */
4304 else
4305 SET_CF(); /* Reserved, error. */
4306 break;
4307undecoded:
4308#endif /* VBOX */
4309 default:
4310 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4311 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4312 SET_CF();
4313 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4314 break;
4315 }
4316}
4317
4318#if BX_USE_PS2_MOUSE
4319 void
4320int15_function_mouse(regs, ES, DS, FLAGS)
4321 pusha_regs_t regs; // REGS pushed via pusha
4322 Bit16u ES, DS, FLAGS;
4323{
4324 Bit16u ebda_seg=read_word(0x0040,0x000E);
4325 Bit8u mouse_flags_1, mouse_flags_2;
4326 Bit16u mouse_driver_seg;
4327 Bit16u mouse_driver_offset;
4328 Bit8u mouse_cmd;
4329 Bit8u ret, mouse_data1, mouse_data2, mouse_data3;
4330
4331BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4332
4333 switch (regs.u.r8.ah) {
4334 case 0xC2:
4335 // Return Codes status in AH
4336 // =========================
4337 // 00: success
4338 // 01: invalid subfunction (AL > 7)
4339 // 02: invalid input value (out of allowable range)
4340 // 03: interface error
4341 // 04: resend command received from mouse controller,
4342 // device driver should attempt command again
4343 // 05: cannot enable mouse, since no far call has been installed
4344 // 80/86: mouse service not implemented
4345
4346 if (regs.u.r8.al > 7) {
4347BX_DEBUG_INT15("unsupported subfn\n");
4348 // invalid function
4349 SET_CF();
4350 regs.u.r8.ah = 1;
4351 break;
4352 }
4353
4354 // Valid subfn; disable AUX input and IRQ12, assume no error
4355 set_kbd_command_byte(0x65);
4356 CLEAR_CF();
4357 regs.u.r8.ah = 0;
4358
4359 switch (regs.u.r8.al) {
4360 case 0: // Disable/Enable Mouse
4361BX_DEBUG_INT15("case 0: ");
4362 if (regs.u.r8.bh > 1) {
4363 BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs.u.r8.bh);
4364 // invalid subfunction
4365 SET_CF();
4366 regs.u.r8.ah = 1;
4367 break;
4368 }
4369 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4370 if ( (mouse_flags_2 & 0x80) == 0 ) {
4371 BX_DEBUG_INT15("INT 15h C2 Enable/Disable Mouse, no far call handler\n");
4372 SET_CF();
4373 regs.u.r8.ah = 5; // no far call installed
4374 break;
4375 }
4376 if (regs.u.r8.bh == 0) {
4377BX_DEBUG_INT15("Disable Mouse\n");
4378 mouse_cmd = 0xF5; // disable mouse command
4379 } else {
4380BX_DEBUG_INT15("Enable Mouse\n");
4381 mouse_cmd = 0xF4; // enable mouse command
4382 }
4383
4384 ret = send_to_mouse_ctrl(mouse_cmd); // disable mouse command
4385 if (ret == 0) {
4386 ret = get_mouse_data(&mouse_data1);
4387 if ( (ret == 0) || (mouse_data1 == 0xFA) ) {
4388 // success
4389 break;
4390 }
4391 }
4392
4393 // interface error
4394 SET_CF();
4395 regs.u.r8.ah = 3;
4396 break;
4397
4398 case 5: // Initialize Mouse
4399 // Valid package sizes are 1 to 8
4400 if ( (regs.u.r8.bh < 1) || (regs.u.r8.bh > 8) ) {
4401 SET_CF();
4402 regs.u.r8.ah = 2; // invalid input
4403 break;
4404 }
4405 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4406 mouse_flags_2 = (mouse_flags_2 & 0xf8) | (regs.u.r8.bh - 1);
4407 write_byte(ebda_seg, 0x0027, mouse_flags_2);
4408 // fall through!
4409
4410 case 1: // Reset Mouse
4411BX_DEBUG_INT15("case 1 or 5:\n");
4412 // clear current package byte index
4413 mouse_flags_1 = read_byte(ebda_seg, 0x0026);
4414 mouse_flags_1 = mouse_flags_1 & 0xf8;
4415 write_byte(ebda_seg, 0x0026, mouse_flags_1);
4416 ret = send_to_mouse_ctrl(0xFF); // reset mouse command
4417 if (ret == 0) {
4418 ret = get_mouse_data(&mouse_data3);
4419 // if no mouse attached, it will return RESEND
4420 if (mouse_data3 == 0xfe) {
4421 SET_CF();
4422 regs.u.r8.ah = 4; // resend
4423 break;
4424 }
4425 if (mouse_data3 != 0xfa)
4426 BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3);
4427 if ( ret == 0 ) {
4428 ret = get_mouse_data(&mouse_data1);
4429 if ( ret == 0 ) {
4430 ret = get_mouse_data(&mouse_data2);
4431 if ( ret == 0 ) {
4432 // success
4433 regs.u.r8.bl = mouse_data1;
4434 regs.u.r8.bh = mouse_data2;
4435 break;
4436 }
4437 }
4438 }
4439 }
4440
4441 // interface error
4442 SET_CF();
4443 regs.u.r8.ah = 3;
4444 break;
4445
4446 case 2: // Set Sample Rate
4447BX_DEBUG_INT15("case 2:\n");
4448 switch (regs.u.r8.bh) {
4449 case 0: mouse_data1 = 10; break; // 10 reports/sec
4450 case 1: mouse_data1 = 20; break; // 20 reports/sec
4451 case 2: mouse_data1 = 40; break; // 40 reports/sec
4452 case 3: mouse_data1 = 60; break; // 60 reports/sec
4453 case 4: mouse_data1 = 80; break; // 80 reports/sec
4454 case 5: mouse_data1 = 100; break; // 100 reports/sec (default)
4455 case 6: mouse_data1 = 200; break; // 200 reports/sec
4456 default: mouse_data1 = 0;
4457 }
4458 if (mouse_data1 > 0) {
4459 ret = send_to_mouse_ctrl(0xF3); // set sample rate command
4460 if (ret == 0) {
4461 ret = get_mouse_data(&mouse_data2);
4462 ret = send_to_mouse_ctrl(mouse_data1);
4463 ret = get_mouse_data(&mouse_data2);
4464 // success
4465 } else {
4466 // interface error
4467 SET_CF();
4468 regs.u.r8.ah = 3;
4469 }
4470 } else {
4471 // invalid input
4472 SET_CF();
4473 regs.u.r8.ah = 2;
4474 }
4475 break;
4476
4477 case 3: // Set Resolution
4478BX_DEBUG_INT15("case 3:\n");
4479 // BX:
4480 // 0 = 25 dpi, 1 count per millimeter
4481 // 1 = 50 dpi, 2 counts per millimeter
4482 // 2 = 100 dpi, 4 counts per millimeter
4483 // 3 = 200 dpi, 8 counts per millimeter
4484 if (regs.u.r8.bh < 4) {
4485 ret = send_to_mouse_ctrl(0xE8); // set resolution command
4486 if (ret == 0) {
4487 ret = get_mouse_data(&mouse_data1);
4488 if (mouse_data1 != 0xfa)
4489 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4490 ret = send_to_mouse_ctrl(regs.u.r8.bh);
4491 ret = get_mouse_data(&mouse_data1);
4492 if (mouse_data1 != 0xfa)
4493 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4494 // success
4495 } else {
4496 // interface error
4497 SET_CF();
4498 regs.u.r8.ah = 3;
4499 }
4500 } else {
4501 // invalid input
4502 SET_CF();
4503 regs.u.r8.ah = 2;
4504 }
4505 break;
4506
4507 case 4: // Get Device ID
4508BX_DEBUG_INT15("case 4:\n");
4509 ret = send_to_mouse_ctrl(0xF2); // get mouse ID command
4510 if (ret == 0) {
4511 ret = get_mouse_data(&mouse_data1);
4512 ret = get_mouse_data(&mouse_data2);
4513 regs.u.r8.bh = mouse_data2;
4514 // success
4515 } else {
4516 // interface error
4517 SET_CF();
4518 regs.u.r8.ah = 3;
4519 }
4520 break;
4521
4522 case 6: // Return Status & Set Scaling Factor...
4523BX_DEBUG_INT15("case 6:\n");
4524 switch (regs.u.r8.bh) {
4525 case 0: // Return Status
4526 ret = send_to_mouse_ctrl(0xE9); // get mouse info command
4527 if (ret == 0) {
4528 ret = get_mouse_data(&mouse_data1);
4529 if (mouse_data1 != 0xfa)
4530 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4531 if (ret == 0) {
4532 ret = get_mouse_data(&mouse_data1);
4533 if ( ret == 0 ) {
4534 ret = get_mouse_data(&mouse_data2);
4535 if ( ret == 0 ) {
4536 ret = get_mouse_data(&mouse_data3);
4537 if ( ret == 0 ) {
4538 regs.u.r8.bl = mouse_data1;
4539 regs.u.r8.cl = mouse_data2;
4540 regs.u.r8.dl = mouse_data3;
4541 // success
4542 break;
4543 }
4544 }
4545 }
4546 }
4547 }
4548
4549 // interface error
4550 SET_CF();
4551 regs.u.r8.ah = 3;
4552 break;
4553
4554 case 1: // Set Scaling Factor to 1:1
4555 case 2: // Set Scaling Factor to 2:1
4556 if (regs.u.r8.bh == 1) {
4557 ret = send_to_mouse_ctrl(0xE6);
4558 } else {
4559 ret = send_to_mouse_ctrl(0xE7);
4560 }
4561 if (ret == 0) {
4562 get_mouse_data(&mouse_data1);
4563 ret = (mouse_data1 != 0xFA);
4564 }
4565 if (ret != 0) {
4566 // interface error
4567 SET_CF();
4568 regs.u.r8.ah = 3;
4569 }
4570 break;
4571
4572 default:
4573 BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs.u.r8.bh);
4574 // invalid subfunction
4575 SET_CF();
4576 regs.u.r8.ah = 1;
4577 }
4578 break;
4579
4580 case 7: // Set Mouse Handler Address
4581BX_DEBUG_INT15("case 7:\n");
4582 mouse_driver_seg = ES;
4583 mouse_driver_offset = regs.u.r16.bx;
4584 write_word(ebda_seg, 0x0022, mouse_driver_offset);
4585 write_word(ebda_seg, 0x0024, mouse_driver_seg);
4586 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4587 if (mouse_driver_offset == 0 && mouse_driver_seg == 0) {
4588 /* remove handler */
4589 if ( (mouse_flags_2 & 0x80) != 0 ) {
4590 mouse_flags_2 &= ~0x80;
4591 }
4592 }
4593 else {
4594 /* install handler */
4595 mouse_flags_2 |= 0x80;
4596 }
4597 write_byte(ebda_seg, 0x0027, mouse_flags_2);
4598 break;
4599
4600 default:
4601 BX_PANIC("INT 15h C2 default case entered\n");
4602 // invalid subfunction
4603 SET_CF();
4604 regs.u.r8.ah = 1;
4605 }
4606BX_DEBUG_INT15("returning cf = %u, ah = %02x\n", (unsigned)GET_CF(), (unsigned)regs.u.r8.ah);
4607 // Re-enable AUX input and IRQ12
4608 set_kbd_command_byte(0x47);
4609 break;
4610
4611 default:
4612 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4613 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4614 SET_CF();
4615 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4616 break;
4617 }
4618}
4619#endif // BX_USE_PS2_MOUSE
4620
4621
4622void set_e820_range(ES, DI, start, end, extra_start, extra_end, type)
4623 Bit16u ES;
4624 Bit16u DI;
4625 Bit32u start;
4626 Bit32u end;
4627 Bit8u extra_start;
4628 Bit8u extra_end;
4629 Bit16u type;
4630{
4631 write_word(ES, DI, start);
4632 write_word(ES, DI+2, start >> 16);
4633 write_word(ES, DI+4, extra_start);
4634 write_word(ES, DI+6, 0x00);
4635
4636 end -= start;
4637 extra_end -= extra_start;
4638 write_word(ES, DI+8, end);
4639 write_word(ES, DI+10, end >> 16);
4640 write_word(ES, DI+12, extra_end);
4641 write_word(ES, DI+14, 0x0000);
4642
4643 write_word(ES, DI+16, type);
4644 write_word(ES, DI+18, 0x0);
4645}
4646
4647 void
4648int15_function32(regs, ES, DS, FLAGS)
4649 pushad_regs_t regs; // REGS pushed via pushad
4650 Bit16u ES, DS, FLAGS;
4651{
4652 Bit32u extended_memory_size=0; // 64bits long
4653 Bit32u extra_lowbits_memory_size=0;
4654 Bit16u CX,DX;
4655 Bit8u extra_highbits_memory_size=0;
4656
4657BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4658
4659 switch (regs.u.r8.ah) {
4660 case 0x86:
4661 // Wait for CX:DX microseconds. currently using the
4662 // refresh request port 0x61 bit4, toggling every 15usec
4663
4664 CX = regs.u.r16.cx;
4665 DX = regs.u.r16.dx;
4666
4667ASM_START
4668 sti
4669
4670 ;; Get the count in eax
4671 ;; VBOX: corrected _int15_function -> _int15_function32 here.
4672 mov bx, sp
4673 SEG SS
4674 mov ax, _int15_function32.CX [bx]
4675 shl eax, #16
4676 SEG SS
4677 mov ax, _int15_function32.DX [bx]
4678
4679 ;; convert to numbers of 15usec ticks
4680 mov ebx, #15
4681 xor edx, edx
4682 div eax, ebx
4683 mov ecx, eax
4684
4685 ;; wait for ecx number of refresh requests
4686 in al, #0x61
4687 and al,#0x10
4688 mov ah, al
4689
4690 or ecx, ecx
4691 je int1586_tick_end
4692int1586_tick:
4693 in al, #0x61
4694 and al,#0x10
4695 cmp al, ah
4696 je int1586_tick
4697 mov ah, al
4698 dec ecx
4699 jnz int1586_tick
4700int1586_tick_end:
4701ASM_END
4702
4703 break;
4704
4705 case 0xe8:
4706 switch(regs.u.r8.al)
4707 {
4708 case 0x20: // coded by osmaker aka K.J.
4709 if(regs.u.r32.edx == 0x534D4150)
4710 {
4711 extended_memory_size = inb_cmos(0x35);
4712 extended_memory_size <<= 8;
4713 extended_memory_size |= inb_cmos(0x34);
4714 extended_memory_size *= 64;
4715#ifndef VBOX /* The following excludes 0xf0000000 thru 0xffffffff. Trust DevPcBios.cpp to get this right. */
4716 // greater than EFF00000???
4717 if(extended_memory_size > 0x3bc000) {
4718 extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4719 }
4720#endif /* !VBOX */
4721 extended_memory_size *= 1024;
4722 extended_memory_size += (16L * 1024 * 1024);
4723
4724 if(extended_memory_size <= (16L * 1024 * 1024)) {
4725 extended_memory_size = inb_cmos(0x31);
4726 extended_memory_size <<= 8;
4727 extended_memory_size |= inb_cmos(0x30);
4728 extended_memory_size *= 1024;
4729 extended_memory_size += (1L * 1024 * 1024);
4730 }
4731
4732#ifdef VBOX /* We've already used the CMOS entries for SATA.
4733 BTW. This is the amount of memory above 4GB measured in 64KB units. */
4734 extra_lowbits_memory_size = inb_cmos(0x62);
4735 extra_lowbits_memory_size <<= 8;
4736 extra_lowbits_memory_size |= inb_cmos(0x61);
4737 extra_lowbits_memory_size <<= 16;
4738 extra_highbits_memory_size = inb_cmos(0x63);
4739 /* 0x64 and 0x65 can be used if we need to dig 1 TB or more at a later point. */
4740#else
4741 extra_lowbits_memory_size = inb_cmos(0x5c);
4742 extra_lowbits_memory_size <<= 8;
4743 extra_lowbits_memory_size |= inb_cmos(0x5b);
4744 extra_lowbits_memory_size *= 64;
4745 extra_lowbits_memory_size *= 1024;
4746 extra_highbits_memory_size = inb_cmos(0x5d);
4747#endif /* !VBOX */
4748
4749 switch(regs.u.r16.bx)
4750 {
4751 case 0:
4752 set_e820_range(ES, regs.u.r16.di,
4753#ifndef VBOX /** @todo Upstream suggests the following, needs checking. (see next as well) */
4754 0x0000000L, 0x0009f000L, 0, 0, 1);
4755#else
4756 0x0000000L, 0x0009fc00L, 0, 0, 1);
4757#endif
4758 regs.u.r32.ebx = 1;
4759 break;
4760 case 1:
4761 set_e820_range(ES, regs.u.r16.di,
4762#ifndef VBOX /** @todo Upstream suggests the following, needs checking. (see next as well) */
4763 0x0009f000L, 0x000a0000L, 0, 0, 2);
4764#else
4765 0x0009fc00L, 0x000a0000L, 0, 0, 2);
4766#endif
4767 regs.u.r32.ebx = 2;
4768 break;
4769 case 2:
4770#ifdef VBOX
4771 /* Mark the BIOS as reserved. VBox doesn't currently
4772 * use the 0xe0000-0xeffff area. It does use the
4773 * 0xd0000-0xdffff area for the BIOS logo, but it's
4774 * not worth marking it as reserved. Note that various
4775 * Windows versions don't accept (read: in debug builds
4776 * they trigger the "Too many similar traps" assertion)
4777 * a single reserved range from 0xd0000 to 0xffffff.
4778 * A 128K area starting from 0xd0000 works. */
4779 set_e820_range(ES, regs.u.r16.di,
4780 0x000f0000L, 0x00100000L, 0, 0, 2);
4781#else /* !VBOX */
4782 set_e820_range(ES, regs.u.r16.di,
4783 0x000e8000L, 0x00100000L, 0, 0, 2);
4784#endif /* !VBOX */
4785 regs.u.r32.ebx = 3;
4786 break;
4787 case 3:
4788#if BX_ROMBIOS32 || defined(VBOX)
4789 set_e820_range(ES, regs.u.r16.di,
4790 0x00100000L,
4791 extended_memory_size - ACPI_DATA_SIZE, 0, 0, 1);
4792 regs.u.r32.ebx = 4;
4793#else
4794 set_e820_range(ES, regs.u.r16.di,
4795 0x00100000L,
4796 extended_memory_size, 1);
4797 regs.u.r32.ebx = 5;
4798#endif
4799 break;
4800 case 4:
4801 set_e820_range(ES, regs.u.r16.di,
4802 extended_memory_size - ACPI_DATA_SIZE,
4803 extended_memory_size, 0, 0, 3); // ACPI RAM
4804 regs.u.r32.ebx = 5;
4805 break;
4806 case 5:
4807 /* 256KB BIOS area at the end of 4 GB */
4808#ifdef VBOX
4809 /* We don't set the end to 1GB here and rely on the 32-bit
4810 unsigned wrap around effect (0-0xfffc0000L). */
4811#endif
4812 set_e820_range(ES, regs.u.r16.di,
4813 0xfffc0000L, 0x00000000L, 0, 0, 2);
4814 /* Temporary disabled MCFG code */
4815#if 0
4816 regs.u.r32.ebx = 6;
4817 break;
4818 case 6:
4819 /* PCI MMIO config space */
4820 set_e820_range(ES, regs.u.r16.di,
4821 0xd0000000L, 0xe0000000L, 0, 0, 2);
4822 if (extra_highbits_memory_size || extra_lowbits_memory_size)
4823 regs.u.r32.ebx = 7;
4824 else
4825 regs.u.r32.ebx = 0;
4826 break;
4827 case 7:
4828#else
4829 if (extra_highbits_memory_size || extra_lowbits_memory_size)
4830 regs.u.r32.ebx = 6;
4831 else
4832 regs.u.r32.ebx = 0;
4833 break;
4834 case 6:
4835#endif
4836#ifdef VBOX /* Don't succeeded if no memory above 4 GB. */
4837 /* Mapping of memory above 4 GB if present.
4838 Note: set_e820_range needs do no borrowing in the
4839 subtraction because of the nice numbers. */
4840 if (extra_highbits_memory_size || extra_lowbits_memory_size)
4841 {
4842 set_e820_range(ES, regs.u.r16.di,
4843 0x00000000L, extra_lowbits_memory_size,
4844 1 /*GB*/, extra_highbits_memory_size + 1 /*GB*/, 1);
4845 regs.u.r32.ebx = 0;
4846 }
4847 break;
4848 /* fall thru */
4849#else /* !VBOX */
4850 /* Mapping of memory above 4 GB */
4851 set_e820_range(ES, regs.u.r16.di, 0x00000000L,
4852 extra_lowbits_memory_size, 1, extra_highbits_memory_size
4853 + 1, 1);
4854 regs.u.r32.ebx = 0;
4855 break;
4856#endif /* !VBOX */
4857 default: /* AX=E820, DX=534D4150, BX unrecognized */
4858 goto int15_unimplemented;
4859 break;
4860 }
4861 regs.u.r32.eax = 0x534D4150;
4862 regs.u.r32.ecx = 0x14;
4863 CLEAR_CF();
4864 } else {
4865 // if DX != 0x534D4150)
4866 goto int15_unimplemented;
4867 }
4868 break;
4869
4870 case 0x01:
4871 // do we have any reason to fail here ?
4872 CLEAR_CF();
4873
4874 // my real system sets ax and bx to 0
4875 // this is confirmed by Ralph Brown list
4876 // but syslinux v1.48 is known to behave
4877 // strangely if ax is set to 0
4878 // regs.u.r16.ax = 0;
4879 // regs.u.r16.bx = 0;
4880
4881 // Get the amount of extended memory (above 1M)
4882 regs.u.r8.cl = inb_cmos(0x30);
4883 regs.u.r8.ch = inb_cmos(0x31);
4884
4885 // limit to 15M
4886 if(regs.u.r16.cx > 0x3c00)
4887 {
4888 regs.u.r16.cx = 0x3c00;
4889 }
4890
4891 // Get the amount of extended memory above 16M in 64k blocs
4892 regs.u.r8.dl = inb_cmos(0x34);
4893 regs.u.r8.dh = inb_cmos(0x35);
4894
4895 // Set configured memory equal to extended memory
4896 regs.u.r16.ax = regs.u.r16.cx;
4897 regs.u.r16.bx = regs.u.r16.dx;
4898 break;
4899 default: /* AH=0xE8?? but not implemented */
4900 goto int15_unimplemented;
4901 }
4902 break;
4903 int15_unimplemented:
4904 // fall into the default
4905 default:
4906 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4907 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4908 SET_CF();
4909 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4910 break;
4911 }
4912}
4913
4914 void
4915int16_function(DI, SI, BP, SP, BX, DX, CX, AX, FLAGS)
4916 Bit16u DI, SI, BP, SP, BX, DX, CX, AX, FLAGS;
4917{
4918 Bit8u scan_code, ascii_code, shift_flags, led_flags, count;
4919 Bit16u kbd_code, max;
4920
4921 BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX, BX, CX, DX);
4922
4923 shift_flags = read_byte(0x0040, 0x17);
4924 led_flags = read_byte(0x0040, 0x97);
4925 if ((((shift_flags >> 4) & 0x07) ^ (led_flags & 0x07)) != 0) {
4926ASM_START
4927 cli
4928ASM_END
4929 outb(0x60, 0xed);
4930 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
4931 if ((inb(0x60) == 0xfa)) {
4932 led_flags &= 0xf8;
4933 led_flags |= ((shift_flags >> 4) & 0x07);
4934 outb(0x60, led_flags & 0x07);
4935 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
4936 inb(0x60);
4937 write_byte(0x0040, 0x97, led_flags);
4938 }
4939ASM_START
4940 sti
4941ASM_END
4942 }
4943
4944 switch (GET_AH()) {
4945 case 0x00: /* read keyboard input */
4946
4947 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4948 BX_PANIC("KBD: int16h: out of keyboard input\n");
4949 }
4950 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4951 else if (ascii_code == 0xE0) ascii_code = 0;
4952 AX = (scan_code << 8) | ascii_code;
4953 break;
4954
4955 case 0x01: /* check keyboard status */
4956 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4957 SET_ZF();
4958 return;
4959 }
4960 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4961 else if (ascii_code == 0xE0) ascii_code = 0;
4962 AX = (scan_code << 8) | ascii_code;
4963 CLEAR_ZF();
4964 break;
4965
4966 case 0x02: /* get shift flag status */
4967 shift_flags = read_byte(0x0040, 0x17);
4968 SET_AL(shift_flags);
4969 break;
4970
4971 case 0x05: /* store key-stroke into buffer */
4972 if ( !enqueue_key(GET_CH(), GET_CL()) ) {
4973 SET_AL(1);
4974 }
4975 else {
4976 SET_AL(0);
4977 }
4978 break;
4979
4980 case 0x09: /* GET KEYBOARD FUNCTIONALITY */
4981 // bit Bochs Description
4982 // 7 0 reserved
4983 // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
4984 // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
4985 // 4 1 INT 16/AH=0Ah supported
4986 // 3 0 INT 16/AX=0306h supported
4987 // 2 0 INT 16/AX=0305h supported
4988 // 1 0 INT 16/AX=0304h supported
4989 // 0 0 INT 16/AX=0300h supported
4990 //
4991 SET_AL(0x30);
4992 break;
4993
4994 case 0x0A: /* GET KEYBOARD ID */
4995 count = 2;
4996 kbd_code = 0x0;
4997 outb(0x60, 0xf2);
4998 /* Wait for data */
4999 max=0xffff;
5000 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
5001 if (max>0x0) {
5002 if ((inb(0x60) == 0xfa)) {
5003 do {
5004 max=0xffff;
5005 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
5006 if (max>0x0) {
5007 kbd_code >>= 8;
5008 kbd_code |= (inb(0x60) << 8);
5009 }
5010 } while (--count>0);
5011 }
5012 }
5013 BX=kbd_code;
5014 break;
5015
5016 case 0x10: /* read MF-II keyboard input */
5017
5018 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
5019 BX_PANIC("KBD: int16h: out of keyboard input\n");
5020 }
5021 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
5022 AX = (scan_code << 8) | ascii_code;
5023 break;
5024
5025 case 0x11: /* check MF-II keyboard status */
5026 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
5027 SET_ZF();
5028 return;
5029 }
5030 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
5031 AX = (scan_code << 8) | ascii_code;
5032 CLEAR_ZF();
5033 break;
5034
5035 case 0x12: /* get extended keyboard status */
5036 shift_flags = read_byte(0x0040, 0x17);
5037 SET_AL(shift_flags);
5038 shift_flags = read_byte(0x0040, 0x18) & 0x73;
5039 shift_flags |= read_byte(0x0040, 0x96) & 0x0c;
5040 SET_AH(shift_flags);
5041 BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX);
5042 break;
5043
5044 case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
5045 SET_AH(0x80); // function int16 ah=0x10-0x12 supported
5046 break;
5047
5048 case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
5049 // don't change AH : function int16 ah=0x20-0x22 NOT supported
5050 break;
5051
5052 case 0x6F:
5053 if (GET_AL() == 0x08)
5054 SET_AH(0x02); // unsupported, aka normal keyboard
5055
5056 default:
5057 BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
5058 }
5059}
5060
5061 unsigned int
5062dequeue_key(scan_code, ascii_code, incr)
5063 Bit8u *scan_code;
5064 Bit8u *ascii_code;
5065 unsigned int incr;
5066{
5067 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail;
5068 Bit16u ss;
5069 Bit8u acode, scode;
5070
5071#if BX_CPU < 2
5072 buffer_start = 0x001E;
5073 buffer_end = 0x003E;
5074#else
5075 buffer_start = read_word(0x0040, 0x0080);
5076 buffer_end = read_word(0x0040, 0x0082);
5077#endif
5078
5079 buffer_head = read_word(0x0040, 0x001a);
5080 buffer_tail = read_word(0x0040, 0x001c);
5081
5082 if (buffer_head != buffer_tail) {
5083 ss = get_SS();
5084 acode = read_byte(0x0040, buffer_head);
5085 scode = read_byte(0x0040, buffer_head+1);
5086 write_byte(ss, ascii_code, acode);
5087 write_byte(ss, scan_code, scode);
5088
5089 if (incr) {
5090 buffer_head += 2;
5091 if (buffer_head >= buffer_end)
5092 buffer_head = buffer_start;
5093 write_word(0x0040, 0x001a, buffer_head);
5094 }
5095 return(1);
5096 }
5097 else {
5098 return(0);
5099 }
5100}
5101
5102static char panic_msg_keyb_buffer_full[] = "%s: keyboard input buffer full\n";
5103
5104 Bit8u
5105send_to_mouse_ctrl(sendbyte)
5106 Bit8u sendbyte;
5107{
5108 Bit8u response;
5109
5110 // wait for chance to write to ctrl
5111 if ( inb(0x64) & 0x02 )
5112 BX_PANIC(panic_msg_keyb_buffer_full,"sendmouse");
5113 outb(0x64, 0xD4);
5114 outb(0x60, sendbyte);
5115 return(0);
5116}
5117
5118
5119 Bit8u
5120get_mouse_data(data)
5121 Bit8u *data;
5122{
5123 Bit8u response;
5124 Bit16u ss;
5125
5126 while ( (inb(0x64) & 0x21) != 0x21 ) {
5127 }
5128
5129 response = inb(0x60);
5130
5131 ss = get_SS();
5132 write_byte(ss, data, response);
5133 return(0);
5134}
5135
5136 void
5137set_kbd_command_byte(command_byte)
5138 Bit8u command_byte;
5139{
5140 if ( inb(0x64) & 0x02 )
5141 BX_PANIC(panic_msg_keyb_buffer_full,"setkbdcomm");
5142
5143 outb(0x64, 0x60); // write command byte
5144 outb(0x60, command_byte);
5145}
5146
5147 void
5148int09_function(DI, SI, BP, SP, BX, DX, CX, AX)
5149 Bit16u DI, SI, BP, SP, BX, DX, CX, AX;
5150{
5151 Bit8u scancode, asciicode, shift_flags;
5152 Bit8u mf2_flags, mf2_state;
5153
5154 //
5155 // DS has been set to F000 before call
5156 //
5157
5158
5159 scancode = GET_AL();
5160
5161 if (scancode == 0) {
5162 BX_INFO("KBD: int09 handler: AL=0\n");
5163 return;
5164 }
5165
5166
5167 shift_flags = read_byte(0x0040, 0x17);
5168 mf2_flags = read_byte(0x0040, 0x18);
5169 mf2_state = read_byte(0x0040, 0x96);
5170 asciicode = 0;
5171
5172 switch (scancode) {
5173 case 0x3a: /* Caps Lock press */
5174 shift_flags ^= 0x40;
5175 write_byte(0x0040, 0x17, shift_flags);
5176 mf2_flags |= 0x40;
5177 write_byte(0x0040, 0x18, mf2_flags);
5178 break;
5179 case 0xba: /* Caps Lock release */
5180 mf2_flags &= ~0x40;
5181 write_byte(0x0040, 0x18, mf2_flags);
5182 break;
5183
5184 case 0x2a: /* L Shift press */
5185 shift_flags |= 0x02;
5186 write_byte(0x0040, 0x17, shift_flags);
5187 break;
5188 case 0xaa: /* L Shift release */
5189 shift_flags &= ~0x02;
5190 write_byte(0x0040, 0x17, shift_flags);
5191 break;
5192
5193 case 0x36: /* R Shift press */
5194 shift_flags |= 0x01;
5195 write_byte(0x0040, 0x17, shift_flags);
5196 break;
5197 case 0xb6: /* R Shift release */
5198 shift_flags &= ~0x01;
5199 write_byte(0x0040, 0x17, shift_flags);
5200 break;
5201
5202 case 0x1d: /* Ctrl press */
5203 if ((mf2_state & 0x01) == 0) {
5204 shift_flags |= 0x04;
5205 write_byte(0x0040, 0x17, shift_flags);
5206 if (mf2_state & 0x02) {
5207 mf2_state |= 0x04;
5208 write_byte(0x0040, 0x96, mf2_state);
5209 } else {
5210 mf2_flags |= 0x01;
5211 write_byte(0x0040, 0x18, mf2_flags);
5212 }
5213 }
5214 break;
5215 case 0x9d: /* Ctrl release */
5216 if ((mf2_state & 0x01) == 0) {
5217 shift_flags &= ~0x04;
5218 write_byte(0x0040, 0x17, shift_flags);
5219 if (mf2_state & 0x02) {
5220 mf2_state &= ~0x04;
5221 write_byte(0x0040, 0x96, mf2_state);
5222 } else {
5223 mf2_flags &= ~0x01;
5224 write_byte(0x0040, 0x18, mf2_flags);
5225 }
5226 }
5227 break;
5228
5229 case 0x38: /* Alt press */
5230 shift_flags |= 0x08;
5231 write_byte(0x0040, 0x17, shift_flags);
5232 if (mf2_state & 0x02) {
5233 mf2_state |= 0x08;
5234 write_byte(0x0040, 0x96, mf2_state);
5235 } else {
5236 mf2_flags |= 0x02;
5237 write_byte(0x0040, 0x18, mf2_flags);
5238 }
5239 break;
5240 case 0xb8: /* Alt release */
5241 shift_flags &= ~0x08;
5242 write_byte(0x0040, 0x17, shift_flags);
5243 if (mf2_state & 0x02) {
5244 mf2_state &= ~0x08;
5245 write_byte(0x0040, 0x96, mf2_state);
5246 } else {
5247 mf2_flags &= ~0x02;
5248 write_byte(0x0040, 0x18, mf2_flags);
5249 }
5250 break;
5251
5252 case 0x45: /* Num Lock press */
5253 if ((mf2_state & 0x03) == 0) {
5254 mf2_flags |= 0x20;
5255 write_byte(0x0040, 0x18, mf2_flags);
5256 shift_flags ^= 0x20;
5257 write_byte(0x0040, 0x17, shift_flags);
5258 }
5259 break;
5260 case 0xc5: /* Num Lock release */
5261 if ((mf2_state & 0x03) == 0) {
5262 mf2_flags &= ~0x20;
5263 write_byte(0x0040, 0x18, mf2_flags);
5264 }
5265 break;
5266
5267 case 0x46: /* Scroll Lock press */
5268 mf2_flags |= 0x10;
5269 write_byte(0x0040, 0x18, mf2_flags);
5270 shift_flags ^= 0x10;
5271 write_byte(0x0040, 0x17, shift_flags);
5272 break;
5273
5274 case 0xc6: /* Scroll Lock release */
5275 mf2_flags &= ~0x10;
5276 write_byte(0x0040, 0x18, mf2_flags);
5277 break;
5278
5279#ifdef VBOX
5280 case 0x53: /* Del press */
5281 if ((shift_flags & 0x0f) == 0x0c)
5282 {
5283ASM_START
5284 /* Ctrl+Alt+Del => Reboot */
5285 jmp 0xf000:post
5286ASM_END
5287 }
5288 /* fall through */
5289#endif
5290
5291 default:
5292 if (scancode & 0x80) {
5293 break; /* toss key releases ... */
5294 }
5295 if (scancode > MAX_SCAN_CODE) {
5296 BX_INFO("KBD: int09h_handler(): unknown scancode read: 0x%02x!\n", scancode);
5297 return;
5298 }
5299 if (shift_flags & 0x08) { /* ALT */
5300 asciicode = scan_to_scanascii[scancode].alt;
5301 scancode = scan_to_scanascii[scancode].alt >> 8;
5302 } else if (shift_flags & 0x04) { /* CONTROL */
5303 asciicode = scan_to_scanascii[scancode].control;
5304 scancode = scan_to_scanascii[scancode].control >> 8;
5305 } else if (((mf2_state & 0x02) > 0) && ((scancode >= 0x47) && (scancode <= 0x53))) {
5306 /* extended keys handling */
5307 asciicode = 0xe0;
5308 scancode = scan_to_scanascii[scancode].normal >> 8;
5309 } else if (shift_flags & 0x03) { /* LSHIFT + RSHIFT */
5310 /* check if lock state should be ignored
5311 * because a SHIFT key are pressed */
5312
5313 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
5314 asciicode = scan_to_scanascii[scancode].normal;
5315 scancode = scan_to_scanascii[scancode].normal >> 8;
5316 } else {
5317 asciicode = scan_to_scanascii[scancode].shift;
5318 scancode = scan_to_scanascii[scancode].shift >> 8;
5319 }
5320 } else {
5321 /* check if lock is on */
5322 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
5323 asciicode = scan_to_scanascii[scancode].shift;
5324 scancode = scan_to_scanascii[scancode].shift >> 8;
5325 } else {
5326 asciicode = scan_to_scanascii[scancode].normal;
5327 scancode = scan_to_scanascii[scancode].normal >> 8;
5328 }
5329 }
5330 if (scancode==0 && asciicode==0) {
5331 BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
5332 }
5333 enqueue_key(scancode, asciicode);
5334 break;
5335 }
5336 if ((scancode & 0x7f) != 0x1d) {
5337 mf2_state &= ~0x01;
5338 }
5339 mf2_state &= ~0x02;
5340 write_byte(0x0040, 0x96, mf2_state);
5341}
5342
5343 unsigned int
5344enqueue_key(scan_code, ascii_code)
5345 Bit8u scan_code, ascii_code;
5346{
5347 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail, temp_tail;
5348
5349#if BX_CPU < 2
5350 buffer_start = 0x001E;
5351 buffer_end = 0x003E;
5352#else
5353 buffer_start = read_word(0x0040, 0x0080);
5354 buffer_end = read_word(0x0040, 0x0082);
5355#endif
5356
5357 buffer_head = read_word(0x0040, 0x001A);
5358 buffer_tail = read_word(0x0040, 0x001C);
5359
5360 temp_tail = buffer_tail;
5361 buffer_tail += 2;
5362 if (buffer_tail >= buffer_end)
5363 buffer_tail = buffer_start;
5364
5365 if (buffer_tail == buffer_head) {
5366 return(0);
5367 }
5368
5369 write_byte(0x0040, temp_tail, ascii_code);
5370 write_byte(0x0040, temp_tail+1, scan_code);
5371 write_word(0x0040, 0x001C, buffer_tail);
5372 return(1);
5373}
5374
5375
5376 void
5377int74_function(make_farcall, Z, Y, X, status)
5378 Bit16u make_farcall, Z, Y, X, status;
5379{
5380 Bit16u ebda_seg=read_word(0x0040,0x000E);
5381 Bit8u in_byte, index, package_count;
5382 Bit8u mouse_flags_1, mouse_flags_2;
5383
5384BX_DEBUG_INT74("entering int74_function\n");
5385 make_farcall = 0;
5386
5387 in_byte = inb(0x64);
5388 if ( (in_byte & 0x21) != 0x21 ) {
5389 return;
5390 }
5391 in_byte = inb(0x60);
5392BX_DEBUG_INT74("int74: read byte %02x\n", in_byte);
5393
5394 mouse_flags_1 = read_byte(ebda_seg, 0x0026);
5395 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
5396
5397 if ( (mouse_flags_2 & 0x80) != 0x80 ) {
5398 return;
5399 }
5400
5401 package_count = mouse_flags_2 & 0x07;
5402 index = mouse_flags_1 & 0x07;
5403 write_byte(ebda_seg, 0x28 + index, in_byte);
5404
5405 if ( index >= package_count ) {
5406BX_DEBUG_INT74("int74_function: make_farcall=1\n");
5407 status = read_byte(ebda_seg, 0x0028 + 0);
5408 X = read_byte(ebda_seg, 0x0028 + 1);
5409 Y = read_byte(ebda_seg, 0x0028 + 2);
5410 Z = 0;
5411 mouse_flags_1 = 0;
5412 // check if far call handler installed
5413 if (mouse_flags_2 & 0x80)
5414 make_farcall = 1;
5415 }
5416 else {
5417 mouse_flags_1++;
5418 }
5419 write_byte(ebda_seg, 0x0026, mouse_flags_1);
5420}
5421
5422#define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
5423
5424#if BX_USE_ATADRV
5425
5426 void
5427int13_harddisk(EHBX, EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5428 Bit16u EHBX, EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5429{
5430 Bit32u lba;
5431 Bit16u ebda_seg=read_word(0x0040,0x000E);
5432 Bit16u cylinder, head, sector;
5433 Bit16u segment, offset;
5434 Bit16u npc, nph, npspt, nlc, nlh, nlspt;
5435 Bit16u size, count;
5436 Bit8u device, status;
5437
5438 BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5439
5440 write_byte(0x0040, 0x008e, 0); // clear completion flag
5441
5442#ifdef VBOX_WITH_SCSI
5443 // basic check : device has to be defined
5444 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_STORAGE_DEVICES) ) {
5445 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5446 goto int13_fail;
5447 }
5448#else
5449 // basic check : device has to be defined
5450 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES) ) {
5451 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5452 goto int13_fail;
5453 }
5454#endif
5455
5456 // Get the ata channel
5457 device=read_byte(ebda_seg,&EbdaData->ata.hdidmap[GET_ELDL()-0x80]);
5458
5459#ifdef VBOX_WITH_SCSI
5460 // basic check : device has to be valid
5461 if (device >= BX_MAX_STORAGE_DEVICES) {
5462 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5463 goto int13_fail;
5464 }
5465#else
5466 // basic check : device has to be valid
5467 if (device >= BX_MAX_ATA_DEVICES) {
5468 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5469 goto int13_fail;
5470 }
5471#endif
5472
5473 switch (GET_AH()) {
5474
5475 case 0x00: /* disk controller reset */
5476#ifdef VBOX_WITH_SCSI
5477 /* SCSI controller does not need a reset. */
5478 if (!VBOX_IS_SCSI_DEVICE(device))
5479#endif
5480 ata_reset (device);
5481 goto int13_success;
5482 break;
5483
5484 case 0x01: /* read disk status */
5485 status = read_byte(0x0040, 0x0074);
5486 SET_AH(status);
5487 SET_DISK_RET_STATUS(0);
5488 /* set CF if error status read */
5489 if (status) goto int13_fail_nostatus;
5490 else goto int13_success_noah;
5491 break;
5492
5493 case 0x02: // read disk sectors
5494 case 0x03: // write disk sectors
5495 case 0x04: // verify disk sectors
5496
5497 count = GET_AL();
5498 cylinder = GET_CH();
5499 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
5500 sector = (GET_CL() & 0x3f);
5501 head = GET_DH();
5502
5503 segment = ES;
5504 offset = BX;
5505
5506 if ( (count > 128) || (count == 0) ) {
5507 BX_INFO("int13_harddisk: function %02x, count out of range!\n",GET_AH());
5508 goto int13_fail;
5509 }
5510
5511#ifdef VBOX_WITH_SCSI
5512 if (!VBOX_IS_SCSI_DEVICE(device))
5513#endif
5514 {
5515 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
5516 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
5517 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
5518 }
5519#ifdef VBOX_WITH_SCSI
5520 else
5521 {
5522 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5523
5524 nlc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.cylinders);
5525 nlh = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.heads);
5526 nlspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.spt);
5527 }
5528#endif
5529
5530 // sanity check on cyl heads, sec
5531 if( (cylinder >= nlc) || (head >= nlh) || (sector > nlspt )) {
5532 BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder, head, sector);
5533 goto int13_fail;
5534 }
5535
5536 // FIXME verify
5537 if ( GET_AH() == 0x04 ) goto int13_success;
5538
5539#ifdef VBOX_WITH_SCSI
5540 if (!VBOX_IS_SCSI_DEVICE(device))
5541#endif
5542 {
5543 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5544 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5545 }
5546#ifdef VBOX_WITH_SCSI
5547 else
5548 {
5549 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5550 nph = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.heads);
5551 npspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.spt);
5552 }
5553#endif
5554
5555 // if needed, translate lchs to lba, and execute command
5556#ifdef VBOX_WITH_SCSI
5557 if (( (nph != nlh) || (npspt != nlspt)) || VBOX_IS_SCSI_DEVICE(device)) {
5558 lba = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
5559 sector = 0; // this forces the command to be lba
5560 }
5561#else
5562 if (( (nph != nlh) || (npspt != nlspt)) ) {
5563 lba = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
5564 sector = 0; // this forces the command to be lba
5565 }
5566#endif
5567
5568 if ( GET_AH() == 0x02 )
5569 {
5570#ifdef VBOX_WITH_SCSI
5571 if (VBOX_IS_SCSI_DEVICE(device))
5572 status=scsi_read_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5573 else
5574#endif
5575 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, cylinder, head, sector, lba, segment, offset);
5576 }
5577 else
5578 {
5579#ifdef VBOX_WITH_SCSI
5580 if (VBOX_IS_SCSI_DEVICE(device))
5581 status=scsi_write_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5582 else
5583#endif
5584 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, cylinder, head, sector, lba, segment, offset);
5585 }
5586
5587 // Set nb of sector transferred
5588 SET_AL(read_word(ebda_seg, &EbdaData->ata.trsfsectors));
5589
5590 if (status != 0) {
5591 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5592 SET_AH(0x0c);
5593 goto int13_fail_noah;
5594 }
5595
5596 goto int13_success;
5597 break;
5598
5599 case 0x05: /* format disk track */
5600 BX_INFO("format disk track called\n");
5601 goto int13_success;
5602 return;
5603 break;
5604
5605 case 0x08: /* read disk drive parameters */
5606
5607 // Get logical geometry from table
5608#ifdef VBOX_WITH_SCSI
5609 if (!VBOX_IS_SCSI_DEVICE(device))
5610#endif
5611 {
5612 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
5613 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
5614 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
5615 }
5616#ifdef VBOX_WITH_SCSI
5617 else
5618 {
5619 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5620 nlc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.cylinders);
5621 nlh = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.heads);
5622 nlspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.spt);
5623 }
5624#endif
5625
5626 count = read_byte(ebda_seg, &EbdaData->ata.hdcount);
5627#ifndef VBOX
5628 nlc = nlc - 2; /* 0 based , last sector not used */
5629#else /* VBOX */
5630 /* Maximum cylinder number is just one less than the number of cylinders. */
5631 nlc = nlc - 1; /* 0 based , last sector not used */
5632#endif /* VBOX */
5633 SET_AL(0);
5634 SET_CH(nlc & 0xff);
5635 SET_CL(((nlc >> 2) & 0xc0) | (nlspt & 0x3f));
5636 SET_DH(nlh - 1);
5637 SET_DL(count); /* FIXME returns 0, 1, or n hard drives */
5638
5639 // FIXME should set ES & DI
5640
5641 goto int13_success;
5642 break;
5643
5644 case 0x10: /* check drive ready */
5645 // should look at 40:8E also???
5646
5647 // Read the status from controller
5648 status = inb(read_word(ebda_seg, &EbdaData->ata.channels[device/2].iobase1) + ATA_CB_STAT);
5649 if ( (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY ) {
5650 goto int13_success;
5651 }
5652 else {
5653 SET_AH(0xAA);
5654 goto int13_fail_noah;
5655 }
5656 break;
5657
5658 case 0x15: /* read disk drive size */
5659
5660 // Get physical geometry from table
5661#ifdef VBOX_WITH_SCSI
5662 if (!VBOX_IS_SCSI_DEVICE(device))
5663#endif
5664 {
5665 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5666 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5667 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5668 }
5669#ifdef VBOX_WITH_SCSI
5670 else
5671 {
5672 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5673 npc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.cylinders);
5674 nph = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.heads);
5675 npspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.spt);
5676 }
5677#endif
5678
5679 // Compute sector count seen by int13
5680#ifndef VBOX
5681 lba = (Bit32u)(npc - 1) * (Bit32u)nph * (Bit32u)npspt;
5682#else /* VBOX */
5683 /* Is it so hard to multiply a couple of counts (without introducing
5684 * arbitrary off by one errors)? */
5685 lba = (Bit32u)npc * (Bit32u)nph * (Bit32u)npspt;
5686#endif /* VBOX */
5687 CX = lba >> 16;
5688 DX = lba & 0xffff;
5689
5690 SET_AH(3); // hard disk accessible
5691 goto int13_success_noah;
5692 break;
5693
5694 case 0x41: // IBM/MS installation check
5695 BX=0xaa55; // install check
5696 SET_AH(0x30); // EDD 3.0
5697 CX=0x0007; // ext disk access and edd, removable supported
5698 goto int13_success_noah;
5699 break;
5700
5701 case 0x42: // IBM/MS extended read
5702 case 0x43: // IBM/MS extended write
5703 case 0x44: // IBM/MS verify
5704 case 0x47: // IBM/MS extended seek
5705
5706 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5707 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5708 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5709
5710 // Can't use 64 bits lba
5711 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5712 if (lba != 0L) {
5713 BX_PANIC("int13_harddisk: function %02x. Can't use 64bits lba\n",GET_AH());
5714 goto int13_fail;
5715 }
5716
5717 // Get 32 bits lba and check
5718 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5719
5720#ifdef VBOX_WITH_SCSI
5721 if (VBOX_IS_SCSI_DEVICE(device))
5722 {
5723 if (lba >= read_dword(ebda_seg, &EbdaData->scsi.devices[VBOX_GET_SCSI_DEVICE(device)].device_info.sectors) ) {
5724 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5725 goto int13_fail;
5726 }
5727 }
5728 else
5729#endif
5730 if (lba >= read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors) ) {
5731 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5732 goto int13_fail;
5733 }
5734
5735
5736 // If verify or seek
5737 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5738 goto int13_success;
5739
5740 // Execute the command
5741 if ( GET_AH() == 0x42 )
5742#ifdef VBOX
5743 {
5744#ifdef VBOX_WITH_SCSI
5745 if (VBOX_IS_SCSI_DEVICE(device))
5746 status=scsi_read_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5747 else
5748#endif
5749 {
5750 if (count >= 256 || lba + count >= 268435456)
5751 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS_EXT, count, 0, 0, 0, lba, segment, offset);
5752 else
5753 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba, segment, offset);
5754 }
5755 }
5756#else /* !VBOX */
5757 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba, segment, offset);
5758#endif /* VBOX */
5759 else
5760#ifdef VBOX
5761 {
5762#ifdef VBOX_WITH_SCSI
5763 if (VBOX_IS_SCSI_DEVICE(device))
5764 status=scsi_write_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5765 else
5766#endif
5767 {
5768 if (count >= 256 || lba + count >= 268435456)
5769 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS_EXT, count, 0, 0, 0, lba, segment, offset);
5770 else
5771 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
5772 }
5773 }
5774#else /* !VBOX */
5775 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
5776#endif /* VBOX */
5777
5778 count=read_word(ebda_seg, &EbdaData->ata.trsfsectors);
5779 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5780
5781 if (status != 0) {
5782 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5783 SET_AH(0x0c);
5784 goto int13_fail_noah;
5785 }
5786
5787 goto int13_success;
5788 break;
5789
5790 case 0x45: // IBM/MS lock/unlock drive
5791 case 0x49: // IBM/MS extended media change
5792 goto int13_success; // Always success for HD
5793 break;
5794
5795 case 0x46: // IBM/MS eject media
5796 SET_AH(0xb2); // Volume Not Removable
5797 goto int13_fail_noah; // Always fail for HD
5798 break;
5799
5800 case 0x48: // IBM/MS get drive parameters
5801 size=read_word(DS,SI+(Bit16u)&Int13DPT->size);
5802
5803 // Buffer is too small
5804 if(size < 0x1a)
5805 goto int13_fail;
5806
5807 // EDD 1.x
5808 if(size >= 0x1a) {
5809 Bit16u blksize;
5810
5811#ifdef VBOX_WITH_SCSI
5812 if (!VBOX_IS_SCSI_DEVICE(device))
5813#endif
5814 {
5815 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5816 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5817 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5818 lba = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors);
5819 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5820 }
5821#ifdef VBOX_WITH_SCSI
5822 else
5823 {
5824 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5825 npc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.cylinders);
5826 nph = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.heads);
5827 npspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.spt);
5828 lba = read_dword(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.sectors);
5829 blksize = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.blksize);
5830 }
5831#endif
5832
5833 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5834 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x02); // geometry is valid
5835 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, (Bit32u)npc);
5836 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, (Bit32u)nph);
5837 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, (Bit32u)npspt);
5838 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, lba); // FIXME should be Bit64
5839 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0L);
5840 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5841 }
5842
5843 // EDD 2.x
5844 if(size >= 0x1e) {
5845 Bit8u channel, dev, irq, mode, checksum, i, translation;
5846 Bit16u iobase1, iobase2, options;
5847
5848 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5849
5850 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5851 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5852
5853 // Fill in dpte
5854 channel = device / 2;
5855 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5856 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5857 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5858 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5859 translation = read_byte(ebda_seg, &EbdaData->ata.devices[device].translation);
5860
5861 options = (translation==ATA_TRANSLATION_NONE?0:1<<3); // chs translation
5862 options |= (1<<4); // lba translation
5863 options |= (mode==ATA_MODE_PIO32?1:0<<7);
5864 options |= (translation==ATA_TRANSLATION_LBA?1:0<<9);
5865 options |= (translation==ATA_TRANSLATION_RECHS?3:0<<9);
5866
5867 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5868 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5869 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5870 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5871 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5872 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5873 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5874 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5875 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5876 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5877 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5878
5879 checksum=0;
5880 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5881 checksum = ~checksum;
5882 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5883 }
5884
5885 // EDD 3.x
5886 if(size >= 0x42) {
5887 Bit8u channel, iface, checksum, i;
5888 Bit16u iobase1;
5889
5890 channel = device / 2;
5891 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5892 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5893
5894 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5895 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5896 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5897 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5898 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5899
5900 if (iface==ATA_IFACE_ISA) {
5901 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5902 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5903 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5904 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5905 }
5906 else {
5907 // FIXME PCI
5908 }
5909 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5910 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5911 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5912 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5913
5914 if (iface==ATA_IFACE_ISA) {
5915 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5916 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5917 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5918 }
5919 else {
5920 // FIXME PCI
5921 }
5922 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5923 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5924 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5925 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5926
5927 checksum=0;
5928 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5929 checksum = ~checksum;
5930 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5931 }
5932
5933 goto int13_success;
5934 break;
5935
5936 case 0x4e: // // IBM/MS set hardware configuration
5937 // DMA, prefetch, PIO maximum not supported
5938 switch (GET_AL()) {
5939 case 0x01:
5940 case 0x03:
5941 case 0x04:
5942 case 0x06:
5943 goto int13_success;
5944 break;
5945 default :
5946 goto int13_fail;
5947 }
5948 break;
5949
5950 case 0x09: /* initialize drive parameters */
5951 case 0x0c: /* seek to specified cylinder */
5952 case 0x0d: /* alternate disk reset */
5953 case 0x11: /* recalibrate */
5954 case 0x14: /* controller internal diagnostic */
5955 BX_INFO("int13_harddisk: function %02xh unimplemented, returns success\n", GET_AH());
5956 goto int13_success;
5957 break;
5958
5959 case 0x0a: /* read disk sectors with ECC */
5960 case 0x0b: /* write disk sectors with ECC */
5961 case 0x18: // set media type for format
5962 case 0x50: // IBM/MS send packet command
5963 default:
5964 BX_INFO("int13_harddisk: function %02xh unsupported, returns fail\n", GET_AH());
5965 goto int13_fail;
5966 break;
5967 }
5968
5969int13_fail:
5970 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5971int13_fail_noah:
5972 SET_DISK_RET_STATUS(GET_AH());
5973int13_fail_nostatus:
5974 SET_CF(); // error occurred
5975 return;
5976
5977int13_success:
5978 SET_AH(0x00); // no error
5979int13_success_noah:
5980 SET_DISK_RET_STATUS(0x00);
5981 CLEAR_CF(); // no error
5982 return;
5983}
5984
5985// ---------------------------------------------------------------------------
5986// Start of int13 for cdrom
5987// ---------------------------------------------------------------------------
5988
5989 void
5990int13_cdrom(EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5991 Bit16u EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5992{
5993 Bit16u ebda_seg=read_word(0x0040,0x000E);
5994 Bit8u device, status, locks;
5995 Bit8u atacmd[12];
5996 Bit32u lba;
5997 Bit16u count, segment, offset, i, size;
5998
5999 BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6000
6001 SET_DISK_RET_STATUS(0x00);
6002
6003 /* basic check : device should be 0xE0+ */
6004 if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES) ) {
6005 BX_INFO("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
6006 goto int13_fail;
6007 }
6008
6009 // Get the ata channel
6010 device=read_byte(ebda_seg,&EbdaData->ata.cdidmap[GET_ELDL()-0xE0]);
6011
6012 /* basic check : device has to be valid */
6013 if (device >= BX_MAX_ATA_DEVICES) {
6014 BX_INFO("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
6015 goto int13_fail;
6016 }
6017
6018 switch (GET_AH()) {
6019
6020 // all those functions return SUCCESS
6021 case 0x00: /* disk controller reset */
6022 case 0x09: /* initialize drive parameters */
6023 case 0x0c: /* seek to specified cylinder */
6024 case 0x0d: /* alternate disk reset */
6025 case 0x10: /* check drive ready */
6026 case 0x11: /* recalibrate */
6027 case 0x14: /* controller internal diagnostic */
6028 case 0x16: /* detect disk change */
6029 goto int13_success;
6030 break;
6031
6032 // all those functions return disk write-protected
6033 case 0x03: /* write disk sectors */
6034 case 0x05: /* format disk track */
6035 case 0x43: // IBM/MS extended write
6036 SET_AH(0x03);
6037 goto int13_fail_noah;
6038 break;
6039
6040 case 0x01: /* read disk status */
6041 status = read_byte(0x0040, 0x0074);
6042 SET_AH(status);
6043 SET_DISK_RET_STATUS(0);
6044
6045 /* set CF if error status read */
6046 if (status) goto int13_fail_nostatus;
6047 else goto int13_success_noah;
6048 break;
6049
6050 case 0x15: /* read disk drive size */
6051 SET_AH(0x02);
6052 goto int13_fail_noah;
6053 break;
6054
6055 case 0x41: // IBM/MS installation check
6056 BX=0xaa55; // install check
6057 SET_AH(0x30); // EDD 2.1
6058 CX=0x0007; // ext disk access, removable and edd
6059 goto int13_success_noah;
6060 break;
6061
6062 case 0x42: // IBM/MS extended read
6063 case 0x44: // IBM/MS verify sectors
6064 case 0x47: // IBM/MS extended seek
6065
6066 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
6067 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
6068 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
6069
6070 // Can't use 64 bits lba
6071 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
6072 if (lba != 0L) {
6073 BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
6074 goto int13_fail;
6075 }
6076
6077 // Get 32 bits lba
6078 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
6079
6080 // If verify or seek
6081 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
6082 goto int13_success;
6083
6084 memsetb(get_SS(),atacmd,0,12);
6085 atacmd[0]=0x28; // READ command
6086 atacmd[7]=(count & 0xff00) >> 8; // Sectors
6087 atacmd[8]=(count & 0x00ff); // Sectors
6088 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
6089 atacmd[3]=(lba & 0x00ff0000) >> 16;
6090 atacmd[4]=(lba & 0x0000ff00) >> 8;
6091 atacmd[5]=(lba & 0x000000ff);
6092 status = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, count*2048L, ATA_DATA_IN, segment,offset);
6093
6094 count = (Bit16u)(read_dword(ebda_seg, &EbdaData->ata.trsfbytes) >> 11);
6095 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
6096
6097 if (status != 0) {
6098 BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status);
6099 SET_AH(0x0c);
6100 goto int13_fail_noah;
6101 }
6102
6103 goto int13_success;
6104 break;
6105
6106 case 0x45: // IBM/MS lock/unlock drive
6107 if (GET_AL() > 2) goto int13_fail;
6108
6109 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
6110
6111 switch (GET_AL()) {
6112 case 0 : // lock
6113 if (locks == 0xff) {
6114 SET_AH(0xb4);
6115 SET_AL(1);
6116 goto int13_fail_noah;
6117 }
6118 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, ++locks);
6119 SET_AL(1);
6120 break;
6121 case 1 : // unlock
6122 if (locks == 0x00) {
6123 SET_AH(0xb0);
6124 SET_AL(0);
6125 goto int13_fail_noah;
6126 }
6127 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, --locks);
6128 SET_AL(locks==0?0:1);
6129 break;
6130 case 2 : // status
6131 SET_AL(locks==0?0:1);
6132 break;
6133 }
6134 goto int13_success;
6135 break;
6136
6137 case 0x46: // IBM/MS eject media
6138 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
6139
6140 if (locks != 0) {
6141 SET_AH(0xb1); // media locked
6142 goto int13_fail_noah;
6143 }
6144 // FIXME should handle 0x31 no media in device
6145 // FIXME should handle 0xb5 valid request failed
6146
6147 // Call removable media eject
6148 ASM_START
6149 push bp
6150 mov bp, sp
6151
6152 mov ah, #0x52
6153 int #0x15
6154 mov _int13_cdrom.status + 2[bp], ah
6155 jnc int13_cdrom_rme_end
6156 mov _int13_cdrom.status, #1
6157int13_cdrom_rme_end:
6158 pop bp
6159 ASM_END
6160
6161 if (status != 0) {
6162 SET_AH(0xb1); // media locked
6163 goto int13_fail_noah;
6164 }
6165
6166 goto int13_success;
6167 break;
6168
6169 case 0x48: // IBM/MS get drive parameters
6170 size = read_word(DS,SI+(Bit16u)&Int13Ext->size);
6171
6172 // Buffer is too small
6173 if(size < 0x1a)
6174 goto int13_fail;
6175
6176 // EDD 1.x
6177 if(size >= 0x1a) {
6178 Bit16u cylinders, heads, spt, blksize;
6179
6180 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
6181
6182 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
6183 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x74); // removable, media change, lockable, max values
6184 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, 0xffffffff);
6185 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, 0xffffffff);
6186 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, 0xffffffff);
6187 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, 0xffffffff); // FIXME should be Bit64
6188 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0xffffffff);
6189 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
6190 }
6191
6192 // EDD 2.x
6193 if(size >= 0x1e) {
6194 Bit8u channel, dev, irq, mode, checksum, i;
6195 Bit16u iobase1, iobase2, options;
6196
6197 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
6198
6199 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
6200 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
6201
6202 // Fill in dpte
6203 channel = device / 2;
6204 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
6205 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
6206 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
6207 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
6208
6209 // FIXME atapi device
6210 options = (1<<4); // lba translation
6211 options |= (1<<5); // removable device
6212 options |= (1<<6); // atapi device
6213 options |= (mode==ATA_MODE_PIO32?1:0<<7);
6214
6215 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
6216 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
6217 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
6218 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
6219 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
6220 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
6221 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
6222 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
6223 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
6224 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
6225 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
6226
6227 checksum=0;
6228 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
6229 checksum = ~checksum;
6230 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
6231 }
6232
6233 // EDD 3.x
6234 if(size >= 0x42) {
6235 Bit8u channel, iface, checksum, i;
6236 Bit16u iobase1;
6237
6238 channel = device / 2;
6239 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
6240 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
6241
6242 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
6243 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
6244 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
6245 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
6246 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
6247
6248 if (iface==ATA_IFACE_ISA) {
6249 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
6250 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
6251 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
6252 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
6253 }
6254 else {
6255 // FIXME PCI
6256 }
6257 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
6258 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
6259 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
6260 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
6261
6262 if (iface==ATA_IFACE_ISA) {
6263 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
6264 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
6265 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
6266 }
6267 else {
6268 // FIXME PCI
6269 }
6270 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
6271 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
6272 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
6273 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
6274
6275 checksum=0;
6276 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
6277 checksum = ~checksum;
6278 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
6279 }
6280
6281 goto int13_success;
6282 break;
6283
6284 case 0x49: // IBM/MS extended media change
6285 // always send changed ??
6286 SET_AH(06);
6287 goto int13_fail_nostatus;
6288 break;
6289
6290 case 0x4e: // // IBM/MS set hardware configuration
6291 // DMA, prefetch, PIO maximum not supported
6292 switch (GET_AL()) {
6293 case 0x01:
6294 case 0x03:
6295 case 0x04:
6296 case 0x06:
6297 goto int13_success;
6298 break;
6299 default :
6300 goto int13_fail;
6301 }
6302 break;
6303
6304 // all those functions return unimplemented
6305 case 0x02: /* read sectors */
6306 case 0x04: /* verify sectors */
6307 case 0x08: /* read disk drive parameters */
6308 case 0x0a: /* read disk sectors with ECC */
6309 case 0x0b: /* write disk sectors with ECC */
6310 case 0x18: /* set media type for format */
6311 case 0x50: // ? - send packet command
6312 default:
6313 BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
6314 goto int13_fail;
6315 break;
6316 }
6317
6318int13_fail:
6319 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6320int13_fail_noah:
6321 SET_DISK_RET_STATUS(GET_AH());
6322int13_fail_nostatus:
6323 SET_CF(); // error occurred
6324 return;
6325
6326int13_success:
6327 SET_AH(0x00); // no error
6328int13_success_noah:
6329 SET_DISK_RET_STATUS(0x00);
6330 CLEAR_CF(); // no error
6331 return;
6332}
6333
6334// ---------------------------------------------------------------------------
6335// End of int13 for cdrom
6336// ---------------------------------------------------------------------------
6337
6338#if BX_ELTORITO_BOOT
6339// ---------------------------------------------------------------------------
6340// Start of int13 for eltorito functions
6341// ---------------------------------------------------------------------------
6342
6343 void
6344int13_eltorito(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
6345 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
6346{
6347 Bit16u ebda_seg=read_word(0x0040,0x000E);
6348
6349 BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6350 // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
6351
6352 switch (GET_AH()) {
6353
6354 // FIXME ElTorito Various. Should be implemented
6355 case 0x4a: // ElTorito - Initiate disk emu
6356 case 0x4c: // ElTorito - Initiate disk emu and boot
6357 case 0x4d: // ElTorito - Return Boot catalog
6358 BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX);
6359 goto int13_fail;
6360 break;
6361
6362 case 0x4b: // ElTorito - Terminate disk emu
6363 // FIXME ElTorito Hardcoded
6364 write_byte(DS,SI+0x00,0x13);
6365 write_byte(DS,SI+0x01,read_byte(ebda_seg,&EbdaData->cdemu.media));
6366 write_byte(DS,SI+0x02,read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
6367 write_byte(DS,SI+0x03,read_byte(ebda_seg,&EbdaData->cdemu.controller_index));
6368 write_dword(DS,SI+0x04,read_dword(ebda_seg,&EbdaData->cdemu.ilba));
6369 write_word(DS,SI+0x08,read_word(ebda_seg,&EbdaData->cdemu.device_spec));
6370 write_word(DS,SI+0x0a,read_word(ebda_seg,&EbdaData->cdemu.buffer_segment));
6371 write_word(DS,SI+0x0c,read_word(ebda_seg,&EbdaData->cdemu.load_segment));
6372 write_word(DS,SI+0x0e,read_word(ebda_seg,&EbdaData->cdemu.sector_count));
6373 write_byte(DS,SI+0x10,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.cylinders));
6374 write_byte(DS,SI+0x11,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.spt));
6375 write_byte(DS,SI+0x12,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.heads));
6376
6377 // If we have to terminate emulation
6378 if(GET_AL() == 0x00) {
6379 // FIXME ElTorito Various. Should be handled accordingly to spec
6380 write_byte(ebda_seg,&EbdaData->cdemu.active, 0x00); // bye bye
6381 }
6382
6383 goto int13_success;
6384 break;
6385
6386 default:
6387 BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
6388 goto int13_fail;
6389 break;
6390 }
6391
6392int13_fail:
6393 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6394 SET_DISK_RET_STATUS(GET_AH());
6395 SET_CF(); // error occurred
6396 return;
6397
6398int13_success:
6399 SET_AH(0x00); // no error
6400 SET_DISK_RET_STATUS(0x00);
6401 CLEAR_CF(); // no error
6402 return;
6403}
6404
6405// ---------------------------------------------------------------------------
6406// End of int13 for eltorito functions
6407// ---------------------------------------------------------------------------
6408
6409// ---------------------------------------------------------------------------
6410// Start of int13 when emulating a device from the cd
6411// ---------------------------------------------------------------------------
6412
6413 void
6414int13_cdemu(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
6415 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
6416{
6417 Bit16u ebda_seg=read_word(0x0040,0x000E);
6418 Bit8u device, status;
6419 Bit16u vheads, vspt, vcylinders;
6420 Bit16u head, sector, cylinder, nbsectors;
6421 Bit32u vlba, ilba, slba, elba;
6422 Bit16u before, segment, offset;
6423 Bit8u atacmd[12];
6424
6425 BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6426
6427 /* at this point, we are emulating a floppy/harddisk */
6428
6429 // Recompute the device number
6430 device = read_byte(ebda_seg,&EbdaData->cdemu.controller_index) * 2;
6431 device += read_byte(ebda_seg,&EbdaData->cdemu.device_spec);
6432
6433 SET_DISK_RET_STATUS(0x00);
6434
6435 /* basic checks : emulation should be active, dl should equal the emulated drive */
6436 if( (read_byte(ebda_seg,&EbdaData->cdemu.active) ==0 )
6437 || (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive ) != GET_DL())) {
6438 BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
6439 goto int13_fail;
6440 }
6441
6442 switch (GET_AH()) {
6443
6444 // all those functions return SUCCESS
6445 case 0x00: /* disk controller reset */
6446 case 0x09: /* initialize drive parameters */
6447 case 0x0c: /* seek to specified cylinder */
6448 case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
6449 case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
6450 case 0x11: /* recalibrate */
6451 case 0x14: /* controller internal diagnostic */
6452 case 0x16: /* detect disk change */
6453 goto int13_success;
6454 break;
6455
6456 // all those functions return disk write-protected
6457 case 0x03: /* write disk sectors */
6458 case 0x05: /* format disk track */
6459 SET_AH(0x03);
6460 goto int13_fail_noah;
6461 break;
6462
6463 case 0x01: /* read disk status */
6464 status=read_byte(0x0040, 0x0074);
6465 SET_AH(status);
6466 SET_DISK_RET_STATUS(0);
6467
6468 /* set CF if error status read */
6469 if (status) goto int13_fail_nostatus;
6470 else goto int13_success_noah;
6471 break;
6472
6473 case 0x02: // read disk sectors
6474 case 0x04: // verify disk sectors
6475 vspt = read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
6476 vcylinders = read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders);
6477 vheads = read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads);
6478
6479 ilba = read_dword(ebda_seg,&EbdaData->cdemu.ilba);
6480
6481 sector = GET_CL() & 0x003f;
6482 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
6483 head = GET_DH();
6484 nbsectors = GET_AL();
6485 segment = ES;
6486 offset = BX;
6487
6488 // no sector to read ?
6489 if(nbsectors==0) goto int13_success;
6490
6491 // sanity checks sco openserver needs this!
6492 if ((sector > vspt)
6493 || (cylinder >= vcylinders)
6494 || (head >= vheads)) {
6495 goto int13_fail;
6496 }
6497
6498 // After controls, verify do nothing
6499 if (GET_AH() == 0x04) goto int13_success;
6500
6501 segment = ES+(BX / 16);
6502 offset = BX % 16;
6503
6504 // calculate the virtual lba inside the image
6505 vlba=((((Bit32u)cylinder*(Bit32u)vheads)+(Bit32u)head)*(Bit32u)vspt)+((Bit32u)(sector-1));
6506
6507 // In advance so we don't loose the count
6508 SET_AL(nbsectors);
6509
6510 // start lba on cd
6511 slba = (Bit32u)vlba/4;
6512 before= (Bit16u)vlba%4;
6513
6514 // end lba on cd
6515 elba = (Bit32u)(vlba+nbsectors-1)/4;
6516
6517 memsetb(get_SS(),atacmd,0,12);
6518 atacmd[0]=0x28; // READ command
6519 atacmd[7]=((Bit16u)(elba-slba+1) & 0xff00) >> 8; // Sectors
6520 atacmd[8]=((Bit16u)(elba-slba+1) & 0x00ff); // Sectors
6521 atacmd[2]=(ilba+slba & 0xff000000) >> 24; // LBA
6522 atacmd[3]=(ilba+slba & 0x00ff0000) >> 16;
6523 atacmd[4]=(ilba+slba & 0x0000ff00) >> 8;
6524 atacmd[5]=(ilba+slba & 0x000000ff);
6525 if((status = ata_cmd_packet(device, 12, get_SS(), atacmd, before*512, nbsectors*512L, ATA_DATA_IN, segment,offset)) != 0) {
6526 BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status);
6527 SET_AH(0x02);
6528 SET_AL(0);
6529 goto int13_fail_noah;
6530 }
6531
6532 goto int13_success;
6533 break;
6534
6535 case 0x08: /* read disk drive parameters */
6536 vspt=read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
6537 vcylinders=read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders) - 1;
6538 vheads=read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads) - 1;
6539
6540 SET_AL( 0x00 );
6541 SET_BL( 0x00 );
6542 SET_CH( vcylinders & 0xff );
6543 SET_CL((( vcylinders >> 2) & 0xc0) | ( vspt & 0x3f ));
6544 SET_DH( vheads );
6545 SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2
6546 // FIXME ElTorito Harddisk. should send the HD count
6547
6548 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
6549 case 0x01: SET_BL( 0x02 ); break;
6550 case 0x02: SET_BL( 0x04 ); break;
6551 case 0x03: SET_BL( 0x06 ); break;
6552 }
6553
6554ASM_START
6555 push bp
6556 mov bp, sp
6557 mov ax, #diskette_param_table2
6558 mov _int13_cdemu.DI+2[bp], ax
6559 mov _int13_cdemu.ES+2[bp], cs
6560 pop bp
6561ASM_END
6562 goto int13_success;
6563 break;
6564
6565 case 0x15: /* read disk drive size */
6566 // FIXME ElTorito Harddisk. What geometry to send ?
6567 SET_AH(0x03);
6568 goto int13_success_noah;
6569 break;
6570
6571 // all those functions return unimplemented
6572 case 0x0a: /* read disk sectors with ECC */
6573 case 0x0b: /* write disk sectors with ECC */
6574 case 0x18: /* set media type for format */
6575 case 0x41: // IBM/MS installation check
6576 // FIXME ElTorito Harddisk. Darwin would like to use EDD
6577 case 0x42: // IBM/MS extended read
6578 case 0x43: // IBM/MS extended write
6579 case 0x44: // IBM/MS verify sectors
6580 case 0x45: // IBM/MS lock/unlock drive
6581 case 0x46: // IBM/MS eject media
6582 case 0x47: // IBM/MS extended seek
6583 case 0x48: // IBM/MS get drive parameters
6584 case 0x49: // IBM/MS extended media change
6585 case 0x4e: // ? - set hardware configuration
6586 case 0x50: // ? - send packet command
6587 default:
6588 BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
6589 goto int13_fail;
6590 break;
6591 }
6592
6593int13_fail:
6594 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6595int13_fail_noah:
6596 SET_DISK_RET_STATUS(GET_AH());
6597int13_fail_nostatus:
6598 SET_CF(); // error occurred
6599 return;
6600
6601int13_success:
6602 SET_AH(0x00); // no error
6603int13_success_noah:
6604 SET_DISK_RET_STATUS(0x00);
6605 CLEAR_CF(); // no error
6606 return;
6607}
6608
6609// ---------------------------------------------------------------------------
6610// End of int13 when emulating a device from the cd
6611// ---------------------------------------------------------------------------
6612
6613#endif // BX_ELTORITO_BOOT
6614
6615#else //BX_USE_ATADRV
6616
6617 void
6618outLBA(cylinder,hd_heads,head,hd_sectors,sector,dl)
6619 Bit16u cylinder;
6620 Bit16u hd_heads;
6621 Bit16u head;
6622 Bit16u hd_sectors;
6623 Bit16u sector;
6624 Bit16u dl;
6625{
6626ASM_START
6627 push bp
6628 mov bp, sp
6629 push eax
6630 push ebx
6631 push edx
6632 xor eax,eax
6633 mov ax,4[bp] // cylinder
6634 xor ebx,ebx
6635 mov bl,6[bp] // hd_heads
6636 imul ebx
6637
6638 mov bl,8[bp] // head
6639 add eax,ebx
6640 mov bl,10[bp] // hd_sectors
6641 imul ebx
6642 mov bl,12[bp] // sector
6643 add eax,ebx
6644
6645 dec eax
6646 mov dx,#0x1f3
6647 out dx,al
6648 mov dx,#0x1f4
6649 mov al,ah
6650 out dx,al
6651 shr eax,#16
6652 mov dx,#0x1f5
6653 out dx,al
6654 and ah,#0xf
6655 mov bl,14[bp] // dl
6656 and bl,#1
6657 shl bl,#4
6658 or ah,bl
6659 or ah,#0xe0
6660 mov al,ah
6661 mov dx,#0x01f6
6662 out dx,al
6663 pop edx
6664 pop ebx
6665 pop eax
6666 pop bp
6667ASM_END
6668}
6669
6670 void
6671int13_harddisk(EHBX, EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
6672 Bit16u EHBX, EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
6673{
6674 Bit8u drive, num_sectors, sector, head, status, mod;
6675 Bit8u drive_map;
6676 Bit8u n_drives;
6677 Bit16u cyl_mod, ax;
6678 Bit16u max_cylinder, cylinder, total_sectors;
6679 Bit16u hd_cylinders;
6680 Bit8u hd_heads, hd_sectors;
6681 Bit16u val16;
6682 Bit8u sector_count;
6683 unsigned int i;
6684 Bit16u tempbx;
6685 Bit16u dpsize;
6686
6687 Bit16u count, segment, offset;
6688 Bit32u lba;
6689 Bit16u error;
6690
6691 BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6692
6693 write_byte(0x0040, 0x008e, 0); // clear completion flag
6694
6695 /* at this point, DL is >= 0x80 to be passed from the floppy int13h
6696 handler code */
6697 /* check how many disks first (cmos reg 0x12), return an error if
6698 drive not present */
6699 drive_map = inb_cmos(0x12);
6700 drive_map = (((drive_map & 0xf0)==0) ? 0 : 1) |
6701 (((drive_map & 0x0f)==0) ? 0 : 2);
6702 n_drives = (drive_map==0) ? 0 :
6703 ((drive_map==3) ? 2 : 1);
6704
6705 if (!(drive_map & (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
6706 SET_AH(0x01);
6707 SET_DISK_RET_STATUS(0x01);
6708 SET_CF(); /* error occurred */
6709 return;
6710 }
6711
6712 switch (GET_AH()) {
6713
6714 case 0x00: /* disk controller reset */
6715BX_DEBUG_INT13_HD("int13_f00\n");
6716
6717 SET_AH(0);
6718 SET_DISK_RET_STATUS(0);
6719 set_diskette_ret_status(0);
6720 set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
6721 set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
6722 CLEAR_CF(); /* successful */
6723 return;
6724 break;
6725
6726 case 0x01: /* read disk status */
6727BX_DEBUG_INT13_HD("int13_f01\n");
6728 status = read_byte(0x0040, 0x0074);
6729 SET_AH(status);
6730 SET_DISK_RET_STATUS(0);
6731 /* set CF if error status read */
6732 if (status) SET_CF();
6733 else CLEAR_CF();
6734 return;
6735 break;
6736
6737 case 0x04: // verify disk sectors
6738 case 0x02: // read disk sectors
6739 drive = GET_ELDL();
6740 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6741
6742 num_sectors = GET_AL();
6743 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
6744 sector = (GET_CL() & 0x3f);
6745 head = GET_DH();
6746
6747
6748 if (hd_cylinders > 1024) {
6749 if (hd_cylinders <= 2048) {
6750 cylinder <<= 1;
6751 }
6752 else if (hd_cylinders <= 4096) {
6753 cylinder <<= 2;
6754 }
6755 else if (hd_cylinders <= 8192) {
6756 cylinder <<= 3;
6757 }
6758 else { // hd_cylinders <= 16384
6759 cylinder <<= 4;
6760 }
6761
6762 ax = head / hd_heads;
6763 cyl_mod = ax & 0xff;
6764 head = ax >> 8;
6765 cylinder |= cyl_mod;
6766 }
6767
6768 if ( (cylinder >= hd_cylinders) ||
6769 (sector > hd_sectors) ||
6770 (head >= hd_heads) ) {
6771 SET_AH(1);
6772 SET_DISK_RET_STATUS(1);
6773 SET_CF(); /* error occurred */
6774 return;
6775 }
6776
6777 if ( (num_sectors > 128) || (num_sectors == 0) )
6778 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6779
6780 if (head > 15)
6781 BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
6782
6783 if ( GET_AH() == 0x04 ) {
6784 SET_AH(0);
6785 SET_DISK_RET_STATUS(0);
6786 CLEAR_CF();
6787 return;
6788 }
6789
6790 status = inb(0x1f7);
6791 if (status & 0x80) {
6792 BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
6793 }
6794 outb(0x01f2, num_sectors);
6795 /* activate LBA? (tomv) */
6796 if (hd_heads > 16) {
6797BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder, head, sector);
6798 outLBA(cylinder,hd_heads,head,hd_sectors,sector,drive);
6799 }
6800 else {
6801 outb(0x01f3, sector);
6802 outb(0x01f4, cylinder & 0x00ff);
6803 outb(0x01f5, cylinder >> 8);
6804 outb(0x01f6, 0xa0 | ((drive & 0x01)<<4) | (head & 0x0f));
6805 }
6806 outb(0x01f7, 0x20);
6807
6808 while (1) {
6809 status = inb(0x1f7);
6810 if ( !(status & 0x80) ) break;
6811 }
6812
6813 if (status & 0x01) {
6814 BX_PANIC("hard drive BIOS:(read/verify) read error\n");
6815 } else if ( !(status & 0x08) ) {
6816 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6817 BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
6818 }
6819
6820 sector_count = 0;
6821 tempbx = BX;
6822
6823ASM_START
6824 sti ;; enable higher priority interrupts
6825ASM_END
6826
6827 while (1) {
6828ASM_START
6829 ;; store temp bx in real DI register
6830 push bp
6831 mov bp, sp
6832 mov di, _int13_harddisk.tempbx + 2 [bp]
6833 pop bp
6834
6835 ;; adjust if there will be an overrun
6836 cmp di, #0xfe00
6837 jbe i13_f02_no_adjust
6838i13_f02_adjust:
6839 sub di, #0x0200 ; sub 512 bytes from offset
6840 mov ax, es
6841 add ax, #0x0020 ; add 512 to segment
6842 mov es, ax
6843
6844i13_f02_no_adjust:
6845 mov cx, #0x0100 ;; counter (256 words = 512b)
6846 mov dx, #0x01f0 ;; AT data read port
6847
6848 rep
6849 insw ;; CX words transferred from port(DX) to ES:[DI]
6850
6851i13_f02_done:
6852 ;; store real DI register back to temp bx
6853 push bp
6854 mov bp, sp
6855 mov _int13_harddisk.tempbx + 2 [bp], di
6856 pop bp
6857ASM_END
6858
6859 sector_count++;
6860 num_sectors--;
6861 if (num_sectors == 0) {
6862 status = inb(0x1f7);
6863 if ( (status & 0xc9) != 0x40 )
6864 BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status);
6865 break;
6866 }
6867 else {
6868 status = inb(0x1f7);
6869 if ( (status & 0xc9) != 0x48 )
6870 BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status);
6871 continue;
6872 }
6873 }
6874
6875 SET_AH(0);
6876 SET_DISK_RET_STATUS(0);
6877 SET_AL(sector_count);
6878 CLEAR_CF(); /* successful */
6879 return;
6880 break;
6881
6882
6883 case 0x03: /* write disk sectors */
6884BX_DEBUG_INT13_HD("int13_f03\n");
6885 drive = GET_ELDL ();
6886 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6887
6888 num_sectors = GET_AL();
6889 cylinder = GET_CH();
6890 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
6891 sector = (GET_CL() & 0x3f);
6892 head = GET_DH();
6893
6894 if (hd_cylinders > 1024) {
6895 if (hd_cylinders <= 2048) {
6896 cylinder <<= 1;
6897 }
6898 else if (hd_cylinders <= 4096) {
6899 cylinder <<= 2;
6900 }
6901 else if (hd_cylinders <= 8192) {
6902 cylinder <<= 3;
6903 }
6904 else { // hd_cylinders <= 16384
6905 cylinder <<= 4;
6906 }
6907
6908 ax = head / hd_heads;
6909 cyl_mod = ax & 0xff;
6910 head = ax >> 8;
6911 cylinder |= cyl_mod;
6912 }
6913
6914 if ( (cylinder >= hd_cylinders) ||
6915 (sector > hd_sectors) ||
6916 (head >= hd_heads) ) {
6917 SET_AH( 1);
6918 SET_DISK_RET_STATUS(1);
6919 SET_CF(); /* error occurred */
6920 return;
6921 }
6922
6923 if ( (num_sectors > 128) || (num_sectors == 0) )
6924 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6925
6926 if (head > 15)
6927 BX_PANIC("hard drive BIOS:(read) head > 15\n");
6928
6929 status = inb(0x1f7);
6930 if (status & 0x80) {
6931 BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
6932 }
6933// should check for Drive Ready Bit also in status reg
6934 outb(0x01f2, num_sectors);
6935
6936 /* activate LBA? (tomv) */
6937 if (hd_heads > 16) {
6938BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder, head, sector);
6939 outLBA(cylinder,hd_heads,head,hd_sectors,sector,GET_ELDL());
6940 }
6941 else {
6942 outb(0x01f3, sector);
6943 outb(0x01f4, cylinder & 0x00ff);
6944 outb(0x01f5, cylinder >> 8);
6945 outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head & 0x0f));
6946 }
6947 outb(0x01f7, 0x30);
6948
6949 // wait for busy bit to turn off after seeking
6950 while (1) {
6951 status = inb(0x1f7);
6952 if ( !(status & 0x80) ) break;
6953 }
6954
6955 if ( !(status & 0x08) ) {
6956 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6957 BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
6958 }
6959
6960 sector_count = 0;
6961 tempbx = BX;
6962
6963ASM_START
6964 sti ;; enable higher priority interrupts
6965ASM_END
6966
6967 while (1) {
6968ASM_START
6969 ;; store temp bx in real SI register
6970 push bp
6971 mov bp, sp
6972 mov si, _int13_harddisk.tempbx + 2 [bp]
6973 pop bp
6974
6975 ;; adjust if there will be an overrun
6976 cmp si, #0xfe00
6977 jbe i13_f03_no_adjust
6978i13_f03_adjust:
6979 sub si, #0x0200 ; sub 512 bytes from offset
6980 mov ax, es
6981 add ax, #0x0020 ; add 512 to segment
6982 mov es, ax
6983
6984i13_f03_no_adjust:
6985 mov cx, #0x0100 ;; counter (256 words = 512b)
6986 mov dx, #0x01f0 ;; AT data read port
6987
6988 seg ES
6989 rep
6990 outsw ;; CX words transferred from ES:[SI] to port(DX)
6991
6992 ;; store real SI register back to temp bx
6993 push bp
6994 mov bp, sp
6995 mov _int13_harddisk.tempbx + 2 [bp], si
6996 pop bp
6997ASM_END
6998
6999 sector_count++;
7000 num_sectors--;
7001 if (num_sectors == 0) {
7002 status = inb(0x1f7);
7003 if ( (status & 0xe9) != 0x40 )
7004 BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status);
7005 break;
7006 }
7007 else {
7008 status = inb(0x1f7);
7009 if ( (status & 0xc9) != 0x48 )
7010 BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status);
7011 continue;
7012 }
7013 }
7014
7015 SET_AH(0);
7016 SET_DISK_RET_STATUS(0);
7017 SET_AL(sector_count);
7018 CLEAR_CF(); /* successful */
7019 return;
7020 break;
7021
7022 case 0x05: /* format disk track */
7023BX_DEBUG_INT13_HD("int13_f05\n");
7024 BX_PANIC("format disk track called\n");
7025 /* nop */
7026 SET_AH(0);
7027 SET_DISK_RET_STATUS(0);
7028 CLEAR_CF(); /* successful */
7029 return;
7030 break;
7031
7032 case 0x08: /* read disk drive parameters */
7033BX_DEBUG_INT13_HD("int13_f08\n");
7034
7035 drive = GET_ELDL ();
7036 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
7037
7038 // translate CHS
7039 //
7040 if (hd_cylinders <= 1024) {
7041 // hd_cylinders >>= 0;
7042 // hd_heads <<= 0;
7043 }
7044 else if (hd_cylinders <= 2048) {
7045 hd_cylinders >>= 1;
7046 hd_heads <<= 1;
7047 }
7048 else if (hd_cylinders <= 4096) {
7049 hd_cylinders >>= 2;
7050 hd_heads <<= 2;
7051 }
7052 else if (hd_cylinders <= 8192) {
7053 hd_cylinders >>= 3;
7054 hd_heads <<= 3;
7055 }
7056 else { // hd_cylinders <= 16384
7057 hd_cylinders >>= 4;
7058 hd_heads <<= 4;
7059 }
7060
7061 max_cylinder = hd_cylinders - 2; /* 0 based */
7062 SET_AL(0);
7063 SET_CH(max_cylinder & 0xff);
7064 SET_CL(((max_cylinder >> 2) & 0xc0) | (hd_sectors & 0x3f));
7065 SET_DH(hd_heads - 1);
7066 SET_DL(n_drives); /* returns 0, 1, or 2 hard drives */
7067 SET_AH(0);
7068 SET_DISK_RET_STATUS(0);
7069 CLEAR_CF(); /* successful */
7070
7071 return;
7072 break;
7073
7074 case 0x09: /* initialize drive parameters */
7075BX_DEBUG_INT13_HD("int13_f09\n");
7076 SET_AH(0);
7077 SET_DISK_RET_STATUS(0);
7078 CLEAR_CF(); /* successful */
7079 return;
7080 break;
7081
7082 case 0x0a: /* read disk sectors with ECC */
7083BX_DEBUG_INT13_HD("int13_f0a\n");
7084 case 0x0b: /* write disk sectors with ECC */
7085BX_DEBUG_INT13_HD("int13_f0b\n");
7086 BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
7087 return;
7088 break;
7089
7090 case 0x0c: /* seek to specified cylinder */
7091BX_DEBUG_INT13_HD("int13_f0c\n");
7092 BX_INFO("int13h function 0ch (seek) not implemented!\n");
7093 SET_AH(0);
7094 SET_DISK_RET_STATUS(0);
7095 CLEAR_CF(); /* successful */
7096 return;
7097 break;
7098
7099 case 0x0d: /* alternate disk reset */
7100BX_DEBUG_INT13_HD("int13_f0d\n");
7101 SET_AH(0);
7102 SET_DISK_RET_STATUS(0);
7103 CLEAR_CF(); /* successful */
7104 return;
7105 break;
7106
7107 case 0x10: /* check drive ready */
7108BX_DEBUG_INT13_HD("int13_f10\n");
7109 //SET_AH(0);
7110 //SET_DISK_RET_STATUS(0);
7111 //CLEAR_CF(); /* successful */
7112 //return;
7113 //break;
7114
7115 // should look at 40:8E also???
7116 status = inb(0x01f7);
7117 if ( (status & 0xc0) == 0x40 ) {
7118 SET_AH(0);
7119 SET_DISK_RET_STATUS(0);
7120 CLEAR_CF(); // drive ready
7121 return;
7122 }
7123 else {
7124 SET_AH(0xAA);
7125 SET_DISK_RET_STATUS(0xAA);
7126 SET_CF(); // not ready
7127 return;
7128 }
7129 break;
7130
7131 case 0x11: /* recalibrate */
7132BX_DEBUG_INT13_HD("int13_f11\n");
7133 SET_AH(0);
7134 SET_DISK_RET_STATUS(0);
7135 CLEAR_CF(); /* successful */
7136 return;
7137 break;
7138
7139 case 0x14: /* controller internal diagnostic */
7140BX_DEBUG_INT13_HD("int13_f14\n");
7141 SET_AH(0);
7142 SET_DISK_RET_STATUS(0);
7143 CLEAR_CF(); /* successful */
7144 SET_AL(0);
7145 return;
7146 break;
7147
7148 case 0x15: /* read disk drive size */
7149 drive = GET_ELDL();
7150 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
7151ASM_START
7152 push bp
7153 mov bp, sp
7154 mov al, _int13_harddisk.hd_heads + 2 [bp]
7155 mov ah, _int13_harddisk.hd_sectors + 2 [bp]
7156 mul al, ah ;; ax = heads * sectors
7157 mov bx, _int13_harddisk.hd_cylinders + 2 [bp]
7158 dec bx ;; use (cylinders - 1) ???
7159 mul ax, bx ;; dx:ax = (cylinders -1) * (heads * sectors)
7160 ;; now we need to move the 32bit result dx:ax to what the
7161 ;; BIOS wants which is cx:dx.
7162 ;; and then into CX:DX on the stack
7163 mov _int13_harddisk.CX + 2 [bp], dx
7164 mov _int13_harddisk.DX + 2 [bp], ax
7165 pop bp
7166ASM_END
7167 SET_AH(3); // hard disk accessible
7168 SET_DISK_RET_STATUS(0); // ??? should this be 0
7169 CLEAR_CF(); // successful
7170 return;
7171 break;
7172
7173 case 0x18: // set media type for format
7174 case 0x41: // IBM/MS
7175 case 0x42: // IBM/MS
7176 case 0x43: // IBM/MS
7177 case 0x44: // IBM/MS
7178 case 0x45: // IBM/MS lock/unlock drive
7179 case 0x46: // IBM/MS eject media
7180 case 0x47: // IBM/MS extended seek
7181 case 0x49: // IBM/MS extended media change
7182 case 0x50: // IBM/MS send packet command
7183 default:
7184 BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
7185
7186 SET_AH(1); // code=invalid function in AH or invalid parameter
7187 SET_DISK_RET_STATUS(1);
7188 SET_CF(); /* unsuccessful */
7189 return;
7190 break;
7191 }
7192}
7193
7194static char panic_msg_reg12h[] = "HD%d cmos reg 12h not type F\n";
7195static char panic_msg_reg19h[] = "HD%d cmos reg %02xh not user definable type 47\n";
7196
7197 void
7198get_hd_geometry(drive, hd_cylinders, hd_heads, hd_sectors)
7199 Bit8u drive;
7200 Bit16u *hd_cylinders;
7201 Bit8u *hd_heads;
7202 Bit8u *hd_sectors;
7203{
7204 Bit8u hd_type;
7205 Bit16u ss;
7206 Bit16u cylinders;
7207 Bit8u iobase;
7208
7209 ss = get_SS();
7210 if (drive == 0x80) {
7211 hd_type = inb_cmos(0x12) & 0xf0;
7212 if (hd_type != 0xf0)
7213 BX_INFO(panic_msg_reg12h,0);
7214 hd_type = inb_cmos(0x19); // HD0: extended type
7215 if (hd_type != 47)
7216 BX_INFO(panic_msg_reg19h,0,0x19);
7217 iobase = 0x1b;
7218 } else {
7219 hd_type = inb_cmos(0x12) & 0x0f;
7220 if (hd_type != 0x0f)
7221 BX_INFO(panic_msg_reg12h,1);
7222 hd_type = inb_cmos(0x1a); // HD1: extended type
7223 if (hd_type != 47)
7224 BX_INFO(panic_msg_reg19h,0,0x1a);
7225 iobase = 0x24;
7226 }
7227
7228 // cylinders
7229 cylinders = inb_cmos(iobase) | (inb_cmos(iobase+1) << 8);
7230 write_word(ss, hd_cylinders, cylinders);
7231
7232 // heads
7233 write_byte(ss, hd_heads, inb_cmos(iobase+2));
7234
7235 // sectors per track
7236 write_byte(ss, hd_sectors, inb_cmos(iobase+8));
7237}
7238
7239#endif //else BX_USE_ATADRV
7240
7241#if BX_SUPPORT_FLOPPY
7242
7243//////////////////////
7244// FLOPPY functions //
7245//////////////////////
7246
7247void floppy_reset_controller()
7248{
7249 Bit8u val8;
7250
7251 // Reset controller
7252 val8 = inb(0x03f2);
7253 outb(0x03f2, val8 & ~0x04);
7254 outb(0x03f2, val8 | 0x04);
7255
7256 // Wait for controller to come out of reset
7257 do {
7258 val8 = inb(0x3f4);
7259 } while ( (val8 & 0xc0) != 0x80 );
7260}
7261
7262void floppy_prepare_controller(drive)
7263 Bit16u drive;
7264{
7265 Bit8u val8, dor, prev_reset;
7266
7267 // set 40:3e bit 7 to 0
7268 val8 = read_byte(0x0040, 0x003e);
7269 val8 &= 0x7f;
7270 write_byte(0x0040, 0x003e, val8);
7271
7272 // turn on motor of selected drive, DMA & int enabled, normal operation
7273 prev_reset = inb(0x03f2) & 0x04;
7274 if (drive)
7275 dor = 0x20;
7276 else
7277 dor = 0x10;
7278 dor |= 0x0c;
7279 dor |= drive;
7280 outb(0x03f2, dor);
7281
7282 // reset the disk motor timeout value of INT 08
7283 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
7284
7285#ifdef VBOX
7286 // program data rate
7287 val8 = read_byte(0x0040, 0x008b);
7288 val8 >>= 6;
7289 outb(0x03f7, val8);
7290#endif
7291
7292 // wait for drive readiness
7293 do {
7294 val8 = inb(0x3f4);
7295 } while ( (val8 & 0xc0) != 0x80 );
7296
7297 if (prev_reset == 0) {
7298 // turn on interrupts
7299ASM_START
7300 sti
7301ASM_END
7302 // wait on 40:3e bit 7 to become 1
7303 do {
7304 val8 = read_byte(0x0040, 0x003e);
7305 } while ( (val8 & 0x80) == 0 );
7306 val8 &= 0x7f;
7307ASM_START
7308 cli
7309ASM_END
7310 write_byte(0x0040, 0x003e, val8);
7311 }
7312}
7313
7314 bx_bool
7315floppy_media_known(drive)
7316 Bit16u drive;
7317{
7318 Bit8u val8;
7319 Bit16u media_state_offset;
7320
7321 val8 = read_byte(0x0040, 0x003e); // diskette recal status
7322 if (drive)
7323 val8 >>= 1;
7324 val8 &= 0x01;
7325 if (val8 == 0)
7326 return(0);
7327
7328 media_state_offset = 0x0090;
7329 if (drive)
7330 media_state_offset += 1;
7331
7332 val8 = read_byte(0x0040, media_state_offset);
7333 val8 = (val8 >> 4) & 0x01;
7334 if (val8 == 0)
7335 return(0);
7336
7337 // check pass, return KNOWN
7338 return(1);
7339}
7340
7341 bx_bool
7342floppy_media_sense(drive)
7343 Bit16u drive;
7344{
7345 bx_bool retval;
7346 Bit16u media_state_offset;
7347 Bit8u drive_type, config_data, media_state;
7348
7349 if (floppy_drive_recal(drive) == 0) {
7350 return(0);
7351 }
7352
7353 // for now cheat and get drive type from CMOS,
7354 // assume media is same as drive type
7355
7356 // ** config_data **
7357 // Bitfields for diskette media control:
7358 // Bit(s) Description (Table M0028)
7359 // 7-6 last data rate set by controller
7360 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
7361 // 5-4 last diskette drive step rate selected
7362 // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
7363 // 3-2 {data rate at start of operation}
7364 // 1-0 reserved
7365
7366 // ** media_state **
7367 // Bitfields for diskette drive media state:
7368 // Bit(s) Description (Table M0030)
7369 // 7-6 data rate
7370 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
7371 // 5 double stepping required (e.g. 360kB in 1.2MB)
7372 // 4 media type established
7373 // 3 drive capable of supporting 4MB media
7374 // 2-0 on exit from BIOS, contains
7375 // 000 trying 360kB in 360kB
7376 // 001 trying 360kB in 1.2MB
7377 // 010 trying 1.2MB in 1.2MB
7378 // 011 360kB in 360kB established
7379 // 100 360kB in 1.2MB established
7380 // 101 1.2MB in 1.2MB established
7381 // 110 reserved
7382 // 111 all other formats/drives
7383
7384 drive_type = inb_cmos(0x10);
7385 if (drive == 0)
7386 drive_type >>= 4;
7387 else
7388 drive_type &= 0x0f;
7389 if ( drive_type == 1 ) {
7390 // 360K 5.25" drive
7391 config_data = 0x00; // 0000 0000
7392 media_state = 0x25; // 0010 0101
7393 retval = 1;
7394 }
7395 else if ( drive_type == 2 ) {
7396 // 1.2 MB 5.25" drive
7397 config_data = 0x00; // 0000 0000
7398 media_state = 0x25; // 0010 0101 // need double stepping??? (bit 5)
7399 retval = 1;
7400 }
7401 else if ( drive_type == 3 ) {
7402 // 720K 3.5" drive
7403 config_data = 0x00; // 0000 0000 ???
7404 media_state = 0x17; // 0001 0111
7405 retval = 1;
7406 }
7407 else if ( drive_type == 4 ) {
7408 // 1.44 MB 3.5" drive
7409 config_data = 0x00; // 0000 0000
7410 media_state = 0x17; // 0001 0111
7411 retval = 1;
7412 }
7413 else if ( drive_type == 5 ) {
7414 // 2.88 MB 3.5" drive
7415 config_data = 0xCC; // 1100 1100
7416 media_state = 0xD7; // 1101 0111
7417 retval = 1;
7418 }
7419 //
7420 // Extended floppy size uses special cmos setting
7421 else if ( drive_type == 6 ) {
7422 // 160k 5.25" drive
7423 config_data = 0x00; // 0000 0000
7424 media_state = 0x27; // 0010 0111
7425 retval = 1;
7426 }
7427 else if ( drive_type == 7 ) {
7428 // 180k 5.25" drive
7429 config_data = 0x00; // 0000 0000
7430 media_state = 0x27; // 0010 0111
7431 retval = 1;
7432 }
7433 else if ( drive_type == 8 ) {
7434 // 320k 5.25" drive
7435 config_data = 0x00; // 0000 0000
7436 media_state = 0x27; // 0010 0111
7437 retval = 1;
7438 }
7439
7440 else {
7441 // not recognized
7442 config_data = 0x00; // 0000 0000
7443 media_state = 0x00; // 0000 0000
7444 retval = 0;
7445 }
7446
7447 if (drive == 0)
7448 media_state_offset = 0x90;
7449 else
7450 media_state_offset = 0x91;
7451 write_byte(0x0040, 0x008B, config_data);
7452 write_byte(0x0040, media_state_offset, media_state);
7453
7454 return(retval);
7455}
7456
7457 bx_bool
7458floppy_drive_recal(drive)
7459 Bit16u drive;
7460{
7461 Bit8u val8;
7462 Bit16u curr_cyl_offset;
7463
7464 floppy_prepare_controller(drive);
7465
7466 // send Recalibrate command (2 bytes) to controller
7467 outb(0x03f5, 0x07); // 07: Recalibrate
7468 outb(0x03f5, drive); // 0=drive0, 1=drive1
7469
7470 // turn on interrupts
7471ASM_START
7472 sti
7473ASM_END
7474
7475 // wait on 40:3e bit 7 to become 1
7476 do {
7477 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7478 } while ( val8 == 0 );
7479
7480 val8 = 0; // separate asm from while() loop
7481 // turn off interrupts
7482ASM_START
7483 cli
7484ASM_END
7485
7486 // set 40:3e bit 7 to 0, and calibrated bit
7487 val8 = read_byte(0x0040, 0x003e);
7488 val8 &= 0x7f;
7489 if (drive) {
7490 val8 |= 0x02; // Drive 1 calibrated
7491 curr_cyl_offset = 0x0095;
7492 } else {
7493 val8 |= 0x01; // Drive 0 calibrated
7494 curr_cyl_offset = 0x0094;
7495 }
7496 write_byte(0x0040, 0x003e, val8);
7497 write_byte(0x0040, curr_cyl_offset, 0); // current cylinder is 0
7498
7499 return(1);
7500}
7501
7502
7503
7504 bx_bool
7505floppy_drive_exists(drive)
7506 Bit16u drive;
7507{
7508 Bit8u drive_type;
7509
7510 // check CMOS to see if drive exists
7511 drive_type = inb_cmos(0x10);
7512 if (drive == 0)
7513 drive_type >>= 4;
7514 else
7515 drive_type &= 0x0f;
7516 if ( drive_type == 0 )
7517 return(0);
7518 else
7519 return(1);
7520}
7521
7522 void
7523int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
7524 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
7525{
7526 Bit8u drive, num_sectors, track, sector, head, status;
7527 Bit16u base_address, base_count, base_es;
7528 Bit8u page, mode_register, val8, dor;
7529 Bit8u return_status[7];
7530 Bit8u drive_type, num_floppies, ah;
7531 Bit16u es, last_addr;
7532
7533 BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
7534
7535 ah = GET_AH();
7536
7537 switch ( ah ) {
7538 case 0x00: // diskette controller reset
7539BX_DEBUG_INT13_FL("floppy f00\n");
7540 drive = GET_ELDL();
7541 if (drive > 1) {
7542 SET_AH(1); // invalid param
7543 set_diskette_ret_status(1);
7544 SET_CF();
7545 return;
7546 }
7547 drive_type = inb_cmos(0x10);
7548
7549 if (drive == 0)
7550 drive_type >>= 4;
7551 else
7552 drive_type &= 0x0f;
7553 if (drive_type == 0) {
7554 SET_AH(0x80); // drive not responding
7555 set_diskette_ret_status(0x80);
7556 SET_CF();
7557 return;
7558 }
7559 SET_AH(0);
7560 set_diskette_ret_status(0);
7561 CLEAR_CF(); // successful
7562 set_diskette_current_cyl(drive, 0); // current cylinder
7563 return;
7564
7565 case 0x01: // Read Diskette Status
7566 CLEAR_CF();
7567 val8 = read_byte(0x0000, 0x0441);
7568 SET_AH(val8);
7569 if (val8) {
7570 SET_CF();
7571 }
7572 return;
7573
7574 case 0x02: // Read Diskette Sectors
7575 case 0x03: // Write Diskette Sectors
7576 case 0x04: // Verify Diskette Sectors
7577 num_sectors = GET_AL();
7578 track = GET_CH();
7579 sector = GET_CL();
7580 head = GET_DH();
7581 drive = GET_ELDL();
7582
7583 if ( (drive > 1) || (head > 1) ||
7584 (num_sectors == 0) || (num_sectors > 72) ) {
7585BX_INFO("floppy: drive>1 || head>1 ...\n");
7586 SET_AH(1);
7587 set_diskette_ret_status(1);
7588 SET_AL(0); // no sectors read
7589 SET_CF(); // error occurred
7590 return;
7591 }
7592
7593 // see if drive exists
7594 if (floppy_drive_exists(drive) == 0) {
7595 SET_AH(0x80); // not responding
7596 set_diskette_ret_status(0x80);
7597 SET_AL(0); // no sectors read
7598 SET_CF(); // error occurred
7599 return;
7600 }
7601
7602 // see if media in drive, and type is known
7603 if (floppy_media_known(drive) == 0) {
7604 if (floppy_media_sense(drive) == 0) {
7605 SET_AH(0x0C); // Media type not found
7606 set_diskette_ret_status(0x0C);
7607 SET_AL(0); // no sectors read
7608 SET_CF(); // error occurred
7609 return;
7610 }
7611 }
7612
7613 if (ah == 0x02) {
7614 // Read Diskette Sectors
7615
7616 //-----------------------------------
7617 // set up DMA controller for transfer
7618 //-----------------------------------
7619
7620 // es:bx = pointer to where to place information from diskette
7621 // port 04: DMA-1 base and current address, channel 2
7622 // port 05: DMA-1 base and current count, channel 2
7623 page = (ES >> 12); // upper 4 bits
7624 base_es = (ES << 4); // lower 16bits contributed by ES
7625 base_address = base_es + BX; // lower 16 bits of address
7626 // contributed by ES:BX
7627 if ( base_address < base_es ) {
7628 // in case of carry, adjust page by 1
7629 page++;
7630 }
7631 base_count = (num_sectors * 512) - 1;
7632
7633 // check for 64K boundary overrun
7634 last_addr = base_address + base_count;
7635 if (last_addr < base_address) {
7636 SET_AH(0x09);
7637 set_diskette_ret_status(0x09);
7638 SET_AL(0); // no sectors read
7639 SET_CF(); // error occurred
7640 return;
7641 }
7642
7643 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7644 outb(0x000a, 0x06);
7645
7646 BX_DEBUG_INT13_FL("clear flip-flop\n");
7647 outb(0x000c, 0x00); // clear flip-flop
7648 outb(0x0004, base_address);
7649 outb(0x0004, base_address>>8);
7650 BX_DEBUG_INT13_FL("clear flip-flop\n");
7651 outb(0x000c, 0x00); // clear flip-flop
7652 outb(0x0005, base_count);
7653 outb(0x0005, base_count>>8);
7654
7655 // port 0b: DMA-1 Mode Register
7656 mode_register = 0x46; // single mode, increment, autoinit disable,
7657 // transfer type=write, channel 2
7658 BX_DEBUG_INT13_FL("setting mode register\n");
7659 outb(0x000b, mode_register);
7660
7661 BX_DEBUG_INT13_FL("setting page register\n");
7662 // port 81: DMA-1 Page Register, channel 2
7663 outb(0x0081, page);
7664
7665 BX_DEBUG_INT13_FL("unmask chan 2\n");
7666 outb(0x000a, 0x02); // unmask channel 2
7667
7668 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7669 outb(0x000a, 0x02);
7670
7671 //--------------------------------------
7672 // set up floppy controller for transfer
7673 //--------------------------------------
7674 floppy_prepare_controller(drive);
7675
7676 // send read-normal-data command (9 bytes) to controller
7677 outb(0x03f5, 0xe6); // e6: read normal data
7678 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7679 outb(0x03f5, track);
7680 outb(0x03f5, head);
7681 outb(0x03f5, sector);
7682 outb(0x03f5, 2); // 512 byte sector size
7683 outb(0x03f5, sector + num_sectors - 1); // last sector to read on track
7684 outb(0x03f5, 0); // Gap length
7685 outb(0x03f5, 0xff); // Gap length
7686
7687 // turn on interrupts
7688 ASM_START
7689 sti
7690 ASM_END
7691
7692 // wait on 40:3e bit 7 to become 1
7693 do {
7694 val8 = read_byte(0x0040, 0x0040);
7695 if (val8 == 0) {
7696 floppy_reset_controller();
7697 SET_AH(0x80); // drive not ready (timeout)
7698 set_diskette_ret_status(0x80);
7699 SET_AL(0); // no sectors read
7700 SET_CF(); // error occurred
7701 return;
7702 }
7703 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7704 } while ( val8 == 0 );
7705
7706 val8 = 0; // separate asm from while() loop
7707 // turn off interrupts
7708 ASM_START
7709 cli
7710 ASM_END
7711
7712 // set 40:3e bit 7 to 0
7713 val8 = read_byte(0x0040, 0x003e);
7714 val8 &= 0x7f;
7715 write_byte(0x0040, 0x003e, val8);
7716
7717 // check port 3f4 for accessibility to status bytes
7718 val8 = inb(0x3f4);
7719 if ( (val8 & 0xc0) != 0xc0 )
7720 BX_PANIC("int13_diskette: ctrl not ready\n");
7721
7722 // read 7 return status bytes from controller
7723 // using loop index broken, have to unroll...
7724 return_status[0] = inb(0x3f5);
7725 return_status[1] = inb(0x3f5);
7726 return_status[2] = inb(0x3f5);
7727 return_status[3] = inb(0x3f5);
7728 return_status[4] = inb(0x3f5);
7729 return_status[5] = inb(0x3f5);
7730 return_status[6] = inb(0x3f5);
7731 // record in BIOS Data Area
7732 write_byte(0x0040, 0x0042, return_status[0]);
7733 write_byte(0x0040, 0x0043, return_status[1]);
7734 write_byte(0x0040, 0x0044, return_status[2]);
7735 write_byte(0x0040, 0x0045, return_status[3]);
7736 write_byte(0x0040, 0x0046, return_status[4]);
7737 write_byte(0x0040, 0x0047, return_status[5]);
7738 write_byte(0x0040, 0x0048, return_status[6]);
7739
7740 if ( (return_status[0] & 0xc0) != 0 ) {
7741 SET_AH(0x20);
7742 set_diskette_ret_status(0x20);
7743 SET_AL(0); // no sectors read
7744 SET_CF(); // error occurred
7745 return;
7746 }
7747
7748 // ??? should track be new val from return_status[3] ?
7749 set_diskette_current_cyl(drive, track);
7750 // AL = number of sectors read (same value as passed)
7751 SET_AH(0x00); // success
7752 CLEAR_CF(); // success
7753 return;
7754 } else if (ah == 0x03) {
7755 // Write Diskette Sectors
7756
7757 //-----------------------------------
7758 // set up DMA controller for transfer
7759 //-----------------------------------
7760
7761 // es:bx = pointer to where to place information from diskette
7762 // port 04: DMA-1 base and current address, channel 2
7763 // port 05: DMA-1 base and current count, channel 2
7764 page = (ES >> 12); // upper 4 bits
7765 base_es = (ES << 4); // lower 16bits contributed by ES
7766 base_address = base_es + BX; // lower 16 bits of address
7767 // contributed by ES:BX
7768 if ( base_address < base_es ) {
7769 // in case of carry, adjust page by 1
7770 page++;
7771 }
7772 base_count = (num_sectors * 512) - 1;
7773
7774 // check for 64K boundary overrun
7775 last_addr = base_address + base_count;
7776 if (last_addr < base_address) {
7777 SET_AH(0x09);
7778 set_diskette_ret_status(0x09);
7779 SET_AL(0); // no sectors read
7780 SET_CF(); // error occurred
7781 return;
7782 }
7783
7784 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7785 outb(0x000a, 0x06);
7786
7787 outb(0x000c, 0x00); // clear flip-flop
7788 outb(0x0004, base_address);
7789 outb(0x0004, base_address>>8);
7790 outb(0x000c, 0x00); // clear flip-flop
7791 outb(0x0005, base_count);
7792 outb(0x0005, base_count>>8);
7793
7794 // port 0b: DMA-1 Mode Register
7795 mode_register = 0x4a; // single mode, increment, autoinit disable,
7796 // transfer type=read, channel 2
7797 outb(0x000b, mode_register);
7798
7799 // port 81: DMA-1 Page Register, channel 2
7800 outb(0x0081, page);
7801
7802 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7803 outb(0x000a, 0x02);
7804
7805 //--------------------------------------
7806 // set up floppy controller for transfer
7807 //--------------------------------------
7808 floppy_prepare_controller(drive);
7809
7810 // send write-normal-data command (9 bytes) to controller
7811 outb(0x03f5, 0xc5); // c5: write normal data
7812 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7813 outb(0x03f5, track);
7814 outb(0x03f5, head);
7815 outb(0x03f5, sector);
7816 outb(0x03f5, 2); // 512 byte sector size
7817 outb(0x03f5, sector + num_sectors - 1); // last sector to write on track
7818 outb(0x03f5, 0); // Gap length
7819 outb(0x03f5, 0xff); // Gap length
7820
7821 // turn on interrupts
7822 ASM_START
7823 sti
7824 ASM_END
7825
7826 // wait on 40:3e bit 7 to become 1
7827 do {
7828 val8 = read_byte(0x0040, 0x0040);
7829 if (val8 == 0) {
7830 floppy_reset_controller();
7831 SET_AH(0x80); // drive not ready (timeout)
7832 set_diskette_ret_status(0x80);
7833 SET_AL(0); // no sectors written
7834 SET_CF(); // error occurred
7835 return;
7836 }
7837 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7838 } while ( val8 == 0 );
7839
7840 val8 = 0; // separate asm from while() loop
7841 // turn off interrupts
7842 ASM_START
7843 cli
7844 ASM_END
7845
7846 // set 40:3e bit 7 to 0
7847 val8 = read_byte(0x0040, 0x003e);
7848 val8 &= 0x7f;
7849 write_byte(0x0040, 0x003e, val8);
7850
7851 // check port 3f4 for accessibility to status bytes
7852 val8 = inb(0x3f4);
7853 if ( (val8 & 0xc0) != 0xc0 )
7854 BX_PANIC("int13_diskette: ctrl not ready\n");
7855
7856 // read 7 return status bytes from controller
7857 // using loop index broken, have to unroll...
7858 return_status[0] = inb(0x3f5);
7859 return_status[1] = inb(0x3f5);
7860 return_status[2] = inb(0x3f5);
7861 return_status[3] = inb(0x3f5);
7862 return_status[4] = inb(0x3f5);
7863 return_status[5] = inb(0x3f5);
7864 return_status[6] = inb(0x3f5);
7865 // record in BIOS Data Area
7866 write_byte(0x0040, 0x0042, return_status[0]);
7867 write_byte(0x0040, 0x0043, return_status[1]);
7868 write_byte(0x0040, 0x0044, return_status[2]);
7869 write_byte(0x0040, 0x0045, return_status[3]);
7870 write_byte(0x0040, 0x0046, return_status[4]);
7871 write_byte(0x0040, 0x0047, return_status[5]);
7872 write_byte(0x0040, 0x0048, return_status[6]);
7873
7874 if ( (return_status[0] & 0xc0) != 0 ) {
7875 if ( (return_status[1] & 0x02) != 0 ) {
7876 // diskette not writable.
7877 // AH=status code=0x03 (tried to write on write-protected disk)
7878 // AL=number of sectors written=0
7879 AX = 0x0300;
7880 SET_CF();
7881 return;
7882 } else {
7883 BX_PANIC("int13_diskette_function: read error\n");
7884 }
7885 }
7886
7887 // ??? should track be new val from return_status[3] ?
7888 set_diskette_current_cyl(drive, track);
7889 // AL = number of sectors read (same value as passed)
7890 SET_AH(0x00); // success
7891 CLEAR_CF(); // success
7892 return;
7893 } else { // if (ah == 0x04)
7894 // Verify Diskette Sectors
7895
7896 // ??? should track be new val from return_status[3] ?
7897 set_diskette_current_cyl(drive, track);
7898 // AL = number of sectors verified (same value as passed)
7899 CLEAR_CF(); // success
7900 SET_AH(0x00); // success
7901 return;
7902 }
7903 break;
7904
7905 case 0x05: // format diskette track
7906BX_DEBUG_INT13_FL("floppy f05\n");
7907
7908 num_sectors = GET_AL();
7909 track = GET_CH();
7910 head = GET_DH();
7911 drive = GET_ELDL();
7912
7913 if ((drive > 1) || (head > 1) || (track > 79) ||
7914 (num_sectors == 0) || (num_sectors > 18)) {
7915 SET_AH(1);
7916 set_diskette_ret_status(1);
7917 SET_CF(); // error occurred
7918 }
7919
7920 // see if drive exists
7921 if (floppy_drive_exists(drive) == 0) {
7922 SET_AH(0x80); // drive not responding
7923 set_diskette_ret_status(0x80);
7924 SET_CF(); // error occurred
7925 return;
7926 }
7927
7928 // see if media in drive, and type is known
7929 if (floppy_media_known(drive) == 0) {
7930 if (floppy_media_sense(drive) == 0) {
7931 SET_AH(0x0C); // Media type not found
7932 set_diskette_ret_status(0x0C);
7933 SET_AL(0); // no sectors read
7934 SET_CF(); // error occurred
7935 return;
7936 }
7937 }
7938
7939 // set up DMA controller for transfer
7940 page = (ES >> 12); // upper 4 bits
7941 base_es = (ES << 4); // lower 16bits contributed by ES
7942 base_address = base_es + BX; // lower 16 bits of address
7943 // contributed by ES:BX
7944 if ( base_address < base_es ) {
7945 // in case of carry, adjust page by 1
7946 page++;
7947 }
7948 base_count = (num_sectors * 4) - 1;
7949
7950 // check for 64K boundary overrun
7951 last_addr = base_address + base_count;
7952 if (last_addr < base_address) {
7953 SET_AH(0x09);
7954 set_diskette_ret_status(0x09);
7955 SET_AL(0); // no sectors read
7956 SET_CF(); // error occurred
7957 return;
7958 }
7959
7960 outb(0x000a, 0x06);
7961 outb(0x000c, 0x00); // clear flip-flop
7962 outb(0x0004, base_address);
7963 outb(0x0004, base_address>>8);
7964 outb(0x000c, 0x00); // clear flip-flop
7965 outb(0x0005, base_count);
7966 outb(0x0005, base_count>>8);
7967 mode_register = 0x4a; // single mode, increment, autoinit disable,
7968 // transfer type=read, channel 2
7969 outb(0x000b, mode_register);
7970 // port 81: DMA-1 Page Register, channel 2
7971 outb(0x0081, page);
7972 outb(0x000a, 0x02);
7973
7974 // set up floppy controller for transfer
7975 floppy_prepare_controller(drive);
7976
7977 // send format-track command (6 bytes) to controller
7978 outb(0x03f5, 0x4d); // 4d: format track
7979 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7980 outb(0x03f5, 2); // 512 byte sector size
7981 outb(0x03f5, num_sectors); // number of sectors per track
7982 outb(0x03f5, 0); // Gap length
7983 outb(0x03f5, 0xf6); // Fill byte
7984 // turn on interrupts
7985 ASM_START
7986 sti
7987 ASM_END
7988
7989 // wait on 40:3e bit 7 to become 1
7990 do {
7991 val8 = read_byte(0x0040, 0x0040);
7992 if (val8 == 0) {
7993 floppy_reset_controller();
7994 SET_AH(0x80); // drive not ready (timeout)
7995 set_diskette_ret_status(0x80);
7996 SET_CF(); // error occurred
7997 return;
7998 }
7999 val8 = (read_byte(0x0040, 0x003e) & 0x80);
8000 } while ( val8 == 0 );
8001
8002 val8 = 0; // separate asm from while() loop
8003 // turn off interrupts
8004 ASM_START
8005 cli
8006 ASM_END
8007 // set 40:3e bit 7 to 0
8008 val8 = read_byte(0x0040, 0x003e);
8009 val8 &= 0x7f;
8010 write_byte(0x0040, 0x003e, val8);
8011 // check port 3f4 for accessibility to status bytes
8012 val8 = inb(0x3f4);
8013 if ( (val8 & 0xc0) != 0xc0 )
8014 BX_PANIC("int13_diskette: ctrl not ready\n");
8015
8016 // read 7 return status bytes from controller
8017 // using loop index broken, have to unroll...
8018 return_status[0] = inb(0x3f5);
8019 return_status[1] = inb(0x3f5);
8020 return_status[2] = inb(0x3f5);
8021 return_status[3] = inb(0x3f5);
8022 return_status[4] = inb(0x3f5);
8023 return_status[5] = inb(0x3f5);
8024 return_status[6] = inb(0x3f5);
8025 // record in BIOS Data Area
8026 write_byte(0x0040, 0x0042, return_status[0]);
8027 write_byte(0x0040, 0x0043, return_status[1]);
8028 write_byte(0x0040, 0x0044, return_status[2]);
8029 write_byte(0x0040, 0x0045, return_status[3]);
8030 write_byte(0x0040, 0x0046, return_status[4]);
8031 write_byte(0x0040, 0x0047, return_status[5]);
8032 write_byte(0x0040, 0x0048, return_status[6]);
8033
8034 if ( (return_status[0] & 0xc0) != 0 ) {
8035 if ( (return_status[1] & 0x02) != 0 ) {
8036 // diskette not writable.
8037 // AH=status code=0x03 (tried to write on write-protected disk)
8038 // AL=number of sectors written=0
8039 AX = 0x0300;
8040 SET_CF();
8041 return;
8042 } else {
8043 BX_PANIC("int13_diskette_function: write error\n");
8044 }
8045 }
8046
8047 SET_AH(0);
8048 set_diskette_ret_status(0);
8049 set_diskette_current_cyl(drive, 0);
8050 CLEAR_CF(); // successful
8051 return;
8052
8053
8054 case 0x08: // read diskette drive parameters
8055BX_DEBUG_INT13_FL("floppy f08\n");
8056 drive = GET_ELDL();
8057
8058 if (drive > 1) {
8059 AX = 0;
8060 BX = 0;
8061 CX = 0;
8062 DX = 0;
8063 ES = 0;
8064 DI = 0;
8065 SET_DL(num_floppies);
8066 SET_CF();
8067 return;
8068 }
8069
8070 drive_type = inb_cmos(0x10);
8071 num_floppies = 0;
8072 if (drive_type & 0xf0)
8073 num_floppies++;
8074 if (drive_type & 0x0f)
8075 num_floppies++;
8076
8077 if (drive == 0)
8078 drive_type >>= 4;
8079 else
8080 drive_type &= 0x0f;
8081
8082 SET_BH(0);
8083 SET_BL(drive_type);
8084 SET_AH(0);
8085 SET_AL(0);
8086 SET_DL(num_floppies);
8087
8088 switch (drive_type) {
8089 case 0: // none
8090 CX = 0;
8091 SET_DH(0); // max head #
8092 break;
8093
8094 case 1: // 360KB, 5.25"
8095 CX = 0x2709; // 40 tracks, 9 sectors
8096 SET_DH(1); // max head #
8097 break;
8098
8099 case 2: // 1.2MB, 5.25"
8100 CX = 0x4f0f; // 80 tracks, 15 sectors
8101 SET_DH(1); // max head #
8102 break;
8103
8104 case 3: // 720KB, 3.5"
8105 CX = 0x4f09; // 80 tracks, 9 sectors
8106 SET_DH(1); // max head #
8107 break;
8108
8109 case 4: // 1.44MB, 3.5"
8110 CX = 0x4f12; // 80 tracks, 18 sectors
8111 SET_DH(1); // max head #
8112 break;
8113
8114 case 5: // 2.88MB, 3.5"
8115 CX = 0x4f24; // 80 tracks, 36 sectors
8116 SET_DH(1); // max head #
8117 break;
8118
8119 case 6: // 160k, 5.25"
8120 CX = 0x2708; // 40 tracks, 8 sectors
8121 SET_DH(0); // max head #
8122 break;
8123
8124 case 7: // 180k, 5.25"
8125 CX = 0x2709; // 40 tracks, 9 sectors
8126 SET_DH(0); // max head #
8127 break;
8128
8129 case 8: // 320k, 5.25"
8130 CX = 0x2708; // 40 tracks, 8 sectors
8131 SET_DH(1); // max head #
8132 break;
8133
8134 default: // ?
8135 BX_PANIC("floppy: int13: bad floppy type\n");
8136 }
8137
8138 /* set es & di to point to 11 byte diskette param table in ROM */
8139ASM_START
8140 push bp
8141 mov bp, sp
8142 mov ax, #diskette_param_table2
8143 mov _int13_diskette_function.DI+2[bp], ax
8144 mov _int13_diskette_function.ES+2[bp], cs
8145 pop bp
8146ASM_END
8147 CLEAR_CF(); // success
8148 /* disk status not changed upon success */
8149 return;
8150
8151
8152 case 0x15: // read diskette drive type
8153BX_DEBUG_INT13_FL("floppy f15\n");
8154 drive = GET_ELDL();
8155 if (drive > 1) {
8156 SET_AH(0); // only 2 drives supported
8157 // set_diskette_ret_status here ???
8158 SET_CF();
8159 return;
8160 }
8161 drive_type = inb_cmos(0x10);
8162
8163 if (drive == 0)
8164 drive_type >>= 4;
8165 else
8166 drive_type &= 0x0f;
8167 CLEAR_CF(); // successful, not present
8168 if (drive_type==0) {
8169 SET_AH(0); // drive not present
8170 }
8171 else {
8172 SET_AH(1); // drive present, does not support change line
8173 }
8174
8175 return;
8176
8177 case 0x16: // get diskette change line status
8178BX_DEBUG_INT13_FL("floppy f16\n");
8179 drive = GET_ELDL();
8180 if (drive > 1) {
8181 SET_AH(0x01); // invalid drive
8182 set_diskette_ret_status(0x01);
8183 SET_CF();
8184 return;
8185 }
8186
8187 SET_AH(0x06); // change line not supported
8188 set_diskette_ret_status(0x06);
8189 SET_CF();
8190 return;
8191
8192 case 0x17: // set diskette type for format(old)
8193BX_DEBUG_INT13_FL("floppy f17\n");
8194 /* not used for 1.44M floppies */
8195 SET_AH(0x01); // not supported
8196 set_diskette_ret_status(1); /* not supported */
8197 SET_CF();
8198 return;
8199
8200 case 0x18: // set diskette type for format(new)
8201BX_DEBUG_INT13_FL("floppy f18\n");
8202 SET_AH(0x01); // do later
8203 set_diskette_ret_status(1);
8204 SET_CF();
8205 return;
8206
8207 default:
8208 BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
8209
8210 // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
8211 SET_AH(0x01); // ???
8212 set_diskette_ret_status(1);
8213 SET_CF();
8214 return;
8215 // }
8216 }
8217}
8218#else // #if BX_SUPPORT_FLOPPY
8219 void
8220int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
8221 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
8222{
8223 Bit8u val8;
8224
8225 switch ( GET_AH() ) {
8226
8227 case 0x01: // Read Diskette Status
8228 CLEAR_CF();
8229 val8 = read_byte(0x0000, 0x0441);
8230 SET_AH(val8);
8231 if (val8) {
8232 SET_CF();
8233 }
8234 return;
8235
8236 default:
8237 SET_CF();
8238 write_byte(0x0000, 0x0441, 0x01);
8239 SET_AH(0x01);
8240 }
8241}
8242#endif // #if BX_SUPPORT_FLOPPY
8243
8244 void
8245set_diskette_ret_status(value)
8246 Bit8u value;
8247{
8248 write_byte(0x0040, 0x0041, value);
8249}
8250
8251 void
8252set_diskette_current_cyl(drive, cyl)
8253 Bit8u drive;
8254 Bit8u cyl;
8255{
8256 if (drive > 1)
8257 BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
8258 write_byte(0x0040, 0x0094+drive, cyl);
8259}
8260
8261 void
8262determine_floppy_media(drive)
8263 Bit16u drive;
8264{
8265#if 0
8266 Bit8u val8, DOR, ctrl_info;
8267
8268 ctrl_info = read_byte(0x0040, 0x008F);
8269 if (drive==1)
8270 ctrl_info >>= 4;
8271 else
8272 ctrl_info &= 0x0f;
8273
8274#if 0
8275 if (drive == 0) {
8276 DOR = 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
8277 }
8278 else {
8279 DOR = 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
8280 }
8281#endif
8282
8283 if ( (ctrl_info & 0x04) != 0x04 ) {
8284 // Drive not determined means no drive exists, done.
8285 return;
8286 }
8287
8288#if 0
8289 // check Main Status Register for readiness
8290 val8 = inb(0x03f4) & 0x80; // Main Status Register
8291 if (val8 != 0x80)
8292 BX_PANIC("d_f_m: MRQ bit not set\n");
8293
8294 // change line
8295
8296 // existing BDA values
8297
8298 // turn on drive motor
8299 outb(0x03f2, DOR); // Digital Output Register
8300 //
8301#endif
8302 BX_PANIC("d_f_m: OK so far\n");
8303#endif
8304}
8305
8306 void
8307int17_function(regs, ds, iret_addr)
8308 pusha_regs_t regs; // regs pushed from PUSHA instruction
8309 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8310 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8311{
8312 Bit16u addr,timeout;
8313 Bit8u val8;
8314
8315 ASM_START
8316 sti
8317 ASM_END
8318
8319 addr = read_word(0x0040, (regs.u.r16.dx << 1) + 8);
8320 if ((regs.u.r8.ah < 3) && (regs.u.r16.dx < 3) && (addr > 0)) {
8321 timeout = read_byte(0x0040, 0x0078 + regs.u.r16.dx) << 8;
8322 if (regs.u.r8.ah == 0) {
8323 outb(addr, regs.u.r8.al);
8324 val8 = inb(addr+2);
8325 outb(addr+2, val8 | 0x01); // send strobe
8326 ASM_START
8327 nop
8328 ASM_END
8329 outb(addr+2, val8 & ~0x01);
8330 while (((inb(addr+1) & 0x40) == 0x40) && (timeout)) {
8331 timeout--;
8332 }
8333 }
8334 if (regs.u.r8.ah == 1) {
8335 val8 = inb(addr+2);
8336 outb(addr+2, val8 & ~0x04); // send init
8337 ASM_START
8338 nop
8339 ASM_END
8340 outb(addr+2, val8 | 0x04);
8341 }
8342 val8 = inb(addr+1);
8343 regs.u.r8.ah = (val8 ^ 0x48);
8344 if (!timeout) regs.u.r8.ah |= 0x01;
8345 ClearCF(iret_addr.flags);
8346 } else {
8347 SetCF(iret_addr.flags); // Unsupported
8348 }
8349}
8350
8351// returns bootsegment in ax, drive in bl
8352 Bit32u
8353int19_function(bseqnr)
8354Bit8u bseqnr;
8355{
8356 Bit16u ebda_seg=read_word(0x0040,0x000E);
8357 Bit16u bootseq;
8358 Bit8u bootdrv;
8359 Bit8u bootcd;
8360#ifdef VBOX
8361 Bit8u bootlan;
8362#endif /* VBOX */
8363 Bit8u bootchk;
8364 Bit16u bootseg;
8365 Bit16u status;
8366 Bit8u lastdrive=0;
8367
8368 // if BX_ELTORITO_BOOT is not defined, old behavior
8369 // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
8370 // in preparation for the initial INT 13h (0=floppy A:, 0x80=C:)
8371 // 0: system boot sequence, first drive C: then A:
8372 // 1: system boot sequence, first drive A: then C:
8373 // else BX_ELTORITO_BOOT is defined
8374 // CMOS regs 0x3D and 0x38 contain the boot sequence:
8375 // CMOS reg 0x3D & 0x0f : 1st boot device
8376 // CMOS reg 0x3D & 0xf0 : 2nd boot device
8377 // CMOS reg 0x38 & 0xf0 : 3rd boot device
8378#ifdef VBOX
8379 // CMOS reg 0x3C & 0x0f : 4th boot device
8380#endif /* VBOX */
8381 // boot device codes:
8382 // 0x00 : not defined
8383 // 0x01 : first floppy
8384 // 0x02 : first harddrive
8385 // 0x03 : first cdrom
8386#ifdef VBOX
8387 // 0x04 : local area network
8388#endif /* VBOX */
8389 // else : boot failure
8390
8391 // Get the boot sequence
8392#if BX_ELTORITO_BOOT
8393 bootseq=inb_cmos(0x3d);
8394 bootseq|=((inb_cmos(0x38) & 0xf0) << 4);
8395#ifdef VBOX
8396 bootseq|=((inb_cmos(0x3c) & 0x0f) << 12);
8397 if (read_byte(ebda_seg, &EbdaData->uForceBootDevice))
8398 bootseq = read_byte(ebda_seg, &EbdaData->uForceBootDevice);
8399 /* Boot delay hack. */
8400 if (bseqnr == 1)
8401 delay_boot((inb_cmos(0x3c) & 0xf0) >> 4); /* Implemented in logo.c */
8402#endif /* VBOX */
8403
8404 if (bseqnr==2) bootseq >>= 4;
8405 if (bseqnr==3) bootseq >>= 8;
8406#ifdef VBOX
8407 if (bseqnr==4) bootseq >>= 12;
8408#endif /* VBOX */
8409 if (bootseq<0x10) lastdrive = 1;
8410 bootdrv=0x00; bootcd=0;
8411#ifdef VBOX
8412 bootlan=0;
8413#endif /* VBOX */
8414
8415 switch(bootseq & 0x0f) {
8416 case 0x01:
8417 bootdrv=0x00;
8418 bootcd=0;
8419 break;
8420 case 0x02:
8421 {
8422 // Get the Boot drive.
8423 Bit8u boot_drive = read_byte(ebda_seg, &EbdaData->uForceBootDrive);
8424
8425 bootdrv = boot_drive + 0x80;
8426 bootcd=0;
8427 break;
8428 }
8429 case 0x03:
8430 bootdrv=0x00;
8431 bootcd=1;
8432 break;
8433#ifdef VBOX
8434 case 0x04: bootlan=1; break;
8435#endif /* VBOX */
8436 default: return 0x00000000;
8437 }
8438#else
8439 bootseq=inb_cmos(0x2d);
8440
8441 if (bseqnr==2) {
8442 bootseq ^= 0x20;
8443 lastdrive = 1;
8444 }
8445 bootdrv=0x00; bootcd=0;
8446 if((bootseq&0x20)==0) bootdrv=0x80;
8447#endif // BX_ELTORITO_BOOT
8448
8449#if BX_ELTORITO_BOOT
8450 // We have to boot from cd
8451 if (bootcd != 0) {
8452 status = cdrom_boot();
8453
8454 // If failure
8455 if ( (status & 0x00ff) !=0 ) {
8456 print_cdromboot_failure(status);
8457#ifdef VBOX
8458 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
8459#else /* !VBOX */
8460 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
8461#endif /* !VBOX */
8462 return 0x00000000;
8463 }
8464
8465 bootseg = read_word(ebda_seg,&EbdaData->cdemu.load_segment);
8466 bootdrv = (Bit8u)(status>>8);
8467 }
8468
8469#endif // BX_ELTORITO_BOOT
8470
8471#ifdef VBOX
8472 // Check for boot from LAN first
8473 if (bootlan == 1) {
8474 if (read_word(VBOX_LANBOOT_SEG,0) == 0xaa55) {
8475 Bit16u pnpoff;
8476 Bit32u manuf;
8477 // This is NOT a generic PnP implementation, but an Etherboot-specific hack.
8478 pnpoff = read_word(VBOX_LANBOOT_SEG,0x1a);
8479 if (read_dword(VBOX_LANBOOT_SEG,pnpoff) == 0x506e5024) {
8480 // Found PnP signature
8481 manuf = read_dword(VBOX_LANBOOT_SEG,read_word(VBOX_LANBOOT_SEG,pnpoff+0xe));
8482 if (manuf == 0x65687445) {
8483 // Found Etherboot ROM
8484 print_boot_device(bootcd, bootlan, bootdrv);
8485ASM_START
8486 push ds
8487 push es
8488 pusha
8489 calli 0x0006,VBOX_LANBOOT_SEG
8490 popa
8491 pop es
8492 pop ds
8493ASM_END
8494 } else if (manuf == 0x65746E49) {
8495 // Found Intel PXE ROM
8496 print_boot_device(bootcd, bootlan, bootdrv);
8497ASM_START
8498 push ds
8499 push es
8500 pusha
8501 sti ; Why are interrupts disabled now? Because we were called through an INT!
8502 push #VBOX_LANBOOT_SEG
8503 pop ds
8504 mov bx,#0x1a ; PnP header offset
8505 mov bx,[bx]
8506 add bx,#0x1a ; BEV offset in PnP header
8507 mov ax,[bx]
8508 test ax,ax
8509 jz no_rom
8510bev_jump:
8511 push cs
8512 push #no_rom
8513 push #VBOX_LANBOOT_SEG
8514 push ax
8515 retf ; call Boot Entry Vector
8516no_rom:
8517 popa
8518 pop es
8519 pop ds
8520ASM_END
8521 }
8522 }
8523 }
8524
8525 // boot from LAN will not return if successful.
8526 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
8527 return 0x00000000;
8528 }
8529#endif /* VBOX */
8530 // We have to boot from harddisk or floppy
8531#ifdef VBOX
8532 if (bootcd == 0 && bootlan == 0) {
8533#else /* !VBOX */
8534 if (bootcd == 0) {
8535#endif /* !VBOX */
8536 bootseg=0x07c0;
8537
8538ASM_START
8539 push bp
8540 mov bp, sp
8541
8542 xor ax, ax
8543 mov _int19_function.status + 2[bp], ax
8544 mov dl, _int19_function.bootdrv + 2[bp]
8545 mov ax, _int19_function.bootseg + 2[bp]
8546 mov es, ax ;; segment
8547 xor bx, bx ;; offset
8548 mov ah, #0x02 ;; function 2, read diskette sector
8549 mov al, #0x01 ;; read 1 sector
8550 mov ch, #0x00 ;; track 0
8551 mov cl, #0x01 ;; sector 1
8552 mov dh, #0x00 ;; head 0
8553 int #0x13 ;; read sector
8554 jnc int19_load_done
8555 mov ax, #0x0001
8556 mov _int19_function.status + 2[bp], ax
8557
8558int19_load_done:
8559 pop bp
8560ASM_END
8561
8562 if (status != 0) {
8563#ifdef VBOX
8564 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
8565#else /* !VBOX */
8566 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
8567#endif /* !VBOX */
8568 return 0x00000000;
8569 }
8570 }
8571
8572#ifdef VBOX
8573 // Don't check boot sectors on floppies and don't read CMOS - byte
8574 // 0x38 in CMOS always has the low bit clear.
8575 // There is *no* requirement whatsoever for a valid boot sector to
8576 // have a 55AAh signature. UNIX boot floppies typically have no such
8577 // signature. In general, it is impossible to tell a valid bootsector
8578 // from an invalid one.
8579 // NB: It is somewhat common for failed OS installs to have the
8580 // 0x55AA signature and a valid partition table but zeros in the
8581 // rest of the boot sector. We do a quick check by comparing the first
8582 // two words of boot sector; if identical, the boot sector is
8583 // extremely unlikely to be valid.
8584#endif
8585 // check signature if instructed by cmos reg 0x38, only for floppy
8586 // bootchk = 1 : signature check disabled
8587 // bootchk = 0 : signature check enabled
8588 if (bootdrv != 0) bootchk = 0;
8589#ifdef VBOX
8590 else bootchk = 1; /* disable 0x55AA signature check on drive A: */
8591#else
8592 else bootchk = inb_cmos(0x38) & 0x01;
8593#endif
8594
8595#if BX_ELTORITO_BOOT
8596 // if boot from cd, no signature check
8597 if (bootcd != 0)
8598 bootchk = 1;
8599#endif // BX_ELTORITO_BOOT
8600
8601 if (bootchk == 0) {
8602 if (read_word(bootseg,0x1fe) != 0xaa55 ||
8603 read_word(bootseg,0) == read_word(bootseg,2)) {
8604#ifdef VBOX
8605 print_boot_failure(bootcd, bootlan, bootdrv, 0, lastdrive);
8606#else /* !VBOX */
8607 print_boot_failure(bootcd, bootdrv, 0, lastdrive);
8608#endif /* VBOX */
8609 return 0x00000000;
8610 }
8611 }
8612
8613#if BX_ELTORITO_BOOT
8614 // Print out the boot string
8615#ifdef VBOX
8616 print_boot_device(bootcd, bootlan, bootdrv);
8617#else /* !VBOX */
8618 print_boot_device(bootcd, bootdrv);
8619#endif /* !VBOX */
8620#else // BX_ELTORITO_BOOT
8621#ifdef VBOX
8622 print_boot_device(0, bootlan, bootdrv);
8623#else /* !VBOX */
8624 print_boot_device(0, bootdrv);
8625#endif /* !VBOX */
8626#endif // BX_ELTORITO_BOOT
8627
8628 // return the boot segment
8629 return (((Bit32u)bootdrv) << 16) + bootseg;
8630}
8631
8632 void
8633int1a_function(regs, ds, iret_addr)
8634 pusha_regs_t regs; // regs pushed from PUSHA instruction
8635 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8636 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8637{
8638 Bit8u val8;
8639
8640 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);
8641
8642 ASM_START
8643 sti
8644 ASM_END
8645
8646 switch (regs.u.r8.ah) {
8647 case 0: // get current clock count
8648 ASM_START
8649 cli
8650 ASM_END
8651 regs.u.r16.cx = BiosData->ticks_high;
8652 regs.u.r16.dx = BiosData->ticks_low;
8653 regs.u.r8.al = BiosData->midnight_flag;
8654 BiosData->midnight_flag = 0; // reset flag
8655 ASM_START
8656 sti
8657 ASM_END
8658 // AH already 0
8659 ClearCF(iret_addr.flags); // OK
8660 break;
8661
8662 case 1: // Set Current Clock Count
8663 ASM_START
8664 cli
8665 ASM_END
8666 BiosData->ticks_high = regs.u.r16.cx;
8667 BiosData->ticks_low = regs.u.r16.dx;
8668 BiosData->midnight_flag = 0; // reset flag
8669 ASM_START
8670 sti
8671 ASM_END
8672 regs.u.r8.ah = 0;
8673 ClearCF(iret_addr.flags); // OK
8674 break;
8675
8676
8677 case 2: // Read CMOS Time
8678 if (rtc_updating()) {
8679 SetCF(iret_addr.flags);
8680 break;
8681 }
8682
8683 regs.u.r8.dh = inb_cmos(0x00); // Seconds
8684 regs.u.r8.cl = inb_cmos(0x02); // Minutes
8685 regs.u.r8.ch = inb_cmos(0x04); // Hours
8686 regs.u.r8.dl = inb_cmos(0x0b) & 0x01; // Stat Reg B
8687 regs.u.r8.ah = 0;
8688 regs.u.r8.al = regs.u.r8.ch;
8689 ClearCF(iret_addr.flags); // OK
8690 break;
8691
8692 case 3: // Set CMOS Time
8693 // Using a debugger, I notice the following masking/setting
8694 // of bits in Status Register B, by setting Reg B to
8695 // a few values and getting its value after INT 1A was called.
8696 //
8697 // try#1 try#2 try#3
8698 // before 1111 1101 0111 1101 0000 0000
8699 // after 0110 0010 0110 0010 0000 0010
8700 //
8701 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8702 // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
8703 if (rtc_updating()) {
8704 init_rtc();
8705 // fall through as if an update were not in progress
8706 }
8707 outb_cmos(0x00, regs.u.r8.dh); // Seconds
8708 outb_cmos(0x02, regs.u.r8.cl); // Minutes
8709 outb_cmos(0x04, regs.u.r8.ch); // Hours
8710 // Set Daylight Savings time enabled bit to requested value
8711 val8 = (inb_cmos(0x0b) & 0x60) | 0x02 | (regs.u.r8.dl & 0x01);
8712 // (reg B already selected)
8713 outb_cmos(0x0b, val8);
8714 regs.u.r8.ah = 0;
8715 regs.u.r8.al = val8; // val last written to Reg B
8716 ClearCF(iret_addr.flags); // OK
8717 break;
8718
8719 case 4: // Read CMOS Date
8720 regs.u.r8.ah = 0;
8721 if (rtc_updating()) {
8722 SetCF(iret_addr.flags);
8723 break;
8724 }
8725 regs.u.r8.cl = inb_cmos(0x09); // Year
8726 regs.u.r8.dh = inb_cmos(0x08); // Month
8727 regs.u.r8.dl = inb_cmos(0x07); // Day of Month
8728 regs.u.r8.ch = inb_cmos(0x32); // Century
8729 regs.u.r8.al = regs.u.r8.ch;
8730 ClearCF(iret_addr.flags); // OK
8731 break;
8732
8733 case 5: // Set CMOS Date
8734 // Using a debugger, I notice the following masking/setting
8735 // of bits in Status Register B, by setting Reg B to
8736 // a few values and getting its value after INT 1A was called.
8737 //
8738 // try#1 try#2 try#3 try#4
8739 // before 1111 1101 0111 1101 0000 0010 0000 0000
8740 // after 0110 1101 0111 1101 0000 0010 0000 0000
8741 //
8742 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8743 // My assumption: RegB = (RegB & 01111111b)
8744 if (rtc_updating()) {
8745 init_rtc();
8746 SetCF(iret_addr.flags);
8747 break;
8748 }
8749 outb_cmos(0x09, regs.u.r8.cl); // Year
8750 outb_cmos(0x08, regs.u.r8.dh); // Month
8751 outb_cmos(0x07, regs.u.r8.dl); // Day of Month
8752 outb_cmos(0x32, regs.u.r8.ch); // Century
8753 val8 = inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
8754 outb_cmos(0x0b, val8);
8755 regs.u.r8.ah = 0;
8756 regs.u.r8.al = val8; // AL = val last written to Reg B
8757 ClearCF(iret_addr.flags); // OK
8758 break;
8759
8760 case 6: // Set Alarm Time in CMOS
8761 // Using a debugger, I notice the following masking/setting
8762 // of bits in Status Register B, by setting Reg B to
8763 // a few values and getting its value after INT 1A was called.
8764 //
8765 // try#1 try#2 try#3
8766 // before 1101 1111 0101 1111 0000 0000
8767 // after 0110 1111 0111 1111 0010 0000
8768 //
8769 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8770 // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
8771 val8 = inb_cmos(0x0b); // Get Status Reg B
8772 regs.u.r16.ax = 0;
8773 if (val8 & 0x20) {
8774 // Alarm interrupt enabled already
8775 SetCF(iret_addr.flags); // Error: alarm in use
8776 break;
8777 }
8778 if (rtc_updating()) {
8779 init_rtc();
8780 // fall through as if an update were not in progress
8781 }
8782 outb_cmos(0x01, regs.u.r8.dh); // Seconds alarm
8783 outb_cmos(0x03, regs.u.r8.cl); // Minutes alarm
8784 outb_cmos(0x05, regs.u.r8.ch); // Hours alarm
8785 outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
8786 // enable Status Reg B alarm bit, clear halt clock bit
8787 outb_cmos(0x0b, (val8 & 0x7f) | 0x20);
8788 ClearCF(iret_addr.flags); // OK
8789 break;
8790
8791 case 7: // Turn off Alarm
8792 // Using a debugger, I notice the following masking/setting
8793 // of bits in Status Register B, by setting Reg B to
8794 // a few values and getting its value after INT 1A was called.
8795 //
8796 // try#1 try#2 try#3 try#4
8797 // before 1111 1101 0111 1101 0010 0000 0010 0010
8798 // after 0100 0101 0101 0101 0000 0000 0000 0010
8799 //
8800 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8801 // My assumption: RegB = (RegB & 01010111b)
8802 val8 = inb_cmos(0x0b); // Get Status Reg B
8803 // clear clock-halt bit, disable alarm bit
8804 outb_cmos(0x0b, val8 & 0x57); // disable alarm bit
8805 regs.u.r8.ah = 0;
8806 regs.u.r8.al = val8; // val last written to Reg B
8807 ClearCF(iret_addr.flags); // OK
8808 break;
8809#if BX_PCIBIOS
8810 case 0xb1:
8811 // real mode PCI BIOS functions now handled in assembler code
8812 // this C code handles the error code for information only
8813 if (regs.u.r8.bl == 0xff) {
8814 BX_INFO("PCI BIOS: PCI not present\n");
8815 } else if (regs.u.r8.bl == 0x81) {
8816 BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs.u.r8.al);
8817 } else if (regs.u.r8.bl == 0x83) {
8818 BX_INFO("bad PCI vendor ID %04x\n", regs.u.r16.dx);
8819 } else if (regs.u.r8.bl == 0x86) {
8820 if (regs.u.r8.al == 0x02) {
8821 BX_INFO("PCI device %04x:%04x not found at index %d\n", regs.u.r16.dx, regs.u.r16.cx, regs.u.r16.si);
8822 } else {
8823 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);
8824 }
8825 }
8826 regs.u.r8.ah = regs.u.r8.bl;
8827 SetCF(iret_addr.flags);
8828 break;
8829#endif
8830
8831 default:
8832 SetCF(iret_addr.flags); // Unsupported
8833 }
8834}
8835
8836 void
8837int70_function(regs, ds, iret_addr)
8838 pusha_regs_t regs; // regs pushed from PUSHA instruction
8839 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8840 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8841{
8842 // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
8843 Bit8u registerB = 0, registerC = 0;
8844
8845 // Check which modes are enabled and have occurred.
8846 registerB = inb_cmos( 0xB );
8847 registerC = inb_cmos( 0xC );
8848
8849 if( ( registerB & 0x60 ) != 0 ) {
8850 if( ( registerC & 0x20 ) != 0 ) {
8851 // Handle Alarm Interrupt.
8852ASM_START
8853 sti
8854 int #0x4a
8855 cli
8856ASM_END
8857 }
8858 if( ( registerC & 0x40 ) != 0 ) {
8859 // Handle Periodic Interrupt.
8860
8861 if( read_byte( 0x40, 0xA0 ) != 0 ) {
8862 // Wait Interval (Int 15, AH=83) active.
8863 Bit32u time, toggle;
8864
8865 time = read_dword( 0x40, 0x9C ); // Time left in microseconds.
8866 if( time < 0x3D1 ) {
8867 // Done waiting.
8868 Bit16u segment, offset;
8869
8870 segment = read_word( 0x40, 0x98 );
8871 offset = read_word( 0x40, 0x9A );
8872 write_byte( 0x40, 0xA0, 0 ); // Turn of status byte.
8873 outb_cmos( 0xB, registerB & 0x37 ); // Clear the Periodic Interrupt.
8874 write_byte(segment, offset, read_byte(segment, offset) | 0x80 ); // Write to specified flag byte.
8875 } else {
8876 // Continue waiting.
8877 time -= 0x3D1;
8878 write_dword( 0x40, 0x9C, time );
8879 }
8880 }
8881 }
8882 }
8883
8884ASM_START
8885 call eoi_both_pics
8886ASM_END
8887}
8888
8889 void
8890dummy_isr_function(regs, ds, iret_addr)
8891 pusha_regs_t regs; // regs pushed from PUSHA instruction
8892 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8893 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8894{
8895 // Interrupt handler for unexpected hardware interrupts. We have to clear
8896 // the PIC because if we don't, the next EOI will clear the wrong interrupt
8897 // and all hell will break loose! This routine also masks the unexpected
8898 // interrupt so it will generally be called only once for each unexpected
8899 // interrupt level.
8900 Bit8u isrA, isrB, imr, last_int = 0xFF;
8901
8902 outb( 0x20, 0x0B );
8903 isrA = inb( 0x20 );
8904 if (isrA) {
8905 outb( 0xA0, 0x0B );
8906 isrB = inb( 0xA0 );
8907 if (isrB) {
8908 imr = inb( 0xA1 );
8909 outb( 0xA1, imr | isrB ); // Mask this interrupt
8910 outb( 0xA0, 0x20 ); // Send EOI on slave PIC
8911 } else {
8912 imr = inb( 0x21 );
8913 isrA &= 0xFB; // Never mask the cascade interrupt
8914 outb( 0x21, imr | isrA); // Mask this interrupt
8915 }
8916 outb( 0x20, 0x20 ); // Send EOI on master PIC
8917 last_int = isrA;
8918 }
8919 write_byte( 0x40, 0x6B, last_int ); // Write INTR_FLAG
8920}
8921
8922ASM_START
8923;------------------------------------------
8924;- INT74h : PS/2 mouse hardware interrupt -
8925;------------------------------------------
8926int74_handler:
8927 sti
8928 pusha
8929 push ds ;; save DS
8930 push #0x00 ;; placeholder for status
8931 push #0x00 ;; placeholder for X
8932 push #0x00 ;; placeholder for Y
8933 push #0x00 ;; placeholder for Z
8934 push #0x00 ;; placeholder for make_far_call boolean
8935 call _int74_function
8936 pop cx ;; remove make_far_call from stack
8937 jcxz int74_done
8938
8939 ;; make far call to EBDA:0022
8940 push #0x00
8941 pop ds
8942 push 0x040E ;; push 0000:040E (opcodes 0xff, 0x36, 0x0E, 0x04)
8943 pop ds
8944 //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
8945 call far ptr[0x22]
8946int74_done:
8947 cli
8948 call eoi_both_pics
8949 add sp, #8 ;; pop status, x, y, z
8950
8951 pop ds ;; restore DS
8952 popa
8953 iret
8954
8955
8956;; This will perform an IRET, but will retain value of current CF
8957;; by altering flags on stack. Better than RETF #02.
8958iret_modify_cf:
8959 jc carry_set
8960 push bp
8961 mov bp, sp
8962 and BYTE [bp + 0x06], #0xfe
8963 pop bp
8964 iret
8965carry_set:
8966 push bp
8967 mov bp, sp
8968 or BYTE [bp + 0x06], #0x01
8969 pop bp
8970 iret
8971
8972
8973;----------------------
8974;- INT13h (relocated) -
8975;----------------------
8976;
8977; int13_relocated is a little bit messed up since I played with it
8978; I have to rewrite it:
8979; - call a function that detect which function to call
8980; - make all called C function get the same parameters list
8981;
8982int13_relocated:
8983 cld ;; we will be doing some string I/O
8984
8985#if BX_ELTORITO_BOOT
8986 ;; check for an eltorito function
8987 cmp ah,#0x4a
8988 jb int13_not_eltorito
8989 cmp ah,#0x4d
8990 ja int13_not_eltorito
8991
8992 pusha
8993 push es
8994 push ds
8995 push ss
8996 pop ds
8997
8998 push #int13_out
8999 jmp _int13_eltorito ;; ELDX not used
9000
9001int13_not_eltorito:
9002 push ax
9003 push bx
9004 push cx
9005 push dx
9006
9007 ;; check if emulation active
9008 call _cdemu_isactive
9009 cmp al,#0x00
9010 je int13_cdemu_inactive
9011
9012 ;; check if access to the emulated drive
9013 call _cdemu_emulated_drive
9014 pop dx
9015 push dx
9016 cmp al,dl ;; int13 on emulated drive
9017 jne int13_nocdemu
9018
9019 pop dx
9020 pop cx
9021 pop bx
9022 pop ax
9023
9024 pusha
9025 push es
9026 push ds
9027 push ss
9028 pop ds
9029
9030 push #int13_out
9031 jmp _int13_cdemu ;; ELDX not used
9032
9033int13_nocdemu:
9034 and dl,#0xE0 ;; mask to get device class, including cdroms
9035 cmp al,dl ;; al is 0x00 or 0x80
9036 jne int13_cdemu_inactive ;; inactive for device class
9037
9038 pop dx
9039 pop cx
9040 pop bx
9041 pop ax
9042
9043 push ax
9044 push cx
9045 push dx
9046 push bx
9047
9048 dec dl ;; real drive is dl - 1
9049 jmp int13_legacy
9050
9051int13_cdemu_inactive:
9052 pop dx
9053 pop cx
9054 pop bx
9055 pop ax
9056
9057#endif // BX_ELTORITO_BOOT
9058
9059int13_noeltorito:
9060
9061 push ax
9062 push cx
9063 push dx
9064 push bx
9065
9066int13_legacy:
9067
9068 push dx ;; push eltorito value of dx instead of sp
9069
9070 push bp
9071 push si
9072 push di
9073
9074 push es
9075 push ds
9076 push ss
9077 pop ds
9078
9079 ;; now the 16-bit registers can be restored with:
9080 ;; pop ds; pop es; popa; iret
9081 ;; arguments passed to functions should be
9082 ;; DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS
9083
9084 test dl, #0x80
9085 jnz int13_notfloppy
9086
9087 push #int13_out
9088 jmp _int13_diskette_function
9089
9090int13_notfloppy:
9091
9092#if BX_USE_ATADRV
9093
9094 cmp dl, #0xE0
9095 jb int13_notcdrom
9096
9097 // ebx is modified: BSD 5.2.1 boot loader problem
9098 // someone should figure out which 32 bit register that actually are used
9099
9100 shr ebx, #16
9101 push bx
9102
9103 call _int13_cdrom
9104
9105 pop bx
9106 shl ebx, #16
9107
9108 jmp int13_out
9109
9110int13_notcdrom:
9111
9112#endif
9113
9114int13_disk:
9115 ;; int13_harddisk modifies high word of EAX and EBX
9116 shr eax, #16
9117 push ax
9118 shr ebx, #16
9119 push bx
9120 call _int13_harddisk
9121 pop bx
9122 shl ebx, #16
9123 pop ax
9124 shl eax, #16
9125
9126int13_out:
9127 pop ds
9128 pop es
9129 popa
9130 iret
9131
9132;----------
9133;- INT18h -
9134;----------
9135int18_handler: ;; Boot Failure routing
9136 call _int18_panic_msg
9137 hlt
9138 iret
9139
9140;----------
9141;- INT19h -
9142;----------
9143int19_relocated: ;; Boot function, relocated
9144
9145#ifdef VBOX
9146 // If an already booted OS calls int 0x19 to reboot, it is not sufficient
9147 // just to try booting from the configured drives. All BIOS variables and
9148 // interrupt vectors need to be reset, otherwise strange things may happen.
9149 // The approach used is faking a warm reboot (which just skips showing the
9150 // logo), which is a bit more than what we need, but hey, it's fast.
9151 mov bp, sp
9152 mov ax, 2[bp]
9153 cmp ax, #0xf000
9154 jz bios_initiated_boot
9155 xor ax, ax
9156 mov ds, ax
9157 mov ax, #0x1234
9158 mov 0x472, ax
9159 jmp post
9160bios_initiated_boot:
9161#endif /* VBOX */
9162
9163 ;; int19 was beginning to be really complex, so now it
9164 ;; just calls a C function that does the work
9165 ;; it returns in BL the boot drive, and in AX the boot segment
9166 ;; the boot segment will be 0x0000 if something has failed
9167
9168 push bp
9169 mov bp, sp
9170
9171 ;; drop ds
9172 xor ax, ax
9173 mov ds, ax
9174
9175 ;; 1st boot device
9176 mov ax, #0x0001
9177 push ax
9178 call _int19_function
9179 inc sp
9180 inc sp
9181 ;; bl contains the boot drive
9182 ;; ax contains the boot segment or 0 if failure
9183
9184 test ax, ax ;; if ax is 0 try next boot device
9185 jnz boot_setup
9186
9187 ;; 2nd boot device
9188 mov ax, #0x0002
9189 push ax
9190 call _int19_function
9191 inc sp
9192 inc sp
9193 test ax, ax ;; if ax is 0 try next boot device
9194 jnz boot_setup
9195
9196 ;; 3rd boot device
9197 mov ax, #0x0003
9198 push ax
9199 call _int19_function
9200 inc sp
9201 inc sp
9202#ifdef VBOX
9203 test ax, ax ;; if ax is 0 try next boot device
9204 jnz boot_setup
9205
9206 ;; 4th boot device
9207 mov ax, #0x0004
9208 push ax
9209 call _int19_function
9210 inc sp
9211 inc sp
9212#endif /* VBOX */
9213 test ax, ax ;; if ax is 0 call int18
9214 jz int18_handler
9215
9216boot_setup:
9217 mov dl, bl ;; set drive so guest os find it
9218 shl eax, #0x04 ;; convert seg to ip
9219 mov 2[bp], ax ;; set ip
9220
9221 shr eax, #0x04 ;; get cs back
9222 and ax, #0xF000 ;; remove what went in ip
9223 mov 4[bp], ax ;; set cs
9224 xor ax, ax
9225 mov es, ax ;; set es to zero fixes [ 549815 ]
9226 mov [bp], ax ;; set bp to zero
9227 mov ax, #0xaa55 ;; set ok flag
9228
9229 pop bp
9230 iret ;; Beam me up Scotty
9231
9232;----------
9233;- INT1Ch -
9234;----------
9235int1c_handler: ;; User Timer Tick
9236 iret
9237
9238
9239;----------------------
9240;- POST: Floppy Drive -
9241;----------------------
9242floppy_drive_post:
9243 xor ax, ax
9244 mov ds, ax
9245
9246 mov al, #0x00
9247 mov 0x043e, al ;; drive 0 & 1 uncalibrated, no interrupt has occurred
9248
9249 mov 0x043f, al ;; diskette motor status: read op, drive0, motors off
9250
9251 mov 0x0440, al ;; diskette motor timeout counter: not active
9252 mov 0x0441, al ;; diskette controller status return code
9253
9254 mov 0x0442, al ;; disk & diskette controller status register 0
9255 mov 0x0443, al ;; diskette controller status register 1
9256 mov 0x0444, al ;; diskette controller status register 2
9257 mov 0x0445, al ;; diskette controller cylinder number
9258 mov 0x0446, al ;; diskette controller head number
9259 mov 0x0447, al ;; diskette controller sector number
9260 mov 0x0448, al ;; diskette controller bytes written
9261
9262 mov 0x048b, al ;; diskette configuration data
9263
9264 ;; -----------------------------------------------------------------
9265 ;; (048F) diskette controller information
9266 ;;
9267 mov al, #0x10 ;; get CMOS diskette drive type
9268 out 0x70, AL
9269 in AL, 0x71
9270 mov ah, al ;; save byte to AH
9271
9272look_drive0:
9273 shr al, #4 ;; look at top 4 bits for drive 0
9274 jz f0_missing ;; jump if no drive0
9275 mov bl, #0x07 ;; drive0 determined, multi-rate, has changed line
9276 jmp look_drive1
9277f0_missing:
9278 mov bl, #0x00 ;; no drive0
9279
9280look_drive1:
9281 mov al, ah ;; restore from AH
9282 and al, #0x0f ;; look at bottom 4 bits for drive 1
9283 jz f1_missing ;; jump if no drive1
9284 or bl, #0x70 ;; drive1 determined, multi-rate, has changed line
9285f1_missing:
9286 ;; leave high bits in BL zerod
9287 mov 0x048f, bl ;; put new val in BDA (diskette controller information)
9288 ;; -----------------------------------------------------------------
9289
9290 mov al, #0x00
9291 mov 0x0490, al ;; diskette 0 media state
9292 mov 0x0491, al ;; diskette 1 media state
9293
9294 ;; diskette 0,1 operational starting state
9295 ;; drive type has not been determined,
9296 ;; has no changed detection line
9297 mov 0x0492, al
9298 mov 0x0493, al
9299
9300 mov 0x0494, al ;; diskette 0 current cylinder
9301 mov 0x0495, al ;; diskette 1 current cylinder
9302
9303 mov al, #0x02
9304 out #0x0a, al ;; clear DMA-1 channel 2 mask bit
9305
9306 SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
9307 SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
9308 SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
9309
9310 ret
9311
9312
9313;--------------------
9314;- POST: HARD DRIVE -
9315;--------------------
9316; relocated here because the primary POST area isnt big enough.
9317hard_drive_post:
9318 // IRQ 14 = INT 76h
9319 // INT 76h calls INT 15h function ax=9100
9320
9321 mov al, #0x0a ; 0000 1010 = reserved, disable IRQ 14
9322 mov dx, #0x03f6
9323 out dx, al
9324
9325 xor ax, ax
9326 mov ds, ax
9327 mov 0x0474, al /* hard disk status of last operation */
9328 mov 0x0477, al /* hard disk port offset (XT only ???) */
9329 mov 0x048c, al /* hard disk status register */
9330 mov 0x048d, al /* hard disk error register */
9331 mov 0x048e, al /* hard disk task complete flag */
9332 mov al, #0x01
9333 mov 0x0475, al /* hard disk number attached */
9334 mov al, #0xc0
9335 mov 0x0476, al /* hard disk control byte */
9336 SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
9337 SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
9338 ;; INT 41h: hard disk 0 configuration pointer
9339 ;; INT 46h: hard disk 1 configuration pointer
9340 SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D)
9341 SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D)
9342
9343#ifndef VBOX /* This is done later (and the CMOS format is now different). */
9344 ;; move disk geometry data from CMOS to EBDA disk parameter table(s)
9345 mov al, #0x12
9346 out #0x70, al
9347 in al, #0x71
9348 and al, #0xf0
9349 cmp al, #0xf0
9350 je post_d0_extended
9351 jmp check_for_hd1
9352post_d0_extended:
9353 mov al, #0x19
9354 out #0x70, al
9355 in al, #0x71
9356 cmp al, #47 ;; decimal 47 - user definable
9357 je post_d0_type47
9358 HALT(__LINE__)
9359post_d0_type47:
9360 ;; CMOS purpose param table offset
9361 ;; 1b cylinders low 0
9362 ;; 1c cylinders high 1
9363 ;; 1d heads 2
9364 ;; 1e write pre-comp low 5
9365 ;; 1f write pre-comp high 6
9366 ;; 20 retries/bad map/heads>8 8
9367 ;; 21 landing zone low C
9368 ;; 22 landing zone high D
9369 ;; 23 sectors/track E
9370
9371 mov ax, #EBDA_SEG
9372 mov ds, ax
9373
9374 ;;; Filling EBDA table for hard disk 0.
9375 mov al, #0x1f
9376 out #0x70, al
9377 in al, #0x71
9378 mov ah, al
9379 mov al, #0x1e
9380 out #0x70, al
9381 in al, #0x71
9382 mov (0x003d + 0x05), ax ;; write precomp word
9383
9384 mov al, #0x20
9385 out #0x70, al
9386 in al, #0x71
9387 mov (0x003d + 0x08), al ;; drive control byte
9388
9389 mov al, #0x22
9390 out #0x70, al
9391 in al, #0x71
9392 mov ah, al
9393 mov al, #0x21
9394 out #0x70, al
9395 in al, #0x71
9396 mov (0x003d + 0x0C), ax ;; landing zone word
9397
9398 mov al, #0x1c ;; get cylinders word in AX
9399 out #0x70, al
9400 in al, #0x71 ;; high byte
9401 mov ah, al
9402 mov al, #0x1b
9403 out #0x70, al
9404 in al, #0x71 ;; low byte
9405 mov bx, ax ;; BX = cylinders
9406
9407 mov al, #0x1d
9408 out #0x70, al
9409 in al, #0x71
9410 mov cl, al ;; CL = heads
9411
9412 mov al, #0x23
9413 out #0x70, al
9414 in al, #0x71
9415 mov dl, al ;; DL = sectors
9416
9417 cmp bx, #1024
9418 jnbe hd0_post_logical_chs ;; if cylinders > 1024, use translated style CHS
9419
9420hd0_post_physical_chs:
9421 ;; no logical CHS mapping used, just physical CHS
9422 ;; use Standard Fixed Disk Parameter Table (FDPT)
9423 mov (0x003d + 0x00), bx ;; number of physical cylinders
9424 mov (0x003d + 0x02), cl ;; number of physical heads
9425 mov (0x003d + 0x0E), dl ;; number of physical sectors
9426 jmp check_for_hd1
9427
9428hd0_post_logical_chs:
9429 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
9430 mov (0x003d + 0x09), bx ;; number of physical cylinders
9431 mov (0x003d + 0x0b), cl ;; number of physical heads
9432 mov (0x003d + 0x04), dl ;; number of physical sectors
9433 mov (0x003d + 0x0e), dl ;; number of logical sectors (same)
9434 mov al, #0xa0
9435 mov (0x003d + 0x03), al ;; A0h signature, indicates translated table
9436
9437 cmp bx, #2048
9438 jnbe hd0_post_above_2048
9439 ;; 1024 < c <= 2048 cylinders
9440 shr bx, #0x01
9441 shl cl, #0x01
9442 jmp hd0_post_store_logical
9443
9444hd0_post_above_2048:
9445 cmp bx, #4096
9446 jnbe hd0_post_above_4096
9447 ;; 2048 < c <= 4096 cylinders
9448 shr bx, #0x02
9449 shl cl, #0x02
9450 jmp hd0_post_store_logical
9451
9452hd0_post_above_4096:
9453 cmp bx, #8192
9454 jnbe hd0_post_above_8192
9455 ;; 4096 < c <= 8192 cylinders
9456 shr bx, #0x03
9457 shl cl, #0x03
9458 jmp hd0_post_store_logical
9459
9460hd0_post_above_8192:
9461 ;; 8192 < c <= 16384 cylinders
9462 shr bx, #0x04
9463 shl cl, #0x04
9464
9465hd0_post_store_logical:
9466 mov (0x003d + 0x00), bx ;; number of physical cylinders
9467 mov (0x003d + 0x02), cl ;; number of physical heads
9468 ;; checksum
9469 mov cl, #0x0f ;; repeat count
9470 mov si, #0x003d ;; offset to disk0 FDPT
9471 mov al, #0x00 ;; sum
9472hd0_post_checksum_loop:
9473 add al, [si]
9474 inc si
9475 dec cl
9476 jnz hd0_post_checksum_loop
9477 not al ;; now take 2s complement
9478 inc al
9479 mov [si], al
9480;;; Done filling EBDA table for hard disk 0.
9481
9482
9483check_for_hd1:
9484 ;; is there really a second hard disk? if not, return now
9485 mov al, #0x12
9486 out #0x70, al
9487 in al, #0x71
9488 and al, #0x0f
9489 jnz post_d1_exists
9490 ret
9491post_d1_exists:
9492 ;; check that the hd type is really 0x0f.
9493 cmp al, #0x0f
9494 jz post_d1_extended
9495 HALT(__LINE__)
9496post_d1_extended:
9497 ;; check that the extended type is 47 - user definable
9498 mov al, #0x1a
9499 out #0x70, al
9500 in al, #0x71
9501 cmp al, #47 ;; decimal 47 - user definable
9502 je post_d1_type47
9503 HALT(__LINE__)
9504post_d1_type47:
9505 ;; Table for disk1.
9506 ;; CMOS purpose param table offset
9507 ;; 0x24 cylinders low 0
9508 ;; 0x25 cylinders high 1
9509 ;; 0x26 heads 2
9510 ;; 0x27 write pre-comp low 5
9511 ;; 0x28 write pre-comp high 6
9512 ;; 0x29 heads>8 8
9513 ;; 0x2a landing zone low C
9514 ;; 0x2b landing zone high D
9515 ;; 0x2c sectors/track E
9516;;; Fill EBDA table for hard disk 1.
9517 mov ax, #EBDA_SEG
9518 mov ds, ax
9519 mov al, #0x28
9520 out #0x70, al
9521 in al, #0x71
9522 mov ah, al
9523 mov al, #0x27
9524 out #0x70, al
9525 in al, #0x71
9526 mov (0x004d + 0x05), ax ;; write precomp word
9527
9528 mov al, #0x29
9529 out #0x70, al
9530 in al, #0x71
9531 mov (0x004d + 0x08), al ;; drive control byte
9532
9533 mov al, #0x2b
9534 out #0x70, al
9535 in al, #0x71
9536 mov ah, al
9537 mov al, #0x2a
9538 out #0x70, al
9539 in al, #0x71
9540 mov (0x004d + 0x0C), ax ;; landing zone word
9541
9542 mov al, #0x25 ;; get cylinders word in AX
9543 out #0x70, al
9544 in al, #0x71 ;; high byte
9545 mov ah, al
9546 mov al, #0x24
9547 out #0x70, al
9548 in al, #0x71 ;; low byte
9549 mov bx, ax ;; BX = cylinders
9550
9551 mov al, #0x26
9552 out #0x70, al
9553 in al, #0x71
9554 mov cl, al ;; CL = heads
9555
9556 mov al, #0x2c
9557 out #0x70, al
9558 in al, #0x71
9559 mov dl, al ;; DL = sectors
9560
9561 cmp bx, #1024
9562 jnbe hd1_post_logical_chs ;; if cylinders > 1024, use translated style CHS
9563
9564hd1_post_physical_chs:
9565 ;; no logical CHS mapping used, just physical CHS
9566 ;; use Standard Fixed Disk Parameter Table (FDPT)
9567 mov (0x004d + 0x00), bx ;; number of physical cylinders
9568 mov (0x004d + 0x02), cl ;; number of physical heads
9569 mov (0x004d + 0x0E), dl ;; number of physical sectors
9570 ret
9571
9572hd1_post_logical_chs:
9573 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
9574 mov (0x004d + 0x09), bx ;; number of physical cylinders
9575 mov (0x004d + 0x0b), cl ;; number of physical heads
9576 mov (0x004d + 0x04), dl ;; number of physical sectors
9577 mov (0x004d + 0x0e), dl ;; number of logical sectors (same)
9578 mov al, #0xa0
9579 mov (0x004d + 0x03), al ;; A0h signature, indicates translated table
9580
9581 cmp bx, #2048
9582 jnbe hd1_post_above_2048
9583 ;; 1024 < c <= 2048 cylinders
9584 shr bx, #0x01
9585 shl cl, #0x01
9586 jmp hd1_post_store_logical
9587
9588hd1_post_above_2048:
9589 cmp bx, #4096
9590 jnbe hd1_post_above_4096
9591 ;; 2048 < c <= 4096 cylinders
9592 shr bx, #0x02
9593 shl cl, #0x02
9594 jmp hd1_post_store_logical
9595
9596hd1_post_above_4096:
9597 cmp bx, #8192
9598 jnbe hd1_post_above_8192
9599 ;; 4096 < c <= 8192 cylinders
9600 shr bx, #0x03
9601 shl cl, #0x03
9602 jmp hd1_post_store_logical
9603
9604hd1_post_above_8192:
9605 ;; 8192 < c <= 16384 cylinders
9606 shr bx, #0x04
9607 shl cl, #0x04
9608
9609hd1_post_store_logical:
9610 mov (0x004d + 0x00), bx ;; number of physical cylinders
9611 mov (0x004d + 0x02), cl ;; number of physical heads
9612 ;; checksum
9613 mov cl, #0x0f ;; repeat count
9614 mov si, #0x004d ;; offset to disk0 FDPT
9615 mov al, #0x00 ;; sum
9616hd1_post_checksum_loop:
9617 add al, [si]
9618 inc si
9619 dec cl
9620 jnz hd1_post_checksum_loop
9621 not al ;; now take 2s complement
9622 inc al
9623 mov [si], al
9624;;; Done filling EBDA table for hard disk 1.
9625#endif /* !VBOX */
9626
9627 ret
9628
9629;--------------------
9630;- POST: EBDA segment
9631;--------------------
9632; relocated here because the primary POST area isnt big enough.
9633; the SET_INT_VECTORs have nothing to do with EBDA but do not
9634; fit into the primary POST area either
9635ebda_post:
9636 SET_INT_VECTOR(0x0D, #0xF000, #dummy_isr); IRQ 5
9637 SET_INT_VECTOR(0x0F, #0xF000, #dummy_isr); IRQ 7
9638 SET_INT_VECTOR(0x72, #0xF000, #dummy_isr); IRQ 11
9639 SET_INT_VECTOR(0x77, #0xF000, #dummy_isr); IRQ 15
9640
9641#if BX_USE_EBDA
9642 mov ax, #EBDA_SEG
9643 mov ds, ax
9644 mov byte ptr [0x0], #EBDA_SIZE
9645#endif
9646 xor ax, ax ; mov EBDA seg into 40E
9647 mov ds, ax
9648 mov word ptr [0x40E], #EBDA_SEG
9649 ret;;
9650
9651;--------------------
9652;- POST: EOI + jmp via [0x40:67)
9653;--------------------
9654; relocated here because the primary POST area isnt big enough.
9655eoi_jmp_post:
9656 call eoi_both_pics
9657
9658 xor ax, ax
9659 mov ds, ax
9660
9661 jmp far ptr [0x467]
9662
9663
9664;--------------------
9665eoi_both_pics:
9666 mov al, #0x20
9667 out #0xA0, al ;; slave PIC EOI
9668eoi_master_pic:
9669 mov al, #0x20
9670 out #0x20, al ;; master PIC EOI
9671 ret
9672
9673;--------------------
9674BcdToBin:
9675 ;; in: AL in BCD format
9676 ;; out: AL in binary format, AH will always be 0
9677 ;; trashes BX
9678 mov bl, al
9679 and bl, #0x0f ;; bl has low digit
9680 shr al, #4 ;; al has high digit
9681 mov bh, #10
9682 mul al, bh ;; multiply high digit by 10 (result in AX)
9683 add al, bl ;; then add low digit
9684 ret
9685
9686;--------------------
9687timer_tick_post:
9688 ;; Setup the Timer Ticks Count (0x46C:dword) and
9689 ;; Timer Ticks Roller Flag (0x470:byte)
9690 ;; The Timer Ticks Count needs to be set according to
9691 ;; the current CMOS time, as if ticks have been occurring
9692 ;; at 18.2hz since midnight up to this point. Calculating
9693 ;; this is a little complicated. Here are the factors I gather
9694 ;; regarding this. 14,318,180 hz was the original clock speed,
9695 ;; chosen so it could be divided by either 3 to drive the 5Mhz CPU
9696 ;; at the time, or 4 to drive the CGA video adapter. The div3
9697 ;; source was divided again by 4 to feed a 1.193Mhz signal to
9698 ;; the timer. With a maximum 16bit timer count, this is again
9699 ;; divided down by 65536 to 18.2hz.
9700 ;;
9701 ;; 14,318,180 Hz clock
9702 ;; /3 = 4,772,726 Hz fed to original 5Mhz CPU
9703 ;; /4 = 1,193,181 Hz fed to timer
9704 ;; /65536 (maximum timer count) = 18.20650736 ticks/second
9705 ;; 1 second = 18.20650736 ticks
9706 ;; 1 minute = 1092.390442 ticks
9707 ;; 1 hour = 65543.42651 ticks
9708 ;;
9709 ;; Given the values in the CMOS clock, one could calculate
9710 ;; the number of ticks by the following:
9711 ;; ticks = (BcdToBin(seconds) * 18.206507) +
9712 ;; (BcdToBin(minutes) * 1092.3904)
9713 ;; (BcdToBin(hours) * 65543.427)
9714 ;; To get a little more accuracy, since Im using integer
9715 ;; arithmetic, I use:
9716 ;; ticks = (BcdToBin(seconds) * 18206507) / 1000000 +
9717 ;; (BcdToBin(minutes) * 10923904) / 10000 +
9718 ;; (BcdToBin(hours) * 65543427) / 1000
9719
9720 ;; assuming DS=0000
9721
9722 ;; get CMOS seconds
9723 xor eax, eax ;; clear EAX
9724 mov al, #0x00
9725 out #0x70, al
9726 in al, #0x71 ;; AL has CMOS seconds in BCD
9727 call BcdToBin ;; EAX now has seconds in binary
9728 mov edx, #18206507
9729 mul eax, edx
9730 mov ebx, #1000000
9731 xor edx, edx
9732 div eax, ebx
9733 mov ecx, eax ;; ECX will accumulate total ticks
9734
9735 ;; get CMOS minutes
9736 xor eax, eax ;; clear EAX
9737 mov al, #0x02
9738 out #0x70, al
9739 in al, #0x71 ;; AL has CMOS minutes in BCD
9740 call BcdToBin ;; EAX now has minutes in binary
9741 mov edx, #10923904
9742 mul eax, edx
9743 mov ebx, #10000
9744 xor edx, edx
9745 div eax, ebx
9746 add ecx, eax ;; add to total ticks
9747
9748 ;; get CMOS hours
9749 xor eax, eax ;; clear EAX
9750 mov al, #0x04
9751 out #0x70, al
9752 in al, #0x71 ;; AL has CMOS hours in BCD
9753 call BcdToBin ;; EAX now has hours in binary
9754 mov edx, #65543427
9755 mul eax, edx
9756 mov ebx, #1000
9757 xor edx, edx
9758 div eax, ebx
9759 add ecx, eax ;; add to total ticks
9760
9761 mov 0x46C, ecx ;; Timer Ticks Count
9762 xor al, al
9763 mov 0x470, al ;; Timer Ticks Rollover Flag
9764 ret
9765
9766;--------------------
9767int76_handler:
9768 ;; record completion in BIOS task complete flag
9769 push ax
9770 push ds
9771 mov ax, #0x0040
9772 mov ds, ax
9773 mov 0x008E, #0xff
9774 call eoi_both_pics
9775 pop ds
9776 pop ax
9777 iret
9778
9779
9780;--------------------
9781#ifdef VBOX
9782init_pic:
9783 ;; init PIC
9784 mov al, #0x11 ; send initialisation commands
9785 out 0x20, al
9786 out 0xa0, al
9787 mov al, #0x08
9788 out 0x21, al
9789 mov al, #0x70
9790 out 0xa1, al
9791 mov al, #0x04
9792 out 0x21, al
9793 mov al, #0x02
9794 out 0xa1, al
9795 mov al, #0x01
9796 out 0x21, al
9797 out 0xa1, al
9798 mov al, #0xb8
9799 out 0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6
9800#if BX_USE_PS2_MOUSE
9801 mov al, #0x8f
9802#else
9803 mov al, #0x9f
9804#endif
9805 out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14
9806 ret
9807#endif /* VBOX */
9808
9809;--------------------
9810#if BX_APM
9811
9812use32 386
9813#define APM_PROT32
9814#include "apmbios.S"
9815
9816use16 386
9817#define APM_PROT16
9818#include "apmbios.S"
9819
9820#define APM_REAL
9821#include "apmbios.S"
9822
9823#endif
9824
9825;--------------------
9826#if BX_PCIBIOS
9827use32 386
9828.align 16
9829bios32_structure:
9830 db 0x5f, 0x33, 0x32, 0x5f ;; "_32_" signature
9831 dw bios32_entry_point, 0xf ;; 32 bit physical address
9832 db 0 ;; revision level
9833 ;; length in paragraphs and checksum stored in a word to prevent errors
9834 dw (~(((bios32_entry_point >> 8) + (bios32_entry_point & 0xff) + 0x32) \
9835 & 0xff) << 8) + 0x01
9836 db 0,0,0,0,0 ;; reserved
9837
9838.align 16
9839bios32_entry_point:
9840 pushfd
9841 cmp eax, #0x49435024 ;; "$PCI"
9842 jne unknown_service
9843
9844#ifdef PCI_FIXED_HOST_BRIDGE_1
9845 mov eax, #0x80000000
9846 mov dx, #0x0cf8
9847 out dx, eax
9848 mov dx, #0x0cfc
9849 in eax, dx
9850 cmp eax, #PCI_FIXED_HOST_BRIDGE_1
9851 je device_ok
9852#endif
9853
9854#ifdef PCI_FIXED_HOST_BRIDGE_2
9855 /* 0x1e << 11 */
9856 mov eax, #0x8000f000
9857 mov dx, #0x0cf8
9858 out dx, eax
9859 mov dx, #0x0cfc
9860 in eax, dx
9861 cmp eax, #PCI_FIXED_HOST_BRIDGE_2
9862 je device_ok
9863#endif
9864 jmp unknown_service
9865device_ok:
9866 mov ebx, #0x000f0000
9867 mov ecx, #0
9868 mov edx, #pcibios_protected
9869 xor al, al
9870 jmp bios32_end
9871unknown_service:
9872 mov al, #0x80
9873bios32_end:
9874#ifdef BX_QEMU
9875 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
9876#endif
9877 popfd
9878 retf
9879
9880.align 16
9881pcibios_protected:
9882 pushfd
9883 cli
9884 push esi
9885 push edi
9886 cmp al, #0x01 ;; installation check
9887 jne pci_pro_f02
9888 mov bx, #0x0210
9889 mov cx, #0
9890 mov edx, #0x20494350 ;; "PCI "
9891 mov al, #0x01
9892 jmp pci_pro_ok
9893pci_pro_f02: ;; find pci device
9894 cmp al, #0x02
9895 jne pci_pro_f03
9896 shl ecx, #16
9897 mov cx, dx
9898 xor ebx, ebx
9899 mov di, #0x00
9900pci_pro_devloop:
9901 call pci_pro_select_reg
9902 mov dx, #0x0cfc
9903 in eax, dx
9904 cmp eax, ecx
9905 jne pci_pro_nextdev
9906 cmp si, #0
9907 je pci_pro_ok
9908 dec si
9909pci_pro_nextdev:
9910 inc ebx
9911 cmp ebx, #0x10000
9912 jne pci_pro_devloop
9913 mov ah, #0x86
9914 jmp pci_pro_fail
9915pci_pro_f03: ;; find class code
9916 cmp al, #0x03
9917 jne pci_pro_f08
9918 xor ebx, ebx
9919 mov di, #0x08
9920pci_pro_devloop2:
9921 call pci_pro_select_reg
9922 mov dx, #0x0cfc
9923 in eax, dx
9924 shr eax, #8
9925 cmp eax, ecx
9926 jne pci_pro_nextdev2
9927 cmp si, #0
9928 je pci_pro_ok
9929 dec si
9930pci_pro_nextdev2:
9931 inc ebx
9932 cmp ebx, #0x10000
9933 jne pci_pro_devloop2
9934 mov ah, #0x86
9935 jmp pci_pro_fail
9936pci_pro_f08: ;; read configuration byte
9937 cmp al, #0x08
9938 jne pci_pro_f09
9939 call pci_pro_select_reg
9940 push edx
9941 mov dx, di
9942 and dx, #0x03
9943 add dx, #0x0cfc
9944 in al, dx
9945 pop edx
9946 mov cl, al
9947 jmp pci_pro_ok
9948pci_pro_f09: ;; read configuration word
9949 cmp al, #0x09
9950 jne pci_pro_f0a
9951 call pci_pro_select_reg
9952 push edx
9953 mov dx, di
9954 and dx, #0x02
9955 add dx, #0x0cfc
9956 in ax, dx
9957 pop edx
9958 mov cx, ax
9959 jmp pci_pro_ok
9960pci_pro_f0a: ;; read configuration dword
9961 cmp al, #0x0a
9962 jne pci_pro_f0b
9963 call pci_pro_select_reg
9964 push edx
9965 mov dx, #0x0cfc
9966 in eax, dx
9967 pop edx
9968 mov ecx, eax
9969 jmp pci_pro_ok
9970pci_pro_f0b: ;; write configuration byte
9971 cmp al, #0x0b
9972 jne pci_pro_f0c
9973 call pci_pro_select_reg
9974 push edx
9975 mov dx, di
9976 and dx, #0x03
9977 add dx, #0x0cfc
9978 mov al, cl
9979 out dx, al
9980 pop edx
9981 jmp pci_pro_ok
9982pci_pro_f0c: ;; write configuration word
9983 cmp al, #0x0c
9984 jne pci_pro_f0d
9985 call pci_pro_select_reg
9986 push edx
9987 mov dx, di
9988 and dx, #0x02
9989 add dx, #0x0cfc
9990 mov ax, cx
9991 out dx, ax
9992 pop edx
9993 jmp pci_pro_ok
9994pci_pro_f0d: ;; write configuration dword
9995 cmp al, #0x0d
9996 jne pci_pro_unknown
9997 call pci_pro_select_reg
9998 push edx
9999 mov dx, #0x0cfc
10000 mov eax, ecx
10001 out dx, eax
10002 pop edx
10003 jmp pci_pro_ok
10004pci_pro_unknown:
10005 mov ah, #0x81
10006pci_pro_fail:
10007 pop edi
10008 pop esi
10009#ifdef BX_QEMU
10010 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
10011#endif
10012 popfd
10013 stc
10014 retf
10015pci_pro_ok:
10016 xor ah, ah
10017 pop edi
10018 pop esi
10019#ifdef BX_QEMU
10020 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
10021#endif
10022 popfd
10023 clc
10024 retf
10025
10026pci_pro_select_reg:
10027 push edx
10028 mov eax, #0x800000
10029 mov ax, bx
10030 shl eax, #8
10031 and di, #0xff
10032 or ax, di
10033 and al, #0xfc
10034 mov dx, #0x0cf8
10035 out dx, eax
10036 pop edx
10037 ret
10038
10039use16 386
10040
10041pcibios_real:
10042 push eax
10043 push dx
10044#ifdef PCI_FIXED_HOST_BRIDGE_1
10045 mov eax, #0x80000000
10046 mov dx, #0x0cf8
10047 out dx, eax
10048 mov dx, #0x0cfc
10049 in eax, dx
10050 cmp eax, #PCI_FIXED_HOST_BRIDGE_1
10051 je pci_present
10052#endif
10053
10054#ifdef PCI_FIXED_HOST_BRIDGE_2
10055 /* 0x1e << 11 */
10056 mov eax, #0x8000f000
10057 mov dx, #0x0cf8
10058 out dx, eax
10059 mov dx, #0x0cfc
10060 in eax, dx
10061 cmp eax, #PCI_FIXED_HOST_BRIDGE_2
10062 je pci_present
10063#endif
10064 pop dx
10065 pop eax
10066 mov ah, #0xff
10067 stc
10068 ret
10069pci_present:
10070 pop dx
10071 pop eax
10072 cmp al, #0x01 ;; installation check
10073 jne pci_real_f02
10074 mov ax, #0x0001
10075 mov bx, #0x0210
10076 mov cx, #0
10077 mov edx, #0x20494350 ;; "PCI "
10078 mov edi, #0xf0000
10079 mov di, #pcibios_protected
10080 clc
10081 ret
10082pci_real_f02: ;; find pci device
10083 push esi
10084 push edi
10085 push edx
10086 cmp al, #0x02
10087 jne pci_real_f03
10088 shl ecx, #16
10089 mov cx, dx
10090 xor ebx, ebx
10091 mov di, #0x00
10092pci_real_devloop:
10093 call pci_real_select_reg
10094 mov dx, #0x0cfc
10095 in eax, dx
10096 cmp eax, ecx
10097 jne pci_real_nextdev
10098 cmp si, #0
10099 je pci_real_ok
10100 dec si
10101pci_real_nextdev:
10102 inc ebx
10103 cmp ebx, #0x10000
10104 jne pci_real_devloop
10105 mov dx, cx
10106 shr ecx, #16
10107 mov ax, #0x8602
10108 jmp pci_real_fail
10109pci_real_f03: ;; find class code
10110 cmp al, #0x03
10111 jne pci_real_f08
10112 xor ebx, ebx
10113 mov di, #0x08
10114pci_real_devloop2:
10115 call pci_real_select_reg
10116 mov dx, #0x0cfc
10117 in eax, dx
10118 shr eax, #8
10119 cmp eax, ecx
10120 jne pci_real_nextdev2
10121 cmp si, #0
10122 je pci_real_ok
10123 dec si
10124pci_real_nextdev2:
10125 inc ebx
10126 cmp ebx, #0x10000
10127 jne pci_real_devloop2
10128 mov ax, #0x8603
10129 jmp pci_real_fail
10130pci_real_f08: ;; read configuration byte
10131 cmp al, #0x08
10132 jne pci_real_f09
10133 call pci_real_select_reg
10134 push dx
10135 mov dx, di
10136 and dx, #0x03
10137 add dx, #0x0cfc
10138 in al, dx
10139 pop dx
10140 mov cl, al
10141 jmp pci_real_ok
10142pci_real_f09: ;; read configuration word
10143 cmp al, #0x09
10144 jne pci_real_f0a
10145 call pci_real_select_reg
10146 push dx
10147 mov dx, di
10148 and dx, #0x02
10149 add dx, #0x0cfc
10150 in ax, dx
10151 pop dx
10152 mov cx, ax
10153 jmp pci_real_ok
10154pci_real_f0a: ;; read configuration dword
10155 cmp al, #0x0a
10156 jne pci_real_f0b
10157 call pci_real_select_reg
10158 push dx
10159 mov dx, #0x0cfc
10160 in eax, dx
10161 pop dx
10162 mov ecx, eax
10163 jmp pci_real_ok
10164pci_real_f0b: ;; write configuration byte
10165 cmp al, #0x0b
10166 jne pci_real_f0c
10167 call pci_real_select_reg
10168 push dx
10169 mov dx, di
10170 and dx, #0x03
10171 add dx, #0x0cfc
10172 mov al, cl
10173 out dx, al
10174 pop dx
10175 jmp pci_real_ok
10176pci_real_f0c: ;; write configuration word
10177 cmp al, #0x0c
10178 jne pci_real_f0d
10179 call pci_real_select_reg
10180 push dx
10181 mov dx, di
10182 and dx, #0x02
10183 add dx, #0x0cfc
10184 mov ax, cx
10185 out dx, ax
10186 pop dx
10187 jmp pci_real_ok
10188pci_real_f0d: ;; write configuration dword
10189 cmp al, #0x0d
10190 jne pci_real_f0e
10191 call pci_real_select_reg
10192 push dx
10193 mov dx, #0x0cfc
10194 mov eax, ecx
10195 out dx, eax
10196 pop dx
10197 jmp pci_real_ok
10198pci_real_f0e: ;; get irq routing options
10199 cmp al, #0x0e
10200 jne pci_real_unknown
10201 SEG ES
10202 cmp word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
10203 jb pci_real_too_small
10204 SEG ES
10205 mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
10206 pushf
10207 push ds
10208 push es
10209 push cx
10210 push si
10211 push di
10212 cld
10213 mov si, #pci_routing_table_structure_start
10214 push cs
10215 pop ds
10216 SEG ES
10217 mov cx, [di+2]
10218 SEG ES
10219 mov es, [di+4]
10220 mov di, cx
10221 mov cx, #pci_routing_table_structure_end - pci_routing_table_structure_start
10222 rep
10223 movsb
10224 pop di
10225 pop si
10226 pop cx
10227 pop es
10228 pop ds
10229 popf
10230 mov bx, #(1 << 9) | (1 << 11) ;; irq 9 and 11 are used
10231 jmp pci_real_ok
10232pci_real_too_small:
10233 SEG ES
10234 mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
10235 mov ah, #0x89
10236 jmp pci_real_fail
10237
10238pci_real_unknown:
10239 mov ah, #0x81
10240pci_real_fail:
10241 pop edx
10242 pop edi
10243 pop esi
10244 stc
10245 ret
10246pci_real_ok:
10247 xor ah, ah
10248 pop edx
10249 pop edi
10250 pop esi
10251 clc
10252 ret
10253
10254;; prepare from reading the PCI config space; on input:
10255;; bx = bus/dev/fn
10256;; di = offset into config space header
10257;; destroys eax and may modify di
10258pci_real_select_reg:
10259 push dx
10260 mov eax, #0x800000
10261 mov ax, bx
10262 shl eax, #8
10263 and di, #0xff
10264 or ax, di
10265 and al, #0xfc
10266 mov dx, #0x0cf8
10267 out dx, eax
10268 pop dx
10269 ret
10270
10271.align 16
10272pci_routing_table_structure:
10273 db 0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature
10274 db 0, 1 ;; version
10275#ifdef VBOX
10276 dw 32 + (30 * 16) ;; table size
10277#else /* !VBOX */
10278 dw 32 + (6 * 16) ;; table size
10279#endif /* !VBOX */
10280 db 0 ;; PCI interrupt router bus
10281 db 0x08 ;; PCI interrupt router DevFunc
10282 dw 0x0000 ;; PCI exclusive IRQs
10283 dw 0x8086 ;; compatible PCI interrupt router vendor ID
10284 dw 0x7000 ;; compatible PCI interrupt router device ID
10285 dw 0,0 ;; Miniport data
10286 db 0,0,0,0,0,0,0,0,0,0,0 ;; reserved
10287#ifdef VBOX
10288 db 0x00 ;; checksum (set by biossums)
10289#else /* !VBOX */
10290 db 0x07 ;; checksum
10291#endif /* !VBOX */
10292pci_routing_table_structure_start:
10293 ;; first slot entry PCI-to-ISA (embedded)
10294 db 0 ;; pci bus number
10295 db 0x08 ;; pci device number (bit 7-3)
10296 db 0x60 ;; link value INTA#: pointer into PCI2ISA config space
10297 dw 0xdef8 ;; IRQ bitmap INTA#
10298 db 0x61 ;; link value INTB#
10299 dw 0xdef8 ;; IRQ bitmap INTB#
10300 db 0x62 ;; link value INTC#
10301 dw 0xdef8 ;; IRQ bitmap INTC#
10302 db 0x63 ;; link value INTD#
10303 dw 0xdef8 ;; IRQ bitmap INTD#
10304 db 0 ;; physical slot (0 = embedded)
10305 db 0 ;; reserved
10306 ;; second slot entry: 1st PCI slot
10307 db 0 ;; pci bus number
10308 db 0x10 ;; pci device number (bit 7-3)
10309 db 0x61 ;; link value INTA#
10310 dw 0xdef8 ;; IRQ bitmap INTA#
10311 db 0x62 ;; link value INTB#
10312 dw 0xdef8 ;; IRQ bitmap INTB#
10313 db 0x63 ;; link value INTC#
10314 dw 0xdef8 ;; IRQ bitmap INTC#
10315 db 0x60 ;; link value INTD#
10316 dw 0xdef8 ;; IRQ bitmap INTD#
10317 db 1 ;; physical slot (0 = embedded)
10318 db 0 ;; reserved
10319 ;; third slot entry: 2nd PCI slot
10320 db 0 ;; pci bus number
10321 db 0x18 ;; pci device number (bit 7-3)
10322 db 0x62 ;; link value INTA#
10323 dw 0xdef8 ;; IRQ bitmap INTA#
10324 db 0x63 ;; link value INTB#
10325 dw 0xdef8 ;; IRQ bitmap INTB#
10326 db 0x60 ;; link value INTC#
10327 dw 0xdef8 ;; IRQ bitmap INTC#
10328 db 0x61 ;; link value INTD#
10329 dw 0xdef8 ;; IRQ bitmap INTD#
10330 db 2 ;; physical slot (0 = embedded)
10331 db 0 ;; reserved
10332 ;; 4th slot entry: 3rd PCI slot
10333 db 0 ;; pci bus number
10334 db 0x20 ;; pci device number (bit 7-3)
10335 db 0x63 ;; link value INTA#
10336 dw 0xdef8 ;; IRQ bitmap INTA#
10337 db 0x60 ;; link value INTB#
10338 dw 0xdef8 ;; IRQ bitmap INTB#
10339 db 0x61 ;; link value INTC#
10340 dw 0xdef8 ;; IRQ bitmap INTC#
10341 db 0x62 ;; link value INTD#
10342 dw 0xdef8 ;; IRQ bitmap INTD#
10343 db 3 ;; physical slot (0 = embedded)
10344 db 0 ;; reserved
10345 ;; 5th slot entry: 4rd PCI slot
10346 db 0 ;; pci bus number
10347 db 0x28 ;; pci device number (bit 7-3)
10348 db 0x60 ;; link value INTA#
10349 dw 0xdef8 ;; IRQ bitmap INTA#
10350 db 0x61 ;; link value INTB#
10351 dw 0xdef8 ;; IRQ bitmap INTB#
10352 db 0x62 ;; link value INTC#
10353 dw 0xdef8 ;; IRQ bitmap INTC#
10354 db 0x63 ;; link value INTD#
10355 dw 0xdef8 ;; IRQ bitmap INTD#
10356 db 4 ;; physical slot (0 = embedded)
10357 db 0 ;; reserved
10358 ;; 6th slot entry: 5rd PCI slot
10359 db 0 ;; pci bus number
10360 db 0x30 ;; pci device number (bit 7-3)
10361 db 0x61 ;; link value INTA#
10362 dw 0xdef8 ;; IRQ bitmap INTA#
10363 db 0x62 ;; link value INTB#
10364 dw 0xdef8 ;; IRQ bitmap INTB#
10365 db 0x63 ;; link value INTC#
10366 dw 0xdef8 ;; IRQ bitmap INTC#
10367 db 0x60 ;; link value INTD#
10368 dw 0xdef8 ;; IRQ bitmap INTD#
10369 db 5 ;; physical slot (0 = embedded)
10370 db 0 ;; reserved
10371#ifdef VBOX
10372 ;; 7th slot entry: 6th PCI slot
10373 db 0 ;; pci bus number
10374 db 0x38 ;; pci device number (bit 7-3)
10375 db 0x62 ;; link value INTA#
10376 dw 0xdef8 ;; IRQ bitmap INTA#
10377 db 0x63 ;; link value INTB#
10378 dw 0xdef8 ;; IRQ bitmap INTB#
10379 db 0x60 ;; link value INTC#
10380 dw 0xdef8 ;; IRQ bitmap INTC#
10381 db 0x61 ;; link value INTD#
10382 dw 0xdef8 ;; IRQ bitmap INTD#
10383 db 6 ;; physical slot (0 = embedded)
10384 db 0 ;; reserved
10385 ;; 8th slot entry: 7th PCI slot
10386 db 0 ;; pci bus number
10387 db 0x40 ;; pci device number (bit 7-3)
10388 db 0x63 ;; link value INTA#
10389 dw 0xdef8 ;; IRQ bitmap INTA#
10390 db 0x60 ;; link value INTB#
10391 dw 0xdef8 ;; IRQ bitmap INTB#
10392 db 0x61 ;; link value INTC#
10393 dw 0xdef8 ;; IRQ bitmap INTC#
10394 db 0x62 ;; link value INTD#
10395 dw 0xdef8 ;; IRQ bitmap INTD#
10396 db 7 ;; physical slot (0 = embedded)
10397 db 0 ;; reserved
10398 ;; 9th slot entry: 8th PCI slot
10399 db 0 ;; pci bus number
10400 db 0x48 ;; pci device number (bit 7-3)
10401 db 0x60 ;; link value INTA#
10402 dw 0xdef8 ;; IRQ bitmap INTA#
10403 db 0x61 ;; link value INTB#
10404 dw 0xdef8 ;; IRQ bitmap INTB#
10405 db 0x62 ;; link value INTC#
10406 dw 0xdef8 ;; IRQ bitmap INTC#
10407 db 0x63 ;; link value INTD#
10408 dw 0xdef8 ;; IRQ bitmap INTD#
10409 db 8 ;; physical slot (0 = embedded)
10410 db 0 ;; reserved
10411 ;; 10th slot entry: 9th PCI slot
10412 db 0 ;; pci bus number
10413 db 0x50 ;; pci device number (bit 7-3)
10414 db 0x61 ;; link value INTA#
10415 dw 0xdef8 ;; IRQ bitmap INTA#
10416 db 0x62 ;; link value INTB#
10417 dw 0xdef8 ;; IRQ bitmap INTB#
10418 db 0x63 ;; link value INTC#
10419 dw 0xdef8 ;; IRQ bitmap INTC#
10420 db 0x60 ;; link value INTD#
10421 dw 0xdef8 ;; IRQ bitmap INTD#
10422 db 9 ;; physical slot (0 = embedded)
10423 db 0 ;; reserved
10424 ;; 11th slot entry: 10th PCI slot
10425 db 0 ;; pci bus number
10426 db 0x58 ;; pci device number (bit 7-3)
10427 db 0x62 ;; link value INTA#
10428 dw 0xdef8 ;; IRQ bitmap INTA#
10429 db 0x63 ;; link value INTB#
10430 dw 0xdef8 ;; IRQ bitmap INTB#
10431 db 0x60 ;; link value INTC#
10432 dw 0xdef8 ;; IRQ bitmap INTC#
10433 db 0x61 ;; link value INTD#
10434 dw 0xdef8 ;; IRQ bitmap INTD#
10435 db 10 ;; physical slot (0 = embedded)
10436 db 0 ;; reserved
10437 ;; 12th slot entry: 11th PCI slot
10438 db 0 ;; pci bus number
10439 db 0x60 ;; pci device number (bit 7-3)
10440 db 0x63 ;; link value INTA#
10441 dw 0xdef8 ;; IRQ bitmap INTA#
10442 db 0x60 ;; link value INTB#
10443 dw 0xdef8 ;; IRQ bitmap INTB#
10444 db 0x61 ;; link value INTC#
10445 dw 0xdef8 ;; IRQ bitmap INTC#
10446 db 0x62 ;; link value INTD#
10447 dw 0xdef8 ;; IRQ bitmap INTD#
10448 db 11 ;; physical slot (0 = embedded)
10449 db 0 ;; reserved
10450 ;; 13th slot entry: 12th PCI slot
10451 db 0 ;; pci bus number
10452 db 0x68 ;; pci device number (bit 7-3)
10453 db 0x60 ;; link value INTA#
10454 dw 0xdef8 ;; IRQ bitmap INTA#
10455 db 0x61 ;; link value INTB#
10456 dw 0xdef8 ;; IRQ bitmap INTB#
10457 db 0x62 ;; link value INTC#
10458 dw 0xdef8 ;; IRQ bitmap INTC#
10459 db 0x63 ;; link value INTD#
10460 dw 0xdef8 ;; IRQ bitmap INTD#
10461 db 12 ;; physical slot (0 = embedded)
10462 db 0 ;; reserved
10463 ;; 14th slot entry: 13th PCI slot
10464 db 0 ;; pci bus number
10465 db 0x70 ;; pci device number (bit 7-3)
10466 db 0x61 ;; link value INTA#
10467 dw 0xdef8 ;; IRQ bitmap INTA#
10468 db 0x62 ;; link value INTB#
10469 dw 0xdef8 ;; IRQ bitmap INTB#
10470 db 0x63 ;; link value INTC#
10471 dw 0xdef8 ;; IRQ bitmap INTC#
10472 db 0x60 ;; link value INTD#
10473 dw 0xdef8 ;; IRQ bitmap INTD#
10474 db 13 ;; physical slot (0 = embedded)
10475 db 0 ;; reserved
10476 ;; 15th slot entry: 14th PCI slot
10477 db 0 ;; pci bus number
10478 db 0x78 ;; pci device number (bit 7-3)
10479 db 0x62 ;; link value INTA#
10480 dw 0xdef8 ;; IRQ bitmap INTA#
10481 db 0x63 ;; link value INTB#
10482 dw 0xdef8 ;; IRQ bitmap INTB#
10483 db 0x60 ;; link value INTC#
10484 dw 0xdef8 ;; IRQ bitmap INTC#
10485 db 0x61 ;; link value INTD#
10486 dw 0xdef8 ;; IRQ bitmap INTD#
10487 db 14 ;; physical slot (0 = embedded)
10488 db 0 ;; reserved
10489 ;; 16th slot entry: 15th PCI slot
10490 db 0 ;; pci bus number
10491 db 0x80 ;; pci device number (bit 7-3)
10492 db 0x63 ;; link value INTA#
10493 dw 0xdef8 ;; IRQ bitmap INTA#
10494 db 0x60 ;; link value INTB#
10495 dw 0xdef8 ;; IRQ bitmap INTB#
10496 db 0x61 ;; link value INTC#
10497 dw 0xdef8 ;; IRQ bitmap INTC#
10498 db 0x62 ;; link value INTD#
10499 dw 0xdef8 ;; IRQ bitmap INTD#
10500 db 15 ;; physical slot (0 = embedded)
10501 db 0 ;; reserved
10502 ;; 17th slot entry: 16th PCI slot
10503 db 0 ;; pci bus number
10504 db 0x88 ;; pci device number (bit 7-3)
10505 db 0x60 ;; link value INTA#
10506 dw 0xdef8 ;; IRQ bitmap INTA#
10507 db 0x61 ;; link value INTB#
10508 dw 0xdef8 ;; IRQ bitmap INTB#
10509 db 0x62 ;; link value INTC#
10510 dw 0xdef8 ;; IRQ bitmap INTC#
10511 db 0x63 ;; link value INTD#
10512 dw 0xdef8 ;; IRQ bitmap INTD#
10513 db 16 ;; physical slot (0 = embedded)
10514 db 0 ;; reserved
10515 ;; 18th slot entry: 17th PCI slot
10516 db 0 ;; pci bus number
10517 db 0x90 ;; pci device number (bit 7-3)
10518 db 0x61 ;; link value INTA#
10519 dw 0xdef8 ;; IRQ bitmap INTA#
10520 db 0x62 ;; link value INTB#
10521 dw 0xdef8 ;; IRQ bitmap INTB#
10522 db 0x63 ;; link value INTC#
10523 dw 0xdef8 ;; IRQ bitmap INTC#
10524 db 0x60 ;; link value INTD#
10525 dw 0xdef8 ;; IRQ bitmap INTD#
10526 db 17 ;; physical slot (0 = embedded)
10527 db 0 ;; reserved
10528 ;; 19th slot entry: 18th PCI slot
10529 db 0 ;; pci bus number
10530 db 0x98 ;; pci device number (bit 7-3)
10531 db 0x62 ;; link value INTA#
10532 dw 0xdef8 ;; IRQ bitmap INTA#
10533 db 0x63 ;; link value INTB#
10534 dw 0xdef8 ;; IRQ bitmap INTB#
10535 db 0x60 ;; link value INTC#
10536 dw 0xdef8 ;; IRQ bitmap INTC#
10537 db 0x61 ;; link value INTD#
10538 dw 0xdef8 ;; IRQ bitmap INTD#
10539 db 18 ;; physical slot (0 = embedded)
10540 db 0 ;; reserved
10541 ;; 20th slot entry: 19th PCI slot
10542 db 0 ;; pci bus number
10543 db 0xa0 ;; pci device number (bit 7-3)
10544 db 0x63 ;; link value INTA#
10545 dw 0xdef8 ;; IRQ bitmap INTA#
10546 db 0x60 ;; link value INTB#
10547 dw 0xdef8 ;; IRQ bitmap INTB#
10548 db 0x61 ;; link value INTC#
10549 dw 0xdef8 ;; IRQ bitmap INTC#
10550 db 0x62 ;; link value INTD#
10551 dw 0xdef8 ;; IRQ bitmap INTD#
10552 db 19 ;; physical slot (0 = embedded)
10553 db 0 ;; reserved
10554 ;; 21st slot entry: 20th PCI slot
10555 db 0 ;; pci bus number
10556 db 0xa8 ;; pci device number (bit 7-3)
10557 db 0x60 ;; link value INTA#
10558 dw 0xdef8 ;; IRQ bitmap INTA#
10559 db 0x61 ;; link value INTB#
10560 dw 0xdef8 ;; IRQ bitmap INTB#
10561 db 0x62 ;; link value INTC#
10562 dw 0xdef8 ;; IRQ bitmap INTC#
10563 db 0x63 ;; link value INTD#
10564 dw 0xdef8 ;; IRQ bitmap INTD#
10565 db 20 ;; physical slot (0 = embedded)
10566 db 0 ;; reserved
10567 ;; 22nd slot entry: 21st PCI slot
10568 db 0 ;; pci bus number
10569 db 0xb0 ;; pci device number (bit 7-3)
10570 db 0x61 ;; link value INTA#
10571 dw 0xdef8 ;; IRQ bitmap INTA#
10572 db 0x62 ;; link value INTB#
10573 dw 0xdef8 ;; IRQ bitmap INTB#
10574 db 0x63 ;; link value INTC#
10575 dw 0xdef8 ;; IRQ bitmap INTC#
10576 db 0x60 ;; link value INTD#
10577 dw 0xdef8 ;; IRQ bitmap INTD#
10578 db 21 ;; physical slot (0 = embedded)
10579 db 0 ;; reserved
10580 ;; 23rd slot entry: 22nd PCI slot
10581 db 0 ;; pci bus number
10582 db 0xb8 ;; pci device number (bit 7-3)
10583 db 0x62 ;; link value INTA#
10584 dw 0xdef8 ;; IRQ bitmap INTA#
10585 db 0x63 ;; link value INTB#
10586 dw 0xdef8 ;; IRQ bitmap INTB#
10587 db 0x60 ;; link value INTC#
10588 dw 0xdef8 ;; IRQ bitmap INTC#
10589 db 0x61 ;; link value INTD#
10590 dw 0xdef8 ;; IRQ bitmap INTD#
10591 db 22 ;; physical slot (0 = embedded)
10592 db 0 ;; reserved
10593 ;; 24th slot entry: 23rd PCI slot
10594 db 0 ;; pci bus number
10595 db 0xc0 ;; pci device number (bit 7-3)
10596 db 0x63 ;; link value INTA#
10597 dw 0xdef8 ;; IRQ bitmap INTA#
10598 db 0x60 ;; link value INTB#
10599 dw 0xdef8 ;; IRQ bitmap INTB#
10600 db 0x61 ;; link value INTC#
10601 dw 0xdef8 ;; IRQ bitmap INTC#
10602 db 0x62 ;; link value INTD#
10603 dw 0xdef8 ;; IRQ bitmap INTD#
10604 db 23 ;; physical slot (0 = embedded)
10605 db 0 ;; reserved
10606 ;; 25th slot entry: 24th PCI slot
10607 db 0 ;; pci bus number
10608 db 0xc8 ;; pci device number (bit 7-3)
10609 db 0x60 ;; link value INTA#
10610 dw 0xdef8 ;; IRQ bitmap INTA#
10611 db 0x61 ;; link value INTB#
10612 dw 0xdef8 ;; IRQ bitmap INTB#
10613 db 0x62 ;; link value INTC#
10614 dw 0xdef8 ;; IRQ bitmap INTC#
10615 db 0x63 ;; link value INTD#
10616 dw 0xdef8 ;; IRQ bitmap INTD#
10617 db 24 ;; physical slot (0 = embedded)
10618 db 0 ;; reserved
10619 ;; 26th slot entry: 25th PCI slot
10620 db 0 ;; pci bus number
10621 db 0xd0 ;; pci device number (bit 7-3)
10622 db 0x61 ;; link value INTA#
10623 dw 0xdef8 ;; IRQ bitmap INTA#
10624 db 0x62 ;; link value INTB#
10625 dw 0xdef8 ;; IRQ bitmap INTB#
10626 db 0x63 ;; link value INTC#
10627 dw 0xdef8 ;; IRQ bitmap INTC#
10628 db 0x60 ;; link value INTD#
10629 dw 0xdef8 ;; IRQ bitmap INTD#
10630 db 25 ;; physical slot (0 = embedded)
10631 db 0 ;; reserved
10632 ;; 27th slot entry: 26th PCI slot
10633 db 0 ;; pci bus number
10634 db 0xd8 ;; pci device number (bit 7-3)
10635 db 0x62 ;; link value INTA#
10636 dw 0xdef8 ;; IRQ bitmap INTA#
10637 db 0x63 ;; link value INTB#
10638 dw 0xdef8 ;; IRQ bitmap INTB#
10639 db 0x60 ;; link value INTC#
10640 dw 0xdef8 ;; IRQ bitmap INTC#
10641 db 0x61 ;; link value INTD#
10642 dw 0xdef8 ;; IRQ bitmap INTD#
10643 db 26 ;; physical slot (0 = embedded)
10644 db 0 ;; reserved
10645 ;; 28th slot entry: 27th PCI slot
10646 db 0 ;; pci bus number
10647 db 0xe0 ;; pci device number (bit 7-3)
10648 db 0x63 ;; link value INTA#
10649 dw 0xdef8 ;; IRQ bitmap INTA#
10650 db 0x60 ;; link value INTB#
10651 dw 0xdef8 ;; IRQ bitmap INTB#
10652 db 0x61 ;; link value INTC#
10653 dw 0xdef8 ;; IRQ bitmap INTC#
10654 db 0x62 ;; link value INTD#
10655 dw 0xdef8 ;; IRQ bitmap INTD#
10656 db 27 ;; physical slot (0 = embedded)
10657 db 0 ;; reserved
10658 ;; 29th slot entry: 28th PCI slot
10659 db 0 ;; pci bus number
10660 db 0xe8 ;; pci device number (bit 7-3)
10661 db 0x60 ;; link value INTA#
10662 dw 0xdef8 ;; IRQ bitmap INTA#
10663 db 0x61 ;; link value INTB#
10664 dw 0xdef8 ;; IRQ bitmap INTB#
10665 db 0x62 ;; link value INTC#
10666 dw 0xdef8 ;; IRQ bitmap INTC#
10667 db 0x63 ;; link value INTD#
10668 dw 0xdef8 ;; IRQ bitmap INTD#
10669 db 28 ;; physical slot (0 = embedded)
10670 db 0 ;; reserved
10671 ;; 30th slot entry: 29th PCI slot
10672 db 0 ;; pci bus number
10673 db 0xf0 ;; pci device number (bit 7-3)
10674 db 0x61 ;; link value INTA#
10675 dw 0xdef8 ;; IRQ bitmap INTA#
10676 db 0x62 ;; link value INTB#
10677 dw 0xdef8 ;; IRQ bitmap INTB#
10678 db 0x63 ;; link value INTC#
10679 dw 0xdef8 ;; IRQ bitmap INTC#
10680 db 0x60 ;; link value INTD#
10681 dw 0xdef8 ;; IRQ bitmap INTD#
10682 db 29 ;; physical slot (0 = embedded)
10683 db 0 ;; reserved
10684#endif /* VBOX */
10685pci_routing_table_structure_end:
10686
10687#if !BX_ROMBIOS32
10688pci_irq_list:
10689 db 11, 10, 9, 5;
10690
10691pcibios_init_sel_reg:
10692 push eax
10693 mov eax, #0x800000
10694 mov ax, bx
10695 shl eax, #8
10696 and dl, #0xfc
10697 or al, dl
10698 mov dx, #0x0cf8
10699 out dx, eax
10700 pop eax
10701 ret
10702
10703pcibios_init_iomem_bases:
10704 push bp
10705 mov bp, sp
10706 mov eax, #0xe0000000 ;; base for memory init
10707 push eax
10708 mov ax, #0xc000 ;; base for i/o init
10709 push ax
10710 mov ax, #0x0010 ;; start at base address #0
10711 push ax
10712 mov bx, #0x0008
10713pci_init_io_loop1:
10714 mov dl, #0x00
10715 call pcibios_init_sel_reg
10716 mov dx, #0x0cfc
10717 in ax, dx
10718 cmp ax, #0xffff
10719 jz next_pci_dev
10720#ifndef VBOX /* This currently breaks restoring a previously saved state. */
10721 mov dl, #0x04 ;; disable i/o and memory space access
10722 call pcibios_init_sel_reg
10723 mov dx, #0x0cfc
10724 in al, dx
10725 and al, #0xfc
10726 out dx, al
10727pci_init_io_loop2:
10728 mov dl, [bp-8]
10729 call pcibios_init_sel_reg
10730 mov dx, #0x0cfc
10731 in eax, dx
10732 test al, #0x01
10733 jnz init_io_base
10734 mov ecx, eax
10735 mov eax, #0xffffffff
10736 out dx, eax
10737 in eax, dx
10738 cmp eax, ecx
10739 je next_pci_base
10740 xor eax, #0xffffffff
10741 mov ecx, eax
10742 mov eax, [bp-4]
10743 out dx, eax
10744 add eax, ecx ;; calculate next free mem base
10745 add eax, #0x01000000
10746 and eax, #0xff000000
10747 mov [bp-4], eax
10748 jmp next_pci_base
10749init_io_base:
10750 mov cx, ax
10751 mov ax, #0xffff
10752 out dx, ax
10753 in ax, dx
10754 cmp ax, cx
10755 je next_pci_base
10756 xor ax, #0xfffe
10757 mov cx, ax
10758 mov ax, [bp-6]
10759 out dx, ax
10760 add ax, cx ;; calculate next free i/o base
10761 add ax, #0x0100
10762 and ax, #0xff00
10763 mov [bp-6], ax
10764next_pci_base:
10765 mov al, [bp-8]
10766 add al, #0x04
10767 cmp al, #0x28
10768 je enable_iomem_space
10769 mov byte ptr[bp-8], al
10770 jmp pci_init_io_loop2
10771#endif /* !VBOX */
10772enable_iomem_space:
10773 mov dl, #0x04 ;; enable i/o and memory space access if available
10774 call pcibios_init_sel_reg
10775 mov dx, #0x0cfc
10776 in al, dx
10777 or al, #0x07
10778 out dx, al
10779#ifdef VBOX
10780 mov dl, #0x00 ;; check if PCI device is AMD PCNet
10781 call pcibios_init_sel_reg
10782 mov dx, #0x0cfc
10783 in eax, dx
10784 cmp eax, #0x20001022
10785 jne next_pci_dev
10786 mov dl, #0x10 ;; get I/O address
10787 call pcibios_init_sel_reg
10788 mov dx, #0x0cfc
10789 in ax, dx
10790 and ax, #0xfffc
10791 mov cx, ax
10792 mov dx, cx
10793 add dx, #0x14 ;; reset register if PCNet is in word I/O mode
10794 in ax, dx ;; reset is performed by reading the reset register
10795 mov dx, cx
10796 add dx, #0x18 ;; reset register if PCNet is in word I/O mode
10797 in eax, dx ;; reset is performed by reading the reset register
10798#endif /* VBOX */
10799next_pci_dev:
10800 mov byte ptr[bp-8], #0x10
10801 inc bx
10802 cmp bx, #0x0100
10803 jne pci_init_io_loop1
10804 mov sp, bp
10805 pop bp
10806 ret
10807
10808pcibios_init_set_elcr:
10809 push ax
10810 push cx
10811 mov dx, #0x04d0
10812 test al, #0x08
10813 jz is_master_pic
10814 inc dx
10815 and al, #0x07
10816is_master_pic:
10817 mov cl, al
10818 mov bl, #0x01
10819 shl bl, cl
10820 in al, dx
10821 or al, bl
10822 out dx, al
10823 pop cx
10824 pop ax
10825 ret
10826
10827pcibios_init_irqs:
10828 push ds
10829 push bp
10830 mov ax, #0xf000
10831 mov ds, ax
10832 mov dx, #0x04d0 ;; reset ELCR1 + ELCR2
10833 mov al, #0x00
10834 out dx, al
10835 inc dx
10836 out dx, al
10837 mov si, #pci_routing_table_structure
10838 mov bh, [si+8]
10839 mov bl, [si+9]
10840 mov dl, #0x00
10841 call pcibios_init_sel_reg
10842 mov dx, #0x0cfc
10843 in eax, dx
10844 cmp eax, [si+12] ;; check irq router
10845 jne pci_init_end
10846 mov dl, [si+34]
10847 call pcibios_init_sel_reg
10848 push bx ;; save irq router bus + devfunc
10849 mov dx, #0x0cfc
10850 mov ax, #0x8080
10851 out dx, ax ;; reset PIRQ route control
10852 add dx, #2
10853 out dx, ax
10854 mov ax, [si+6]
10855 sub ax, #0x20
10856 shr ax, #4
10857 mov cx, ax
10858 add si, #0x20 ;; set pointer to 1st entry
10859 mov bp, sp
10860 mov ax, #pci_irq_list
10861 push ax
10862 xor ax, ax
10863 push ax
10864pci_init_irq_loop1:
10865 mov bh, [si]
10866 mov bl, [si+1]
10867pci_init_irq_loop2:
10868 mov dl, #0x00
10869 call pcibios_init_sel_reg
10870 mov dx, #0x0cfc
10871 in ax, dx
10872 cmp ax, #0xffff
10873 jnz pci_test_int_pin
10874 test bl, #0x07
10875 jz next_pir_entry
10876 jmp next_pci_func
10877pci_test_int_pin:
10878 mov dl, #0x3c
10879 call pcibios_init_sel_reg
10880 mov dx, #0x0cfd
10881 in al, dx
10882 and al, #0x07
10883 jz next_pci_func
10884 dec al ;; determine pirq reg
10885 mov dl, #0x03
10886 mul al, dl
10887 add al, #0x02
10888 xor ah, ah
10889 mov bx, ax
10890 mov al, [si+bx]
10891 mov dl, al
10892 mov bx, [bp]
10893 call pcibios_init_sel_reg
10894 mov dx, #0x0cfc
10895 and al, #0x03
10896 add dl, al
10897 in al, dx
10898 cmp al, #0x80
10899 jb pirq_found
10900 mov bx, [bp-2] ;; pci irq list pointer
10901 mov al, [bx]
10902 out dx, al
10903 inc bx
10904 mov [bp-2], bx
10905 call pcibios_init_set_elcr
10906pirq_found:
10907 mov bh, [si]
10908 mov bl, [si+1]
10909 add bl, [bp-3] ;; pci function number
10910 mov dl, #0x3c
10911 call pcibios_init_sel_reg
10912 mov dx, #0x0cfc
10913 out dx, al
10914next_pci_func:
10915 inc byte ptr[bp-3]
10916 inc bl
10917 test bl, #0x07
10918 jnz pci_init_irq_loop2
10919next_pir_entry:
10920 add si, #0x10
10921 mov byte ptr[bp-3], #0x00
10922 loop pci_init_irq_loop1
10923 mov sp, bp
10924 pop bx
10925pci_init_end:
10926 pop bp
10927 pop ds
10928 ret
10929#endif // !BX_ROMBIOS32
10930#endif // BX_PCIBIOS
10931
10932#if BX_ROMBIOS32
10933rombios32_init:
10934 ;; save a20 and enable it
10935 in al, 0x92
10936 push ax
10937 or al, #0x02
10938 out 0x92, al
10939
10940 ;; save SS:SP to the BDA
10941 xor ax, ax
10942 mov ds, ax
10943 mov 0x0469, ss
10944 mov 0x0467, sp
10945
10946 SEG CS
10947 lidt [pmode_IDT_info]
10948 SEG CS
10949 lgdt [rombios32_gdt_48]
10950 ;; set PE bit in CR0
10951 mov eax, cr0
10952 or al, #0x01
10953 mov cr0, eax
10954 ;; start protected mode code: ljmpl 0x10:rombios32_init1
10955 db 0x66, 0xea
10956 dw rombios32_05
10957 dw 0x000f ;; high 16 bit address
10958 dw 0x0010
10959
10960use32 386
10961rombios32_05:
10962 ;; init data segments
10963 mov eax, #0x18
10964 mov ds, ax
10965 mov es, ax
10966 mov ss, ax
10967 xor eax, eax
10968 mov fs, ax
10969 mov gs, ax
10970 cld
10971
10972 ;; copy rombios32 code to ram (ram offset = 1MB)
10973 mov esi, #0xfffe0000
10974 mov edi, #0x00040000
10975 mov ecx, #0x10000 / 4
10976 rep
10977 movsd
10978
10979 ;; init the stack pointer
10980 mov esp, #0x00080000
10981
10982 ;; call rombios32 code
10983 mov eax, #0x00040000
10984 call eax
10985
10986 ;; return to 16 bit protected mode first
10987 db 0xea
10988 dd rombios32_10
10989 dw 0x20
10990
10991use16 386
10992rombios32_10:
10993 ;; restore data segment limits to 0xffff
10994 mov ax, #0x28
10995 mov ds, ax
10996 mov es, ax
10997 mov ss, ax
10998 mov fs, ax
10999 mov gs, ax
11000
11001 ;; reset PE bit in CR0
11002 mov eax, cr0
11003 and al, #0xFE
11004 mov cr0, eax
11005
11006 ;; far jump to flush CPU queue after transition to real mode
11007 JMP_AP(0xf000, rombios32_real_mode)
11008
11009rombios32_real_mode:
11010 ;; restore IDT to normal real-mode defaults
11011 SEG CS
11012 lidt [rmode_IDT_info]
11013
11014 xor ax, ax
11015 mov ds, ax
11016 mov es, ax
11017 mov fs, ax
11018 mov gs, ax
11019
11020 ;; restore SS:SP from the BDA
11021 mov ss, 0x0469
11022 xor esp, esp
11023 mov sp, 0x0467
11024 ;; restore a20
11025 pop ax
11026 out 0x92, al
11027 ret
11028
11029rombios32_gdt_48:
11030 dw 0x30
11031 dw rombios32_gdt
11032 dw 0x000f
11033
11034rombios32_gdt:
11035 dw 0, 0, 0, 0
11036 dw 0, 0, 0, 0
11037 dw 0xffff, 0, 0x9b00, 0x00cf ; 32 bit flat code segment (0x10)
11038 dw 0xffff, 0, 0x9300, 0x00cf ; 32 bit flat data segment (0x18)
11039 dw 0xffff, 0, 0x9b0f, 0x0000 ; 16 bit code segment base=0xf0000 limit=0xffff
11040 dw 0xffff, 0, 0x9300, 0x0000 ; 16 bit data segment base=0x0 limit=0xffff
11041#endif // BX_ROMBIOS32
11042
11043
11044; parallel port detection: base address in DX, index in BX, timeout in CL
11045detect_parport:
11046 push dx
11047 add dx, #2
11048 in al, dx
11049 and al, #0xdf ; clear input mode
11050 out dx, al
11051 pop dx
11052 mov al, #0xaa
11053 out dx, al
11054 in al, dx
11055 cmp al, #0xaa
11056 jne no_parport
11057 push bx
11058 shl bx, #1
11059 mov [bx+0x408], dx ; Parallel I/O address
11060 pop bx
11061 mov [bx+0x478], cl ; Parallel printer timeout
11062 inc bx
11063no_parport:
11064 ret
11065
11066; serial port detection: base address in DX, index in BX, timeout in CL
11067detect_serial:
11068 push dx
11069 inc dx
11070 mov al, #0x02
11071 out dx, al
11072 in al, dx
11073 cmp al, #0x02
11074 jne no_serial
11075 inc dx
11076 in al, dx
11077 cmp al, #0x02
11078 jne no_serial
11079 dec dx
11080 xor al, al
11081 out dx, al
11082 pop dx
11083 push bx
11084 shl bx, #1
11085 mov [bx+0x400], dx ; Serial I/O address
11086 pop bx
11087 mov [bx+0x47c], cl ; Serial timeout
11088 inc bx
11089 ret
11090no_serial:
11091 pop dx
11092 ret
11093
11094rom_checksum:
11095 push ax
11096 push bx
11097 push cx
11098 xor ax, ax
11099 xor bx, bx
11100 xor cx, cx
11101 mov ch, [2]
11102 shl cx, #1
11103checksum_loop:
11104 add al, [bx]
11105 inc bx
11106 loop checksum_loop
11107 and al, #0xff
11108 pop cx
11109 pop bx
11110 pop ax
11111 ret
11112
11113rom_scan:
11114 ;; Scan for existence of valid expansion ROMS.
11115 ;; Video ROM: from 0xC0000..0xC7FFF in 2k increments
11116 ;; General ROM: from 0xC8000..0xDFFFF in 2k increments
11117 ;; System ROM: only 0xE0000
11118 ;;
11119 ;; Header:
11120 ;; Offset Value
11121 ;; 0 0x55
11122 ;; 1 0xAA
11123 ;; 2 ROM length in 512-byte blocks
11124 ;; 3 ROM initialization entry point (FAR CALL)
11125
11126 mov cx, #0xc000
11127rom_scan_loop:
11128 mov ds, cx
11129 mov ax, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
11130 cmp [0], #0xAA55 ;; look for signature
11131 jne rom_scan_increment
11132 call rom_checksum
11133 jnz rom_scan_increment
11134 mov al, [2] ;; change increment to ROM length in 512-byte blocks
11135
11136 ;; We want our increment in 512-byte quantities, rounded to
11137 ;; the nearest 2k quantity, since we only scan at 2k intervals.
11138 test al, #0x03
11139 jz block_count_rounded
11140 and al, #0xfc ;; needs rounding up
11141 add al, #0x04
11142block_count_rounded:
11143
11144 xor bx, bx ;; Restore DS back to 0000:
11145 mov ds, bx
11146 push ax ;; Save AX
11147 ;; Push addr of ROM entry point
11148 push cx ;; Push seg
11149 push #0x0003 ;; Push offset
11150 mov bp, sp ;; Call ROM init routine using seg:off on stack
11151 db 0xff ;; call_far ss:[bp+0]
11152 db 0x5e
11153 db 0
11154 cli ;; In case expansion ROM BIOS turns IF on
11155 add sp, #2 ;; Pop offset value
11156 pop cx ;; Pop seg value (restore CX)
11157 pop ax ;; Restore AX
11158rom_scan_increment:
11159 shl ax, #5 ;; convert 512-bytes blocks to 16-byte increments
11160 ;; because the segment selector is shifted left 4 bits.
11161 add cx, ax
11162 cmp cx, #0xe800 ;; Must encompass VBOX_LANBOOT_SEG!
11163 jbe rom_scan_loop
11164
11165 xor ax, ax ;; Restore DS back to 0000:
11166 mov ds, ax
11167 ret
11168
11169#define LVT0 0xFEE00350
11170#define LVT1 0xFEE00360
11171
11172;; Program LVT0/LVT1 entries in the local APIC. Some Linux kernels (e.g., RHEL4
11173;; SMP 32-bit) expect the entries to be unmasked in virtual wire mode.
11174
11175setup_lapic:
11176 pushf
11177 cli ;; Interrupts would kill us!
11178 call pmode_enter
11179 mov esi, #LVT0 ;; Program LVT0 to ExtINT and unmask
11180 mov eax, [esi]
11181 and eax, #0xfffe00ff
11182 or ah, #0x07
11183 mov [esi], eax
11184 mov esi, #LVT1 ;; Program LVT1 to NMI and unmask
11185 mov eax, [esi]
11186 and eax, #0xfffe00ff
11187 or ah, #0x04
11188 mov [esi], eax
11189 call pmode_exit
11190 popf
11191 ret
11192
11193;; Enter and exit minimal protected-mode environment. May only be called from
11194;; the F000 segment (16-bit). Does not switch stacks. Must be run with disabled
11195;; interrupts(!). On return from pmode_enter, DS contains a selector which can
11196;; address the entire 4GB address space.
11197
11198pmode_enter:
11199 push cs
11200 pop ds
11201 lgdt [pmbios_gdt_desc]
11202 mov eax, cr0
11203 or al, #0x1
11204 mov cr0, eax
11205 JMP_AP(0x20, really_enter_pm)
11206really_enter_pm:
11207 mov ax, #0x18
11208 mov ds, ax
11209 ret
11210
11211pmode_exit:
11212 mov eax, cr0
11213 and al, #0xfe
11214 mov cr0, eax
11215 JMP_AP(0xF000, really_exit_pm)
11216really_exit_pm:
11217 ret
11218
11219pmbios_gdt_desc:
11220 dw 0x30
11221 dw pmbios_gdt
11222 dw 0x000f
11223
11224pmbios_gdt:
11225 dw 0, 0, 0, 0
11226 dw 0, 0, 0, 0
11227 dw 0xffff, 0, 0x9b00, 0x00cf ; 32 bit flat code segment (0x10)
11228 dw 0xffff, 0, 0x9300, 0x00cf ; 32 bit flat data segment (0x18)
11229 dw 0xffff, 0, 0x9b0f, 0x0000 ; 16 bit code segment base=0xf0000 limit=0xffff
11230 dw 0xffff, 0, 0x9300, 0x0000 ; 16 bit data segment base=0x0 limit=0xffff
11231
11232;; for 'C' strings and other data, insert them here with
11233;; a the following hack:
11234;; DATA_SEG_DEFS_HERE
11235
11236
11237;; the following area can be used to write dynamically generated tables
11238 .align 16
11239bios_table_area_start:
11240 dd 0xaafb4442
11241 dd bios_table_area_end - bios_table_area_start - 8;
11242
11243;--------
11244;- POST -
11245;--------
11246.org 0xe05b ; POST Entry Point
11247bios_table_area_end:
11248post:
11249
11250 xor ax, ax
11251
11252 ;; first reset the DMA controllers
11253 out 0x0d,al
11254 out 0xda,al
11255
11256 ;; then initialize the DMA controllers
11257 mov al, #0xC0
11258 out 0xD6, al ; cascade mode of channel 4 enabled
11259 mov al, #0x00
11260 out 0xD4, al ; unmask channel 4
11261
11262 ;; Examine CMOS shutdown status.
11263 mov AL, #0x0f
11264 out 0x70, AL
11265 in AL, 0x71
11266
11267 ;; backup status
11268 mov bl, al
11269
11270 ;; Reset CMOS shutdown status.
11271 mov AL, #0x0f
11272 out 0x70, AL ; select CMOS register Fh
11273 mov AL, #0x00
11274 out 0x71, AL ; set shutdown action to normal
11275
11276 ;; Examine CMOS shutdown status.
11277 mov al, bl
11278
11279 ;; 0x00, 0x09, 0x0D+ = normal startup
11280 cmp AL, #0x00
11281 jz normal_post
11282 cmp AL, #0x0d
11283 jae normal_post
11284 cmp AL, #0x09
11285 je normal_post
11286
11287 ;; 0x05 = eoi + jmp via [0x40:0x67] jump
11288 cmp al, #0x05
11289 je eoi_jmp_post
11290
11291#ifdef VBOX
11292 ;; just ignore all other CMOS shutdown status values (OpenSolaris sets it to 0xA for some reason in certain cases)
11293 ;; (shutdown_status_panic just crashes the VM as it calls int 0x10 before the IDT table has been initialized)
11294 jmp normal_post
11295#else
11296 ;; Examine CMOS shutdown status.
11297 ;; 0x01,0x02,0x03,0x04,0x06,0x07,0x08, 0x0a, 0x0b, 0x0c = Unimplemented shutdown status.
11298 push bx
11299 call _shutdown_status_panic
11300#endif
11301
11302#if 0
11303 HALT(__LINE__)
11304 ;
11305 ;#if 0
11306 ; 0xb0, 0x20, /* mov al, #0x20 */
11307 ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */
11308 ;#endif
11309 ;
11310 pop es
11311 pop ds
11312 popa
11313 iret
11314#endif
11315
11316normal_post:
11317 ; case 0: normal startup
11318
11319 cli
11320 mov ax, #0xfffe
11321 mov sp, ax
11322 xor ax, ax
11323 mov ds, ax
11324 mov ss, ax
11325
11326#ifndef VBOX
11327 ;; zero out BIOS data area (40:00..40:ff)
11328 mov es, ax
11329 mov cx, #0x0080 ;; 128 words
11330 mov di, #0x0400
11331 cld
11332 rep
11333 stosw
11334#else /* VBOX */
11335 ;; zero out segment 0 (includes BIOS data area) except word at 40:72
11336 mov es, ax
11337 xor di, di
11338 cld
11339 mov cx, #0x0239 ;; 569 words
11340 rep
11341 stosw
11342 inc di
11343 inc di
11344 mov cx, #0x7dc6 ;; 32198 words
11345 rep
11346 stosw
11347 ;; zero out remaining base memory except the last 16 bytes of the EBDA
11348 ;; because we store the MP table there
11349 xor eax, eax
11350 xor bx, bx
11351memory_zero_loop:
11352 add bx, #0x1000
11353 cmp bx, #0x9000
11354 jae memory_cleared
11355 mov es, bx
11356 xor di, di
11357 mov cx, #0x4000
11358 rep
11359 stosd
11360 jmp memory_zero_loop
11361memory_cleared:
11362 mov es, bx
11363 xor di, di
11364 mov cx, #0x3f00
11365 rep
11366 stosd
11367 xor bx, bx
11368#endif
11369
11370 call _log_bios_start
11371
11372 ;; set all interrupts to default handler
11373 xor bx, bx ;; offset index
11374 mov cx, #0x0100 ;; counter (256 interrupts)
11375 mov ax, #dummy_iret_handler
11376 mov dx, #0xF000
11377
11378post_default_ints:
11379 mov [bx], ax
11380 add bx, #2
11381 mov [bx], dx
11382 add bx, #2
11383 loop post_default_ints
11384
11385 ;; set vector 0x79 to zero
11386 ;; this is used by 'guardian angel' protection system
11387 SET_INT_VECTOR(0x79, #0, #0)
11388
11389 ;; base memory in K 40:13 (word)
11390 mov ax, #BASE_MEM_IN_K
11391 mov 0x0413, ax
11392
11393
11394 ;; Manufacturing Test 40:12
11395 ;; zerod out above
11396
11397#ifndef VBOX
11398 ;; Warm Boot Flag 0040:0072
11399 ;; value of 1234h = skip memory checks
11400 ;; zerod out above
11401#endif /* !VBOX */
11402
11403
11404 ;; Printer Services vector
11405 SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
11406
11407 ;; Bootstrap failure vector
11408 SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
11409
11410 ;; Bootstrap Loader vector
11411 SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
11412
11413 ;; User Timer Tick vector
11414 SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
11415
11416 ;; Memory Size Check vector
11417 SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
11418
11419 ;; Equipment Configuration Check vector
11420 SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
11421
11422 ;; System Services
11423 SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
11424
11425 ;; EBDA setup
11426 call ebda_post
11427
11428 ;; PIT setup
11429 SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
11430 ;; int 1C already points at dummy_iret_handler (above)
11431 mov al, #0x34 ; timer0: binary count, 16bit count, mode 2
11432 out 0x43, al
11433 mov al, #0x00 ; maximum count of 0000H = 18.2Hz
11434 out 0x40, al
11435 out 0x40, al
11436
11437 ;; Keyboard
11438 SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
11439 SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
11440
11441 xor ax, ax
11442 mov ds, ax
11443 mov 0x0417, al /* keyboard shift flags, set 1 */
11444 mov 0x0418, al /* keyboard shift flags, set 2 */
11445 mov 0x0419, al /* keyboard alt-numpad work area */
11446 mov 0x0471, al /* keyboard ctrl-break flag */
11447 mov 0x0497, al /* keyboard status flags 4 */
11448 mov al, #0x10
11449 mov 0x0496, al /* keyboard status flags 3 */
11450
11451
11452 /* keyboard head of buffer pointer */
11453 mov bx, #0x001E
11454 mov 0x041A, bx
11455
11456 /* keyboard end of buffer pointer */
11457 mov 0x041C, bx
11458
11459 /* keyboard pointer to start of buffer */
11460 mov bx, #0x001E
11461 mov 0x0480, bx
11462
11463 /* keyboard pointer to end of buffer */
11464 mov bx, #0x003E
11465 mov 0x0482, bx
11466
11467 /* init the keyboard */
11468 call _keyboard_init
11469
11470 ;; mov CMOS Equipment Byte to BDA Equipment Word
11471 mov ax, 0x0410
11472 mov al, #0x14
11473 out 0x70, al
11474 in al, 0x71
11475 mov 0x0410, ax
11476
11477
11478 ;; Parallel setup
11479 SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
11480 xor ax, ax
11481 mov ds, ax
11482 xor bx, bx
11483 mov cl, #0x14 ; timeout value
11484 mov dx, #0x378 ; Parallel I/O address, port 1
11485 call detect_parport
11486 mov dx, #0x278 ; Parallel I/O address, port 2
11487 call detect_parport
11488 shl bx, #0x0e
11489 mov ax, 0x410 ; Equipment word bits 14..15 determine # parallel ports
11490 and ax, #0x3fff
11491 or ax, bx ; set number of parallel ports
11492 mov 0x410, ax
11493
11494 ;; Serial setup
11495 SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
11496 SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
11497 xor bx, bx
11498 mov cl, #0x0a ; timeout value
11499 mov dx, #0x03f8 ; Serial I/O address, port 1
11500 call detect_serial
11501 mov dx, #0x02f8 ; Serial I/O address, port 2
11502 call detect_serial
11503 mov dx, #0x03e8 ; Serial I/O address, port 3
11504 call detect_serial
11505 mov dx, #0x02e8 ; Serial I/O address, port 4
11506 call detect_serial
11507 shl bx, #0x09
11508 mov ax, 0x410 ; Equipment word bits 9..11 determine # serial ports
11509 and ax, #0xf1ff
11510 or ax, bx ; set number of serial port
11511 mov 0x410, ax
11512
11513 ;; CMOS RTC
11514 SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
11515 SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
11516 SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
11517 ;; BIOS DATA AREA 0x4CE ???
11518 call timer_tick_post
11519
11520 ;; PS/2 mouse setup
11521 SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
11522
11523 ;; IRQ13 (FPU exception) setup
11524 SET_INT_VECTOR(0x75, #0xF000, #int75_handler)
11525
11526 ;; Video setup
11527 SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
11528
11529#ifdef VBOX
11530 ;; moved the PIC initialization to another place as we need
11531 ;; some space for additions init calls. Otherwise this code
11532 ;; overlaps with the NMI handler at 0xe2c3 (fixed BIOS entry)
11533 call init_pic
11534#else /* !VBOX */
11535 ;; PIC
11536 mov al, #0x11 ; send initialisation commands
11537 out 0x20, al
11538 out 0xa0, al
11539 mov al, #0x08
11540 out 0x21, al
11541 mov al, #0x70
11542 out 0xa1, al
11543 mov al, #0x04
11544 out 0x21, al
11545 mov al, #0x02
11546 out 0xa1, al
11547 mov al, #0x01
11548 out 0x21, al
11549 out 0xa1, al
11550 mov al, #0xb8
11551 out 0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6
11552#if BX_USE_PS2_MOUSE
11553 mov al, #0x8f
11554#else
11555 mov al, #0x9f
11556#endif
11557 out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14
11558#endif /* !VBOX */
11559
11560#if BX_ROMBIOS32
11561 call rombios32_init
11562#else
11563 call pcibios_init_iomem_bases
11564 call pcibios_init_irqs
11565#endif
11566 call setup_lapic
11567 call rom_scan
11568
11569#if BX_USE_ATADRV
11570 ;;
11571 ;; ATA/ATAPI driver setup
11572 ;;
11573 call _ata_init
11574 call _ata_detect
11575 ;;
11576#endif
11577
11578#ifdef VBOX_WITH_SCSI
11579 ;;
11580 ;; SCSI driver setup
11581 ;;
11582 call _scsi_init
11583 ;;
11584#endif
11585
11586 call _print_bios_banner
11587
11588 ;;
11589 ;; Floppy setup
11590 ;;
11591 call floppy_drive_post
11592
11593 ;;
11594 ;; Hard Drive setup
11595 ;;
11596 call hard_drive_post
11597
11598#if BX_ELTORITO_BOOT
11599 ;;
11600 ;; eltorito floppy/harddisk emulation from cd
11601 ;;
11602 call _cdemu_init
11603 ;;
11604#endif // BX_ELTORITO_BOOT
11605
11606 sti ;; enable interrupts
11607 int #0x19
11608
11609.org 0xe2c3 ; NMI Handler Entry Point
11610nmi:
11611 ;; FIXME the NMI handler should not panic
11612 ;; but iret when called from int75 (fpu exception)
11613 call _nmi_handler_msg
11614 iret
11615
11616int75_handler:
11617 out 0xf0, al // clear irq13
11618 call eoi_both_pics // clear interrupt
11619 int 2 // legacy nmi call
11620 iret
11621
11622;-------------------------------------------
11623;- INT 13h Fixed Disk Services Entry Point -
11624;-------------------------------------------
11625.org 0xe3fe ; INT 13h Fixed Disk Services Entry Point
11626int13_handler:
11627 //JMPL(int13_relocated)
11628 jmp int13_relocated
11629
11630.org 0xe401 ; Fixed Disk Parameter Table
11631
11632;----------
11633;- INT19h -
11634;----------
11635.org 0xe6f2 ; INT 19h Boot Load Service Entry Point
11636int19_handler:
11637
11638 jmp int19_relocated
11639;-------------------------------------------
11640;- System BIOS Configuration Data Table
11641;-------------------------------------------
11642.org BIOS_CONFIG_TABLE
11643db 0x08 ; Table size (bytes) -Lo
11644db 0x00 ; Table size (bytes) -Hi
11645db SYS_MODEL_ID
11646db SYS_SUBMODEL_ID
11647db BIOS_REVISION
11648; Feature byte 1
11649; b7: 1=DMA channel 3 used by hard disk
11650; b6: 1=2 interrupt controllers present
11651; b5: 1=RTC present
11652; b4: 1=BIOS calls int 15h/4Fh every key
11653; b3: 1=wait for extern event supported (Int 15h/41h)
11654; b2: 1=extended BIOS data area used
11655; b1: 0=AT or ESDI bus, 1=MicroChannel
11656; b0: 1=Dual bus (MicroChannel + ISA)
11657db (0 << 7) | \
11658 (1 << 6) | \
11659 (1 << 5) | \
11660 (BX_CALL_INT15_4F << 4) | \
11661 (0 << 3) | \
11662 (BX_USE_EBDA << 2) | \
11663 (0 << 1) | \
11664 (0 << 0)
11665; Feature byte 2
11666; b7: 1=32-bit DMA supported
11667; b6: 1=int16h, function 9 supported
11668; b5: 1=int15h/C6h (get POS data) supported
11669; b4: 1=int15h/C7h (get mem map info) supported
11670; b3: 1=int15h/C8h (en/dis CPU) supported
11671; b2: 1=non-8042 kb controller
11672; b1: 1=data streaming supported
11673; b0: reserved
11674db (0 << 7) | \
11675 (1 << 6) | \
11676 (0 << 5) | \
11677 (0 << 4) | \
11678 (0 << 3) | \
11679 (0 << 2) | \
11680 (0 << 1) | \
11681 (0 << 0)
11682; Feature byte 3
11683; b7: not used
11684; b6: reserved
11685; b5: reserved
11686; b4: POST supports ROM-to-RAM enable/disable
11687; b3: SCSI on system board
11688; b2: info panel installed
11689; b1: Initial Machine Load (IML) system - BIOS on disk
11690; b0: SCSI supported in IML
11691db 0x00
11692; Feature byte 4
11693; b7: IBM private
11694; b6: EEPROM present
11695; b5-3: ABIOS presence (011 = not supported)
11696; b2: private
11697; b1: memory split above 16Mb supported
11698; b0: POSTEXT directly supported by POST
11699db 0x00
11700; Feature byte 5 (IBM)
11701; b1: enhanced mouse
11702; b0: flash EPROM
11703db 0x00
11704
11705
11706
11707.org 0xe729 ; Baud Rate Generator Table
11708
11709;----------
11710;- INT14h -
11711;----------
11712.org 0xe739 ; INT 14h Serial Communications Service Entry Point
11713int14_handler:
11714 push ds
11715 pusha
11716 xor ax, ax
11717 mov ds, ax
11718 call _int14_function
11719 popa
11720 pop ds
11721 iret
11722
11723
11724;----------------------------------------
11725;- INT 16h Keyboard Service Entry Point -
11726;----------------------------------------
11727.org 0xe82e
11728int16_handler:
11729
11730 sti
11731 push ds
11732 pushf
11733 pusha
11734
11735 cmp ah, #0x00
11736 je int16_F00
11737 cmp ah, #0x10
11738 je int16_F00
11739
11740 mov bx, #0xf000
11741 mov ds, bx
11742 call _int16_function
11743 popa
11744 popf
11745 pop ds
11746 jz int16_zero_set
11747
11748int16_zero_clear:
11749 push bp
11750 mov bp, sp
11751 //SEG SS
11752 and BYTE [bp + 0x06], #0xbf
11753 pop bp
11754 iret
11755
11756int16_zero_set:
11757 push bp
11758 mov bp, sp
11759 //SEG SS
11760 or BYTE [bp + 0x06], #0x40
11761 pop bp
11762 iret
11763
11764int16_F00:
11765 mov bx, #0x0040
11766 mov ds, bx
11767
11768int16_wait_for_key:
11769 cli
11770 mov bx, 0x001a
11771 cmp bx, 0x001c
11772 jne int16_key_found
11773 sti
11774 nop
11775#if 0
11776 /* no key yet, call int 15h, function AX=9002 */
11777 0x50, /* push AX */
11778 0xb8, 0x02, 0x90, /* mov AX, #0x9002 */
11779 0xcd, 0x15, /* int 15h */
11780 0x58, /* pop AX */
11781 0xeb, 0xea, /* jmp WAIT_FOR_KEY */
11782#endif
11783 jmp int16_wait_for_key
11784
11785int16_key_found:
11786 mov bx, #0xf000
11787 mov ds, bx
11788 call _int16_function
11789 popa
11790 popf
11791 pop ds
11792#if 0
11793 /* notify int16 complete w/ int 15h, function AX=9102 */
11794 0x50, /* push AX */
11795 0xb8, 0x02, 0x91, /* mov AX, #0x9102 */
11796 0xcd, 0x15, /* int 15h */
11797 0x58, /* pop AX */
11798#endif
11799 iret
11800
11801
11802
11803;-------------------------------------------------
11804;- INT09h : Keyboard Hardware Service Entry Point -
11805;-------------------------------------------------
11806.org 0xe987
11807int09_handler:
11808 cli
11809 push ax
11810
11811 mov al, #0xAD ;;disable keyboard
11812 out #0x64, al
11813
11814 mov al, #0x0B
11815 out #0x20, al
11816 in al, #0x20
11817 and al, #0x02
11818 jz int09_finish
11819
11820 in al, #0x60 ;;read key from keyboard controller
11821 sti
11822 push ds
11823 pusha
11824#ifdef BX_CALL_INT15_4F
11825 mov ah, #0x4f ;; allow for keyboard intercept
11826 stc
11827 int #0x15
11828 jnc int09_done
11829#endif
11830
11831 ;; check for extended key
11832 cmp al, #0xe0
11833 jne int09_check_pause
11834 xor ax, ax
11835 mov ds, ax
11836 mov al, BYTE [0x496] ;; mf2_state |= 0x02
11837 or al, #0x02
11838 mov BYTE [0x496], al
11839 jmp int09_done
11840
11841int09_check_pause: ;; check for pause key
11842 cmp al, #0xe1
11843 jne int09_process_key
11844 xor ax, ax
11845 mov ds, ax
11846 mov al, BYTE [0x496] ;; mf2_state |= 0x01
11847 or al, #0x01
11848 mov BYTE [0x496], al
11849 jmp int09_done
11850
11851int09_process_key:
11852 mov bx, #0xf000
11853 mov ds, bx
11854 call _int09_function
11855
11856int09_done:
11857 popa
11858 pop ds
11859 cli
11860 call eoi_master_pic
11861
11862int09_finish:
11863 mov al, #0xAE ;;enable keyboard
11864 out #0x64, al
11865 pop ax
11866 iret
11867
11868
11869;----------------------------------------
11870;- INT 13h Diskette Service Entry Point -
11871;----------------------------------------
11872.org 0xec59
11873int13_diskette:
11874 jmp int13_noeltorito
11875
11876;---------------------------------------------
11877;- INT 0Eh Diskette Hardware ISR Entry Point -
11878;---------------------------------------------
11879.org 0xef57 ; INT 0Eh Diskette Hardware ISR Entry Point
11880int0e_handler:
11881 push ax
11882 push dx
11883 mov dx, #0x03f4
11884 in al, dx
11885 and al, #0xc0
11886 cmp al, #0xc0
11887 je int0e_normal
11888 mov dx, #0x03f5
11889 mov al, #0x08 ; sense interrupt status
11890 out dx, al
11891int0e_loop1:
11892 mov dx, #0x03f4
11893 in al, dx
11894 and al, #0xc0
11895 cmp al, #0xc0
11896 jne int0e_loop1
11897int0e_loop2:
11898 mov dx, #0x03f5
11899 in al, dx
11900 mov dx, #0x03f4
11901 in al, dx
11902 and al, #0xc0
11903 cmp al, #0xc0
11904 je int0e_loop2
11905int0e_normal:
11906 push ds
11907 xor ax, ax ;; segment 0000
11908 mov ds, ax
11909 call eoi_master_pic
11910 mov al, 0x043e
11911 or al, #0x80 ;; diskette interrupt has occurred
11912 mov 0x043e, al
11913 pop ds
11914 pop dx
11915 pop ax
11916 iret
11917
11918
11919.org 0xefc7 ; Diskette Controller Parameter Table
11920diskette_param_table:
11921;; Since no provisions are made for multiple drive types, most
11922;; values in this table are ignored. I set parameters for 1.44M
11923;; floppy here
11924db 0xAF
11925db 0x02 ;; head load time 0000001, DMA used
11926db 0x25
11927db 0x02
11928db 18
11929db 0x1B
11930db 0xFF
11931db 0x6C
11932db 0xF6
11933db 0x0F
11934db 0x08
11935
11936
11937;----------------------------------------
11938;- INT17h : Printer Service Entry Point -
11939;----------------------------------------
11940.org 0xefd2
11941int17_handler:
11942 push ds
11943 pusha
11944 xor ax, ax
11945 mov ds, ax
11946 call _int17_function
11947 popa
11948 pop ds
11949 iret
11950
11951diskette_param_table2:
11952;; New diskette parameter table adding 3 parameters from IBM
11953;; Since no provisions are made for multiple drive types, most
11954;; values in this table are ignored. I set parameters for 1.44M
11955;; floppy here
11956db 0xAF
11957db 0x02 ;; head load time 0000001, DMA used
11958db 0x25
11959db 0x02
11960db 18
11961db 0x1B
11962db 0xFF
11963db 0x6C
11964db 0xF6
11965db 0x0F
11966db 0x08
11967db 79 ;; maximum track
11968db 0 ;; data transfer rate
11969db 4 ;; drive type in cmos
11970
11971.org 0xf045 ; INT 10 Functions 0-Fh Entry Point
11972 HALT(__LINE__)
11973 iret
11974
11975;----------
11976;- INT10h -
11977;----------
11978.org 0xf065 ; INT 10h Video Support Service Entry Point
11979int10_handler:
11980 ;; dont do anything, since the VGA BIOS handles int10h requests
11981 iret
11982
11983.org 0xf0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
11984
11985;----------
11986;- INT12h -
11987;----------
11988.org 0xf841 ; INT 12h Memory Size Service Entry Point
11989; ??? different for Pentium (machine check)?
11990int12_handler:
11991 push ds
11992 mov ax, #0x0040
11993 mov ds, ax
11994 mov ax, 0x0013
11995 pop ds
11996 iret
11997
11998;----------
11999;- INT11h -
12000;----------
12001.org 0xf84d ; INT 11h Equipment List Service Entry Point
12002int11_handler:
12003 push ds
12004 mov ax, #0x0040
12005 mov ds, ax
12006 mov ax, 0x0010
12007 pop ds
12008 iret
12009
12010;----------
12011;- INT15h -
12012;----------
12013.org 0xf859 ; INT 15h System Services Entry Point
12014int15_handler:
12015 pushf
12016#if BX_APM
12017 cmp ah, #0x53
12018 je apm_call
12019#endif
12020 push ds
12021 push es
12022 cmp ah, #0x86
12023 je int15_handler32
12024 cmp ah, #0xE8
12025 je int15_handler32
12026 pusha
12027#if BX_USE_PS2_MOUSE
12028 cmp ah, #0xC2
12029 je int15_handler_mouse
12030#endif
12031 call _int15_function
12032int15_handler_mouse_ret:
12033 popa
12034int15_handler32_ret:
12035 pop es
12036 pop ds
12037 popf
12038 jmp iret_modify_cf
12039#if BX_APM
12040apm_call:
12041 jmp _apmreal_entry
12042#endif
12043
12044#if BX_USE_PS2_MOUSE
12045int15_handler_mouse:
12046 call _int15_function_mouse
12047 jmp int15_handler_mouse_ret
12048#endif
12049
12050int15_handler32:
12051 pushad
12052 call _int15_function32
12053 popad
12054 jmp int15_handler32_ret
12055
12056;; Protected mode IDT descriptor
12057;;
12058;; I just make the limit 0, so the machine will shutdown
12059;; if an exception occurs during protected mode memory
12060;; transfers.
12061;;
12062;; Set base to f0000 to correspond to beginning of BIOS,
12063;; in case I actually define an IDT later
12064;; Set limit to 0
12065
12066pmode_IDT_info:
12067dw 0x0000 ;; limit 15:00
12068dw 0x0000 ;; base 15:00
12069db 0x0f ;; base 23:16
12070
12071;; Real mode IDT descriptor
12072;;
12073;; Set to typical real-mode values.
12074;; base = 000000
12075;; limit = 03ff
12076
12077rmode_IDT_info:
12078dw 0x03ff ;; limit 15:00
12079dw 0x0000 ;; base 15:00
12080db 0x00 ;; base 23:16
12081
12082;;
12083;; Handler for unexpected hardware interrupts
12084;;
12085dummy_isr:
12086 push ds
12087 pushad
12088 xor ax, ax
12089 mov ds, ax
12090 call _dummy_isr_function
12091 popad
12092 pop ds
12093 iret
12094
12095;----------
12096;- INT1Ah -
12097;----------
12098.org 0xfe6e ; INT 1Ah Time-of-day Service Entry Point
12099int1a_handler:
12100#if BX_PCIBIOS
12101 cmp ah, #0xb1
12102 jne int1a_normal
12103 call pcibios_real
12104 jc pcibios_error
12105 retf 2
12106pcibios_error:
12107 mov bl, ah
12108 mov ah, #0xb1
12109 push ds
12110 pusha
12111 mov ax, ss ; set readable descriptor to ds, for calling pcibios
12112 mov ds, ax ; on 16bit protected mode.
12113 jmp int1a_callfunction
12114int1a_normal:
12115#endif
12116 push ds
12117 pusha
12118 xor ax, ax
12119 mov ds, ax
12120int1a_callfunction:
12121 call _int1a_function
12122 popa
12123 pop ds
12124 iret
12125
12126;;
12127;; int70h: IRQ8 - CMOS RTC
12128;;
12129int70_handler:
12130 push ds
12131 pushad
12132 xor ax, ax
12133 mov ds, ax
12134 call _int70_function
12135 popad
12136 pop ds
12137 iret
12138
12139;---------
12140;- INT08 -
12141;---------
12142.org 0xfea5 ; INT 08h System Timer ISR Entry Point
12143int08_handler:
12144 sti
12145 push eax
12146 push ds
12147 xor ax, ax
12148 mov ds, ax
12149
12150 ;; time to turn off drive(s)?
12151 mov al,0x0440
12152 or al,al
12153 jz int08_floppy_off
12154 dec al
12155 mov 0x0440,al
12156 jnz int08_floppy_off
12157 ;; turn motor(s) off
12158 push dx
12159 mov dx,#0x03f2
12160 in al,dx
12161 and al,#0xcf
12162 out dx,al
12163 pop dx
12164int08_floppy_off:
12165
12166 mov eax, 0x046c ;; get ticks dword
12167 inc eax
12168
12169 ;; compare eax to one days worth of timer ticks at 18.2 hz
12170 cmp eax, #0x001800B0
12171 jb int08_store_ticks
12172 ;; there has been a midnight rollover at this point
12173 xor eax, eax ;; zero out counter
12174 inc BYTE 0x0470 ;; increment rollover flag
12175
12176int08_store_ticks:
12177 mov 0x046c, eax ;; store new ticks dword
12178 ;; chain to user timer tick INT #0x1c
12179 //pushf
12180 //;; call_ep [ds:loc]
12181 //CALL_EP( 0x1c << 2 )
12182 int #0x1c
12183 cli
12184 call eoi_master_pic
12185 pop ds
12186 pop eax
12187 iret
12188
12189.org 0xfef3 ; Initial Interrupt Vector Offsets Loaded by POST
12190
12191
12192.org 0xff00
12193.ascii BIOS_COPYRIGHT_STRING
12194
12195#ifdef VBOX
12196// The SMBIOS header
12197.org 0xff30
12198.align 16
12199 db 0x5f, 0x53, 0x4d, 0x5f ; "_SM_" signature
12200 db 0x00 ; checksum (set by biossums)
12201 db 0x1f ; EPS length, defined by standard
12202 db VBOX_SMBIOS_MAJOR_VER ; SMBIOS major version
12203 db VBOX_SMBIOS_MINOR_VER ; SMBIOS minor version
12204 dw VBOX_SMBIOS_MAXSS ; Maximum structure size
12205 db 0x00 ; Entry point revision
12206 db 0x00, 0x00, 0x00, 0x00, 0x00
12207
12208// The DMI header
12209 db 0x5f, 0x44, 0x4d, 0x49, 0x5f ; "_DMI_" signature
12210 db 0x00 ; checksum (set by biossums)
12211 dw VBOX_DMI_TABLE_SIZE ; DMI tables length
12212 dd VBOX_DMI_TABLE_BASE ; DMI tables base
12213 dw VBOX_DMI_TABLE_ENTR ; DMI tables entries
12214 db VBOX_DMI_TABLE_VER ; DMI version
12215 db 0x00 ; Just for alignment
12216#endif
12217
12218;------------------------------------------------
12219;- IRET Instruction for Dummy Interrupt Handler -
12220;------------------------------------------------
12221.org 0xff53 ; IRET Instruction for Dummy Interrupt Handler
12222dummy_iret_handler:
12223 iret
12224
12225.org 0xff54 ; INT 05h Print Screen Service Entry Point
12226 HALT(__LINE__)
12227 iret
12228
12229.org 0xfff0 ; Power-up Entry Point
12230 jmp 0xf000:post
12231
12232.org 0xfff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
12233.ascii BIOS_BUILD_DATE
12234
12235.org 0xfffe ; System Model ID
12236db SYS_MODEL_ID
12237db 0x00 ; filler
12238
12239.org 0xfa6e ;; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
12240ASM_END
12241/*
12242 * This font comes from the fntcol16.zip package (c) by Joseph Gil
12243 * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
12244 * This font is public domain
12245 */
12246static Bit8u vgafont8[128*8]=
12247{
12248 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
12249 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
12250 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
12251 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
12252 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
12253 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
12254 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
12255 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
12256 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
12257 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
12258 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
12259 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
12260 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
12261 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
12262 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
12263 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
12264 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
12265 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
12266 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
12267 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
12268 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
12269 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
12270 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
12271 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
12272 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
12273 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
12274 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
12275 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
12276 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
12277 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
12278 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
12279 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
12280 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
12281 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
12282 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
12283 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
12284 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
12285 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
12286 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
12287 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
12288 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
12289 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
12290 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
12291 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
12292 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
12293 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
12294 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
12295 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
12296 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
12297 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
12298 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
12299 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
12300 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
12301 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
12302 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
12303 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
12304 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
12305 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
12306 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
12307 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
12308 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
12309 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
12310 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
12311 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
12312 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
12313 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
12314 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
12315 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
12316 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
12317 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
12318 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
12319 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
12320 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
12321 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
12322 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
12323 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
12324 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
12325 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
12326 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
12327 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
12328 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
12329 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
12330 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
12331 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
12332 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
12333 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
12334 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
12335 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
12336 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
12337 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
12338 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
12339 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
12340 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
12341 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
12342 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
12343 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
12344 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
12345 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
12346 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
12347 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
12348 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
12349 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
12350 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
12351 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
12352 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
12353 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
12354 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
12355 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
12356 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
12357 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
12358 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
12359 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
12360 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
12361 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
12362 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
12363 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
12364 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
12365 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
12366 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
12367 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
12368 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
12369 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
12370 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
12371 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
12372 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
12373 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
12374 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
12375 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
12376};
12377
12378ASM_START
12379.org 0xcc00
12380// bcc-generated data will be placed here
12381ASM_END
Note: See TracBrowser for help on using the repository browser.

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