VirtualBox

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

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

BIOS: Properly report the number of sectors transferred by ata_cmd_data_in().

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