VirtualBox

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

Last change on this file since 40754 was 40754, checked in by vboxsync, 12 years ago

BIOS: Do a basic sanity check on floppy boot sectors, too.

  • Property svn:eol-style set to native
File size: 339.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 (cbbochs@free.fr)
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 (cbbochs@free.fr)
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#else
231# define BX_MAX_STORAGE_DEVICES BX_MAX_ATA_DEVICES
232#endif
233
234#ifndef VBOX
235#define PANIC_PORT 0x400
236#define PANIC_PORT2 0x401
237#define INFO_PORT 0x402
238#define DEBUG_PORT 0x403
239#else /* VBOX */
240/* Redirect INFO output to backdoor logging port. */
241#define PANIC_PORT 0x400
242#define PANIC_PORT2 0x401
243#define INFO_PORT 0x504
244#define DEBUG_PORT 0x403
245#endif /* VBOX */
246
247// define this if you want to make PCIBIOS working on a specific bridge only
248// undef enables PCIBIOS when at least one PCI device is found
249// i440FX is emulated by Bochs and QEMU
250#define PCI_FIXED_HOST_BRIDGE_1 0x12378086 ;; i440FX PCI bridge
251#define PCI_FIXED_HOST_BRIDGE_2 0x244e8086 ;; ICH9 PCI bridge
252
253// #20 is dec 20
254// #$20 is hex 20 = 32
255// #0x20 is hex 20 = 32
256// LDA #$20
257// JSR $E820
258// LDD .i,S
259// JSR $C682
260// mov al, #$20
261
262// all hex literals should be prefixed with '0x'
263// grep "#[0-9a-fA-F][0-9a-fA-F]" rombios.c
264// no mov SEG-REG, #value, must mov register into seg-reg
265// grep -i "mov[ ]*.s" rombios.c
266
267// This is for compiling with gcc2 and gcc3
268#define ASM_START #asm
269#define ASM_END #endasm
270
271ASM_START
272.rom
273
274.org 0x0000
275
276#if BX_CPU >= 3
277use16 386
278#else
279use16 286
280#endif
281
282MACRO HALT
283 ;; the HALT macro is called with the line number of the HALT call.
284 ;; The line number is then sent to the PANIC_PORT, causing Bochs/Plex
285 ;; to print a BX_PANIC message. This will normally halt the simulation
286 ;; with a message such as "BIOS panic at rombios.c, line 4091".
287 ;; However, users can choose to make panics non-fatal and continue.
288#if BX_VIRTUAL_PORTS
289 mov dx,#PANIC_PORT
290 mov ax,#?1
291 out dx,ax
292#else
293 mov dx,#0x80
294 mov ax,#?1
295 out dx,al
296#endif
297MEND
298
299MACRO JMP_AP
300 db 0xea
301 dw ?2
302 dw ?1
303MEND
304
305MACRO SET_INT_VECTOR
306 mov ax, ?3
307 mov ?1*4, ax
308 mov ax, ?2
309 mov ?1*4+2, ax
310MEND
311
312ASM_END
313
314typedef unsigned char Bit8u;
315typedef unsigned short Bit16u;
316typedef unsigned short bx_bool;
317typedef unsigned long Bit32u;
318
319#if BX_USE_ATADRV
320
321 void memsetb(seg,offset,value,count);
322 void memcpyb(dseg,doffset,sseg,soffset,count);
323 void memcpyd(dseg,doffset,sseg,soffset,count);
324
325 // memset of count bytes
326 void
327 memsetb(seg,offset,value,count)
328 Bit16u seg;
329 Bit16u offset;
330 Bit16u value;
331 Bit16u count;
332 {
333 ASM_START
334 push bp
335 mov bp, sp
336
337 push ax
338 push cx
339 push es
340 push di
341
342 mov cx, 10[bp] ; count
343 test cx, cx
344 je memsetb_end
345 mov ax, 4[bp] ; segment
346 mov es, ax
347 mov ax, 6[bp] ; offset
348 mov di, ax
349 mov al, 8[bp] ; value
350 cld
351 rep
352 stosb
353
354 memsetb_end:
355 pop di
356 pop es
357 pop cx
358 pop ax
359
360 pop bp
361 ASM_END
362 }
363
364#if 0
365 // memcpy of count bytes
366 void
367 memcpyb(dseg,doffset,sseg,soffset,count)
368 Bit16u dseg;
369 Bit16u doffset;
370 Bit16u sseg;
371 Bit16u soffset;
372 Bit16u count;
373 {
374 ASM_START
375 push bp
376 mov bp, sp
377
378 push ax
379 push cx
380 push es
381 push di
382 push ds
383 push si
384
385 mov cx, 12[bp] ; count
386 cmp cx, #0x0000
387 je memcpyb_end
388 mov ax, 4[bp] ; dsegment
389 mov es, ax
390 mov ax, 6[bp] ; doffset
391 mov di, ax
392 mov ax, 8[bp] ; ssegment
393 mov ds, ax
394 mov ax, 10[bp] ; soffset
395 mov si, ax
396 cld
397 rep
398 movsb
399
400 memcpyb_end:
401 pop si
402 pop ds
403 pop di
404 pop es
405 pop cx
406 pop ax
407
408 pop bp
409 ASM_END
410 }
411
412 // memcpy of count dword
413 void
414 memcpyd(dseg,doffset,sseg,soffset,count)
415 Bit16u dseg;
416 Bit16u doffset;
417 Bit16u sseg;
418 Bit16u soffset;
419 Bit16u count;
420 {
421 ASM_START
422 push bp
423 mov bp, sp
424
425 push ax
426 push cx
427 push es
428 push di
429 push ds
430 push si
431
432 mov cx, 12[bp] ; count
433 test cx, cx
434 je memcpyd_end
435 mov ax, 4[bp] ; dsegment
436 mov es, ax
437 mov ax, 6[bp] ; doffset
438 mov di, ax
439 mov ax, 8[bp] ; ssegment
440 mov ds, ax
441 mov ax, 10[bp] ; soffset
442 mov si, ax
443 cld
444 rep
445 movsd
446
447 memcpyd_end:
448 pop si
449 pop ds
450 pop di
451 pop es
452 pop cx
453 pop ax
454
455 pop bp
456 ASM_END
457 }
458#endif
459#endif //BX_USE_ATADRV
460
461 // read_dword and write_dword functions
462 static Bit32u read_dword();
463 static void write_dword();
464
465 Bit32u
466 read_dword(seg, offset)
467 Bit16u seg;
468 Bit16u offset;
469 {
470 ASM_START
471 push bp
472 mov bp, sp
473
474 push bx
475 push ds
476 mov ax, 4[bp] ; segment
477 mov ds, ax
478 mov bx, 6[bp] ; offset
479 mov ax, [bx]
480 add bx, #2
481 mov dx, [bx]
482 ;; ax = return value (word)
483 ;; dx = return value (word)
484 pop ds
485 pop bx
486
487 pop bp
488 ASM_END
489 }
490
491 void
492 write_dword(seg, offset, data)
493 Bit16u seg;
494 Bit16u offset;
495 Bit32u data;
496 {
497 ASM_START
498 push bp
499 mov bp, sp
500
501 push ax
502 push bx
503 push ds
504 mov ax, 4[bp] ; segment
505 mov ds, ax
506 mov bx, 6[bp] ; offset
507 mov ax, 8[bp] ; data word
508 mov [bx], ax ; write data word
509 add bx, #2
510 mov ax, 10[bp] ; data word
511 mov [bx], ax ; write data word
512 pop ds
513 pop bx
514 pop ax
515
516 pop bp
517 ASM_END
518 }
519
520 // Bit32u (unsigned long) and long helper functions
521 ASM_START
522
523 ;; and function
524 landl:
525 landul:
526 SEG SS
527 and ax,[di]
528 SEG SS
529 and bx,2[di]
530 ret
531
532 ;; add function
533 laddl:
534 laddul:
535 SEG SS
536 add ax,[di]
537 SEG SS
538 adc bx,2[di]
539 ret
540
541 ;; cmp function
542 lcmpl:
543 lcmpul:
544 and eax, #0x0000FFFF
545 shl ebx, #16
546 or eax, ebx
547 shr ebx, #16
548 SEG SS
549 cmp eax, dword ptr [di]
550 ret
551
552 ;; sub function
553 lsubl:
554 lsubul:
555 SEG SS
556 sub ax,[di]
557 SEG SS
558 sbb bx,2[di]
559 ret
560
561 ;; mul function
562 lmull:
563 lmulul:
564 and eax, #0x0000FFFF
565 shl ebx, #16
566 or eax, ebx
567 SEG SS
568 mul eax, dword ptr [di]
569 mov ebx, eax
570 shr ebx, #16
571 ret
572
573 ;; dec function
574 ldecl:
575 ldecul:
576 SEG SS
577 dec dword ptr [bx]
578 ret
579
580 ;; or function
581 lorl:
582 lorul:
583 SEG SS
584 or ax,[di]
585 SEG SS
586 or bx,2[di]
587 ret
588
589 ;; inc function
590 lincl:
591 lincul:
592 SEG SS
593 inc dword ptr [bx]
594 ret
595
596 ;; tst function
597 ltstl:
598 ltstul:
599 and eax, #0x0000FFFF
600 shl ebx, #16
601 or eax, ebx
602 shr ebx, #16
603 test eax, eax
604 ret
605
606 ;; sr function
607 lsrul:
608 mov cx,di
609 jcxz lsr_exit
610 and eax, #0x0000FFFF
611 shl ebx, #16
612 or eax, ebx
613 lsr_loop:
614 shr eax, #1
615 loop lsr_loop
616 mov ebx, eax
617 shr ebx, #16
618 lsr_exit:
619 ret
620
621 ;; sl function
622 lsll:
623 lslul:
624 mov cx,di
625 jcxz lsl_exit
626 and eax, #0x0000FFFF
627 shl ebx, #16
628 or eax, ebx
629 lsl_loop:
630 shl eax, #1
631 loop lsl_loop
632 mov ebx, eax
633 shr ebx, #16
634 lsl_exit:
635 ret
636
637 idiv_:
638 cwd
639 idiv bx
640 ret
641
642 idiv_u:
643 xor dx,dx
644 div bx
645 ret
646
647 ldivul:
648 and eax, #0x0000FFFF
649 shl ebx, #16
650 or eax, ebx
651 xor edx, edx
652 SEG SS
653 mov bx, 2[di]
654 shl ebx, #16
655 SEG SS
656 mov bx, [di]
657 div ebx
658 mov ebx, eax
659 shr ebx, #16
660 ret
661
662 ASM_END
663
664// for access to RAM area which is used by interrupt vectors
665// and BIOS Data Area
666
667typedef struct {
668 unsigned char filler1[0x400];
669 unsigned char filler2[0x6c];
670 Bit16u ticks_low;
671 Bit16u ticks_high;
672 Bit8u midnight_flag;
673 } bios_data_t;
674
675#define BiosData ((bios_data_t *) 0)
676
677#if BX_USE_ATADRV
678 typedef struct {
679 Bit16u heads; // # heads
680 Bit16u cylinders; // # cylinders
681 Bit16u spt; // # sectors / track
682 } chs_t;
683
684 // DPTE definition
685 typedef struct {
686 Bit16u iobase1;
687 Bit16u iobase2;
688 Bit8u prefix;
689 Bit8u unused;
690 Bit8u irq;
691 Bit8u blkcount;
692 Bit8u dma;
693 Bit8u pio;
694 Bit16u options;
695 Bit16u reserved;
696 Bit8u revision;
697 Bit8u checksum;
698 } dpte_t;
699
700 typedef struct {
701 Bit8u iface; // ISA or PCI
702 Bit16u iobase1; // IO Base 1
703 Bit16u iobase2; // IO Base 2
704 Bit8u irq; // IRQ
705 } ata_channel_t;
706
707 typedef struct {
708 Bit8u type; // Detected type of ata (ata/atapi/none/unknown/scsi)
709 Bit8u device; // Detected type of attached devices (hd/cd/none)
710 Bit8u removable; // Removable device flag
711 Bit8u lock; // Locks for removable devices
712 Bit8u mode; // transfer mode : PIO 16/32 bits - IRQ - ISADMA - PCIDMA
713 Bit16u blksize; // block size
714
715 Bit8u translation; // type of translation
716 chs_t lchs; // Logical CHS
717 chs_t pchs; // Physical CHS
718
719 Bit32u sectors; // Total sectors count
720 } ata_device_t;
721
722 typedef struct {
723 // ATA channels info
724 ata_channel_t channels[BX_MAX_ATA_INTERFACES];
725
726 // ATA devices info
727 ata_device_t devices[BX_MAX_ATA_DEVICES];
728 //
729 // map between (bios hd id - 0x80) and ata channels and scsi disks.
730 Bit8u hdcount, hdidmap[BX_MAX_STORAGE_DEVICES];
731
732 // map between (bios cd id - 0xE0) and ata channels
733 Bit8u cdcount, cdidmap[BX_MAX_STORAGE_DEVICES];
734
735 // Buffer for DPTE table
736 dpte_t dpte;
737
738 // Count of transferred sectors and bytes
739 Bit16u trsfsectors;
740 Bit32u trsfbytes;
741
742 } ata_t;
743
744#if BX_ELTORITO_BOOT
745 // ElTorito Device Emulation data
746 typedef struct {
747 Bit8u active;
748 Bit8u media;
749 Bit8u emulated_drive;
750 Bit8u controller_index;
751 Bit16u device_spec;
752 Bit32u ilba;
753 Bit16u buffer_segment;
754 Bit16u load_segment;
755 Bit16u sector_count;
756
757 // Virtual device
758 chs_t vdevice;
759 } cdemu_t;
760#endif // BX_ELTORITO_BOOT
761
762#ifdef VBOX_WITH_SCSI
763 typedef struct {
764 // I/O port this device is attached to.
765 Bit16u io_base;
766 // Target Id.
767 Bit8u target_id;
768 // SCSI devices info
769 ata_device_t device_info;
770 } scsi_device_t;
771
772 typedef struct {
773 // SCSi device info
774 scsi_device_t devices[BX_MAX_SCSI_DEVICES];
775 // Number of scsi disks.
776 Bit8u hdcount;
777 } scsi_t;
778#endif
779
780 // for access to EBDA area
781 // The EBDA structure should conform to
782 // http://www.frontiernet.net/~fys/rombios.htm document
783 // I made the ata and cdemu structs begin at 0x121 in the EBDA seg
784 typedef struct {
785 unsigned char filler1[0x3D];
786
787 // FDPT - Can be split into data members if needed
788 unsigned char fdpt0[0x10];
789 unsigned char fdpt1[0x10];
790
791 unsigned char filler2[0xC4];
792
793 // ATA Driver data
794 ata_t ata;
795
796#if BX_ELTORITO_BOOT
797 // El Torito Emulation data
798 cdemu_t cdemu;
799#endif // BX_ELTORITO_BOOT
800
801#ifdef VBOX
802
803#ifdef VBOX_WITH_SCSI
804 // SCSI Driver data
805 scsi_t scsi;
806# endif
807
808#ifdef VBOX_WITH_BIOS_AHCI
809 // AHCI driver data segment;
810 Bit16u SegAhci;
811#endif
812
813 unsigned char uForceBootDrive;
814 unsigned char uForceBootDevice;
815#endif /* VBOX */
816
817 } ebda_data_t;
818
819#ifdef VBOX
820 // the last 16 bytes of the EBDA segment are used for the MPS floating
821 // pointer structure (only if an IOAPIC is present)
822#endif
823
824 #define EbdaData ((ebda_data_t *) 0)
825
826 // for access to the int13ext structure
827 typedef struct {
828 Bit8u size;
829 Bit8u reserved;
830 Bit16u count;
831 Bit16u offset;
832 Bit16u segment;
833 Bit32u lba1;
834 Bit32u lba2;
835 } int13ext_t;
836
837 #define Int13Ext ((int13ext_t *) 0)
838
839 // Disk Physical Table definition
840 typedef struct {
841 Bit16u size;
842 Bit16u infos;
843 Bit32u cylinders;
844 Bit32u heads;
845 Bit32u spt;
846 Bit32u sector_count1;
847 Bit32u sector_count2;
848 Bit16u blksize;
849 Bit16u dpte_offset;
850 Bit16u dpte_segment;
851 Bit16u key;
852 Bit8u dpi_length;
853 Bit8u reserved1;
854 Bit16u reserved2;
855 Bit8u host_bus[4];
856 Bit8u iface_type[8];
857 Bit8u iface_path[8];
858 Bit8u device_path[8];
859 Bit8u reserved3;
860 Bit8u checksum;
861 } dpt_t;
862
863 #define Int13DPT ((dpt_t *) 0)
864
865#endif // BX_USE_ATADRV
866
867typedef struct {
868 union {
869 struct {
870 Bit16u di, si, bp, sp;
871 Bit16u bx, dx, cx, ax;
872 } r16;
873 struct {
874 Bit16u filler[4];
875 Bit8u bl, bh, dl, dh, cl, ch, al, ah;
876 } r8;
877 } u;
878 } pusha_regs_t;
879
880typedef struct {
881 union {
882 struct {
883 Bit32u edi, esi, ebp, esp;
884 Bit32u ebx, edx, ecx, eax;
885 } r32;
886 struct {
887 Bit16u di, filler1, si, filler2, bp, filler3, sp, filler4;
888 Bit16u bx, filler5, dx, filler6, cx, filler7, ax, filler8;
889 } r16;
890 struct {
891 Bit32u filler[4];
892 Bit8u bl, bh;
893 Bit16u filler1;
894 Bit8u dl, dh;
895 Bit16u filler2;
896 Bit8u cl, ch;
897 Bit16u filler3;
898 Bit8u al, ah;
899 Bit16u filler4;
900 } r8;
901 } u;
902} pushad_regs_t;
903
904typedef struct {
905 union {
906 struct {
907 Bit16u flags;
908 } r16;
909 struct {
910 Bit8u flagsl;
911 Bit8u flagsh;
912 } r8;
913 } u;
914 } flags_t;
915
916#define SetCF(x) x.u.r8.flagsl |= 0x01
917#define SetZF(x) x.u.r8.flagsl |= 0x40
918#define ClearCF(x) x.u.r8.flagsl &= 0xfe
919#define ClearZF(x) x.u.r8.flagsl &= 0xbf
920#define GetCF(x) (x.u.r8.flagsl & 0x01)
921
922typedef struct {
923 Bit16u ip;
924 Bit16u cs;
925 flags_t flags;
926 } iret_addr_t;
927
928
929
930static Bit8u inb();
931static Bit8u inb_cmos();
932static void outb();
933static void outb_cmos();
934static Bit16u inw();
935#ifdef VBOX_WITH_BIOS_AHCI
936static Bit32u inl();
937#endif
938static void outw();
939#ifdef VBOX_WITH_BIOS_AHCI
940static void outl();
941#endif
942static void init_rtc();
943static bx_bool rtc_updating();
944
945static Bit8u read_byte();
946static Bit16u read_word();
947static void write_byte();
948static void write_word();
949static void bios_printf();
950
951static Bit8u send_to_mouse_ctrl();
952static Bit8u get_mouse_data();
953static void set_kbd_command_byte();
954
955static void int09_function();
956static void int13_harddisk();
957static void int13_cdrom();
958static void int13_cdemu();
959static void int13_eltorito();
960static void int13_diskette_function();
961static void int14_function();
962static void int15_function();
963static void int16_function();
964static void int17_function();
965static Bit32u int19_function();
966static void int1a_function();
967static void int70_function();
968static void int74_function();
969static void dummy_isr_function();
970static Bit16u get_CS();
971static Bit16u get_SS();
972static unsigned int enqueue_key();
973static unsigned int dequeue_key();
974static void get_hd_geometry();
975static void set_diskette_ret_status();
976static void set_diskette_current_cyl();
977static void determine_floppy_media();
978static bx_bool floppy_drive_exists();
979static bx_bool floppy_drive_recal();
980static bx_bool floppy_media_known();
981static bx_bool floppy_media_sense();
982static bx_bool set_enable_a20();
983static void debugger_on();
984static void debugger_off();
985static void keyboard_init();
986static void keyboard_panic();
987static void shutdown_status_panic();
988static void nmi_handler_msg();
989
990static void print_bios_banner();
991static void print_boot_device();
992static void print_boot_failure();
993static void print_cdromboot_failure();
994
995# if BX_USE_ATADRV
996
997// ATA / ATAPI driver
998void ata_init();
999void ata_detect();
1000void ata_reset();
1001
1002Bit16u ata_cmd_non_data();
1003Bit16u ata_cmd_data_in();
1004Bit16u ata_cmd_data_out();
1005Bit16u ata_cmd_packet();
1006
1007Bit16u atapi_get_sense();
1008Bit16u atapi_is_ready();
1009Bit16u atapi_is_cdrom();
1010
1011#endif // BX_USE_ATADRV
1012
1013#if BX_ELTORITO_BOOT
1014
1015void cdemu_init();
1016Bit8u cdemu_isactive();
1017Bit8u cdemu_emulated_drive();
1018
1019Bit16u cdrom_boot();
1020
1021#endif // BX_ELTORITO_BOOT
1022
1023#ifdef VBOX
1024static char bios_prefix_string[] = "BIOS: ";
1025/* Do not use build timestamps in this string. Otherwise even rebuilding the
1026 * very same code will lead to compare errors when restoring saved state. */
1027static char bios_cvs_version_string[] = "VirtualBox " VBOX_VERSION_STRING;
1028#define BIOS_COPYRIGHT_STRING "Oracle VM VirtualBox BIOS"
1029#else /* !VBOX */
1030static char bios_cvs_version_string[] = "$Revision: 1.176 $ $Date: 2006/12/30 17:13:17 $";
1031
1032#define BIOS_COPYRIGHT_STRING "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team."
1033#endif /* !VBOX */
1034
1035#define BIOS_PRINTF_HALT 1
1036#define BIOS_PRINTF_SCREEN 2
1037#define BIOS_PRINTF_INFO 4
1038#define BIOS_PRINTF_DEBUG 8
1039#define BIOS_PRINTF_ALL (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO)
1040#define BIOS_PRINTF_DEBHALT (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO | BIOS_PRINTF_HALT)
1041
1042#define printf(format, p...) bios_printf(BIOS_PRINTF_SCREEN, format, ##p)
1043
1044// Defines the output macros.
1045// BX_DEBUG goes to INFO port until we can easily choose debug info on a
1046// per-device basis. Debug info are sent only in debug mode
1047#if DEBUG_ROMBIOS
1048# define BX_DEBUG(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
1049#else
1050# define BX_DEBUG(format, p...)
1051#endif
1052#ifdef VBOX
1053#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)
1054#else /* !VBOX */
1055#define BX_INFO(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
1056#endif /* !VBOX */
1057#define BX_PANIC(format, p...) bios_printf(BIOS_PRINTF_DEBHALT, format, ##p)
1058
1059#if DEBUG_ATA
1060# define BX_DEBUG_ATA(a...) BX_DEBUG(a)
1061#else
1062# define BX_DEBUG_ATA(a...)
1063#endif
1064#if DEBUG_INT13_HD
1065# define BX_DEBUG_INT13_HD(a...) BX_DEBUG(a)
1066#else
1067# define BX_DEBUG_INT13_HD(a...)
1068#endif
1069#if DEBUG_INT13_CD
1070# define BX_DEBUG_INT13_CD(a...) BX_DEBUG(a)
1071#else
1072# define BX_DEBUG_INT13_CD(a...)
1073#endif
1074#if DEBUG_INT13_ET
1075# define BX_DEBUG_INT13_ET(a...) BX_DEBUG(a)
1076#else
1077# define BX_DEBUG_INT13_ET(a...)
1078#endif
1079#if DEBUG_INT13_FL
1080# define BX_DEBUG_INT13_FL(a...) BX_DEBUG(a)
1081#else
1082# define BX_DEBUG_INT13_FL(a...)
1083#endif
1084#if DEBUG_INT15
1085# define BX_DEBUG_INT15(a...) BX_DEBUG(a)
1086#else
1087# define BX_DEBUG_INT15(a...)
1088#endif
1089#if DEBUG_INT16
1090# define BX_DEBUG_INT16(a...) BX_DEBUG(a)
1091#else
1092# define BX_DEBUG_INT16(a...)
1093#endif
1094#if DEBUG_INT1A
1095# define BX_DEBUG_INT1A(a...) BX_DEBUG(a)
1096#else
1097# define BX_DEBUG_INT1A(a...)
1098#endif
1099#if DEBUG_INT74
1100# define BX_DEBUG_INT74(a...) BX_DEBUG(a)
1101#else
1102# define BX_DEBUG_INT74(a...)
1103#endif
1104
1105#define SET_AL(val8) AX = ((AX & 0xff00) | (val8))
1106#define SET_BL(val8) BX = ((BX & 0xff00) | (val8))
1107#define SET_CL(val8) CX = ((CX & 0xff00) | (val8))
1108#define SET_DL(val8) DX = ((DX & 0xff00) | (val8))
1109#define SET_AH(val8) AX = ((AX & 0x00ff) | ((val8) << 8))
1110#define SET_BH(val8) BX = ((BX & 0x00ff) | ((val8) << 8))
1111#define SET_CH(val8) CX = ((CX & 0x00ff) | ((val8) << 8))
1112#define SET_DH(val8) DX = ((DX & 0x00ff) | ((val8) << 8))
1113
1114#define GET_AL() ( AX & 0x00ff )
1115#define GET_BL() ( BX & 0x00ff )
1116#define GET_CL() ( CX & 0x00ff )
1117#define GET_DL() ( DX & 0x00ff )
1118#define GET_AH() ( AX >> 8 )
1119#define GET_BH() ( BX >> 8 )
1120#define GET_CH() ( CX >> 8 )
1121#define GET_DH() ( DX >> 8 )
1122
1123#define GET_ELDL() ( ELDX & 0x00ff )
1124#define GET_ELDH() ( ELDX >> 8 )
1125
1126#define SET_CF() FLAGS |= 0x0001
1127#define CLEAR_CF() FLAGS &= 0xfffe
1128#define GET_CF() (FLAGS & 0x0001)
1129
1130#define SET_ZF() FLAGS |= 0x0040
1131#define CLEAR_ZF() FLAGS &= 0xffbf
1132#define GET_ZF() (FLAGS & 0x0040)
1133
1134#define UNSUPPORTED_FUNCTION 0x86
1135
1136#define none 0
1137#define MAX_SCAN_CODE 0x58
1138
1139static struct {
1140 Bit16u normal;
1141 Bit16u shift;
1142 Bit16u control;
1143 Bit16u alt;
1144 Bit8u lock_flags;
1145 } scan_to_scanascii[MAX_SCAN_CODE + 1] = {
1146 { none, none, none, none, none },
1147 { 0x011b, 0x011b, 0x011b, 0x0100, none }, /* escape */
1148 { 0x0231, 0x0221, none, 0x7800, none }, /* 1! */
1149 { 0x0332, 0x0340, 0x0300, 0x7900, none }, /* 2@ */
1150 { 0x0433, 0x0423, none, 0x7a00, none }, /* 3# */
1151 { 0x0534, 0x0524, none, 0x7b00, none }, /* 4$ */
1152 { 0x0635, 0x0625, none, 0x7c00, none }, /* 5% */
1153 { 0x0736, 0x075e, 0x071e, 0x7d00, none }, /* 6^ */
1154 { 0x0837, 0x0826, none, 0x7e00, none }, /* 7& */
1155 { 0x0938, 0x092a, none, 0x7f00, none }, /* 8* */
1156 { 0x0a39, 0x0a28, none, 0x8000, none }, /* 9( */
1157 { 0x0b30, 0x0b29, none, 0x8100, none }, /* 0) */
1158 { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200, none }, /* -_ */
1159 { 0x0d3d, 0x0d2b, none, 0x8300, none }, /* =+ */
1160 { 0x0e08, 0x0e08, 0x0e7f, none, none }, /* backspace */
1161 { 0x0f09, 0x0f00, none, none, none }, /* tab */
1162 { 0x1071, 0x1051, 0x1011, 0x1000, 0x40 }, /* Q */
1163 { 0x1177, 0x1157, 0x1117, 0x1100, 0x40 }, /* W */
1164 { 0x1265, 0x1245, 0x1205, 0x1200, 0x40 }, /* E */
1165 { 0x1372, 0x1352, 0x1312, 0x1300, 0x40 }, /* R */
1166 { 0x1474, 0x1454, 0x1414, 0x1400, 0x40 }, /* T */
1167 { 0x1579, 0x1559, 0x1519, 0x1500, 0x40 }, /* Y */
1168 { 0x1675, 0x1655, 0x1615, 0x1600, 0x40 }, /* U */
1169 { 0x1769, 0x1749, 0x1709, 0x1700, 0x40 }, /* I */
1170 { 0x186f, 0x184f, 0x180f, 0x1800, 0x40 }, /* O */
1171 { 0x1970, 0x1950, 0x1910, 0x1900, 0x40 }, /* P */
1172 { 0x1a5b, 0x1a7b, 0x1a1b, none, none }, /* [{ */
1173 { 0x1b5d, 0x1b7d, 0x1b1d, none, none }, /* ]} */
1174 { 0x1c0d, 0x1c0d, 0x1c0a, none, none }, /* Enter */
1175 { none, none, none, none, none }, /* L Ctrl */
1176 { 0x1e61, 0x1e41, 0x1e01, 0x1e00, 0x40 }, /* A */
1177 { 0x1f73, 0x1f53, 0x1f13, 0x1f00, 0x40 }, /* S */
1178 { 0x2064, 0x2044, 0x2004, 0x2000, 0x40 }, /* D */
1179 { 0x2166, 0x2146, 0x2106, 0x2100, 0x40 }, /* F */
1180 { 0x2267, 0x2247, 0x2207, 0x2200, 0x40 }, /* G */
1181 { 0x2368, 0x2348, 0x2308, 0x2300, 0x40 }, /* H */
1182 { 0x246a, 0x244a, 0x240a, 0x2400, 0x40 }, /* J */
1183 { 0x256b, 0x254b, 0x250b, 0x2500, 0x40 }, /* K */
1184 { 0x266c, 0x264c, 0x260c, 0x2600, 0x40 }, /* L */
1185 { 0x273b, 0x273a, none, none, none }, /* ;: */
1186 { 0x2827, 0x2822, none, none, none }, /* '" */
1187 { 0x2960, 0x297e, none, none, none }, /* `~ */
1188 { none, none, none, none, none }, /* L shift */
1189 { 0x2b5c, 0x2b7c, 0x2b1c, none, none }, /* |\ */
1190 { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, 0x40 }, /* Z */
1191 { 0x2d78, 0x2d58, 0x2d18, 0x2d00, 0x40 }, /* X */
1192 { 0x2e63, 0x2e43, 0x2e03, 0x2e00, 0x40 }, /* C */
1193 { 0x2f76, 0x2f56, 0x2f16, 0x2f00, 0x40 }, /* V */
1194 { 0x3062, 0x3042, 0x3002, 0x3000, 0x40 }, /* B */
1195 { 0x316e, 0x314e, 0x310e, 0x3100, 0x40 }, /* N */
1196 { 0x326d, 0x324d, 0x320d, 0x3200, 0x40 }, /* M */
1197 { 0x332c, 0x333c, none, none, none }, /* ,< */
1198 { 0x342e, 0x343e, none, none, none }, /* .> */
1199 { 0x352f, 0x353f, none, none, none }, /* /? */
1200 { none, none, none, none, none }, /* R Shift */
1201 { 0x372a, 0x372a, none, none, none }, /* * */
1202 { none, none, none, none, none }, /* L Alt */
1203 { 0x3920, 0x3920, 0x3920, 0x3920, none }, /* space */
1204 { none, none, none, none, none }, /* caps lock */
1205 { 0x3b00, 0x5400, 0x5e00, 0x6800, none }, /* F1 */
1206 { 0x3c00, 0x5500, 0x5f00, 0x6900, none }, /* F2 */
1207 { 0x3d00, 0x5600, 0x6000, 0x6a00, none }, /* F3 */
1208 { 0x3e00, 0x5700, 0x6100, 0x6b00, none }, /* F4 */
1209 { 0x3f00, 0x5800, 0x6200, 0x6c00, none }, /* F5 */
1210 { 0x4000, 0x5900, 0x6300, 0x6d00, none }, /* F6 */
1211 { 0x4100, 0x5a00, 0x6400, 0x6e00, none }, /* F7 */
1212 { 0x4200, 0x5b00, 0x6500, 0x6f00, none }, /* F8 */
1213 { 0x4300, 0x5c00, 0x6600, 0x7000, none }, /* F9 */
1214 { 0x4400, 0x5d00, 0x6700, 0x7100, none }, /* F10 */
1215 { none, none, none, none, none }, /* Num Lock */
1216 { none, none, none, none, none }, /* Scroll Lock */
1217 { 0x4700, 0x4737, 0x7700, none, 0x20 }, /* 7 Home */
1218 { 0x4800, 0x4838, none, none, 0x20 }, /* 8 UP */
1219 { 0x4900, 0x4939, 0x8400, none, 0x20 }, /* 9 PgUp */
1220 { 0x4a2d, 0x4a2d, none, none, none }, /* - */
1221 { 0x4b00, 0x4b34, 0x7300, none, 0x20 }, /* 4 Left */
1222 { 0x4c00, 0x4c35, none, none, 0x20 }, /* 5 */
1223 { 0x4d00, 0x4d36, 0x7400, none, 0x20 }, /* 6 Right */
1224 { 0x4e2b, 0x4e2b, none, none, none }, /* + */
1225 { 0x4f00, 0x4f31, 0x7500, none, 0x20 }, /* 1 End */
1226 { 0x5000, 0x5032, none, none, 0x20 }, /* 2 Down */
1227 { 0x5100, 0x5133, 0x7600, none, 0x20 }, /* 3 PgDn */
1228 { 0x5200, 0x5230, none, none, 0x20 }, /* 0 Ins */
1229 { 0x5300, 0x532e, none, none, 0x20 }, /* Del */
1230 { none, none, none, none, none },
1231 { none, none, none, none, none },
1232 { 0x565c, 0x567c, none, none, none }, /* \| */
1233#ifndef VBOX
1234 { 0x5700, 0x5700, none, none, none }, /* F11 */
1235 { 0x5800, 0x5800, none, none, none } /* F12 */
1236#else
1237 { 0x8500, 0x8700, 0x8900, 0x8b00, none }, /* F11 */
1238 { 0x8600, 0x8800, 0x8a00, 0x8c00, none } /* F12 */
1239#endif
1240 };
1241
1242 Bit8u
1243inb(port)
1244 Bit16u port;
1245{
1246ASM_START
1247 push bp
1248 mov bp, sp
1249
1250 push dx
1251 mov dx, 4[bp]
1252 in al, dx
1253 pop dx
1254
1255 pop bp
1256ASM_END
1257}
1258
1259#if BX_USE_ATADRV
1260 Bit16u
1261inw(port)
1262 Bit16u port;
1263{
1264ASM_START
1265 push bp
1266 mov bp, sp
1267
1268 push dx
1269 mov dx, 4[bp]
1270 in ax, dx
1271 pop dx
1272
1273 pop bp
1274ASM_END
1275}
1276#endif
1277
1278#ifdef VBOX_WITH_BIOS_AHCI
1279 Bit32u
1280inl(port)
1281 Bit16u port;
1282{
1283ASM_START
1284 push bp
1285 mov bp, sp
1286
1287 push bx
1288 mov dx, 4[bp]
1289 in eax, dx
1290 mov bx, ax ; Save lower 16 bits
1291 shr eax, #16
1292 mov dx, ax
1293 mov ax, bx
1294 pop bx
1295
1296 pop bp
1297ASM_END
1298}
1299#endif
1300
1301 void
1302outb(port, val)
1303 Bit16u port;
1304 Bit8u val;
1305{
1306ASM_START
1307 push bp
1308 mov bp, sp
1309
1310 push ax
1311 push dx
1312 mov dx, 4[bp]
1313 mov al, 6[bp]
1314 out dx, al
1315 pop dx
1316 pop ax
1317
1318 pop bp
1319ASM_END
1320}
1321
1322#if BX_USE_ATADRV
1323 void
1324outw(port, val)
1325 Bit16u port;
1326 Bit16u val;
1327{
1328ASM_START
1329 push bp
1330 mov bp, sp
1331
1332 push ax
1333 push dx
1334 mov dx, 4[bp]
1335 mov ax, 6[bp]
1336 out dx, ax
1337 pop dx
1338 pop ax
1339
1340 pop bp
1341ASM_END
1342}
1343#endif
1344
1345#ifdef VBOX_WITH_BIOS_AHCI
1346 void
1347outl(port, val)
1348 Bit16u port;
1349 Bit32u val;
1350{
1351ASM_START
1352 push bp
1353 mov bp, sp
1354
1355 push eax
1356 push dx
1357 mov dx, _outl.port + 2[bp]
1358 mov eax, _outl.val + 2[bp]
1359 out dx, eax
1360 pop dx
1361 pop eax
1362
1363 pop bp
1364ASM_END
1365}
1366#endif
1367
1368 void
1369outb_cmos(cmos_reg, val)
1370 Bit8u cmos_reg;
1371 Bit8u val;
1372{
1373ASM_START
1374 push bp
1375 mov bp, sp
1376
1377 mov al, 4[bp] ;; cmos_reg
1378 out 0x70, al
1379 mov al, 6[bp] ;; val
1380 out 0x71, al
1381
1382 pop bp
1383ASM_END
1384}
1385
1386 Bit8u
1387inb_cmos(cmos_reg)
1388 Bit8u cmos_reg;
1389{
1390ASM_START
1391 push bp
1392 mov bp, sp
1393
1394 mov al, 4[bp] ;; cmos_reg
1395 out 0x70, al
1396 in al, 0x71
1397
1398 pop bp
1399ASM_END
1400}
1401
1402 void
1403init_rtc()
1404{
1405 outb_cmos(0x0a, 0x26);
1406 outb_cmos(0x0b, 0x02);
1407 inb_cmos(0x0c);
1408 inb_cmos(0x0d);
1409}
1410
1411 bx_bool
1412rtc_updating()
1413{
1414 // This function checks to see if the update-in-progress bit
1415 // is set in CMOS Status Register A. If not, it returns 0.
1416 // If it is set, it tries to wait until there is a transition
1417 // to 0, and will return 0 if such a transition occurs. A 1
1418 // is returned only after timing out. The maximum period
1419 // that this bit should be set is constrained to 244useconds.
1420 // The count I use below guarantees coverage or more than
1421 // this time, with any reasonable IPS setting.
1422
1423 Bit16u count;
1424
1425 count = 25000;
1426 while (--count != 0) {
1427 if ( (inb_cmos(0x0a) & 0x80) == 0 )
1428 return(0);
1429 }
1430 return(1); // update-in-progress never transitioned to 0
1431}
1432
1433
1434 Bit8u
1435read_byte(seg, offset)
1436 Bit16u seg;
1437 Bit16u offset;
1438{
1439ASM_START
1440 push bp
1441 mov bp, sp
1442
1443 push bx
1444 push ds
1445 mov ax, 4[bp] ; segment
1446 mov ds, ax
1447 mov bx, 6[bp] ; offset
1448 mov al, [bx]
1449 ;; al = return value (byte)
1450 pop ds
1451 pop bx
1452
1453 pop bp
1454ASM_END
1455}
1456
1457 Bit16u
1458read_word(seg, offset)
1459 Bit16u seg;
1460 Bit16u offset;
1461{
1462ASM_START
1463 push bp
1464 mov bp, sp
1465
1466 push bx
1467 push ds
1468 mov ax, 4[bp] ; segment
1469 mov ds, ax
1470 mov bx, 6[bp] ; offset
1471 mov ax, [bx]
1472 ;; ax = return value (word)
1473 pop ds
1474 pop bx
1475
1476 pop bp
1477ASM_END
1478}
1479
1480 void
1481write_byte(seg, offset, data)
1482 Bit16u seg;
1483 Bit16u offset;
1484 Bit8u data;
1485{
1486ASM_START
1487 push bp
1488 mov bp, sp
1489
1490 push ax
1491 push bx
1492 push ds
1493 mov ax, 4[bp] ; segment
1494 mov ds, ax
1495 mov bx, 6[bp] ; offset
1496 mov al, 8[bp] ; data byte
1497 mov [bx], al ; write data byte
1498 pop ds
1499 pop bx
1500 pop ax
1501
1502 pop bp
1503ASM_END
1504}
1505
1506 void
1507write_word(seg, offset, data)
1508 Bit16u seg;
1509 Bit16u offset;
1510 Bit16u data;
1511{
1512ASM_START
1513 push bp
1514 mov bp, sp
1515
1516 push ax
1517 push bx
1518 push ds
1519 mov ax, 4[bp] ; segment
1520 mov ds, ax
1521 mov bx, 6[bp] ; offset
1522 mov ax, 8[bp] ; data word
1523 mov [bx], ax ; write data word
1524 pop ds
1525 pop bx
1526 pop ax
1527
1528 pop bp
1529ASM_END
1530}
1531
1532 Bit16u
1533get_CS()
1534{
1535ASM_START
1536 mov ax, cs
1537ASM_END
1538}
1539
1540 Bit16u
1541get_SS()
1542{
1543ASM_START
1544 mov ax, ss
1545ASM_END
1546}
1547
1548#if BX_DEBUG_SERIAL
1549/* serial debug port*/
1550#define BX_DEBUG_PORT 0x03f8
1551
1552/* data */
1553#define UART_RBR 0x00
1554#define UART_THR 0x00
1555
1556/* control */
1557#define UART_IER 0x01
1558#define UART_IIR 0x02
1559#define UART_FCR 0x02
1560#define UART_LCR 0x03
1561#define UART_MCR 0x04
1562#define UART_DLL 0x00
1563#define UART_DLM 0x01
1564
1565/* status */
1566#define UART_LSR 0x05
1567#define UART_MSR 0x06
1568#define UART_SCR 0x07
1569
1570int uart_can_tx_byte(base_port)
1571 Bit16u base_port;
1572{
1573 return inb(base_port + UART_LSR) & 0x20;
1574}
1575
1576void uart_wait_to_tx_byte(base_port)
1577 Bit16u base_port;
1578{
1579 while (!uart_can_tx_byte(base_port));
1580}
1581
1582void uart_wait_until_sent(base_port)
1583 Bit16u base_port;
1584{
1585 while (!(inb(base_port + UART_LSR) & 0x40));
1586}
1587
1588void uart_tx_byte(base_port, data)
1589 Bit16u base_port;
1590 Bit8u data;
1591{
1592 uart_wait_to_tx_byte(base_port);
1593 outb(base_port + UART_THR, data);
1594 uart_wait_until_sent(base_port);
1595}
1596#endif
1597
1598 void
1599wrch(c)
1600 Bit8u c;
1601{
1602 ASM_START
1603 push bp
1604 mov bp, sp
1605
1606 push bx
1607 mov ah, #0x0e
1608 mov al, 4[bp]
1609 xor bx,bx
1610 int #0x10
1611 pop bx
1612
1613 pop bp
1614 ASM_END
1615}
1616
1617 void
1618send(action, c)
1619 Bit16u action;
1620 Bit8u c;
1621{
1622#if BX_DEBUG_SERIAL
1623 if (c == '\n') uart_tx_byte(BX_DEBUG_PORT, '\r');
1624 uart_tx_byte(BX_DEBUG_PORT, c);
1625#endif
1626#if BX_VIRTUAL_PORTS
1627 if (action & BIOS_PRINTF_DEBUG) outb(DEBUG_PORT, c);
1628 if (action & BIOS_PRINTF_INFO) outb(INFO_PORT, c);
1629#endif
1630 if (action & BIOS_PRINTF_SCREEN) {
1631 if (c == '\n') wrch('\r');
1632 wrch(c);
1633 }
1634}
1635
1636 void
1637put_int(action, val, width, neg)
1638 Bit16u action;
1639 short val, width;
1640 bx_bool neg;
1641{
1642 short nval = val / 10;
1643 if (nval)
1644 put_int(action, nval, width - 1, neg);
1645 else {
1646 while (--width > 0) send(action, ' ');
1647 if (neg) send(action, '-');
1648 }
1649 send(action, val - (nval * 10) + '0');
1650}
1651
1652 void
1653put_uint(action, val, width, neg)
1654 Bit16u action;
1655 unsigned short val;
1656 short width;
1657 bx_bool neg;
1658{
1659 unsigned short nval = val / 10;
1660 if (nval)
1661 put_uint(action, nval, width - 1, neg);
1662 else {
1663 while (--width > 0) send(action, ' ');
1664 if (neg) send(action, '-');
1665 }
1666 send(action, val - (nval * 10) + '0');
1667}
1668
1669 void
1670put_luint(action, val, width, neg)
1671 Bit16u action;
1672 unsigned long val;
1673 short width;
1674 bx_bool neg;
1675{
1676 unsigned long nval = val / 10;
1677 if (nval)
1678 put_luint(action, nval, width - 1, neg);
1679 else {
1680 while (--width > 0) send(action, ' ');
1681 if (neg) send(action, '-');
1682 }
1683 send(action, val - (nval * 10) + '0');
1684}
1685
1686void put_str(action, segment, offset)
1687 Bit16u action;
1688 Bit16u segment;
1689 Bit16u offset;
1690{
1691 Bit8u c;
1692
1693 while (c = read_byte(segment, offset)) {
1694 send(action, c);
1695 offset++;
1696 }
1697}
1698
1699
1700//--------------------------------------------------------------------------
1701// bios_printf()
1702// A compact variable argument printf function.
1703//
1704// Supports %[format_width][length]format
1705// where format can be x,X,u,d,s,S,c
1706// and the optional length modifier is l (ell)
1707//--------------------------------------------------------------------------
1708 void
1709bios_printf(action, s)
1710 Bit16u action;
1711 Bit8u *s;
1712{
1713 Bit8u c, format_char;
1714 bx_bool in_format;
1715 short i;
1716 Bit16u *arg_ptr;
1717 Bit16u arg_seg, arg, nibble, hibyte, shift_count, format_width, hexadd;
1718
1719 arg_ptr = &s;
1720 arg_seg = get_SS();
1721
1722 in_format = 0;
1723 format_width = 0;
1724
1725 if ((action & BIOS_PRINTF_DEBHALT) == BIOS_PRINTF_DEBHALT) {
1726#if BX_VIRTUAL_PORTS
1727 outb(PANIC_PORT2, 0x00);
1728#endif
1729 bios_printf (BIOS_PRINTF_SCREEN, "FATAL: ");
1730 }
1731
1732 while (c = read_byte(get_CS(), s)) {
1733 if ( c == '%' ) {
1734 in_format = 1;
1735 format_width = 0;
1736 }
1737 else if (in_format) {
1738 if ( (c>='0') && (c<='9') ) {
1739 format_width = (format_width * 10) + (c - '0');
1740 }
1741 else {
1742 arg_ptr++; // increment to next arg
1743 arg = read_word(arg_seg, arg_ptr);
1744 if (c == 'x' || c == 'X') {
1745 if (format_width == 0)
1746 format_width = 4;
1747 if (c == 'x')
1748 hexadd = 'a';
1749 else
1750 hexadd = 'A';
1751 for (i=format_width-1; i>=0; i--) {
1752 nibble = (arg >> (4 * i)) & 0x000f;
1753 send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd));
1754 }
1755 }
1756 else if (c == 'u') {
1757 put_uint(action, arg, format_width, 0);
1758 }
1759 else if (c == 'l') {
1760 s++;
1761 c = read_byte(get_CS(), s); /* is it ld,lx,lu? */
1762 arg_ptr++; /* increment to next arg */
1763 hibyte = read_word(arg_seg, arg_ptr);
1764 if (c == 'd') {
1765 if (hibyte & 0x8000)
1766 put_luint(action, 0L-(((Bit32u) hibyte << 16) | arg), format_width-1, 1);
1767 else
1768 put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
1769 }
1770 else if (c == 'u') {
1771 put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
1772 }
1773 else if (c == 'x' || c == 'X')
1774 {
1775 if (format_width == 0)
1776 format_width = 8;
1777 if (c == 'x')
1778 hexadd = 'a';
1779 else
1780 hexadd = 'A';
1781 for (i=format_width-1; i>=0; i--) {
1782 nibble = ((((Bit32u) hibyte <<16) | arg) >> (4 * i)) & 0x000f;
1783 send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd));
1784 }
1785 }
1786 }
1787 else if (c == 'd') {
1788 if (arg & 0x8000)
1789 put_int(action, -arg, format_width - 1, 1);
1790 else
1791 put_int(action, arg, format_width, 0);
1792 }
1793 else if (c == 's') {
1794 put_str(action, get_CS(), arg);
1795 }
1796 else if (c == 'S') {
1797 hibyte = arg;
1798 arg_ptr++;
1799 arg = read_word(arg_seg, arg_ptr);
1800 put_str(action, hibyte, arg);
1801 }
1802 else if (c == 'c') {
1803 send(action, arg);
1804 }
1805 else
1806 BX_PANIC("bios_printf: unknown format\n");
1807 in_format = 0;
1808 }
1809 }
1810 else {
1811 send(action, c);
1812 }
1813 s ++;
1814 }
1815
1816 if (action & BIOS_PRINTF_HALT) {
1817 // freeze in a busy loop.
1818ASM_START
1819 cli
1820 halt2_loop:
1821 hlt
1822 jmp halt2_loop
1823ASM_END
1824 }
1825}
1826
1827//--------------------------------------------------------------------------
1828// keyboard_init
1829//--------------------------------------------------------------------------
1830// this file is based on LinuxBIOS implementation of keyboard.c
1831// could convert to #asm to gain space
1832 void
1833keyboard_init()
1834{
1835 Bit16u max;
1836
1837 /* ------------------- Flush buffers ------------------------*/
1838 /* Wait until buffer is empty */
1839 max=0xffff;
1840 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
1841
1842 /* flush incoming keys */
1843 max=8;
1844 while (--max > 0) {
1845 outb(0x80, 0x00);
1846 if (inb(0x64) & 0x01) {
1847 inb(0x60);
1848 max = 8;
1849 }
1850 }
1851
1852 // Due to timer issues, and if the IPS setting is > 15000000,
1853 // the incoming keys might not be flushed here. That will
1854 // cause a panic a few lines below. See sourceforge bug report :
1855 // [ 642031 ] FATAL: Keyboard RESET error:993
1856
1857 /* ------------------- controller side ----------------------*/
1858 /* send cmd = 0xAA, self test 8042 */
1859 outb(0x64, 0xaa);
1860
1861 /* Wait until buffer is empty */
1862 max=0xffff;
1863 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
1864 if (max==0x0) keyboard_panic(00);
1865
1866 /* Wait for data */
1867 max=0xffff;
1868 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x01);
1869 if (max==0x0) keyboard_panic(01);
1870
1871 /* read self-test result, 0x55 should be returned from 0x60 */
1872 if ((inb(0x60) != 0x55)){
1873 keyboard_panic(991);
1874 }
1875
1876 /* send cmd = 0xAB, keyboard interface test */
1877 outb(0x64,0xab);
1878
1879 /* Wait until buffer is empty */
1880 max=0xffff;
1881 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x10);
1882 if (max==0x0) keyboard_panic(10);
1883
1884 /* Wait for data */
1885 max=0xffff;
1886 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x11);
1887 if (max==0x0) keyboard_panic(11);
1888
1889 /* read keyboard interface test result, */
1890 /* 0x00 should be returned form 0x60 */
1891 if ((inb(0x60) != 0x00)) {
1892 keyboard_panic(992);
1893 }
1894
1895 /* ------------------- keyboard side ------------------------*/
1896 /* reset keyboard and self test (keyboard side) */
1897 outb(0x60, 0xff);
1898
1899 /* Wait until buffer is empty */
1900 max=0xffff;
1901 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x20);
1902 if (max==0x0) keyboard_panic(20);
1903
1904 /* Wait for data */
1905 max=0xffff;
1906 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x21);
1907 if (max==0x0) keyboard_panic(21);
1908
1909 /* keyboard should return ACK */
1910 if ((inb(0x60) != 0xfa)) {
1911 keyboard_panic(993);
1912 }
1913
1914 /* Wait for data */
1915 max=0xffff;
1916 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x31);
1917 if (max==0x0) keyboard_panic(31);
1918
1919 if ((inb(0x60) != 0xaa)) {
1920 keyboard_panic(994);
1921 }
1922
1923 /* Disable keyboard */
1924 outb(0x60, 0xf5);
1925
1926 /* Wait until buffer is empty */
1927 max=0xffff;
1928 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x40);
1929 if (max==0x0) keyboard_panic(40);
1930
1931 /* Wait for data */
1932 max=0xffff;
1933 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x41);
1934 if (max==0x0) keyboard_panic(41);
1935
1936 /* keyboard should return ACK */
1937 if ((inb(0x60) != 0xfa)) {
1938 keyboard_panic(995);
1939 }
1940
1941 /* Write Keyboard Mode */
1942 outb(0x64, 0x60);
1943
1944 /* Wait until buffer is empty */
1945 max=0xffff;
1946 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x50);
1947 if (max==0x0) keyboard_panic(50);
1948
1949 /* send cmd: scan code convert, disable mouse, enable IRQ 1 */
1950 outb(0x60, 0x65);
1951
1952 /* Wait until buffer is empty */
1953 max=0xffff;
1954 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x60);
1955 if (max==0x0) keyboard_panic(60);
1956
1957 /* Enable keyboard */
1958 outb(0x60, 0xf4);
1959
1960 /* Wait until buffer is empty */
1961 max=0xffff;
1962 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x70);
1963 if (max==0x0) keyboard_panic(70);
1964
1965 /* Wait for data */
1966 max=0xffff;
1967 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x71);
1968 if (max==0x0) keyboard_panic(70);
1969
1970 /* keyboard should return ACK */
1971 if ((inb(0x60) != 0xfa)) {
1972 keyboard_panic(996);
1973 }
1974
1975 /* Enable Keyboard clock */
1976 outb(0x64,0xae);
1977 outb(0x64,0xa8);
1978
1979 outb(0x80, 0x77);
1980}
1981
1982//--------------------------------------------------------------------------
1983// keyboard_panic
1984//--------------------------------------------------------------------------
1985 void
1986keyboard_panic(status)
1987 Bit16u status;
1988{
1989 // If you're getting a 993 keyboard panic here,
1990 // please see the comment in keyboard_init
1991
1992 BX_PANIC("Keyboard error:%u\n",status);
1993}
1994
1995//--------------------------------------------------------------------------
1996// shutdown_status_panic
1997// called when the shutdown status is not implemented, displays the status
1998//--------------------------------------------------------------------------
1999 void
2000shutdown_status_panic(status)
2001 Bit16u status;
2002{
2003 BX_PANIC("Unimplemented shutdown status: %02x\n",(Bit8u)status);
2004}
2005
2006#ifdef VBOX
2007#include "logo.c"
2008#endif /* VBOX */
2009
2010//--------------------------------------------------------------------------
2011// print_bios_banner
2012// displays a the bios version
2013//--------------------------------------------------------------------------
2014void
2015print_bios_banner()
2016{
2017#ifdef VBOX
2018 // Skip the logo if a warm boot is requested.
2019 Bit16u warm_boot = read_word(0x0040,0x0072);
2020 write_word(0x0040,0x0072, 0);
2021 if (warm_boot == 0x1234)
2022 return;
2023 /* show graphical logo */
2024 show_logo();
2025#else /* !VBOX */
2026 printf(BX_APPNAME" BIOS - build: %s\n%s\nOptions: ",
2027 BIOS_BUILD_DATE, bios_cvs_version_string);
2028 printf(
2029#if BX_APM
2030 "apmbios "
2031#endif
2032#if BX_PCIBIOS
2033 "pcibios "
2034#endif
2035#if BX_ELTORITO_BOOT
2036 "eltorito "
2037#endif
2038#if BX_ROMBIOS32
2039 "rombios32 "
2040#endif
2041 "\n\n");
2042#endif /* VBOX */
2043}
2044
2045//--------------------------------------------------------------------------
2046// print_boot_device
2047// displays the boot device
2048//--------------------------------------------------------------------------
2049
2050#ifdef VBOX
2051static char drivetypes[][10]={"Floppy","Hard Disk","CD-ROM","LAN"};
2052#else /* !VBOX */
2053static char drivetypes[][10]={"Floppy","Hard Disk","CD-Rom"};
2054#endif /* !VBOX */
2055
2056#ifdef VBOX
2057void
2058print_boot_device(cdboot, lanboot, drive)
2059 Bit8u cdboot; Bit8u lanboot; Bit16u drive;
2060#else /* !VBOX */
2061void
2062print_boot_device(cdboot, drive)
2063 Bit8u cdboot; Bit16u drive;
2064#endif /* !VBOX */
2065{
2066 Bit8u i;
2067
2068#ifdef VBOX
2069 // cdboot contains 0 if lan/floppy/harddisk, 1 otherwise
2070 // lanboot contains 0 if floppy/harddisk, 1 otherwise
2071#else /* !VBOX */
2072 // cdboot contains 0 if floppy/harddisk, 1 otherwise
2073#endif /* !VBOX */
2074 // drive contains real/emulated boot drive
2075
2076 if(cdboot)i=2; // CD-Rom
2077#ifdef VBOX
2078 else if(lanboot)i=3; // LAN
2079#endif /* VBOX */
2080 else if((drive&0x0080)==0x00)i=0; // Floppy
2081 else if((drive&0x0080)==0x80)i=1; // Hard drive
2082 else return;
2083
2084#ifdef VBOX
2085 BX_INFO("Booting from %s...\n",drivetypes[i]);
2086#else /* !VBOX */
2087 printf("Booting from %s...\n",drivetypes[i]);
2088#endif /* !VBOX */
2089}
2090
2091//--------------------------------------------------------------------------
2092// print_boot_failure
2093// displays the reason why boot failed
2094//--------------------------------------------------------------------------
2095#ifdef VBOX
2096 void
2097print_boot_failure(cdboot, lanboot, drive, reason, lastdrive)
2098 Bit8u cdboot; Bit8u lanboot; Bit8u drive; Bit8u reason; Bit8u lastdrive;
2099#else /* !VBOX */
2100 void
2101print_boot_failure(cdboot, drive, reason, lastdrive)
2102 Bit8u cdboot; Bit8u drive; Bit8u lastdrive;
2103#endif /* !VBOX */
2104{
2105 Bit16u drivenum = drive&0x7f;
2106
2107 // cdboot: 1 if boot from cd, 0 otherwise
2108#ifdef VBOX
2109 // lanboot: 1 if boot from lan, 0 otherwise
2110#endif /* VBOX */
2111 // drive : drive number
2112 // reason: 0 signature check failed, 1 read error
2113 // lastdrive: 1 boot drive is the last one in boot sequence
2114
2115 if (cdboot)
2116#ifndef VBOX
2117 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s failed\n",drivetypes[2]);
2118#else /* VBOX */
2119 BX_INFO("Boot from %s failed\n",drivetypes[2]);
2120 else if (lanboot)
2121 BX_INFO("Boot from %s failed\n",drivetypes[3]);
2122#endif /* VBOX */
2123 else if (drive & 0x80)
2124#ifndef VBOX
2125 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[1],drivenum);
2126#else /* VBOX */
2127 BX_INFO("Boot from %s %d failed\n", drivetypes[1],drivenum);
2128#endif /* VBOX */
2129 else
2130#ifndef VBOX
2131 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[0],drivenum);
2132#else /* VBOX */
2133 BX_INFO("Boot from %s %d failed\n", drivetypes[0],drivenum);
2134#endif /* VBOX */
2135
2136 if (lastdrive==1) {
2137 if (reason==0)
2138#ifndef VBOX
2139 BX_PANIC("Not a bootable disk\n");
2140#else /* VBOX */
2141 BX_PANIC("No bootable medium found! System halted.\n");
2142#endif /* VBOX */
2143 else
2144#ifndef VBOX
2145 BX_PANIC("Could not read the boot disk\n");
2146#else /* VBOX */
2147 BX_PANIC("Could not read from the boot medium! System halted.\n");
2148#endif /* VBOX */
2149 }
2150}
2151
2152//--------------------------------------------------------------------------
2153// print_cdromboot_failure
2154// displays the reason why boot failed
2155//--------------------------------------------------------------------------
2156 void
2157print_cdromboot_failure( code )
2158 Bit16u code;
2159{
2160#ifndef VBOX
2161 bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "CDROM boot failure code : %04x\n",code);
2162#else /* VBOX */
2163 BX_INFO("CDROM boot failure code : %04x\n",code);
2164#endif /* VBOX */
2165
2166 return;
2167}
2168
2169void
2170nmi_handler_msg()
2171{
2172 BX_PANIC("NMI Handler called\n");
2173}
2174
2175void
2176int18_panic_msg()
2177{
2178 BX_PANIC("INT18: BOOT FAILURE\n");
2179}
2180
2181void
2182log_bios_start()
2183{
2184#if BX_DEBUG_SERIAL
2185 outb(BX_DEBUG_PORT+UART_LCR, 0x03); /* setup for serial logging: 8N1 */
2186#endif
2187 BX_INFO("%s\n", bios_cvs_version_string);
2188}
2189
2190 bx_bool
2191set_enable_a20(val)
2192 bx_bool val;
2193{
2194 Bit8u oldval;
2195
2196 // Use PS2 System Control port A to set A20 enable
2197
2198 // get current setting first
2199 oldval = inb(0x92);
2200
2201 // change A20 status
2202 if (val)
2203 outb(0x92, oldval | 0x02);
2204 else
2205 outb(0x92, oldval & 0xfd);
2206
2207 return((oldval & 0x02) != 0);
2208}
2209
2210 void
2211debugger_on()
2212{
2213 outb(0xfedc, 0x01);
2214}
2215
2216 void
2217debugger_off()
2218{
2219 outb(0xfedc, 0x00);
2220}
2221
2222#if BX_USE_ATADRV
2223
2224// ---------------------------------------------------------------------------
2225// Start of ATA/ATAPI Driver
2226// ---------------------------------------------------------------------------
2227
2228// Global defines -- ATA register and register bits.
2229// command block & control block regs
2230#define ATA_CB_DATA 0 // data reg in/out pio_base_addr1+0
2231#define ATA_CB_ERR 1 // error in pio_base_addr1+1
2232#define ATA_CB_FR 1 // feature reg out pio_base_addr1+1
2233#define ATA_CB_SC 2 // sector count in/out pio_base_addr1+2
2234#define ATA_CB_SN 3 // sector number in/out pio_base_addr1+3
2235#define ATA_CB_CL 4 // cylinder low in/out pio_base_addr1+4
2236#define ATA_CB_CH 5 // cylinder high in/out pio_base_addr1+5
2237#define ATA_CB_DH 6 // device head in/out pio_base_addr1+6
2238#define ATA_CB_STAT 7 // primary status in pio_base_addr1+7
2239#define ATA_CB_CMD 7 // command out pio_base_addr1+7
2240#define ATA_CB_ASTAT 6 // alternate status in pio_base_addr2+6
2241#define ATA_CB_DC 6 // device control out pio_base_addr2+6
2242#define ATA_CB_DA 7 // device address in pio_base_addr2+7
2243
2244#define ATA_CB_ER_ICRC 0x80 // ATA Ultra DMA bad CRC
2245#define ATA_CB_ER_BBK 0x80 // ATA bad block
2246#define ATA_CB_ER_UNC 0x40 // ATA uncorrected error
2247#define ATA_CB_ER_MC 0x20 // ATA media change
2248#define ATA_CB_ER_IDNF 0x10 // ATA id not found
2249#define ATA_CB_ER_MCR 0x08 // ATA media change request
2250#define ATA_CB_ER_ABRT 0x04 // ATA command aborted
2251#define ATA_CB_ER_NTK0 0x02 // ATA track 0 not found
2252#define ATA_CB_ER_NDAM 0x01 // ATA address mark not found
2253
2254#define ATA_CB_ER_P_SNSKEY 0xf0 // ATAPI sense key (mask)
2255#define ATA_CB_ER_P_MCR 0x08 // ATAPI Media Change Request
2256#define ATA_CB_ER_P_ABRT 0x04 // ATAPI command abort
2257#define ATA_CB_ER_P_EOM 0x02 // ATAPI End of Media
2258#define ATA_CB_ER_P_ILI 0x01 // ATAPI Illegal Length Indication
2259
2260// ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC)
2261#define ATA_CB_SC_P_TAG 0xf8 // ATAPI tag (mask)
2262#define ATA_CB_SC_P_REL 0x04 // ATAPI release
2263#define ATA_CB_SC_P_IO 0x02 // ATAPI I/O
2264#define ATA_CB_SC_P_CD 0x01 // ATAPI C/D
2265
2266// bits 7-4 of the device/head (CB_DH) reg
2267#define ATA_CB_DH_DEV0 0xa0 // select device 0
2268#define ATA_CB_DH_DEV1 0xb0 // select device 1
2269
2270// status reg (CB_STAT and CB_ASTAT) bits
2271#define ATA_CB_STAT_BSY 0x80 // busy
2272#define ATA_CB_STAT_RDY 0x40 // ready
2273#define ATA_CB_STAT_DF 0x20 // device fault
2274#define ATA_CB_STAT_WFT 0x20 // write fault (old name)
2275#define ATA_CB_STAT_SKC 0x10 // seek complete
2276#define ATA_CB_STAT_SERV 0x10 // service
2277#define ATA_CB_STAT_DRQ 0x08 // data request
2278#define ATA_CB_STAT_CORR 0x04 // corrected
2279#define ATA_CB_STAT_IDX 0x02 // index
2280#define ATA_CB_STAT_ERR 0x01 // error (ATA)
2281#define ATA_CB_STAT_CHK 0x01 // check (ATAPI)
2282
2283// device control reg (CB_DC) bits
2284#define ATA_CB_DC_HD15 0x08 // bit should always be set to one
2285#define ATA_CB_DC_SRST 0x04 // soft reset
2286#define ATA_CB_DC_NIEN 0x02 // disable interrupts
2287
2288// Most mandatory and optional ATA commands (from ATA-3),
2289#define ATA_CMD_CFA_ERASE_SECTORS 0xC0
2290#define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03
2291#define ATA_CMD_CFA_TRANSLATE_SECTOR 0x87
2292#define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD
2293#define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38
2294#define ATA_CMD_CHECK_POWER_MODE1 0xE5
2295#define ATA_CMD_CHECK_POWER_MODE2 0x98
2296#define ATA_CMD_DEVICE_RESET 0x08
2297#define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90
2298#define ATA_CMD_FLUSH_CACHE 0xE7
2299#define ATA_CMD_FORMAT_TRACK 0x50
2300#define ATA_CMD_IDENTIFY_DEVICE 0xEC
2301#define ATA_CMD_IDENTIFY_DEVICE_PACKET 0xA1
2302#define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xA1
2303#define ATA_CMD_IDLE1 0xE3
2304#define ATA_CMD_IDLE2 0x97
2305#define ATA_CMD_IDLE_IMMEDIATE1 0xE1
2306#define ATA_CMD_IDLE_IMMEDIATE2 0x95
2307#define ATA_CMD_INITIALIZE_DRIVE_PARAMETERS 0x91
2308#define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
2309#define ATA_CMD_NOP 0x00
2310#define ATA_CMD_PACKET 0xA0
2311#define ATA_CMD_READ_BUFFER 0xE4
2312#define ATA_CMD_READ_DMA 0xC8
2313#define ATA_CMD_READ_DMA_QUEUED 0xC7
2314#define ATA_CMD_READ_MULTIPLE 0xC4
2315#define ATA_CMD_READ_SECTORS 0x20
2316#ifdef VBOX
2317#define ATA_CMD_READ_SECTORS_EXT 0x24
2318#define ATA_CMD_READ_MULTIPLE_EXT 0x29
2319#define ATA_CMD_WRITE_MULTIPLE_EXT 0x39
2320#endif /* VBOX */
2321#define ATA_CMD_READ_VERIFY_SECTORS 0x40
2322#define ATA_CMD_RECALIBRATE 0x10
2323#define ATA_CMD_SEEK 0x70
2324#define ATA_CMD_SET_FEATURES 0xEF
2325#define ATA_CMD_SET_MULTIPLE_MODE 0xC6
2326#define ATA_CMD_SLEEP1 0xE6
2327#define ATA_CMD_SLEEP2 0x99
2328#define ATA_CMD_STANDBY1 0xE2
2329#define ATA_CMD_STANDBY2 0x96
2330#define ATA_CMD_STANDBY_IMMEDIATE1 0xE0
2331#define ATA_CMD_STANDBY_IMMEDIATE2 0x94
2332#define ATA_CMD_WRITE_BUFFER 0xE8
2333#define ATA_CMD_WRITE_DMA 0xCA
2334#define ATA_CMD_WRITE_DMA_QUEUED 0xCC
2335#define ATA_CMD_WRITE_MULTIPLE 0xC5
2336#define ATA_CMD_WRITE_SECTORS 0x30
2337#ifdef VBOX
2338#define ATA_CMD_WRITE_SECTORS_EXT 0x34
2339#endif /* VBOX */
2340#define ATA_CMD_WRITE_VERIFY 0x3C
2341
2342#define ATA_IFACE_NONE 0x00
2343#define ATA_IFACE_ISA 0x00
2344#define ATA_IFACE_PCI 0x01
2345
2346#define ATA_TYPE_NONE 0x00
2347#define ATA_TYPE_UNKNOWN 0x01
2348#define ATA_TYPE_ATA 0x02
2349#define ATA_TYPE_ATAPI 0x03
2350#ifdef VBOX
2351#define ATA_TYPE_SCSI 0x04 // SCSI disk
2352#endif
2353
2354#define ATA_DEVICE_NONE 0x00
2355#define ATA_DEVICE_HD 0xFF
2356#define ATA_DEVICE_CDROM 0x05
2357
2358#define ATA_MODE_NONE 0x00
2359#define ATA_MODE_PIO16 0x00
2360#define ATA_MODE_PIO32 0x01
2361#define ATA_MODE_ISADMA 0x02
2362#define ATA_MODE_PCIDMA 0x03
2363#define ATA_MODE_USEIRQ 0x10
2364
2365#define ATA_TRANSLATION_NONE 0
2366#define ATA_TRANSLATION_LBA 1
2367#define ATA_TRANSLATION_LARGE 2
2368#define ATA_TRANSLATION_RECHS 3
2369
2370#define ATA_DATA_NO 0x00
2371#define ATA_DATA_IN 0x01
2372#define ATA_DATA_OUT 0x02
2373
2374// ---------------------------------------------------------------------------
2375// ATA/ATAPI driver : initialization
2376// ---------------------------------------------------------------------------
2377void ata_init( )
2378{
2379 Bit16u ebda_seg=read_word(0x0040,0x000E);
2380 Bit8u channel, device;
2381
2382 // Channels info init.
2383 for (channel=0; channel<BX_MAX_ATA_INTERFACES; channel++) {
2384 write_byte(ebda_seg,&EbdaData->ata.channels[channel].iface,ATA_IFACE_NONE);
2385 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1,0x0);
2386 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2,0x0);
2387 write_byte(ebda_seg,&EbdaData->ata.channels[channel].irq,0);
2388 }
2389
2390 // Devices info init.
2391 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2392 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
2393 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_NONE);
2394 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable,0);
2395 write_byte(ebda_seg,&EbdaData->ata.devices[device].lock,0);
2396 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode,ATA_MODE_NONE);
2397 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,0x200);
2398 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation,ATA_TRANSLATION_NONE);
2399 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads,0);
2400 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders,0);
2401 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt,0);
2402 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads,0);
2403 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders,0);
2404 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt,0);
2405
2406 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors,0L);
2407 }
2408
2409 // hdidmap and cdidmap init.
2410 for (device=0; device<BX_MAX_STORAGE_DEVICES; device++) {
2411 write_byte(ebda_seg,&EbdaData->ata.hdidmap[device],BX_MAX_STORAGE_DEVICES);
2412 write_byte(ebda_seg,&EbdaData->ata.cdidmap[device],BX_MAX_STORAGE_DEVICES);
2413 }
2414
2415 write_byte(ebda_seg,&EbdaData->ata.hdcount,0);
2416 write_byte(ebda_seg,&EbdaData->ata.cdcount,0);
2417}
2418
2419// ---------------------------------------------------------------------------
2420// ATA/ATAPI driver : device detection
2421// ---------------------------------------------------------------------------
2422
2423void ata_detect( )
2424{
2425 Bit16u ebda_seg=read_word(0x0040,0x000E);
2426 Bit8u hdcount, cdcount, device, type;
2427 Bit8u buffer[0x0200];
2428
2429#if BX_MAX_ATA_INTERFACES > 0
2430 write_byte(ebda_seg,&EbdaData->ata.channels[0].iface,ATA_IFACE_ISA);
2431 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase1,0x1f0);
2432 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase2,0x3f0);
2433 write_byte(ebda_seg,&EbdaData->ata.channels[0].irq,14);
2434#endif
2435#if BX_MAX_ATA_INTERFACES > 1
2436 write_byte(ebda_seg,&EbdaData->ata.channels[1].iface,ATA_IFACE_ISA);
2437 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase1,0x170);
2438 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase2,0x370);
2439 write_byte(ebda_seg,&EbdaData->ata.channels[1].irq,15);
2440#endif
2441#if BX_MAX_ATA_INTERFACES > 2
2442 write_byte(ebda_seg,&EbdaData->ata.channels[2].iface,ATA_IFACE_ISA);
2443 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase1,0x1e8);
2444 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase2,0x3e0);
2445 write_byte(ebda_seg,&EbdaData->ata.channels[2].irq,12);
2446#endif
2447#if BX_MAX_ATA_INTERFACES > 3
2448 write_byte(ebda_seg,&EbdaData->ata.channels[3].iface,ATA_IFACE_ISA);
2449 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase1,0x168);
2450 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase2,0x360);
2451 write_byte(ebda_seg,&EbdaData->ata.channels[3].irq,11);
2452#endif
2453#if BX_MAX_ATA_INTERFACES > 4
2454#error Please fill the ATA interface informations
2455#endif
2456
2457 // Device detection
2458 hdcount=cdcount=0;
2459
2460 for(device=0; device<BX_MAX_ATA_DEVICES; device++) {
2461 Bit16u iobase1, iobase2;
2462 Bit8u channel, slave, shift;
2463 Bit8u sc, sn, cl, ch, st;
2464
2465 channel = device / 2;
2466 slave = device % 2;
2467
2468 iobase1 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1);
2469 iobase2 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2);
2470
2471 // Disable interrupts
2472 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2473
2474 // Look for device
2475 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2476 outb(iobase1+ATA_CB_SC, 0x55);
2477 outb(iobase1+ATA_CB_SN, 0xaa);
2478 outb(iobase1+ATA_CB_SC, 0xaa);
2479 outb(iobase1+ATA_CB_SN, 0x55);
2480 outb(iobase1+ATA_CB_SC, 0x55);
2481 outb(iobase1+ATA_CB_SN, 0xaa);
2482
2483 // If we found something
2484 sc = inb(iobase1+ATA_CB_SC);
2485 sn = inb(iobase1+ATA_CB_SN);
2486
2487 if ( (sc == 0x55) && (sn == 0xaa) ) {
2488 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_UNKNOWN);
2489
2490 // reset the channel
2491 ata_reset(device);
2492
2493 // check for ATA or ATAPI
2494 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2495 sc = inb(iobase1+ATA_CB_SC);
2496 sn = inb(iobase1+ATA_CB_SN);
2497 if ((sc==0x01) && (sn==0x01)) {
2498 cl = inb(iobase1+ATA_CB_CL);
2499 ch = inb(iobase1+ATA_CB_CH);
2500 st = inb(iobase1+ATA_CB_STAT);
2501
2502 if ((cl==0x14) && (ch==0xeb)) {
2503 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATAPI);
2504 } else if ((cl==0x00) && (ch==0x00) && (st!=0x00)) {
2505 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATA);
2506 } else if ((cl==0xff) && (ch==0xff)) {
2507 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
2508 }
2509 }
2510 }
2511
2512#ifdef VBOX
2513 // Enable interrupts
2514 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2515#endif /* VBOX */
2516
2517 type=read_byte(ebda_seg,&EbdaData->ata.devices[device].type);
2518
2519 // Now we send a IDENTIFY command to ATA device
2520 if(type == ATA_TYPE_ATA) {
2521 Bit32u sectors;
2522 Bit16u cylinders, heads, spt, blksize;
2523#ifdef VBOX
2524 Bit16u lcylinders, lheads, lspt;
2525 Bit8u chsgeo_base;
2526#endif /* VBOX */
2527 Bit8u translation, removable, mode;
2528
2529 //Temporary values to do the transfer
2530 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2531 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2532
2533 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE, 1, 0, 0, 0, 0L, get_SS(),buffer) !=0 )
2534 BX_PANIC("ata-detect: Failed to detect ATA device\n");
2535
2536 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2537 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2538#ifdef VBOX
2539 blksize = 512; /* There is no sector size field any more. */
2540#else /* !VBOX */
2541 blksize = read_word(get_SS(),buffer+10);
2542#endif /* !VBOX */
2543
2544 cylinders = read_word(get_SS(),buffer+(1*2)); // word 1
2545 heads = read_word(get_SS(),buffer+(3*2)); // word 3
2546 spt = read_word(get_SS(),buffer+(6*2)); // word 6
2547
2548 sectors = read_dword(get_SS(),buffer+(60*2)); // word 60 and word 61
2549#ifdef VBOX
2550 /** @todo update sectors to be a 64 bit number (also lba...). */
2551 if (sectors == 268435455)
2552 sectors = read_dword(get_SS(),buffer+(100*2)); // words 100 to 103 (someday)
2553 switch (device)
2554 {
2555 case 0:
2556 chsgeo_base = 0x1e;
2557 break;
2558 case 1:
2559 chsgeo_base = 0x26;
2560 break;
2561 case 2:
2562 chsgeo_base = 0x67;
2563 break;
2564 case 3:
2565 chsgeo_base = 0x70;
2566 break;
2567#ifndef VBOX_WITH_BIOS_AHCI
2568 case 4:
2569 chsgeo_base = 0x40;
2570 break;
2571 case 5:
2572 chsgeo_base = 0x48;
2573 break;
2574 case 6:
2575 chsgeo_base = 0x50;
2576 break;
2577 case 7:
2578 chsgeo_base = 0x58;
2579 break;
2580#endif
2581 default:
2582 chsgeo_base = 0;
2583 }
2584 if (chsgeo_base != 0)
2585 {
2586 lcylinders = inb_cmos(chsgeo_base) + (inb_cmos(chsgeo_base+1) << 8);
2587 lheads = inb_cmos(chsgeo_base+2);
2588 lspt = inb_cmos(chsgeo_base+7);
2589 }
2590 else
2591 {
2592 lcylinders = 0;
2593 lheads = 0;
2594 lspt = 0;
2595 }
2596 BX_INFO("ata%d-%d: PCHS=%u/%d/%d LCHS=%u/%u/%u\n", channel, slave, cylinders, heads, spt, lcylinders, lheads, lspt);
2597#endif /* VBOX */
2598
2599 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2600 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2601 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2602 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2603 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads, heads);
2604 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders, cylinders);
2605 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt, spt);
2606 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors, sectors);
2607#ifdef VBOX
2608 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, lheads);
2609 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, lcylinders);
2610 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, lspt);
2611 if (device < 2)
2612 {
2613 Bit8u sum, i;
2614 unsigned char *fdpt;
2615 if (device == 0)
2616 fdpt = &EbdaData->fdpt0;
2617 else
2618 fdpt = &EbdaData->fdpt1;
2619
2620 /* Update the DPT for drive 0/1 pointed to by Int41/46. This used
2621 * to be done at POST time with lots of ugly assembler code, which
2622 * isn't worth the effort of converting from AMI to Award CMOS
2623 * format. Just do it here. */
2624 write_word(ebda_seg, fdpt + 0x00, lcylinders);
2625 write_byte(ebda_seg, fdpt + 0x02, lheads);
2626 write_byte(ebda_seg, fdpt + 0x0e, lspt);
2627 write_word(ebda_seg, fdpt + 0x09, cylinders);
2628 write_byte(ebda_seg, fdpt + 0x0b, heads);
2629 write_byte(ebda_seg, fdpt + 0x04, spt);
2630 write_byte(ebda_seg, fdpt + 0x03, 0xa0);
2631 sum = 0;
2632 for (i = 0; i < 0xf; i++)
2633 sum += read_byte(ebda_seg, fdpt + i);
2634 sum = -sum;
2635 write_byte(ebda_seg, fdpt + 0x0f, sum);
2636 }
2637#else /* !VBOX */
2638 BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel, slave,cylinders, heads, spt);
2639
2640 translation = inb_cmos(0x39 + channel/2);
2641 for (shift=device%4; shift>0; shift--) translation >>= 2;
2642 translation &= 0x03;
2643
2644 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation, translation);
2645
2646 switch (translation) {
2647 case ATA_TRANSLATION_NONE:
2648 BX_INFO("none");
2649 break;
2650 case ATA_TRANSLATION_LBA:
2651 BX_INFO("lba");
2652 break;
2653 case ATA_TRANSLATION_LARGE:
2654 BX_INFO("large");
2655 break;
2656 case ATA_TRANSLATION_RECHS:
2657 BX_INFO("r-echs");
2658 break;
2659 }
2660 switch (translation) {
2661 case ATA_TRANSLATION_NONE:
2662 break;
2663 case ATA_TRANSLATION_LBA:
2664 spt = 63;
2665 sectors /= 63;
2666 heads = sectors / 1024;
2667 if (heads>128) heads = 255;
2668 else if (heads>64) heads = 128;
2669 else if (heads>32) heads = 64;
2670 else if (heads>16) heads = 32;
2671 else heads=16;
2672 cylinders = sectors / heads;
2673 break;
2674 case ATA_TRANSLATION_RECHS:
2675 // Take care not to overflow
2676 if (heads==16) {
2677 if(cylinders>61439) cylinders=61439;
2678 heads=15;
2679 cylinders = (Bit16u)((Bit32u)(cylinders)*16/15);
2680 }
2681 // then go through the large bitshift process
2682 case ATA_TRANSLATION_LARGE:
2683 while(cylinders > 1024) {
2684 cylinders >>= 1;
2685 heads <<= 1;
2686
2687 // If we max out the head count
2688 if (heads > 127) break;
2689 }
2690 break;
2691 }
2692 // clip to 1024 cylinders in lchs
2693 if (cylinders > 1024) cylinders=1024;
2694 BX_INFO(" LCHS=%d/%d/%d\n", cylinders, heads, spt);
2695
2696 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, heads);
2697 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, cylinders);
2698 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, spt);
2699#endif /* VBOX */
2700
2701 // fill hdidmap
2702 write_byte(ebda_seg,&EbdaData->ata.hdidmap[hdcount], device);
2703 hdcount++;
2704 }
2705
2706 // Now we send a IDENTIFY command to ATAPI device
2707 if(type == ATA_TYPE_ATAPI) {
2708
2709 Bit8u type, removable, mode;
2710 Bit16u blksize;
2711
2712 //Temporary values to do the transfer
2713 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_CDROM);
2714 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2715
2716 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE_PACKET, 1, 0, 0, 0, 0L, get_SS(),buffer) != 0)
2717 BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
2718
2719 type = read_byte(get_SS(),buffer+1) & 0x1f;
2720 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2721 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2722 blksize = 2048;
2723
2724 write_byte(ebda_seg,&EbdaData->ata.devices[device].device, type);
2725 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2726 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2727 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2728
2729 // fill cdidmap
2730 write_byte(ebda_seg,&EbdaData->ata.cdidmap[cdcount], device);
2731 cdcount++;
2732 }
2733
2734#ifdef VBOX
2735 // we don't want any noisy output for now
2736#else /* !VBOX */
2737 {
2738 Bit32u sizeinmb;
2739 Bit16u ataversion;
2740 Bit8u c, i, version, model[41];
2741
2742 switch (type) {
2743 case ATA_TYPE_ATA:
2744 sizeinmb = read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors);
2745 sizeinmb >>= 11;
2746 case ATA_TYPE_ATAPI:
2747 // Read ATA/ATAPI version
2748 ataversion=((Bit16u)(read_byte(get_SS(),buffer+161))<<8)|read_byte(get_SS(),buffer+160);
2749 for(version=15;version>0;version--) {
2750 if((ataversion&(1<<version))!=0)
2751 break;
2752 }
2753
2754 // Read model name
2755 for(i=0;i<20;i++){
2756 write_byte(get_SS(),model+(i*2),read_byte(get_SS(),buffer+(i*2)+54+1));
2757 write_byte(get_SS(),model+(i*2)+1,read_byte(get_SS(),buffer+(i*2)+54));
2758 }
2759
2760 // Reformat
2761 write_byte(get_SS(),model+40,0x00);
2762 for(i=39;i>0;i--){
2763 if(read_byte(get_SS(),model+i)==0x20)
2764 write_byte(get_SS(),model+i,0x00);
2765 else break;
2766 }
2767 break;
2768 }
2769
2770 switch (type) {
2771 case ATA_TYPE_ATA:
2772 printf("ata%d %s: ",channel,slave?" slave":"master");
2773 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2774 printf(" ATA-%d Hard-Disk (%lu MBytes)\n", version, sizeinmb);
2775 break;
2776 case ATA_TYPE_ATAPI:
2777 printf("ata%d %s: ",channel,slave?" slave":"master");
2778 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2779 if(read_byte(ebda_seg,&EbdaData->ata.devices[device].device)==ATA_DEVICE_CDROM)
2780 printf(" ATAPI-%d CD-Rom/DVD-Rom\n",version);
2781 else
2782 printf(" ATAPI-%d Device\n",version);
2783 break;
2784 case ATA_TYPE_UNKNOWN:
2785 printf("ata%d %s: Unknown device\n",channel,slave?" slave":"master");
2786 break;
2787 }
2788 }
2789#endif /* !VBOX */
2790 }
2791
2792 // Store the devices counts
2793 write_byte(ebda_seg,&EbdaData->ata.hdcount, hdcount);
2794 write_byte(ebda_seg,&EbdaData->ata.cdcount, cdcount);
2795 write_byte(0x40,0x75, hdcount);
2796
2797#ifdef VBOX
2798 // we don't want any noisy output for now
2799#else /* !VBOX */
2800 printf("\n");
2801#endif /* !VBOX */
2802
2803 // FIXME : should use bios=cmos|auto|disable bits
2804 // FIXME : should know about translation bits
2805 // FIXME : move hard_drive_post here
2806
2807}
2808
2809// ---------------------------------------------------------------------------
2810// ATA/ATAPI driver : software reset
2811// ---------------------------------------------------------------------------
2812// ATA-3
2813// 8.2.1 Software reset - Device 0
2814
2815void ata_reset(device)
2816Bit16u device;
2817{
2818 Bit16u ebda_seg=read_word(0x0040,0x000E);
2819 Bit16u iobase1, iobase2;
2820 Bit8u channel, slave, sn, sc;
2821 Bit16u max;
2822#ifdef VBOX
2823 Bit16u pdelay;
2824#endif /* VBOX */
2825
2826 channel = device / 2;
2827 slave = device % 2;
2828
2829 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2830 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2831
2832 // Reset
2833
2834// 8.2.1 (a) -- set SRST in DC
2835 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN | ATA_CB_DC_SRST);
2836
2837// 8.2.1 (b) -- wait for BSY
2838 max=0xff;
2839 while(--max>0) {
2840 Bit8u status = inb(iobase1+ATA_CB_STAT);
2841 if ((status & ATA_CB_STAT_BSY) != 0) break;
2842 }
2843
2844// 8.2.1 (f) -- clear SRST
2845 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2846
2847 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_NONE) {
2848
2849// 8.2.1 (g) -- check for sc==sn==0x01
2850 // select device
2851 outb(iobase1+ATA_CB_DH, slave?ATA_CB_DH_DEV1:ATA_CB_DH_DEV0);
2852 sc = inb(iobase1+ATA_CB_SC);
2853 sn = inb(iobase1+ATA_CB_SN);
2854
2855 if ( (sc==0x01) && (sn==0x01) ) {
2856
2857// 8.2.1 (h) -- wait for not BSY
2858#ifdef VBOX
2859 max=0xffff; /* The ATA specification says that the drive may be busy for up to 30 seconds. */
2860#else /* !VBOX */
2861 max=0xff;
2862#endif /* !VBOX */
2863 while(--max>0) {
2864 Bit8u status = inb(iobase1+ATA_CB_STAT);
2865 if ((status & ATA_CB_STAT_BSY) == 0) break;
2866#ifdef VBOX
2867 pdelay=0xffff;
2868 while (--pdelay>0) {
2869 /* nothing */
2870 }
2871#endif /* VBOX */
2872 }
2873 }
2874 }
2875
2876// 8.2.1 (i) -- wait for DRDY
2877#ifdef VBOX
2878 max=0x10; /* Speed up for virtual drives. Disks are immediately ready, CDs never */
2879#else /* !VBOX */
2880 max=0xfff;
2881#endif /* !VBOX */
2882 while(--max>0) {
2883 Bit8u status = inb(iobase1+ATA_CB_STAT);
2884 if ((status & ATA_CB_STAT_RDY) != 0) break;
2885 }
2886
2887 // Enable interrupts
2888 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2889}
2890
2891// ---------------------------------------------------------------------------
2892// ATA/ATAPI driver : execute a non data command
2893// ---------------------------------------------------------------------------
2894
2895Bit16u ata_cmd_non_data()
2896{return 0;}
2897
2898// ---------------------------------------------------------------------------
2899// ATA/ATAPI driver : execute a data-in command
2900// ---------------------------------------------------------------------------
2901 // returns
2902 // 0 : no error
2903 // 1 : BUSY bit set
2904 // 2 : read error
2905 // 3 : expected DRQ=1
2906 // 4 : no sectors left to read/verify
2907 // 5 : more sectors to read/verify
2908 // 6 : no sectors left to write
2909 // 7 : more sectors to write
2910Bit16u ata_cmd_data_in(device, command, count, cylinder, head, sector, lba, segment, offset)
2911Bit16u device, command, count, cylinder, head, sector, segment, offset;
2912Bit32u lba;
2913{
2914 Bit16u ebda_seg=read_word(0x0040,0x000E);
2915 Bit16u iobase1, iobase2, blksize, mult_blk_cnt;
2916 Bit8u channel, slave;
2917 Bit8u status, current, mode;
2918
2919 channel = device / 2;
2920 slave = device % 2;
2921
2922 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2923 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2924 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2925 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2926 if (blksize == 0) { /* If transfer size is exactly 64K */
2927 if (mode == ATA_MODE_PIO32) blksize=0x4000;
2928 else blksize=0x8000;
2929 } else {
2930 if (mode == ATA_MODE_PIO32) blksize>>=2;
2931 else blksize>>=1;
2932 }
2933
2934#ifdef VBOX
2935 status = inb(iobase1 + ATA_CB_STAT);
2936 if (status & ATA_CB_STAT_BSY)
2937 {
2938 BX_DEBUG_ATA("ata_cmd_data_in : disk busy\n");
2939 // Enable interrupts
2940 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2941 return 1;
2942 }
2943#endif /* VBOX */
2944
2945 // sector will be 0 only on lba access. Convert to lba-chs
2946 if (sector == 0) {
2947#ifdef VBOX
2948 if (lba + count >= 268435456)
2949 {
2950 sector = (lba & 0xff000000L) >> 24;
2951 cylinder = 0; /* The parameter lba is just a 32 bit value. */
2952 outb(iobase1 + ATA_CB_SC, (count & 0xff00) >> 8);
2953 outb(iobase1 + ATA_CB_SN, sector);
2954 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2955 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2956 /* Leave the bottom 24 bits as is, they are treated correctly by the
2957 * LBA28 code path. */
2958 lba &= 0xffffff;
2959 }
2960#endif /* VBOX */
2961 sector = (Bit16u) (lba & 0x000000ffL);
2962 lba >>= 8;
2963 cylinder = (Bit16u) (lba & 0x0000ffffL);
2964 lba >>= 16;
2965 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
2966 }
2967
2968 // Reset count of transferred data
2969 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2970 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2971 current = 0;
2972
2973#ifndef VBOX
2974 status = inb(iobase1 + ATA_CB_STAT);
2975 if (status & ATA_CB_STAT_BSY) return 1;
2976#endif /* !VBOX */
2977
2978 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2979 outb(iobase1 + ATA_CB_FR, 0x00);
2980 outb(iobase1 + ATA_CB_SC, count);
2981 outb(iobase1 + ATA_CB_SN, sector);
2982 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2983 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2984 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
2985 outb(iobase1 + ATA_CB_CMD, command);
2986
2987 if (command == ATA_CMD_READ_MULTIPLE || command == ATA_CMD_READ_MULTIPLE_EXT) {
2988 mult_blk_cnt = count;
2989 count = 1;
2990 } else {
2991 mult_blk_cnt = 1;
2992 }
2993
2994 while (1) {
2995 status = inb(iobase1 + ATA_CB_STAT);
2996 if ( !(status & ATA_CB_STAT_BSY) ) break;
2997 }
2998
2999 if (status & ATA_CB_STAT_ERR) {
3000 BX_DEBUG_ATA("ata_cmd_data_in : read error\n");
3001#ifdef VBOX
3002 // Enable interrupts
3003 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3004#endif /* VBOX */
3005 return 2;
3006 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
3007 BX_DEBUG_ATA("ata_cmd_data_in : DRQ not set (status %02x)\n", (unsigned) status);
3008#ifdef VBOX
3009 // Enable interrupts
3010 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3011#endif /* VBOX */
3012 return 3;
3013 }
3014
3015 // FIXME : move seg/off translation here
3016
3017ASM_START
3018 sti ;; enable higher priority interrupts
3019ASM_END
3020
3021 while (1) {
3022
3023ASM_START
3024 push bp
3025 mov bp, sp
3026 mov di, _ata_cmd_data_in.offset + 2[bp]
3027 mov ax, _ata_cmd_data_in.segment + 2[bp]
3028 mov cx, _ata_cmd_data_in.blksize + 2[bp]
3029
3030 ;; adjust if there will be an overrun. 2K max sector size
3031 cmp di, #0xf800 ;;
3032 jbe ata_in_no_adjust
3033
3034ata_in_adjust:
3035 sub di, #0x0800 ;; sub 2 kbytes from offset
3036 add ax, #0x0080 ;; add 2 Kbytes to segment
3037
3038ata_in_no_adjust:
3039 mov es, ax ;; segment in es
3040
3041 mov dx, _ata_cmd_data_in.iobase1 + 2[bp] ;; ATA data read port
3042
3043 mov ah, _ata_cmd_data_in.mode + 2[bp]
3044 cmp ah, #ATA_MODE_PIO32
3045 je ata_in_32
3046
3047ata_in_16:
3048 rep
3049 insw ;; CX words transferred from port(DX) to ES:[DI]
3050 jmp ata_in_done
3051
3052ata_in_32:
3053 rep
3054 insd ;; CX dwords transferred from port(DX) to ES:[DI]
3055
3056ata_in_done:
3057 mov _ata_cmd_data_in.offset + 2[bp], di
3058 mov _ata_cmd_data_in.segment + 2[bp], es
3059 pop bp
3060ASM_END
3061
3062 current += mult_blk_cnt;
3063 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
3064 count--;
3065#ifdef VBOX
3066 while (1) {
3067 status = inb(iobase1 + ATA_CB_STAT);
3068 if ( !(status & ATA_CB_STAT_BSY) ) break;
3069 }
3070#else /* !VBOX */
3071 status = inb(iobase1 + ATA_CB_STAT);
3072#endif /* !VBOX */
3073 if (count == 0) {
3074 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3075 != ATA_CB_STAT_RDY ) {
3076 BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n", (unsigned) status);
3077#ifdef VBOX
3078 // Enable interrupts
3079 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3080#endif /* VBOX */
3081 return 4;
3082 }
3083 break;
3084 }
3085 else {
3086 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3087 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3088 BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n", (unsigned) status);
3089#ifdef VBOX
3090 // Enable interrupts
3091 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3092#endif /* VBOX */
3093 return 5;
3094 }
3095 continue;
3096 }
3097 }
3098 // Enable interrupts
3099 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3100 return 0;
3101}
3102
3103// ---------------------------------------------------------------------------
3104// ATA/ATAPI driver : execute a data-out command
3105// ---------------------------------------------------------------------------
3106 // returns
3107 // 0 : no error
3108 // 1 : BUSY bit set
3109 // 2 : read error
3110 // 3 : expected DRQ=1
3111 // 4 : no sectors left to read/verify
3112 // 5 : more sectors to read/verify
3113 // 6 : no sectors left to write
3114 // 7 : more sectors to write
3115Bit16u ata_cmd_data_out(device, command, count, cylinder, head, sector, lba, segment, offset)
3116Bit16u device, command, count, cylinder, head, sector, segment, offset;
3117Bit32u lba;
3118{
3119 Bit16u ebda_seg=read_word(0x0040,0x000E);
3120 Bit16u iobase1, iobase2, blksize;
3121 Bit8u channel, slave;
3122 Bit8u status, current, mode;
3123
3124 channel = device / 2;
3125 slave = device % 2;
3126
3127 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
3128 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
3129 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
3130 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
3131 if (mode == ATA_MODE_PIO32) blksize>>=2;
3132 else blksize>>=1;
3133
3134#ifdef VBOX
3135 status = inb(iobase1 + ATA_CB_STAT);
3136 if (status & ATA_CB_STAT_BSY)
3137 {
3138 // Enable interrupts
3139 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3140 return 1;
3141 }
3142#endif /* VBOX */
3143
3144 // sector will be 0 only on lba access. Convert to lba-chs
3145 if (sector == 0) {
3146#ifdef VBOX
3147 if (lba + count >= 268435456)
3148 {
3149 sector = (lba & 0xff000000L) >> 24;
3150 cylinder = 0; /* The parameter lba is just a 32 bit value. */
3151 outb(iobase1 + ATA_CB_SC, (count & 0xff00) >> 8);
3152 outb(iobase1 + ATA_CB_SN, sector);
3153 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
3154 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
3155 /* Leave the bottom 24 bits as is, they are treated correctly by the
3156 * LBA28 code path. */
3157 lba &= 0xffffff;
3158 }
3159#endif /* VBOX */
3160 sector = (Bit16u) (lba & 0x000000ffL);
3161 lba >>= 8;
3162 cylinder = (Bit16u) (lba & 0x0000ffffL);
3163 lba >>= 16;
3164 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
3165 }
3166
3167 // Reset count of transferred data
3168 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
3169 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
3170 current = 0;
3171
3172#ifndef VBOX
3173 status = inb(iobase1 + ATA_CB_STAT);
3174 if (status & ATA_CB_STAT_BSY) return 1;
3175#endif /* !VBOX */
3176
3177 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
3178 outb(iobase1 + ATA_CB_FR, 0x00);
3179 outb(iobase1 + ATA_CB_SC, count);
3180 outb(iobase1 + ATA_CB_SN, sector);
3181 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
3182 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
3183 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
3184 outb(iobase1 + ATA_CB_CMD, command);
3185
3186 while (1) {
3187 status = inb(iobase1 + ATA_CB_STAT);
3188 if ( !(status & ATA_CB_STAT_BSY) ) break;
3189 }
3190
3191 if (status & ATA_CB_STAT_ERR) {
3192 BX_DEBUG_ATA("ata_cmd_data_out : read error\n");
3193#ifdef VBOX
3194 // Enable interrupts
3195 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3196#endif /* VBOX */
3197 return 2;
3198 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
3199 BX_DEBUG_ATA("ata_cmd_data_out : DRQ not set (status %02x)\n", (unsigned) status);
3200#ifdef VBOX
3201 // Enable interrupts
3202 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3203#endif /* VBOX */
3204 return 3;
3205 }
3206
3207 // FIXME : move seg/off translation here
3208
3209ASM_START
3210 sti ;; enable higher priority interrupts
3211ASM_END
3212
3213 while (1) {
3214
3215ASM_START
3216 push bp
3217 mov bp, sp
3218 mov si, _ata_cmd_data_out.offset + 2[bp]
3219 mov ax, _ata_cmd_data_out.segment + 2[bp]
3220 mov cx, _ata_cmd_data_out.blksize + 2[bp]
3221
3222 ;; adjust if there will be an overrun. 2K max sector size
3223 cmp si, #0xf800 ;;
3224 jbe ata_out_no_adjust
3225
3226ata_out_adjust:
3227 sub si, #0x0800 ;; sub 2 kbytes from offset
3228 add ax, #0x0080 ;; add 2 Kbytes to segment
3229
3230ata_out_no_adjust:
3231 mov es, ax ;; segment in es
3232
3233 mov dx, _ata_cmd_data_out.iobase1 + 2[bp] ;; ATA data write port
3234
3235 mov ah, _ata_cmd_data_out.mode + 2[bp]
3236 cmp ah, #ATA_MODE_PIO32
3237 je ata_out_32
3238
3239ata_out_16:
3240 seg ES
3241 rep
3242 outsw ;; CX words transferred from port(DX) to ES:[SI]
3243 jmp ata_out_done
3244
3245ata_out_32:
3246 seg ES
3247 rep
3248 outsd ;; CX dwords transferred from port(DX) to ES:[SI]
3249
3250ata_out_done:
3251 mov _ata_cmd_data_out.offset + 2[bp], si
3252 mov _ata_cmd_data_out.segment + 2[bp], es
3253 pop bp
3254ASM_END
3255
3256 current++;
3257 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
3258 count--;
3259#ifdef VBOX
3260 while (1) {
3261 status = inb(iobase1 + ATA_CB_STAT);
3262 if ( !(status & ATA_CB_STAT_BSY) ) break;
3263 }
3264#else /* !VBOX */
3265 status = inb(iobase1 + ATA_CB_STAT);
3266#endif /* VBOX */
3267 if (count == 0) {
3268 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3269 != ATA_CB_STAT_RDY ) {
3270 BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n", (unsigned) status);
3271#ifdef VBOX
3272 // Enable interrupts
3273 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3274#endif /* VBOX */
3275 return 6;
3276 }
3277 break;
3278 }
3279 else {
3280 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3281 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3282 BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n", (unsigned) status);
3283#ifdef VBOX
3284 // Enable interrupts
3285 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3286#endif /* VBOX */
3287 return 7;
3288 }
3289 continue;
3290 }
3291 }
3292 // Enable interrupts
3293 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3294 return 0;
3295}
3296
3297// ---------------------------------------------------------------------------
3298// ATA/ATAPI driver : execute a packet command
3299// ---------------------------------------------------------------------------
3300 // returns
3301 // 0 : no error
3302 // 1 : error in parameters
3303 // 2 : BUSY bit set
3304 // 3 : error
3305 // 4 : not ready
3306Bit16u ata_cmd_packet(device, cmdlen, cmdseg, cmdoff, header, length, inout, bufseg, bufoff)
3307Bit8u cmdlen,inout;
3308Bit16u device,cmdseg, cmdoff, bufseg, bufoff;
3309Bit16u header;
3310Bit32u length;
3311{
3312 Bit16u ebda_seg=read_word(0x0040,0x000E);
3313 Bit16u iobase1, iobase2;
3314 Bit16u lcount, lbefore, lafter, count;
3315 Bit8u channel, slave;
3316 Bit8u status, mode, lmode;
3317 Bit32u total, transfer;
3318
3319 channel = device / 2;
3320 slave = device % 2;
3321
3322 // Data out is not supported yet
3323 if (inout == ATA_DATA_OUT) {
3324 BX_INFO("ata_cmd_packet: DATA_OUT not supported yet\n");
3325 return 1;
3326 }
3327
3328 // The header length must be even
3329 if (header & 1) {
3330 BX_DEBUG_ATA("ata_cmd_packet : header must be even (%04x)\n",header);
3331 return 1;
3332 }
3333
3334 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
3335 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
3336 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
3337 transfer= 0L;
3338
3339 if (cmdlen < 12) cmdlen=12;
3340 if (cmdlen > 12) cmdlen=16;
3341 cmdlen>>=1;
3342
3343 // Reset count of transferred data
3344 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
3345 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
3346
3347 status = inb(iobase1 + ATA_CB_STAT);
3348 if (status & ATA_CB_STAT_BSY) return 2;
3349
3350 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
3351 // outb(iobase1 + ATA_CB_FR, 0x00);
3352 // outb(iobase1 + ATA_CB_SC, 0x00);
3353 // outb(iobase1 + ATA_CB_SN, 0x00);
3354 outb(iobase1 + ATA_CB_CL, 0xfff0 & 0x00ff);
3355 outb(iobase1 + ATA_CB_CH, 0xfff0 >> 8);
3356 outb(iobase1 + ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
3357 outb(iobase1 + ATA_CB_CMD, ATA_CMD_PACKET);
3358
3359 // Device should ok to receive command
3360 while (1) {
3361 status = inb(iobase1 + ATA_CB_STAT);
3362 if ( !(status & ATA_CB_STAT_BSY) ) break;
3363 }
3364
3365 if (status & ATA_CB_STAT_ERR) {
3366 BX_DEBUG_ATA("ata_cmd_packet : error, status is %02x\n",status);
3367#ifdef VBOX
3368 // Enable interrupts
3369 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3370#endif /* VBOX */
3371 return 3;
3372 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
3373 BX_DEBUG_ATA("ata_cmd_packet : DRQ not set (status %02x)\n", (unsigned) status);
3374#ifdef VBOX
3375 // Enable interrupts
3376 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3377#endif /* VBOX */
3378 return 4;
3379 }
3380
3381 // Normalize address
3382 cmdseg += (cmdoff / 16);
3383 cmdoff %= 16;
3384
3385 // Send command to device
3386ASM_START
3387 sti ;; enable higher priority interrupts
3388
3389 push bp
3390 mov bp, sp
3391
3392 mov si, _ata_cmd_packet.cmdoff + 2[bp]
3393 mov ax, _ata_cmd_packet.cmdseg + 2[bp]
3394 mov cx, _ata_cmd_packet.cmdlen + 2[bp]
3395 mov es, ax ;; segment in es
3396
3397 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data write port
3398
3399 seg ES
3400 rep
3401 outsw ;; CX words transferred from port(DX) to ES:[SI]
3402
3403 pop bp
3404ASM_END
3405
3406 if (inout == ATA_DATA_NO) {
3407 status = inb(iobase1 + ATA_CB_STAT);
3408 }
3409 else {
3410 while (1) {
3411
3412#ifdef VBOX
3413 while (1) {
3414 status = inb(iobase1 + ATA_CB_STAT);
3415 if ( !(status & ATA_CB_STAT_BSY) ) break;
3416 }
3417#else /* VBOX */
3418 status = inb(iobase1 + ATA_CB_STAT);
3419#endif /* VBOX */
3420
3421 // Check if command completed
3422 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_DRQ) ) ==0 ) break;
3423
3424 if (status & ATA_CB_STAT_ERR) {
3425 BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status);
3426#ifdef VBOX
3427 // Enable interrupts
3428 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3429#endif /* VBOX */
3430 return 3;
3431 }
3432
3433 // Device must be ready to send data
3434 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3435 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3436 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", status);
3437#ifdef VBOX
3438 // Enable interrupts
3439 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3440#endif /* VBOX */
3441 return 4;
3442 }
3443
3444 // Normalize address
3445 bufseg += (bufoff / 16);
3446 bufoff %= 16;
3447
3448 // Get the byte count
3449 lcount = ((Bit16u)(inb(iobase1 + ATA_CB_CH))<<8)+inb(iobase1 + ATA_CB_CL);
3450
3451 // adjust to read what we want
3452 if(header>lcount) {
3453 lbefore=lcount;
3454 header-=lcount;
3455 lcount=0;
3456 }
3457 else {
3458 lbefore=header;
3459 header=0;
3460 lcount-=lbefore;
3461 }
3462
3463 if(lcount>length) {
3464 lafter=lcount-length;
3465 lcount=length;
3466 length=0;
3467 }
3468 else {
3469 lafter=0;
3470 length-=lcount;
3471 }
3472
3473 // Save byte count
3474 count = lcount;
3475
3476 BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore+lcount+lafter,lbefore,lcount,lafter);
3477 BX_DEBUG_ATA("to 0x%04x:0x%04x\n",bufseg,bufoff);
3478
3479 // If counts not dividable by 4, use 16bits mode
3480 lmode = mode;
3481 if (lbefore & 0x03) lmode=ATA_MODE_PIO16;
3482 if (lcount & 0x03) lmode=ATA_MODE_PIO16;
3483 if (lafter & 0x03) lmode=ATA_MODE_PIO16;
3484
3485 // adds an extra byte if count are odd. before is always even
3486 if (lcount & 0x01) {
3487 lcount+=1;
3488 if ((lafter > 0) && (lafter & 0x01)) {
3489 lafter-=1;
3490 }
3491 }
3492
3493 if (lmode == ATA_MODE_PIO32) {
3494 lcount>>=2; lbefore>>=2; lafter>>=2;
3495 }
3496 else {
3497 lcount>>=1; lbefore>>=1; lafter>>=1;
3498 }
3499
3500 ; // FIXME bcc bug
3501
3502ASM_START
3503 push bp
3504 mov bp, sp
3505
3506 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data read port
3507
3508 mov cx, _ata_cmd_packet.lbefore + 2[bp]
3509 jcxz ata_packet_no_before
3510
3511 mov ah, _ata_cmd_packet.lmode + 2[bp]
3512 cmp ah, #ATA_MODE_PIO32
3513 je ata_packet_in_before_32
3514
3515ata_packet_in_before_16:
3516 in ax, dx
3517 loop ata_packet_in_before_16
3518 jmp ata_packet_no_before
3519
3520ata_packet_in_before_32:
3521 push eax
3522ata_packet_in_before_32_loop:
3523 in eax, dx
3524 loop ata_packet_in_before_32_loop
3525 pop eax
3526
3527ata_packet_no_before:
3528 mov cx, _ata_cmd_packet.lcount + 2[bp]
3529 jcxz ata_packet_after
3530
3531 mov di, _ata_cmd_packet.bufoff + 2[bp]
3532 mov ax, _ata_cmd_packet.bufseg + 2[bp]
3533 mov es, ax
3534
3535 mov ah, _ata_cmd_packet.lmode + 2[bp]
3536 cmp ah, #ATA_MODE_PIO32
3537 je ata_packet_in_32
3538
3539ata_packet_in_16:
3540 rep
3541 insw ;; CX words transferred tp port(DX) to ES:[DI]
3542 jmp ata_packet_after
3543
3544ata_packet_in_32:
3545 rep
3546 insd ;; CX dwords transferred to port(DX) to ES:[DI]
3547
3548ata_packet_after:
3549 mov cx, _ata_cmd_packet.lafter + 2[bp]
3550 jcxz ata_packet_done
3551
3552 mov ah, _ata_cmd_packet.lmode + 2[bp]
3553 cmp ah, #ATA_MODE_PIO32
3554 je ata_packet_in_after_32
3555
3556ata_packet_in_after_16:
3557 in ax, dx
3558 loop ata_packet_in_after_16
3559 jmp ata_packet_done
3560
3561ata_packet_in_after_32:
3562 push eax
3563ata_packet_in_after_32_loop:
3564 in eax, dx
3565 loop ata_packet_in_after_32_loop
3566 pop eax
3567
3568ata_packet_done:
3569 pop bp
3570ASM_END
3571
3572 // Compute new buffer address
3573 bufoff += count;
3574
3575 // Save transferred bytes count
3576 transfer += count;
3577 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,transfer);
3578 }
3579 }
3580
3581 // Final check, device must be ready
3582 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3583 != ATA_CB_STAT_RDY ) {
3584 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", (unsigned) status);
3585#ifdef VBOX
3586 // Enable interrupts
3587 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3588#endif /* VBOX */
3589 return 4;
3590 }
3591
3592 // Enable interrupts
3593 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3594 return 0;
3595}
3596
3597// ---------------------------------------------------------------------------
3598// End of ATA/ATAPI Driver
3599// ---------------------------------------------------------------------------
3600
3601// ---------------------------------------------------------------------------
3602// Start of ATA/ATAPI generic functions
3603// ---------------------------------------------------------------------------
3604
3605#if 0 // currently unused
3606 Bit16u
3607atapi_get_sense(device)
3608 Bit16u device;
3609{
3610 Bit8u atacmd[12];
3611 Bit8u buffer[16];
3612 Bit8u i;
3613
3614 memsetb(get_SS(),atacmd,0,12);
3615
3616 // Request SENSE
3617 atacmd[0]=0x03;
3618 atacmd[4]=0x20;
3619 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 16L, ATA_DATA_IN, get_SS(), buffer) != 0)
3620 return 0x0002;
3621
3622 if ((buffer[0] & 0x7e) == 0x70) {
3623 return (((Bit16u)buffer[2]&0x0f)*0x100)+buffer[12];
3624 }
3625
3626 return 0;
3627}
3628
3629 Bit16u
3630atapi_is_ready(device)
3631 Bit16u device;
3632{
3633 Bit8u atacmd[12];
3634 Bit8u buffer[];
3635
3636 memsetb(get_SS(),atacmd,0,12);
3637
3638 // Test Unit Ready
3639 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3640 return 0x000f;
3641
3642 if (atapi_get_sense(device) !=0 ) {
3643 memsetb(get_SS(),atacmd,0,12);
3644
3645 // try to send Test Unit Ready again
3646 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3647 return 0x000f;
3648
3649 return atapi_get_sense(device);
3650 }
3651 return 0;
3652}
3653#endif
3654
3655 Bit16u
3656atapi_is_cdrom(device)
3657 Bit8u device;
3658{
3659 Bit16u ebda_seg=read_word(0x0040,0x000E);
3660
3661 if (device >= BX_MAX_ATA_DEVICES)
3662 return 0;
3663
3664 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_ATAPI)
3665 return 0;
3666
3667 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].device) != ATA_DEVICE_CDROM)
3668 return 0;
3669
3670 return 1;
3671}
3672
3673// ---------------------------------------------------------------------------
3674// End of ATA/ATAPI generic functions
3675// ---------------------------------------------------------------------------
3676
3677#endif // BX_USE_ATADRV
3678
3679#if BX_ELTORITO_BOOT
3680
3681// ---------------------------------------------------------------------------
3682// Start of El-Torito boot functions
3683// ---------------------------------------------------------------------------
3684
3685 void
3686cdemu_init()
3687{
3688 Bit16u ebda_seg=read_word(0x0040,0x000E);
3689
3690 // the only important data is this one for now
3691 write_byte(ebda_seg,&EbdaData->cdemu.active,0x00);
3692}
3693
3694 Bit8u
3695cdemu_isactive()
3696{
3697 Bit16u ebda_seg=read_word(0x0040,0x000E);
3698
3699 return(read_byte(ebda_seg,&EbdaData->cdemu.active));
3700}
3701
3702 Bit8u
3703cdemu_emulated_drive()
3704{
3705 Bit16u ebda_seg=read_word(0x0040,0x000E);
3706
3707 return(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
3708}
3709
3710static char isotag[6]="CD001";
3711static char eltorito[24]="EL TORITO SPECIFICATION";
3712//
3713// Returns ah: emulated drive, al: error code
3714//
3715 Bit16u
3716cdrom_boot()
3717{
3718 Bit16u ebda_seg=read_word(0x0040,0x000E);
3719 Bit8u atacmd[12], buffer[2048];
3720 Bit32u lba;
3721 Bit16u boot_segment, nbsectors, i, error;
3722 Bit8u device;
3723#ifdef VBOX
3724 Bit8u read_try;
3725#endif /* VBOX */
3726
3727 // Find out the first cdrom
3728 for (device=0; device<BX_MAX_ATA_DEVICES;device++) {
3729 if (atapi_is_cdrom(device)) break;
3730 }
3731
3732 // if not found
3733 if(device >= BX_MAX_ATA_DEVICES) return 2;
3734
3735 // Read the Boot Record Volume Descriptor
3736 memsetb(get_SS(),atacmd,0,12);
3737 atacmd[0]=0x28; // READ command
3738 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3739 atacmd[8]=(0x01 & 0x00ff); // Sectors
3740 atacmd[2]=(0x11 & 0xff000000) >> 24; // LBA
3741 atacmd[3]=(0x11 & 0x00ff0000) >> 16;
3742 atacmd[4]=(0x11 & 0x0000ff00) >> 8;
3743 atacmd[5]=(0x11 & 0x000000ff);
3744#ifdef VBOX
3745 for (read_try = 0; read_try <= 4; read_try++)
3746 {
3747 error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer);
3748 if (!error)
3749 break;
3750 }
3751 if (error)
3752 return 3;
3753#else /* !VBOX */
3754 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3755 return 3;
3756#endif /* !VBOX */
3757
3758 // Validity checks
3759 if(buffer[0]!=0)return 4;
3760 for(i=0;i<5;i++){
3761 if(buffer[1+i]!=read_byte(0xf000,&isotag[i]))return 5;
3762 }
3763 for(i=0;i<23;i++)
3764 if(buffer[7+i]!=read_byte(0xf000,&eltorito[i]))return 6;
3765
3766 // ok, now we calculate the Boot catalog address
3767 lba=buffer[0x4A]*0x1000000+buffer[0x49]*0x10000+buffer[0x48]*0x100+buffer[0x47];
3768
3769 // And we read the Boot Catalog
3770 memsetb(get_SS(),atacmd,0,12);
3771 atacmd[0]=0x28; // READ command
3772 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3773 atacmd[8]=(0x01 & 0x00ff); // Sectors
3774 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3775 atacmd[3]=(lba & 0x00ff0000) >> 16;
3776 atacmd[4]=(lba & 0x0000ff00) >> 8;
3777 atacmd[5]=(lba & 0x000000ff);
3778 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3779 return 7;
3780
3781 // Validation entry
3782 if(buffer[0x00]!=0x01)return 8; // Header
3783 if(buffer[0x01]!=0x00)return 9; // Platform
3784 if(buffer[0x1E]!=0x55)return 10; // key 1
3785 if(buffer[0x1F]!=0xAA)return 10; // key 2
3786
3787 // Initial/Default Entry
3788 if(buffer[0x20]!=0x88)return 11; // Bootable
3789
3790 write_byte(ebda_seg,&EbdaData->cdemu.media,buffer[0x21]);
3791 if(buffer[0x21]==0){
3792 // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
3793 // Win2000 cd boot needs to know it booted from cd
3794 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0xE0);
3795 }
3796 else if(buffer[0x21]<4)
3797 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x00);
3798 else
3799 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x80);
3800
3801 write_byte(ebda_seg,&EbdaData->cdemu.controller_index,device/2);
3802 write_byte(ebda_seg,&EbdaData->cdemu.device_spec,device%2);
3803
3804 boot_segment=buffer[0x23]*0x100+buffer[0x22];
3805 if(boot_segment==0x0000)boot_segment=0x07C0;
3806
3807 write_word(ebda_seg,&EbdaData->cdemu.load_segment,boot_segment);
3808 write_word(ebda_seg,&EbdaData->cdemu.buffer_segment,0x0000);
3809
3810 nbsectors=buffer[0x27]*0x100+buffer[0x26];
3811 write_word(ebda_seg,&EbdaData->cdemu.sector_count,nbsectors);
3812
3813 lba=buffer[0x2B]*0x1000000+buffer[0x2A]*0x10000+buffer[0x29]*0x100+buffer[0x28];
3814 write_dword(ebda_seg,&EbdaData->cdemu.ilba,lba);
3815
3816 // And we read the image in memory
3817 memsetb(get_SS(),atacmd,0,12);
3818 atacmd[0]=0x28; // READ command
3819 atacmd[7]=((1+(nbsectors-1)/4) & 0xff00) >> 8; // Sectors
3820 atacmd[8]=((1+(nbsectors-1)/4) & 0x00ff); // Sectors
3821 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3822 atacmd[3]=(lba & 0x00ff0000) >> 16;
3823 atacmd[4]=(lba & 0x0000ff00) >> 8;
3824 atacmd[5]=(lba & 0x000000ff);
3825 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, nbsectors*512L, ATA_DATA_IN, boot_segment,0)) != 0)
3826 return 12;
3827
3828 // Remember the media type
3829 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
3830 case 0x01: // 1.2M floppy
3831 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,15);
3832 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3833 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3834 break;
3835 case 0x02: // 1.44M floppy
3836 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,18);
3837 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3838 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3839 break;
3840 case 0x03: // 2.88M floppy
3841 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,36);
3842 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3843 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3844 break;
3845 case 0x04: // Harddrive
3846 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,read_byte(boot_segment,446+6)&0x3f);
3847 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,
3848 (read_byte(boot_segment,446+6)<<2) + read_byte(boot_segment,446+7) + 1);
3849 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,read_byte(boot_segment,446+5) + 1);
3850 break;
3851 }
3852
3853 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0) {
3854 // Increase bios installed hardware number of devices
3855 if(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)==0x00)
3856 write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
3857 else
3858 write_byte(ebda_seg, &EbdaData->ata.hdcount, read_byte(ebda_seg, &EbdaData->ata.hdcount) + 1);
3859 }
3860
3861
3862 // everything is ok, so from now on, the emulation is active
3863 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0)
3864 write_byte(ebda_seg,&EbdaData->cdemu.active,0x01);
3865
3866 // return the boot drive + no error
3867 return (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)*0x100)+0;
3868}
3869
3870// ---------------------------------------------------------------------------
3871// End of El-Torito boot functions
3872// ---------------------------------------------------------------------------
3873#endif // BX_ELTORITO_BOOT
3874
3875#ifdef VBOX_WITH_SCSI
3876# include "scsi.c"
3877#endif
3878
3879#ifdef VBOX_WITH_BIOS_AHCI
3880# include "ahci.c"
3881#endif
3882
3883 void
3884int14_function(regs, ds, iret_addr)
3885 pusha_regs_t regs; // regs pushed from PUSHA instruction
3886 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
3887 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
3888{
3889 Bit16u addr,timer,val16;
3890 Bit8u timeout;
3891
3892 ASM_START
3893 sti
3894 ASM_END
3895
3896 addr = read_word(0x0040, (regs.u.r16.dx << 1));
3897 timeout = read_byte(0x0040, 0x007C + regs.u.r16.dx);
3898 if ((regs.u.r16.dx < 4) && (addr > 0)) {
3899 switch (regs.u.r8.ah) {
3900 case 0:
3901 outb(addr+3, inb(addr+3) | 0x80);
3902 if (regs.u.r8.al & 0xE0 == 0) {
3903 outb(addr, 0x17);
3904 outb(addr+1, 0x04);
3905 } else {
3906 val16 = 0x600 >> ((regs.u.r8.al & 0xE0) >> 5);
3907 outb(addr, val16 & 0xFF);
3908 outb(addr+1, val16 >> 8);
3909 }
3910 outb(addr+3, regs.u.r8.al & 0x1F);
3911 regs.u.r8.ah = inb(addr+5);
3912 regs.u.r8.al = inb(addr+6);
3913 ClearCF(iret_addr.flags);
3914 break;
3915 case 1:
3916 timer = read_word(0x0040, 0x006C);
3917 while (((inb(addr+5) & 0x60) != 0x60) && (timeout)) {
3918 val16 = read_word(0x0040, 0x006C);
3919 if (val16 != timer) {
3920 timer = val16;
3921 timeout--;
3922 }
3923 }
3924 if (timeout) outb(addr, regs.u.r8.al);
3925 regs.u.r8.ah = inb(addr+5);
3926 if (!timeout) regs.u.r8.ah |= 0x80;
3927 ClearCF(iret_addr.flags);
3928 break;
3929 case 2:
3930 timer = read_word(0x0040, 0x006C);
3931 while (((inb(addr+5) & 0x01) == 0) && (timeout)) {
3932 val16 = read_word(0x0040, 0x006C);
3933 if (val16 != timer) {
3934 timer = val16;
3935 timeout--;
3936 }
3937 }
3938 if (timeout) {
3939 regs.u.r8.ah = 0;
3940 regs.u.r8.al = inb(addr);
3941 } else {
3942 regs.u.r8.ah = inb(addr+5);
3943 }
3944 ClearCF(iret_addr.flags);
3945 break;
3946 case 3:
3947 regs.u.r8.ah = inb(addr+5);
3948 regs.u.r8.al = inb(addr+6);
3949 ClearCF(iret_addr.flags);
3950 break;
3951 default:
3952 SetCF(iret_addr.flags); // Unsupported
3953 }
3954 } else {
3955 SetCF(iret_addr.flags); // Unsupported
3956 }
3957}
3958
3959 void
3960int15_function(regs, ES, DS, FLAGS)
3961 pusha_regs_t regs; // REGS pushed via pusha
3962 Bit16u ES, DS, FLAGS;
3963{
3964 Bit16u ebda_seg=read_word(0x0040,0x000E);
3965 bx_bool prev_a20_enable;
3966 Bit16u base15_00;
3967 Bit8u base23_16;
3968 Bit16u ss;
3969 Bit16u BX,CX,DX;
3970
3971 Bit16u bRegister;
3972 Bit8u irqDisable;
3973
3974BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
3975
3976 switch (regs.u.r8.ah) {
3977#ifdef VBOX
3978 case 0x00: /* assorted functions */
3979 if (regs.u.r8.al != 0xc0)
3980 goto undecoded;
3981 /* GRUB calls int15 with ax=0x00c0 to get the ROM configuration table,
3982 * which we don't support, but logging that event is annoying. In fact
3983 * it is likely that they just misread some specs, because there is a
3984 * int15 BIOS function AH=0xc0 which sounds quite similar to what GRUB
3985 * wants to achieve. */
3986 SET_CF();
3987 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3988 break;
3989#endif
3990 case 0x24: /* A20 Control */
3991 switch (regs.u.r8.al) {
3992 case 0x00:
3993 set_enable_a20(0);
3994 CLEAR_CF();
3995 regs.u.r8.ah = 0;
3996 break;
3997 case 0x01:
3998 set_enable_a20(1);
3999 CLEAR_CF();
4000 regs.u.r8.ah = 0;
4001 break;
4002 case 0x02:
4003 regs.u.r8.al = (inb(0x92) >> 1) & 0x01;
4004 CLEAR_CF();
4005 regs.u.r8.ah = 0;
4006 break;
4007 case 0x03:
4008 CLEAR_CF();
4009 regs.u.r8.ah = 0;
4010 regs.u.r16.bx = 3;
4011 break;
4012 default:
4013 BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs.u.r8.al);
4014 SET_CF();
4015 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4016 }
4017 break;
4018
4019 case 0x41:
4020 SET_CF();
4021 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4022 break;
4023
4024 case 0x4f:
4025 /* keyboard intercept */
4026#if BX_CPU < 2
4027 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4028#else
4029 // nop
4030#endif
4031 SET_CF();
4032 break;
4033
4034 case 0x52: // removable media eject
4035 CLEAR_CF();
4036 regs.u.r8.ah = 0; // "ok ejection may proceed"
4037 break;
4038
4039 case 0x83: {
4040 if( regs.u.r8.al == 0 ) {
4041 // Set Interval requested.
4042 if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
4043 // Interval not already set.
4044 write_byte( 0x40, 0xA0, 1 ); // Set status byte.
4045 write_word( 0x40, 0x98, ES ); // Byte location, segment
4046 write_word( 0x40, 0x9A, regs.u.r16.bx ); // Byte location, offset
4047 write_word( 0x40, 0x9C, regs.u.r16.dx ); // Low word, delay
4048 write_word( 0x40, 0x9E, regs.u.r16.cx ); // High word, delay.
4049 CLEAR_CF( );
4050 irqDisable = inb( 0xA1 );
4051 outb( 0xA1, irqDisable & 0xFE );
4052 bRegister = inb_cmos( 0xB ); // Unmask IRQ8 so INT70 will get through.
4053 outb_cmos( 0xB, bRegister | 0x40 ); // Turn on the Periodic Interrupt timer
4054 } else {
4055 // Interval already set.
4056 BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
4057 SET_CF();
4058 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4059 }
4060 } else if( regs.u.r8.al == 1 ) {
4061 // Clear Interval requested
4062 write_byte( 0x40, 0xA0, 0 ); // Clear status byte
4063 CLEAR_CF( );
4064 bRegister = inb_cmos( 0xB );
4065 outb_cmos( 0xB, bRegister & ~0x40 ); // Turn off the Periodic Interrupt timer
4066 } else {
4067 BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
4068 SET_CF();
4069 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4070 regs.u.r8.al--;
4071 }
4072
4073 break;
4074 }
4075
4076 case 0x87:
4077#if BX_CPU < 3
4078# error "Int15 function 87h not supported on < 80386"
4079#endif
4080 // +++ should probably have descriptor checks
4081 // +++ should have exception handlers
4082
4083 // turn off interrupts
4084ASM_START
4085 cli
4086ASM_END
4087
4088 prev_a20_enable = set_enable_a20(1); // enable A20 line
4089
4090 // 128K max of transfer on 386+ ???
4091 // source == destination ???
4092
4093 // ES:SI points to descriptor table
4094 // offset use initially comments
4095 // ==============================================
4096 // 00..07 Unused zeros Null descriptor
4097 // 08..0f GDT zeros filled in by BIOS
4098 // 10..17 source ssssssss source of data
4099 // 18..1f dest dddddddd destination of data
4100 // 20..27 CS zeros filled in by BIOS
4101 // 28..2f SS zeros filled in by BIOS
4102
4103 //es:si
4104 //eeee0
4105 //0ssss
4106 //-----
4107
4108// check for access rights of source & dest here
4109
4110 // Initialize GDT descriptor
4111 base15_00 = (ES << 4) + regs.u.r16.si;
4112 base23_16 = ES >> 12;
4113 if (base15_00 < (ES<<4))
4114 base23_16++;
4115 write_word(ES, regs.u.r16.si+0x08+0, 47); // limit 15:00 = 6 * 8bytes/descriptor
4116 write_word(ES, regs.u.r16.si+0x08+2, base15_00);// base 15:00
4117 write_byte(ES, regs.u.r16.si+0x08+4, base23_16);// base 23:16
4118 write_byte(ES, regs.u.r16.si+0x08+5, 0x93); // access
4119 write_word(ES, regs.u.r16.si+0x08+6, 0x0000); // base 31:24/reserved/limit 19:16
4120
4121 // Initialize CS descriptor
4122 write_word(ES, regs.u.r16.si+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
4123 write_word(ES, regs.u.r16.si+0x20+2, 0x0000);// base 15:00
4124 write_byte(ES, regs.u.r16.si+0x20+4, 0x000f);// base 23:16
4125 write_byte(ES, regs.u.r16.si+0x20+5, 0x9b); // access
4126 write_word(ES, regs.u.r16.si+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
4127
4128 // Initialize SS descriptor
4129 ss = get_SS();
4130 base15_00 = ss << 4;
4131 base23_16 = ss >> 12;
4132 write_word(ES, regs.u.r16.si+0x28+0, 0xffff); // limit 15:00 = normal 64K limit
4133 write_word(ES, regs.u.r16.si+0x28+2, base15_00);// base 15:00
4134 write_byte(ES, regs.u.r16.si+0x28+4, base23_16);// base 23:16
4135 write_byte(ES, regs.u.r16.si+0x28+5, 0x93); // access
4136 write_word(ES, regs.u.r16.si+0x28+6, 0x0000); // base 31:24/reserved/limit 19:16
4137
4138 CX = regs.u.r16.cx;
4139ASM_START
4140 // Compile generates locals offset info relative to SP.
4141 // Get CX (word count) from stack.
4142 mov bx, sp
4143 SEG SS
4144 mov cx, _int15_function.CX [bx]
4145
4146 // since we need to set SS:SP, save them to the BDA
4147 // for future restore
4148 push eax
4149 xor eax, eax
4150 mov ds, ax
4151 mov 0x0469, ss
4152 mov 0x0467, sp
4153
4154 SEG ES
4155 lgdt [si + 0x08]
4156 SEG CS
4157 lidt [pmode_IDT_info]
4158 ;; perhaps do something with IDT here
4159
4160 ;; set PE bit in CR0
4161 mov eax, cr0
4162 or al, #0x01
4163 mov cr0, eax
4164 ;; far jump to flush CPU queue after transition to protected mode
4165 JMP_AP(0x0020, protected_mode)
4166
4167protected_mode:
4168 ;; GDT points to valid descriptor table, now load SS, DS, ES
4169 mov ax, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
4170 mov ss, ax
4171 mov ax, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
4172 mov ds, ax
4173 mov ax, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
4174 mov es, ax
4175 xor si, si
4176 xor di, di
4177 cld
4178 rep
4179 movsw ;; move CX words from DS:SI to ES:DI
4180
4181 ;; make sure DS and ES limits are 64KB
4182 mov ax, #0x28
4183 mov ds, ax
4184 mov es, ax
4185
4186 ;; reset PG bit in CR0 ???
4187 mov eax, cr0
4188 and al, #0xFE
4189 mov cr0, eax
4190
4191 ;; far jump to flush CPU queue after transition to real mode
4192 JMP_AP(0xf000, real_mode)
4193
4194real_mode:
4195 ;; restore IDT to normal real-mode defaults
4196 SEG CS
4197 lidt [rmode_IDT_info]
4198
4199 // restore SS:SP from the BDA
4200 xor ax, ax
4201 mov ds, ax
4202 mov ss, 0x0469
4203 mov sp, 0x0467
4204 pop eax
4205ASM_END
4206
4207 set_enable_a20(prev_a20_enable);
4208
4209 // turn back on interrupts
4210ASM_START
4211 sti
4212ASM_END
4213
4214 regs.u.r8.ah = 0;
4215 CLEAR_CF();
4216 break;
4217
4218
4219 case 0x88:
4220 // Get the amount of extended memory (above 1M)
4221#if BX_CPU < 2
4222 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4223 SET_CF();
4224#else
4225 regs.u.r8.al = inb_cmos(0x30);
4226 regs.u.r8.ah = inb_cmos(0x31);
4227
4228 // According to Ralf Brown's interrupt the limit should be 15M,
4229 // but real machines mostly return max. 63M.
4230 if(regs.u.r16.ax > 0xffc0)
4231 regs.u.r16.ax = 0xffc0;
4232
4233 CLEAR_CF();
4234#endif
4235 break;
4236
4237#ifdef VBOX
4238 case 0x89:
4239 // Switch to Protected Mode.
4240 // ES:DI points to user-supplied GDT
4241 // BH/BL contains starting interrupt numbers for PIC0/PIC1
4242 // This subfunction does not return!
4243
4244// turn off interrupts
4245ASM_START
4246 cli
4247ASM_END
4248
4249 set_enable_a20(1); // enable A20 line; we're supposed to fail if that fails
4250
4251 // Initialize CS descriptor for BIOS
4252 write_word(ES, regs.u.r16.si+0x38+0, 0xffff);// limit 15:00 = normal 64K limit
4253 write_word(ES, regs.u.r16.si+0x38+2, 0x0000);// base 15:00
4254 write_byte(ES, regs.u.r16.si+0x38+4, 0x000f);// base 23:16 (hardcoded to f000:0000)
4255 write_byte(ES, regs.u.r16.si+0x38+5, 0x9b); // access
4256 write_word(ES, regs.u.r16.si+0x38+6, 0x0000);// base 31:24/reserved/limit 19:16
4257
4258 BX = regs.u.r16.bx;
4259ASM_START
4260 // Compiler generates locals offset info relative to SP.
4261 // Get BX (PIC offsets) from stack.
4262 mov bx, sp
4263 SEG SS
4264 mov bx, _int15_function.BX [bx]
4265
4266 // Program PICs
4267 mov al, #0x11 ; send initialisation commands
4268 out 0x20, al
4269 out 0xa0, al
4270 mov al, bh
4271 out 0x21, al
4272 mov al, bl
4273 out 0xa1, al
4274 mov al, #0x04
4275 out 0x21, al
4276 mov al, #0x02
4277 out 0xa1, al
4278 mov al, #0x01
4279 out 0x21, al
4280 out 0xa1, al
4281 mov al, #0xff ; mask all IRQs, user must re-enable
4282 out 0x21, al
4283 out 0xa1, al
4284
4285 // Load GDT and IDT from supplied data
4286 SEG ES
4287 lgdt [si + 0x08]
4288 SEG ES
4289 lidt [si + 0x10]
4290
4291 // set PE bit in CR0
4292 mov eax, cr0
4293 or al, #0x01
4294 mov cr0, eax
4295 // far jump to flush CPU queue after transition to protected mode
4296 JMP_AP(0x0038, protmode_switch)
4297
4298protmode_switch:
4299 ;; GDT points to valid descriptor table, now load SS, DS, ES
4300 mov ax, #0x28
4301 mov ss, ax
4302 mov ax, #0x18
4303 mov ds, ax
4304 mov ax, #0x20
4305 mov es, ax
4306
4307 // unwind the stack - this will break if calling sequence changes!
4308 mov sp,bp
4309 add sp,#4 ; skip return address
4310 popa ; restore regs
4311 pop ax ; skip saved es
4312 pop ax ; skip saved ds
4313 pop ax ; skip saved flags
4314
4315 // return to caller - note that we do not use IRET because
4316 // we cannot enable interrupts
4317 pop cx ; get return offset
4318 pop ax ; skip return segment
4319 pop ax ; skip flags
4320 mov ax, #0x30 ; ah must be 0 on successful exit
4321 push ax
4322 push cx ; re-create modified ret address on stack
4323 retf
4324
4325ASM_END
4326
4327 break;
4328#endif /* VBOX */
4329
4330 case 0x90:
4331 /* Device busy interrupt. Called by Int 16h when no key available */
4332 break;
4333
4334 case 0x91:
4335 /* Interrupt complete. Called by Int 16h when key becomes available */
4336 break;
4337
4338 case 0xbf:
4339 BX_INFO("*** int 15h function AH=bf not yet supported!\n");
4340 SET_CF();
4341 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4342 break;
4343
4344 case 0xC0:
4345#if 0
4346 SET_CF();
4347 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4348 break;
4349#endif
4350 CLEAR_CF();
4351 regs.u.r8.ah = 0;
4352 regs.u.r16.bx = BIOS_CONFIG_TABLE;
4353 ES = 0xF000;
4354 break;
4355
4356 case 0xc1:
4357 ES = ebda_seg;
4358 CLEAR_CF();
4359 break;
4360
4361 case 0xd8:
4362 bios_printf(BIOS_PRINTF_DEBUG, "EISA BIOS not present\n");
4363 SET_CF();
4364 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4365 break;
4366
4367#ifdef VBOX
4368 /* Make the BIOS warning for pretty much every Linux kernel start
4369 * disappear - it calls with ax=0xe980 to figure out SMI info. */
4370 case 0xe9: /* SMI functions (SpeedStep and similar things) */
4371 SET_CF();
4372 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4373 break;
4374 case 0xec: /* AMD64 target operating mode callback */
4375 if (regs.u.r8.al != 0)
4376 goto undecoded;
4377 regs.u.r8.ah = 0;
4378 if (regs.u.r8.bl >= 1 && regs.u.r8.bl <= 3)
4379 CLEAR_CF(); /* Accepted value. */
4380 else
4381 SET_CF(); /* Reserved, error. */
4382 break;
4383undecoded:
4384#endif /* VBOX */
4385 default:
4386 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4387 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4388 SET_CF();
4389 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4390 break;
4391 }
4392}
4393
4394#if BX_USE_PS2_MOUSE
4395 void
4396int15_function_mouse(regs, ES, DS, FLAGS)
4397 pusha_regs_t regs; // REGS pushed via pusha
4398 Bit16u ES, DS, FLAGS;
4399{
4400 Bit16u ebda_seg=read_word(0x0040,0x000E);
4401 Bit8u mouse_flags_1, mouse_flags_2;
4402 Bit16u mouse_driver_seg;
4403 Bit16u mouse_driver_offset;
4404 Bit8u mouse_cmd;
4405 Bit8u ret, mouse_data1, mouse_data2, mouse_data3;
4406
4407BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4408
4409 switch (regs.u.r8.ah) {
4410 case 0xC2:
4411 // Return Codes status in AH
4412 // =========================
4413 // 00: success
4414 // 01: invalid subfunction (AL > 7)
4415 // 02: invalid input value (out of allowable range)
4416 // 03: interface error
4417 // 04: resend command received from mouse controller,
4418 // device driver should attempt command again
4419 // 05: cannot enable mouse, since no far call has been installed
4420 // 80/86: mouse service not implemented
4421
4422 if (regs.u.r8.al > 7) {
4423BX_DEBUG_INT15("unsupported subfn\n");
4424 // invalid function
4425 SET_CF();
4426 regs.u.r8.ah = 1;
4427 break;
4428 }
4429
4430 // Valid subfn; disable AUX input and IRQ12, assume no error
4431 set_kbd_command_byte(0x65);
4432 CLEAR_CF();
4433 regs.u.r8.ah = 0;
4434
4435 switch (regs.u.r8.al) {
4436 case 0: // Disable/Enable Mouse
4437BX_DEBUG_INT15("case 0: ");
4438 if (regs.u.r8.bh > 1) {
4439 BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs.u.r8.bh);
4440 // invalid subfunction
4441 SET_CF();
4442 regs.u.r8.ah = 1;
4443 break;
4444 }
4445 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4446 if ( (mouse_flags_2 & 0x80) == 0 ) {
4447 BX_DEBUG_INT15("INT 15h C2 Enable/Disable Mouse, no far call handler\n");
4448 SET_CF();
4449 regs.u.r8.ah = 5; // no far call installed
4450 break;
4451 }
4452 if (regs.u.r8.bh == 0) {
4453BX_DEBUG_INT15("Disable Mouse\n");
4454 mouse_cmd = 0xF5; // disable mouse command
4455 } else {
4456BX_DEBUG_INT15("Enable Mouse\n");
4457 mouse_cmd = 0xF4; // enable mouse command
4458 }
4459
4460 ret = send_to_mouse_ctrl(mouse_cmd); // disable mouse command
4461 if (ret == 0) {
4462 ret = get_mouse_data(&mouse_data1);
4463 if ( (ret == 0) || (mouse_data1 == 0xFA) ) {
4464 // success
4465 break;
4466 }
4467 }
4468
4469 // interface error
4470 SET_CF();
4471 regs.u.r8.ah = 3;
4472 break;
4473
4474 case 5: // Initialize Mouse
4475 // Valid package sizes are 1 to 8
4476 if ( (regs.u.r8.bh < 1) || (regs.u.r8.bh > 8) ) {
4477 SET_CF();
4478 regs.u.r8.ah = 2; // invalid input
4479 break;
4480 }
4481 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4482 mouse_flags_2 = (mouse_flags_2 & 0xf8) | (regs.u.r8.bh - 1);
4483 write_byte(ebda_seg, 0x0027, mouse_flags_2);
4484 // fall through!
4485
4486 case 1: // Reset Mouse
4487BX_DEBUG_INT15("case 1 or 5:\n");
4488 // clear current package byte index
4489 mouse_flags_1 = read_byte(ebda_seg, 0x0026);
4490 mouse_flags_1 = mouse_flags_1 & 0xf8;
4491 write_byte(ebda_seg, 0x0026, mouse_flags_1);
4492 ret = send_to_mouse_ctrl(0xFF); // reset mouse command
4493 if (ret == 0) {
4494 ret = get_mouse_data(&mouse_data3);
4495 // if no mouse attached, it will return RESEND
4496 if (mouse_data3 == 0xfe) {
4497 SET_CF();
4498 regs.u.r8.ah = 4; // resend
4499 break;
4500 }
4501 if (mouse_data3 != 0xfa)
4502 BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3);
4503 if ( ret == 0 ) {
4504 ret = get_mouse_data(&mouse_data1);
4505 if ( ret == 0 ) {
4506 ret = get_mouse_data(&mouse_data2);
4507 if ( ret == 0 ) {
4508 // success
4509 regs.u.r8.bl = mouse_data1;
4510 regs.u.r8.bh = mouse_data2;
4511 break;
4512 }
4513 }
4514 }
4515 }
4516
4517 // interface error
4518 SET_CF();
4519 regs.u.r8.ah = 3;
4520 break;
4521
4522 case 2: // Set Sample Rate
4523BX_DEBUG_INT15("case 2:\n");
4524 switch (regs.u.r8.bh) {
4525 case 0: mouse_data1 = 10; break; // 10 reports/sec
4526 case 1: mouse_data1 = 20; break; // 20 reports/sec
4527 case 2: mouse_data1 = 40; break; // 40 reports/sec
4528 case 3: mouse_data1 = 60; break; // 60 reports/sec
4529 case 4: mouse_data1 = 80; break; // 80 reports/sec
4530 case 5: mouse_data1 = 100; break; // 100 reports/sec (default)
4531 case 6: mouse_data1 = 200; break; // 200 reports/sec
4532 default: mouse_data1 = 0;
4533 }
4534 if (mouse_data1 > 0) {
4535 ret = send_to_mouse_ctrl(0xF3); // set sample rate command
4536 if (ret == 0) {
4537 ret = get_mouse_data(&mouse_data2);
4538 ret = send_to_mouse_ctrl(mouse_data1);
4539 ret = get_mouse_data(&mouse_data2);
4540 // success
4541 } else {
4542 // interface error
4543 SET_CF();
4544 regs.u.r8.ah = 3;
4545 }
4546 } else {
4547 // invalid input
4548 SET_CF();
4549 regs.u.r8.ah = 2;
4550 }
4551 break;
4552
4553 case 3: // Set Resolution
4554BX_DEBUG_INT15("case 3:\n");
4555 // BX:
4556 // 0 = 25 dpi, 1 count per millimeter
4557 // 1 = 50 dpi, 2 counts per millimeter
4558 // 2 = 100 dpi, 4 counts per millimeter
4559 // 3 = 200 dpi, 8 counts per millimeter
4560 if (regs.u.r8.bh < 4) {
4561 ret = send_to_mouse_ctrl(0xE8); // set resolution command
4562 if (ret == 0) {
4563 ret = get_mouse_data(&mouse_data1);
4564 if (mouse_data1 != 0xfa)
4565 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4566 ret = send_to_mouse_ctrl(regs.u.r8.bh);
4567 ret = get_mouse_data(&mouse_data1);
4568 if (mouse_data1 != 0xfa)
4569 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4570 // success
4571 } else {
4572 // interface error
4573 SET_CF();
4574 regs.u.r8.ah = 3;
4575 }
4576 } else {
4577 // invalid input
4578 SET_CF();
4579 regs.u.r8.ah = 2;
4580 }
4581 break;
4582
4583 case 4: // Get Device ID
4584BX_DEBUG_INT15("case 4:\n");
4585 ret = send_to_mouse_ctrl(0xF2); // get mouse ID command
4586 if (ret == 0) {
4587 ret = get_mouse_data(&mouse_data1);
4588 ret = get_mouse_data(&mouse_data2);
4589 regs.u.r8.bh = mouse_data2;
4590 // success
4591 } else {
4592 // interface error
4593 SET_CF();
4594 regs.u.r8.ah = 3;
4595 }
4596 break;
4597
4598 case 6: // Return Status & Set Scaling Factor...
4599BX_DEBUG_INT15("case 6:\n");
4600 switch (regs.u.r8.bh) {
4601 case 0: // Return Status
4602 ret = send_to_mouse_ctrl(0xE9); // get mouse info command
4603 if (ret == 0) {
4604 ret = get_mouse_data(&mouse_data1);
4605 if (mouse_data1 != 0xfa)
4606 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4607 if (ret == 0) {
4608 ret = get_mouse_data(&mouse_data1);
4609 if ( ret == 0 ) {
4610 ret = get_mouse_data(&mouse_data2);
4611 if ( ret == 0 ) {
4612 ret = get_mouse_data(&mouse_data3);
4613 if ( ret == 0 ) {
4614 regs.u.r8.bl = mouse_data1;
4615 regs.u.r8.cl = mouse_data2;
4616 regs.u.r8.dl = mouse_data3;
4617 // success
4618 break;
4619 }
4620 }
4621 }
4622 }
4623 }
4624
4625 // interface error
4626 SET_CF();
4627 regs.u.r8.ah = 3;
4628 break;
4629
4630 case 1: // Set Scaling Factor to 1:1
4631 case 2: // Set Scaling Factor to 2:1
4632 if (regs.u.r8.bh == 1) {
4633 ret = send_to_mouse_ctrl(0xE6);
4634 } else {
4635 ret = send_to_mouse_ctrl(0xE7);
4636 }
4637 if (ret == 0) {
4638 get_mouse_data(&mouse_data1);
4639 ret = (mouse_data1 != 0xFA);
4640 }
4641 if (ret != 0) {
4642 // interface error
4643 SET_CF();
4644 regs.u.r8.ah = 3;
4645 }
4646 break;
4647
4648 default:
4649 BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs.u.r8.bh);
4650 // invalid subfunction
4651 SET_CF();
4652 regs.u.r8.ah = 1;
4653 }
4654 break;
4655
4656 case 7: // Set Mouse Handler Address
4657BX_DEBUG_INT15("case 7:\n");
4658 mouse_driver_seg = ES;
4659 mouse_driver_offset = regs.u.r16.bx;
4660 write_word(ebda_seg, 0x0022, mouse_driver_offset);
4661 write_word(ebda_seg, 0x0024, mouse_driver_seg);
4662 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4663 if (mouse_driver_offset == 0 && mouse_driver_seg == 0) {
4664 /* remove handler */
4665 if ( (mouse_flags_2 & 0x80) != 0 ) {
4666 mouse_flags_2 &= ~0x80;
4667 }
4668 }
4669 else {
4670 /* install handler */
4671 mouse_flags_2 |= 0x80;
4672 }
4673 write_byte(ebda_seg, 0x0027, mouse_flags_2);
4674 break;
4675
4676 default:
4677 BX_PANIC("INT 15h C2 default case entered\n");
4678 // invalid subfunction
4679 SET_CF();
4680 regs.u.r8.ah = 1;
4681 }
4682BX_DEBUG_INT15("returning cf = %u, ah = %02x\n", (unsigned)GET_CF(), (unsigned)regs.u.r8.ah);
4683 // Re-enable AUX input and IRQ12
4684 set_kbd_command_byte(0x47);
4685 break;
4686
4687 default:
4688 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4689 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4690 SET_CF();
4691 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4692 break;
4693 }
4694}
4695#endif // BX_USE_PS2_MOUSE
4696
4697
4698void set_e820_range(ES, DI, start, end, extra_start, extra_end, type)
4699 Bit16u ES;
4700 Bit16u DI;
4701 Bit32u start;
4702 Bit32u end;
4703 Bit8u extra_start;
4704 Bit8u extra_end;
4705 Bit16u type;
4706{
4707 write_word(ES, DI, start);
4708 write_word(ES, DI+2, start >> 16);
4709 write_word(ES, DI+4, extra_start);
4710 write_word(ES, DI+6, 0x00);
4711
4712 end -= start;
4713 extra_end -= extra_start;
4714 write_word(ES, DI+8, end);
4715 write_word(ES, DI+10, end >> 16);
4716 write_word(ES, DI+12, extra_end);
4717 write_word(ES, DI+14, 0x0000);
4718
4719 write_word(ES, DI+16, type);
4720 write_word(ES, DI+18, 0x0);
4721}
4722
4723 void
4724int15_function32(regs, ES, DS, FLAGS)
4725 pushad_regs_t regs; // REGS pushed via pushad
4726 Bit16u ES, DS, FLAGS;
4727{
4728 Bit32u extended_memory_size=0; // 64bits long
4729 Bit32u extra_lowbits_memory_size=0;
4730 Bit16u CX,DX;
4731 Bit8u extra_highbits_memory_size=0;
4732 Bit32u mcfgStart, mcfgSize;
4733
4734BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4735
4736 switch (regs.u.r8.ah) {
4737 case 0x86:
4738 // Wait for CX:DX microseconds. currently using the
4739 // refresh request port 0x61 bit4, toggling every 15usec
4740
4741 CX = regs.u.r16.cx;
4742 DX = regs.u.r16.dx;
4743
4744ASM_START
4745 sti
4746
4747 ;; Get the count in eax
4748 ;; VBOX: corrected _int15_function -> _int15_function32 here.
4749 mov bx, sp
4750 SEG SS
4751 mov ax, _int15_function32.CX [bx]
4752 shl eax, #16
4753 SEG SS
4754 mov ax, _int15_function32.DX [bx]
4755
4756 ;; convert to numbers of 15usec ticks
4757 mov ebx, #15
4758 xor edx, edx
4759 div eax, ebx
4760 mov ecx, eax
4761
4762 ;; wait for ecx number of refresh requests
4763 in al, #0x61
4764 and al,#0x10
4765 mov ah, al
4766
4767 or ecx, ecx
4768 je int1586_tick_end
4769int1586_tick:
4770 in al, #0x61
4771 and al,#0x10
4772 cmp al, ah
4773 je int1586_tick
4774 mov ah, al
4775 dec ecx
4776 jnz int1586_tick
4777int1586_tick_end:
4778ASM_END
4779
4780 break;
4781
4782 case 0xe8:
4783 switch(regs.u.r8.al)
4784 {
4785 case 0x20: // coded by osmaker aka K.J.
4786 if(regs.u.r32.edx == 0x534D4150)
4787 {
4788 extended_memory_size = inb_cmos(0x35);
4789 extended_memory_size <<= 8;
4790 extended_memory_size |= inb_cmos(0x34);
4791 extended_memory_size *= 64;
4792#ifndef VBOX /* The following excludes 0xf0000000 thru 0xffffffff. Trust DevPcBios.cpp to get this right. */
4793 // greater than EFF00000???
4794 if(extended_memory_size > 0x3bc000) {
4795 extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4796 }
4797#endif /* !VBOX */
4798 extended_memory_size *= 1024;
4799 extended_memory_size += (16L * 1024 * 1024);
4800
4801 if(extended_memory_size <= (16L * 1024 * 1024)) {
4802 extended_memory_size = inb_cmos(0x31);
4803 extended_memory_size <<= 8;
4804 extended_memory_size |= inb_cmos(0x30);
4805 extended_memory_size *= 1024;
4806 extended_memory_size += (1L * 1024 * 1024);
4807 }
4808
4809#ifdef VBOX /* We've already used the CMOS entries for SATA.
4810 BTW. This is the amount of memory above 4GB measured in 64KB units. */
4811 extra_lowbits_memory_size = inb_cmos(0x62);
4812 extra_lowbits_memory_size <<= 8;
4813 extra_lowbits_memory_size |= inb_cmos(0x61);
4814 extra_lowbits_memory_size <<= 16;
4815 extra_highbits_memory_size = inb_cmos(0x63);
4816 /* 0x64 and 0x65 can be used if we need to dig 1 TB or more at a later point. */
4817#else
4818 extra_lowbits_memory_size = inb_cmos(0x5c);
4819 extra_lowbits_memory_size <<= 8;
4820 extra_lowbits_memory_size |= inb_cmos(0x5b);
4821 extra_lowbits_memory_size *= 64;
4822 extra_lowbits_memory_size *= 1024;
4823 extra_highbits_memory_size = inb_cmos(0x5d);
4824#endif /* !VBOX */
4825
4826 mcfgStart = 0;
4827 mcfgSize = 0;
4828
4829 switch(regs.u.r16.bx)
4830 {
4831 case 0:
4832 set_e820_range(ES, regs.u.r16.di,
4833#ifndef VBOX /** @todo Upstream suggests the following, needs checking. (see next as well) */
4834 0x0000000L, 0x0009f000L, 0, 0, 1);
4835#else
4836 0x0000000L, 0x0009fc00L, 0, 0, 1);
4837#endif
4838 regs.u.r32.ebx = 1;
4839 break;
4840 case 1:
4841 set_e820_range(ES, regs.u.r16.di,
4842#ifndef VBOX /** @todo Upstream suggests the following, needs checking. (see next as well) */
4843 0x0009f000L, 0x000a0000L, 0, 0, 2);
4844#else
4845 0x0009fc00L, 0x000a0000L, 0, 0, 2);
4846#endif
4847 regs.u.r32.ebx = 2;
4848 break;
4849 case 2:
4850#ifdef VBOX
4851 /* Mark the BIOS as reserved. VBox doesn't currently
4852 * use the 0xe0000-0xeffff area. It does use the
4853 * 0xd0000-0xdffff area for the BIOS logo, but it's
4854 * not worth marking it as reserved. (this is not
4855 * true anymore because the VGA adapter handles the logo stuff)
4856 * The whole 0xe0000-0xfffff can be used for the BIOS.
4857 * Note that various
4858 * Windows versions don't accept (read: in debug builds
4859 * they trigger the "Too many similar traps" assertion)
4860 * a single reserved range from 0xd0000 to 0xffffff.
4861 * A 128K area starting from 0xd0000 works. */
4862 set_e820_range(ES, regs.u.r16.di,
4863 0x000f0000L, 0x00100000L, 0, 0, 2);
4864#else /* !VBOX */
4865 set_e820_range(ES, regs.u.r16.di,
4866 0x000e8000L, 0x00100000L, 0, 0, 2);
4867#endif /* !VBOX */
4868 regs.u.r32.ebx = 3;
4869 break;
4870 case 3:
4871#if BX_ROMBIOS32 || defined(VBOX)
4872 set_e820_range(ES, regs.u.r16.di,
4873 0x00100000L,
4874 extended_memory_size - ACPI_DATA_SIZE, 0, 0, 1);
4875 regs.u.r32.ebx = 4;
4876#else
4877 set_e820_range(ES, regs.u.r16.di,
4878 0x00100000L,
4879 extended_memory_size, 1);
4880 regs.u.r32.ebx = 5;
4881#endif
4882 break;
4883 case 4:
4884 set_e820_range(ES, regs.u.r16.di,
4885 extended_memory_size - ACPI_DATA_SIZE,
4886 extended_memory_size, 0, 0, 3); // ACPI RAM
4887 regs.u.r32.ebx = 5;
4888 break;
4889 case 5:
4890 /* 256KB BIOS area at the end of 4 GB */
4891#ifdef VBOX
4892 /* We don't set the end to 1GB here and rely on the 32-bit
4893 unsigned wrap around effect (0-0xfffc0000L). */
4894#endif
4895 set_e820_range(ES, regs.u.r16.di,
4896 0xfffc0000L, 0x00000000L, 0, 0, 2);
4897 if (mcfgStart != 0)
4898 regs.u.r32.ebx = 6;
4899 else
4900 {
4901 if (extra_highbits_memory_size || extra_lowbits_memory_size)
4902 regs.u.r32.ebx = 7;
4903 else
4904 regs.u.r32.ebx = 0;
4905 }
4906 break;
4907 case 6:
4908 /* PCI MMIO config space (MCFG) */
4909 set_e820_range(ES, regs.u.r16.di,
4910 mcfgStart, mcfgStart + mcfgSize, 0, 0, 2);
4911
4912 if (extra_highbits_memory_size || extra_lowbits_memory_size)
4913 regs.u.r32.ebx = 7;
4914 else
4915 regs.u.r32.ebx = 0;
4916 break;
4917 case 7:
4918#ifdef VBOX /* Don't succeeded if no memory above 4 GB. */
4919 /* Mapping of memory above 4 GB if present.
4920 Note: set_e820_range needs do no borrowing in the
4921 subtraction because of the nice numbers. */
4922 if (extra_highbits_memory_size || extra_lowbits_memory_size)
4923 {
4924 set_e820_range(ES, regs.u.r16.di,
4925 0x00000000L, extra_lowbits_memory_size,
4926 1 /*GB*/, extra_highbits_memory_size + 1 /*GB*/, 1);
4927 regs.u.r32.ebx = 0;
4928 }
4929 break;
4930 /* fall thru */
4931#else /* !VBOX */
4932 /* Mapping of memory above 4 GB */
4933 set_e820_range(ES, regs.u.r16.di, 0x00000000L,
4934 extra_lowbits_memory_size, 1, extra_highbits_memory_size
4935 + 1, 1);
4936 regs.u.r32.ebx = 0;
4937 break;
4938#endif /* !VBOX */
4939 default: /* AX=E820, DX=534D4150, BX unrecognized */
4940 goto int15_unimplemented;
4941 break;
4942 }
4943 regs.u.r32.eax = 0x534D4150;
4944 regs.u.r32.ecx = 0x14;
4945 CLEAR_CF();
4946 } else {
4947 // if DX != 0x534D4150)
4948 goto int15_unimplemented;
4949 }
4950 break;
4951
4952 case 0x01:
4953 // do we have any reason to fail here ?
4954 CLEAR_CF();
4955
4956 // my real system sets ax and bx to 0
4957 // this is confirmed by Ralph Brown list
4958 // but syslinux v1.48 is known to behave
4959 // strangely if ax is set to 0
4960 // regs.u.r16.ax = 0;
4961 // regs.u.r16.bx = 0;
4962
4963 // Get the amount of extended memory (above 1M)
4964 regs.u.r8.cl = inb_cmos(0x30);
4965 regs.u.r8.ch = inb_cmos(0x31);
4966
4967 // limit to 15M
4968 if(regs.u.r16.cx > 0x3c00)
4969 {
4970 regs.u.r16.cx = 0x3c00;
4971 }
4972
4973 // Get the amount of extended memory above 16M in 64k blocs
4974 regs.u.r8.dl = inb_cmos(0x34);
4975 regs.u.r8.dh = inb_cmos(0x35);
4976
4977 // Set configured memory equal to extended memory
4978 regs.u.r16.ax = regs.u.r16.cx;
4979 regs.u.r16.bx = regs.u.r16.dx;
4980 break;
4981 default: /* AH=0xE8?? but not implemented */
4982 goto int15_unimplemented;
4983 }
4984 break;
4985 int15_unimplemented:
4986 // fall into the default
4987 default:
4988 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4989 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4990 SET_CF();
4991 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4992 break;
4993 }
4994}
4995
4996 void
4997int16_function(DI, SI, BP, SP, BX, DX, CX, AX, FLAGS)
4998 Bit16u DI, SI, BP, SP, BX, DX, CX, AX, FLAGS;
4999{
5000 Bit8u scan_code, ascii_code, shift_flags, led_flags, count;
5001 Bit16u kbd_code, max;
5002
5003 BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX, BX, CX, DX);
5004
5005 shift_flags = read_byte(0x0040, 0x17);
5006 led_flags = read_byte(0x0040, 0x97);
5007 if ((((shift_flags >> 4) & 0x07) ^ (led_flags & 0x07)) != 0) {
5008ASM_START
5009 cli
5010ASM_END
5011 outb(0x60, 0xed);
5012 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
5013 if ((inb(0x60) == 0xfa)) {
5014 led_flags &= 0xf8;
5015 led_flags |= ((shift_flags >> 4) & 0x07);
5016 outb(0x60, led_flags & 0x07);
5017 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
5018 inb(0x60);
5019 write_byte(0x0040, 0x97, led_flags);
5020 }
5021ASM_START
5022 sti
5023ASM_END
5024 }
5025
5026 switch (GET_AH()) {
5027 case 0x00: /* read keyboard input */
5028
5029 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
5030 BX_PANIC("KBD: int16h: out of keyboard input\n");
5031 }
5032 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
5033 else if (ascii_code == 0xE0) ascii_code = 0;
5034 AX = (scan_code << 8) | ascii_code;
5035 break;
5036
5037 case 0x01: /* check keyboard status */
5038 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
5039 SET_ZF();
5040 return;
5041 }
5042 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
5043 else if (ascii_code == 0xE0) ascii_code = 0;
5044 AX = (scan_code << 8) | ascii_code;
5045 CLEAR_ZF();
5046 break;
5047
5048 case 0x02: /* get shift flag status */
5049 shift_flags = read_byte(0x0040, 0x17);
5050 SET_AL(shift_flags);
5051 break;
5052
5053 case 0x05: /* store key-stroke into buffer */
5054 if ( !enqueue_key(GET_CH(), GET_CL()) ) {
5055 SET_AL(1);
5056 }
5057 else {
5058 SET_AL(0);
5059 }
5060 break;
5061
5062 case 0x09: /* GET KEYBOARD FUNCTIONALITY */
5063 // bit Bochs Description
5064 // 7 0 reserved
5065 // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
5066 // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
5067 // 4 1 INT 16/AH=0Ah supported
5068 // 3 0 INT 16/AX=0306h supported
5069 // 2 0 INT 16/AX=0305h supported
5070 // 1 0 INT 16/AX=0304h supported
5071 // 0 0 INT 16/AX=0300h supported
5072 //
5073 SET_AL(0x30);
5074 break;
5075
5076 case 0x0A: /* GET KEYBOARD ID */
5077 count = 2;
5078 kbd_code = 0x0;
5079ASM_START
5080 cli // avoid racing the interrupt handler
5081ASM_END
5082 outb(0x60, 0xf2);
5083 /* Wait for data */
5084 max=0xffff;
5085 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
5086 if (max>0x0) {
5087 if ((inb(0x60) == 0xfa)) {
5088 do {
5089 max=0xffff;
5090 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
5091 if (max>0x0) {
5092 kbd_code >>= 8;
5093 kbd_code |= (inb(0x60) << 8);
5094 }
5095 } while (--count>0);
5096 }
5097 }
5098 BX=kbd_code;
5099 break;
5100
5101 case 0x10: /* read MF-II keyboard input */
5102
5103 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
5104 BX_PANIC("KBD: int16h: out of keyboard input\n");
5105 }
5106 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
5107 AX = (scan_code << 8) | ascii_code;
5108 break;
5109
5110 case 0x11: /* check MF-II keyboard status */
5111 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
5112 SET_ZF();
5113 return;
5114 }
5115 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
5116 AX = (scan_code << 8) | ascii_code;
5117 CLEAR_ZF();
5118 break;
5119
5120 case 0x12: /* get extended keyboard status */
5121 shift_flags = read_byte(0x0040, 0x17);
5122 SET_AL(shift_flags);
5123 shift_flags = read_byte(0x0040, 0x18) & 0x73;
5124 shift_flags |= read_byte(0x0040, 0x96) & 0x0c;
5125 SET_AH(shift_flags);
5126 BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX);
5127 break;
5128
5129 case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
5130 SET_AH(0x80); // function int16 ah=0x10-0x12 supported
5131 break;
5132
5133 case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
5134 // don't change AH : function int16 ah=0x20-0x22 NOT supported
5135 break;
5136
5137 case 0x6F:
5138 if (GET_AL() == 0x08)
5139 SET_AH(0x02); // unsupported, aka normal keyboard
5140
5141 default:
5142 BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
5143 }
5144}
5145
5146 unsigned int
5147dequeue_key(scan_code, ascii_code, incr)
5148 Bit8u *scan_code;
5149 Bit8u *ascii_code;
5150 unsigned int incr;
5151{
5152 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail;
5153 Bit16u ss;
5154 Bit8u acode, scode;
5155
5156#if BX_CPU < 2
5157 buffer_start = 0x001E;
5158 buffer_end = 0x003E;
5159#else
5160 buffer_start = read_word(0x0040, 0x0080);
5161 buffer_end = read_word(0x0040, 0x0082);
5162#endif
5163
5164 buffer_head = read_word(0x0040, 0x001a);
5165 buffer_tail = read_word(0x0040, 0x001c);
5166
5167 if (buffer_head != buffer_tail) {
5168 ss = get_SS();
5169 acode = read_byte(0x0040, buffer_head);
5170 scode = read_byte(0x0040, buffer_head+1);
5171 write_byte(ss, ascii_code, acode);
5172 write_byte(ss, scan_code, scode);
5173
5174 if (incr) {
5175 buffer_head += 2;
5176 if (buffer_head >= buffer_end)
5177 buffer_head = buffer_start;
5178 write_word(0x0040, 0x001a, buffer_head);
5179 }
5180 return(1);
5181 }
5182 else {
5183 return(0);
5184 }
5185}
5186
5187static char panic_msg_keyb_buffer_full[] = "%s: keyboard input buffer full\n";
5188
5189 Bit8u
5190send_to_mouse_ctrl(sendbyte)
5191 Bit8u sendbyte;
5192{
5193 Bit8u response;
5194
5195 // wait for chance to write to ctrl
5196 if ( inb(0x64) & 0x02 )
5197 BX_PANIC(panic_msg_keyb_buffer_full,"sendmouse");
5198 outb(0x64, 0xD4);
5199 outb(0x60, sendbyte);
5200 return(0);
5201}
5202
5203
5204 Bit8u
5205get_mouse_data(data)
5206 Bit8u *data;
5207{
5208 Bit8u response;
5209 Bit16u ss;
5210
5211 while ( (inb(0x64) & 0x21) != 0x21 ) {
5212 }
5213
5214 response = inb(0x60);
5215
5216 ss = get_SS();
5217 write_byte(ss, data, response);
5218 return(0);
5219}
5220
5221 void
5222set_kbd_command_byte(command_byte)
5223 Bit8u command_byte;
5224{
5225 if ( inb(0x64) & 0x02 )
5226 BX_PANIC(panic_msg_keyb_buffer_full,"setkbdcomm");
5227
5228 outb(0x64, 0x60); // write command byte
5229 outb(0x60, command_byte);
5230}
5231
5232 void
5233int09_function(DI, SI, BP, SP, BX, DX, CX, AX)
5234 Bit16u DI, SI, BP, SP, BX, DX, CX, AX;
5235{
5236 Bit8u scancode, asciicode, shift_flags;
5237 Bit8u mf2_flags, mf2_state, flag;
5238
5239 //
5240 // DS has been set to F000 before call
5241 //
5242
5243
5244 scancode = GET_AL();
5245
5246 if (scancode == 0) {
5247 BX_INFO("KBD: int09 handler: AL=0\n");
5248 return;
5249 }
5250
5251
5252 shift_flags = read_byte(0x0040, 0x17);
5253 mf2_flags = read_byte(0x0040, 0x18);
5254 mf2_state = read_byte(0x0040, 0x96);
5255 asciicode = 0;
5256
5257 switch (scancode) {
5258 case 0x3a: /* Caps Lock press */
5259 shift_flags ^= 0x40;
5260 write_byte(0x0040, 0x17, shift_flags);
5261 mf2_flags |= 0x40;
5262 write_byte(0x0040, 0x18, mf2_flags);
5263 break;
5264 case 0xba: /* Caps Lock release */
5265 mf2_flags &= ~0x40;
5266 write_byte(0x0040, 0x18, mf2_flags);
5267 break;
5268
5269 case 0x2a: /* L Shift press */
5270 case 0xaa: /* L Shift release */
5271 case 0x36: /* R Shift press */
5272 case 0xb6: /* R Shift release */
5273 /* If this was an extended (i.e. faked) key, leave flags alone. */
5274 if (!(mf2_state & 0x02)) {
5275 flag = (scancode & 0x7f) == 0x2a ? 0x02 : 0x01;
5276 if (scancode & 0x80)
5277 shift_flags &= ~flag;
5278 else
5279 shift_flags |= flag;
5280 write_byte(0x0040, 0x17, shift_flags);
5281 }
5282 break;
5283
5284 case 0x1d: /* Ctrl press */
5285 if ((mf2_state & 0x01) == 0) {
5286 shift_flags |= 0x04;
5287 write_byte(0x0040, 0x17, shift_flags);
5288 if (mf2_state & 0x02) {
5289 mf2_state |= 0x04;
5290 write_byte(0x0040, 0x96, mf2_state);
5291 } else {
5292 mf2_flags |= 0x01;
5293 write_byte(0x0040, 0x18, mf2_flags);
5294 }
5295 }
5296 break;
5297 case 0x9d: /* Ctrl release */
5298 if ((mf2_state & 0x01) == 0) {
5299 shift_flags &= ~0x04;
5300 write_byte(0x0040, 0x17, shift_flags);
5301 if (mf2_state & 0x02) {
5302 mf2_state &= ~0x04;
5303 write_byte(0x0040, 0x96, mf2_state);
5304 } else {
5305 mf2_flags &= ~0x01;
5306 write_byte(0x0040, 0x18, mf2_flags);
5307 }
5308 }
5309 break;
5310
5311 case 0x38: /* Alt press */
5312 shift_flags |= 0x08;
5313 write_byte(0x0040, 0x17, shift_flags);
5314 if (mf2_state & 0x02) {
5315 mf2_state |= 0x08;
5316 write_byte(0x0040, 0x96, mf2_state);
5317 } else {
5318 mf2_flags |= 0x02;
5319 write_byte(0x0040, 0x18, mf2_flags);
5320 }
5321 break;
5322 case 0xb8: /* Alt release */
5323 shift_flags &= ~0x08;
5324 write_byte(0x0040, 0x17, shift_flags);
5325 if (mf2_state & 0x02) {
5326 mf2_state &= ~0x08;
5327 write_byte(0x0040, 0x96, mf2_state);
5328 } else {
5329 mf2_flags &= ~0x02;
5330 write_byte(0x0040, 0x18, mf2_flags);
5331 }
5332 break;
5333
5334 case 0x45: /* Num Lock press */
5335 if ((mf2_state & 0x03) == 0) {
5336 mf2_flags |= 0x20;
5337 write_byte(0x0040, 0x18, mf2_flags);
5338 shift_flags ^= 0x20;
5339 write_byte(0x0040, 0x17, shift_flags);
5340 }
5341 break;
5342 case 0xc5: /* Num Lock release */
5343 if ((mf2_state & 0x03) == 0) {
5344 mf2_flags &= ~0x20;
5345 write_byte(0x0040, 0x18, mf2_flags);
5346 }
5347 break;
5348
5349 case 0x46: /* Scroll Lock press */
5350 mf2_flags |= 0x10;
5351 write_byte(0x0040, 0x18, mf2_flags);
5352 shift_flags ^= 0x10;
5353 write_byte(0x0040, 0x17, shift_flags);
5354 break;
5355
5356 case 0xc6: /* Scroll Lock release */
5357 mf2_flags &= ~0x10;
5358 write_byte(0x0040, 0x18, mf2_flags);
5359 break;
5360
5361#ifdef VBOX
5362 case 0x53: /* Del press */
5363 if ((shift_flags & 0x0c) == 0x0c)
5364 {
5365ASM_START
5366 /* Ctrl+Alt+Del => Reboot */
5367 jmp 0xf000:post
5368ASM_END
5369 }
5370 /* fall through */
5371#endif
5372
5373 default:
5374 if (scancode & 0x80) {
5375 break; /* toss key releases ... */
5376 }
5377 if (scancode > MAX_SCAN_CODE) {
5378 BX_INFO("KBD: int09h_handler(): unknown scancode read: 0x%02x!\n", scancode);
5379 return;
5380 }
5381 if (shift_flags & 0x08) { /* ALT */
5382 asciicode = scan_to_scanascii[scancode].alt;
5383 scancode = scan_to_scanascii[scancode].alt >> 8;
5384 } else if (shift_flags & 0x04) { /* CONTROL */
5385 asciicode = scan_to_scanascii[scancode].control;
5386 scancode = scan_to_scanascii[scancode].control >> 8;
5387 } else if (((mf2_state & 0x02) > 0) && ((scancode >= 0x47) && (scancode <= 0x53))) {
5388 /* extended keys handling */
5389 asciicode = 0xe0;
5390 scancode = scan_to_scanascii[scancode].normal >> 8;
5391 } else if (shift_flags & 0x03) { /* LSHIFT + RSHIFT */
5392 /* check if lock state should be ignored
5393 * because a SHIFT key are pressed */
5394
5395 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
5396 asciicode = scan_to_scanascii[scancode].normal;
5397 scancode = scan_to_scanascii[scancode].normal >> 8;
5398 } else {
5399 asciicode = scan_to_scanascii[scancode].shift;
5400 scancode = scan_to_scanascii[scancode].shift >> 8;
5401 }
5402 } else {
5403 /* check if lock is on */
5404 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
5405 asciicode = scan_to_scanascii[scancode].shift;
5406 scancode = scan_to_scanascii[scancode].shift >> 8;
5407 } else {
5408 asciicode = scan_to_scanascii[scancode].normal;
5409 scancode = scan_to_scanascii[scancode].normal >> 8;
5410 }
5411 }
5412 if (scancode==0 && asciicode==0) {
5413 BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
5414 }
5415 enqueue_key(scancode, asciicode);
5416 break;
5417 }
5418 if ((scancode & 0x7f) != 0x1d) {
5419 mf2_state &= ~0x01;
5420 }
5421 mf2_state &= ~0x02;
5422 write_byte(0x0040, 0x96, mf2_state);
5423}
5424
5425 unsigned int
5426enqueue_key(scan_code, ascii_code)
5427 Bit8u scan_code, ascii_code;
5428{
5429 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail, temp_tail;
5430
5431#if BX_CPU < 2
5432 buffer_start = 0x001E;
5433 buffer_end = 0x003E;
5434#else
5435 buffer_start = read_word(0x0040, 0x0080);
5436 buffer_end = read_word(0x0040, 0x0082);
5437#endif
5438
5439 buffer_head = read_word(0x0040, 0x001A);
5440 buffer_tail = read_word(0x0040, 0x001C);
5441
5442 temp_tail = buffer_tail;
5443 buffer_tail += 2;
5444 if (buffer_tail >= buffer_end)
5445 buffer_tail = buffer_start;
5446
5447 if (buffer_tail == buffer_head) {
5448 return(0);
5449 }
5450
5451 write_byte(0x0040, temp_tail, ascii_code);
5452 write_byte(0x0040, temp_tail+1, scan_code);
5453 write_word(0x0040, 0x001C, buffer_tail);
5454 return(1);
5455}
5456
5457
5458 void
5459int74_function(make_farcall, Z, Y, X, status)
5460 Bit16u make_farcall, Z, Y, X, status;
5461{
5462 Bit16u ebda_seg=read_word(0x0040,0x000E);
5463 Bit8u in_byte, index, package_count;
5464 Bit8u mouse_flags_1, mouse_flags_2;
5465
5466BX_DEBUG_INT74("entering int74_function\n");
5467 make_farcall = 0;
5468
5469 in_byte = inb(0x64);
5470 if ( (in_byte & 0x21) != 0x21 ) {
5471 return;
5472 }
5473 in_byte = inb(0x60);
5474BX_DEBUG_INT74("int74: read byte %02x\n", in_byte);
5475
5476 mouse_flags_1 = read_byte(ebda_seg, 0x0026);
5477 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
5478
5479 if ( (mouse_flags_2 & 0x80) != 0x80 ) {
5480 return;
5481 }
5482
5483 package_count = mouse_flags_2 & 0x07;
5484 index = mouse_flags_1 & 0x07;
5485 write_byte(ebda_seg, 0x28 + index, in_byte);
5486
5487 if ( index >= package_count ) {
5488BX_DEBUG_INT74("int74_function: make_farcall=1\n");
5489 status = read_byte(ebda_seg, 0x0028 + 0);
5490 X = read_byte(ebda_seg, 0x0028 + 1);
5491 Y = read_byte(ebda_seg, 0x0028 + 2);
5492 Z = 0;
5493 mouse_flags_1 = 0;
5494 // check if far call handler installed
5495 if (mouse_flags_2 & 0x80)
5496 make_farcall = 1;
5497 }
5498 else {
5499 mouse_flags_1++;
5500 }
5501 write_byte(ebda_seg, 0x0026, mouse_flags_1);
5502}
5503
5504#define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
5505
5506#if BX_USE_ATADRV
5507
5508 void
5509int13_harddisk(EHBX, EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5510 Bit16u EHBX, EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5511{
5512 Bit32u lba;
5513 Bit16u ebda_seg=read_word(0x0040,0x000E);
5514 Bit16u cylinder, head, sector;
5515 Bit16u segment, offset;
5516 Bit16u npc, nph, npspt, nlc, nlh, nlspt;
5517 Bit16u size, count;
5518 Bit8u device, status;
5519
5520 BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5521
5522 write_byte(0x0040, 0x008e, 0); // clear completion flag
5523
5524 // basic check : device has to be defined
5525 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_STORAGE_DEVICES) ) {
5526 BX_DEBUG("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5527 goto int13_fail;
5528 }
5529
5530 // Get the ata channel
5531 device=read_byte(ebda_seg,&EbdaData->ata.hdidmap[GET_ELDL()-0x80]);
5532
5533 // basic check : device has to be valid
5534 if (device >= BX_MAX_STORAGE_DEVICES) {
5535 BX_DEBUG("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5536 goto int13_fail;
5537 }
5538
5539 switch (GET_AH()) {
5540
5541 case 0x00: /* disk controller reset */
5542#ifdef VBOX_WITH_SCSI
5543 /* SCSI controller does not need a reset. */
5544 if (!VBOX_IS_SCSI_DEVICE(device))
5545#endif
5546 ata_reset (device);
5547 goto int13_success;
5548 break;
5549
5550 case 0x01: /* read disk status */
5551 status = read_byte(0x0040, 0x0074);
5552 SET_AH(status);
5553 SET_DISK_RET_STATUS(0);
5554 /* set CF if error status read */
5555 if (status) goto int13_fail_nostatus;
5556 else goto int13_success_noah;
5557 break;
5558
5559 case 0x02: // read disk sectors
5560 case 0x03: // write disk sectors
5561 case 0x04: // verify disk sectors
5562
5563 count = GET_AL();
5564 cylinder = GET_CH();
5565 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
5566 sector = (GET_CL() & 0x3f);
5567 head = GET_DH();
5568
5569 segment = ES;
5570 offset = BX;
5571
5572 if ( (count > 128) || (count == 0) ) {
5573 BX_INFO("int13_harddisk: function %02x, count out of range!\n",GET_AH());
5574 goto int13_fail;
5575 }
5576
5577#ifdef VBOX_WITH_SCSI
5578 if (!VBOX_IS_SCSI_DEVICE(device))
5579#endif
5580 {
5581 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
5582 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
5583 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
5584 }
5585#ifdef VBOX_WITH_SCSI
5586 else
5587 {
5588 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5589
5590 nlc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.cylinders);
5591 nlh = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.heads);
5592 nlspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.spt);
5593 }
5594#endif
5595
5596 // sanity check on cyl heads, sec
5597 if( (cylinder >= nlc) || (head >= nlh) || (sector > nlspt )) {
5598 BX_INFO("int13_harddisk: function %02x, disk %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), GET_DL(), cylinder, head, sector);
5599 goto int13_fail;
5600 }
5601
5602 // FIXME verify
5603 if ( GET_AH() == 0x04 ) goto int13_success;
5604
5605#ifdef VBOX_WITH_SCSI
5606 if (!VBOX_IS_SCSI_DEVICE(device))
5607#endif
5608 {
5609 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5610 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5611 }
5612#ifdef VBOX_WITH_SCSI
5613 else
5614 {
5615 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5616 nph = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.heads);
5617 npspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.spt);
5618 }
5619#endif
5620
5621 // if needed, translate lchs to lba, and execute command
5622#ifdef VBOX_WITH_SCSI
5623 if (( (nph != nlh) || (npspt != nlspt)) || VBOX_IS_SCSI_DEVICE(device)) {
5624 lba = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
5625 sector = 0; // this forces the command to be lba
5626 }
5627#else
5628 if (( (nph != nlh) || (npspt != nlspt)) ) {
5629 lba = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
5630 sector = 0; // this forces the command to be lba
5631 }
5632#endif
5633
5634 if ( GET_AH() == 0x02 )
5635 {
5636#ifdef VBOX_WITH_SCSI
5637 if (VBOX_IS_SCSI_DEVICE(device))
5638 status=scsi_read_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5639 else
5640#endif
5641 {
5642 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,count * 0x200);
5643 status=ata_cmd_data_in(device, ATA_CMD_READ_MULTIPLE, count, cylinder, head, sector, lba, segment, offset);
5644 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,0x200);
5645 }
5646 }
5647 else
5648 {
5649#ifdef VBOX_WITH_SCSI
5650 if (VBOX_IS_SCSI_DEVICE(device))
5651 status=scsi_write_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5652 else
5653#endif
5654 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, cylinder, head, sector, lba, segment, offset);
5655 }
5656
5657 // Set nb of sector transferred
5658 SET_AL(read_word(ebda_seg, &EbdaData->ata.trsfsectors));
5659
5660 if (status != 0) {
5661 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5662 SET_AH(0x0c);
5663 goto int13_fail_noah;
5664 }
5665
5666 goto int13_success;
5667 break;
5668
5669 case 0x05: /* format disk track */
5670 BX_INFO("format disk track called\n");
5671 goto int13_success;
5672 return;
5673 break;
5674
5675 case 0x08: /* read disk drive parameters */
5676
5677 // Get logical geometry from table
5678#ifdef VBOX_WITH_SCSI
5679 if (!VBOX_IS_SCSI_DEVICE(device))
5680#endif
5681 {
5682 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
5683 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
5684 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
5685 }
5686#ifdef VBOX_WITH_SCSI
5687 else
5688 {
5689 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5690 nlc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.cylinders);
5691 nlh = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.heads);
5692 nlspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.lchs.spt);
5693 }
5694#endif
5695
5696 count = read_byte(ebda_seg, &EbdaData->ata.hdcount);
5697#ifndef VBOX
5698 nlc = nlc - 2; /* 0 based , last sector not used */
5699#else /* VBOX */
5700 /* Maximum cylinder number is just one less than the number of cylinders. */
5701 nlc = nlc - 1; /* 0 based , last sector not used */
5702#endif /* VBOX */
5703 SET_AL(0);
5704 SET_CH(nlc & 0xff);
5705 SET_CL(((nlc >> 2) & 0xc0) | (nlspt & 0x3f));
5706 SET_DH(nlh - 1);
5707 SET_DL(count); /* FIXME returns 0, 1, or n hard drives */
5708
5709 // FIXME should set ES & DI
5710
5711 goto int13_success;
5712 break;
5713
5714 case 0x10: /* check drive ready */
5715 // should look at 40:8E also???
5716
5717 // Read the status from controller
5718 status = inb(read_word(ebda_seg, &EbdaData->ata.channels[device/2].iobase1) + ATA_CB_STAT);
5719 if ( (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY ) {
5720 goto int13_success;
5721 }
5722 else {
5723 SET_AH(0xAA);
5724 goto int13_fail_noah;
5725 }
5726 break;
5727
5728 case 0x15: /* read disk drive size */
5729
5730 // Get physical geometry from table
5731#ifdef VBOX_WITH_SCSI
5732 if (!VBOX_IS_SCSI_DEVICE(device))
5733#endif
5734 {
5735 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5736 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5737 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5738 }
5739#ifdef VBOX_WITH_SCSI
5740 else
5741 {
5742 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5743 npc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.cylinders);
5744 nph = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.heads);
5745 npspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.spt);
5746 }
5747#endif
5748
5749 // Compute sector count seen by int13
5750#ifndef VBOX
5751 lba = (Bit32u)(npc - 1) * (Bit32u)nph * (Bit32u)npspt;
5752#else /* VBOX */
5753 /* Is it so hard to multiply a couple of counts (without introducing
5754 * arbitrary off by one errors)? */
5755 lba = (Bit32u)npc * (Bit32u)nph * (Bit32u)npspt;
5756#endif /* VBOX */
5757 CX = lba >> 16;
5758 DX = lba & 0xffff;
5759
5760 SET_AH(3); // hard disk accessible
5761 goto int13_success_noah;
5762 break;
5763
5764 case 0x41: // IBM/MS installation check
5765 BX=0xaa55; // install check
5766 SET_AH(0x30); // EDD 3.0
5767 CX=0x0007; // ext disk access and edd, removable supported
5768 goto int13_success_noah;
5769 break;
5770
5771 case 0x42: // IBM/MS extended read
5772 case 0x43: // IBM/MS extended write
5773 case 0x44: // IBM/MS verify
5774 case 0x47: // IBM/MS extended seek
5775
5776 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5777 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5778 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5779
5780 // Can't use 64 bits lba
5781 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5782 if (lba != 0L) {
5783 BX_PANIC("int13_harddisk: function %02x. Can't use 64bits lba\n",GET_AH());
5784 goto int13_fail;
5785 }
5786
5787 // Get 32 bits lba and check
5788 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5789
5790#ifdef VBOX_WITH_SCSI
5791 if (VBOX_IS_SCSI_DEVICE(device))
5792 {
5793 if (lba >= read_dword(ebda_seg, &EbdaData->scsi.devices[VBOX_GET_SCSI_DEVICE(device)].device_info.sectors) ) {
5794 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5795 goto int13_fail;
5796 }
5797 }
5798 else
5799#endif
5800 if (lba >= read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors) ) {
5801 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5802 goto int13_fail;
5803 }
5804
5805
5806 // If verify or seek
5807 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5808 goto int13_success;
5809
5810 // Execute the command
5811 if ( GET_AH() == 0x42 )
5812#ifdef VBOX
5813 {
5814#ifdef VBOX_WITH_SCSI
5815 if (VBOX_IS_SCSI_DEVICE(device))
5816 status=scsi_read_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5817 else
5818#endif
5819 {
5820 if (lba + count >= 268435456)
5821 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS_EXT, count, 0, 0, 0, lba, segment, offset);
5822 else {
5823 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,count * 0x200);
5824 status=ata_cmd_data_in(device, ATA_CMD_READ_MULTIPLE, count, 0, 0, 0, lba, segment, offset);
5825 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,0x200);
5826 }
5827 }
5828 }
5829#else /* !VBOX */
5830 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba, segment, offset);
5831#endif /* VBOX */
5832 else
5833#ifdef VBOX
5834 {
5835#ifdef VBOX_WITH_SCSI
5836 if (VBOX_IS_SCSI_DEVICE(device))
5837 status=scsi_write_sectors(VBOX_GET_SCSI_DEVICE(device), count, lba, segment, offset);
5838 else
5839#endif
5840 {
5841 if (lba + count >= 268435456)
5842 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS_EXT, count, 0, 0, 0, lba, segment, offset);
5843 else
5844 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
5845 }
5846 }
5847#else /* !VBOX */
5848 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
5849#endif /* VBOX */
5850
5851 count=read_word(ebda_seg, &EbdaData->ata.trsfsectors);
5852 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5853
5854 if (status != 0) {
5855 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5856 SET_AH(0x0c);
5857 goto int13_fail_noah;
5858 }
5859
5860 goto int13_success;
5861 break;
5862
5863 case 0x45: // IBM/MS lock/unlock drive
5864 case 0x49: // IBM/MS extended media change
5865 goto int13_success; // Always success for HD
5866 break;
5867
5868 case 0x46: // IBM/MS eject media
5869 SET_AH(0xb2); // Volume Not Removable
5870 goto int13_fail_noah; // Always fail for HD
5871 break;
5872
5873 case 0x48: // IBM/MS get drive parameters
5874 size=read_word(DS,SI+(Bit16u)&Int13DPT->size);
5875
5876 // Buffer is too small
5877 if(size < 0x1a)
5878 goto int13_fail;
5879
5880 // EDD 1.x
5881 if(size >= 0x1a) {
5882 Bit16u blksize;
5883
5884#ifdef VBOX_WITH_SCSI
5885 if (!VBOX_IS_SCSI_DEVICE(device))
5886#endif
5887 {
5888 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5889 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5890 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5891 lba = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors);
5892 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5893 }
5894#ifdef VBOX_WITH_SCSI
5895 else
5896 {
5897 Bit8u scsi_device = VBOX_GET_SCSI_DEVICE(device);
5898 npc = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.cylinders);
5899 nph = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.heads);
5900 npspt = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.pchs.spt);
5901 lba = read_dword(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.sectors);
5902 blksize = read_word(ebda_seg, &EbdaData->scsi.devices[scsi_device].device_info.blksize);
5903 }
5904#endif
5905
5906 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5907 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x02); // geometry is valid
5908 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, (Bit32u)npc);
5909 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, (Bit32u)nph);
5910 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, (Bit32u)npspt);
5911 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, lba); // FIXME should be Bit64
5912 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0L);
5913 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5914 }
5915
5916 // EDD 2.x
5917 if(size >= 0x1e) {
5918 Bit8u channel, dev, irq, mode, checksum, i, translation;
5919 Bit16u iobase1, iobase2, options;
5920
5921 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5922
5923 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5924 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5925
5926 // Fill in dpte
5927 channel = device / 2;
5928 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5929 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5930 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5931 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5932 translation = read_byte(ebda_seg, &EbdaData->ata.devices[device].translation);
5933
5934 options = (translation==ATA_TRANSLATION_NONE?0:1<<3); // chs translation
5935 options |= (1<<4); // lba translation
5936 options |= (mode==ATA_MODE_PIO32?1:0<<7);
5937 options |= (translation==ATA_TRANSLATION_LBA?1:0<<9);
5938 options |= (translation==ATA_TRANSLATION_RECHS?3:0<<9);
5939
5940 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5941 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5942 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5943 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5944 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5945 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5946 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5947 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5948 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5949 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5950 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5951
5952 checksum=0;
5953 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5954 checksum = -checksum;
5955 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5956 }
5957
5958 // EDD 3.x
5959 if(size >= 0x42) {
5960 Bit8u channel, iface, checksum, i;
5961 Bit16u iobase1;
5962
5963 channel = device / 2;
5964 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5965 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5966
5967 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5968 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5969 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5970 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5971 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5972
5973 if (iface==ATA_IFACE_ISA) {
5974 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5975 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5976 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5977 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], ' ');
5978 }
5979 else {
5980 // FIXME PCI
5981 }
5982 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5983 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5984 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5985 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], ' ');
5986 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[4], ' ');
5987 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[5], ' ');
5988 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[6], ' ');
5989 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[7], ' ');
5990
5991 if (iface==ATA_IFACE_ISA) {
5992 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5993 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5994 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5995 }
5996 else {
5997 // FIXME PCI
5998 }
5999 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
6000 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
6001 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
6002 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
6003
6004 checksum=0;
6005 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
6006 checksum = -checksum;
6007 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
6008 }
6009
6010 goto int13_success;
6011 break;
6012
6013 case 0x4e: // // IBM/MS set hardware configuration
6014 // DMA, prefetch, PIO maximum not supported
6015 switch (GET_AL()) {
6016 case 0x01:
6017 case 0x03:
6018 case 0x04:
6019 case 0x06:
6020 goto int13_success;
6021 break;
6022 default :
6023 goto int13_fail;
6024 }
6025 break;
6026
6027 case 0x09: /* initialize drive parameters */
6028 case 0x0c: /* seek to specified cylinder */
6029 case 0x0d: /* alternate disk reset */
6030 case 0x11: /* recalibrate */
6031 case 0x14: /* controller internal diagnostic */
6032 BX_INFO("int13_harddisk: function %02xh unimplemented, returns success\n", GET_AH());
6033 goto int13_success;
6034 break;
6035
6036 case 0x0a: /* read disk sectors with ECC */
6037 case 0x0b: /* write disk sectors with ECC */
6038 case 0x18: // set media type for format
6039 case 0x50: // IBM/MS send packet command
6040 default:
6041 BX_INFO("int13_harddisk: function %02xh unsupported, returns fail\n", GET_AH());
6042 goto int13_fail;
6043 break;
6044 }
6045
6046int13_fail:
6047 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6048int13_fail_noah:
6049 SET_DISK_RET_STATUS(GET_AH());
6050int13_fail_nostatus:
6051 SET_CF(); // error occurred
6052 return;
6053
6054int13_success:
6055 SET_AH(0x00); // no error
6056int13_success_noah:
6057 SET_DISK_RET_STATUS(0x00);
6058 CLEAR_CF(); // no error
6059 return;
6060}
6061
6062// ---------------------------------------------------------------------------
6063// Start of int13 for cdrom
6064// ---------------------------------------------------------------------------
6065
6066 void
6067int13_cdrom(EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
6068 Bit16u EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
6069{
6070 Bit16u ebda_seg=read_word(0x0040,0x000E);
6071 Bit8u device, status, locks;
6072 Bit8u atacmd[12];
6073 Bit32u lba;
6074 Bit16u count, segment, offset, i, size;
6075
6076 BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6077
6078 SET_DISK_RET_STATUS(0x00);
6079
6080 /* basic check : device should be 0xE0+ */
6081 if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES) ) {
6082 BX_DEBUG("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
6083 goto int13_fail;
6084 }
6085
6086 // Get the ata channel
6087 device=read_byte(ebda_seg,&EbdaData->ata.cdidmap[GET_ELDL()-0xE0]);
6088
6089 /* basic check : device has to be valid */
6090 if (device >= BX_MAX_ATA_DEVICES) {
6091 BX_DEBUG("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
6092 goto int13_fail;
6093 }
6094
6095 switch (GET_AH()) {
6096
6097 // all those functions return SUCCESS
6098 case 0x00: /* disk controller reset */
6099 case 0x09: /* initialize drive parameters */
6100 case 0x0c: /* seek to specified cylinder */
6101 case 0x0d: /* alternate disk reset */
6102 case 0x10: /* check drive ready */
6103 case 0x11: /* recalibrate */
6104 case 0x14: /* controller internal diagnostic */
6105 case 0x16: /* detect disk change */
6106 goto int13_success;
6107 break;
6108
6109 // all those functions return disk write-protected
6110 case 0x03: /* write disk sectors */
6111 case 0x05: /* format disk track */
6112 case 0x43: // IBM/MS extended write
6113 SET_AH(0x03);
6114 goto int13_fail_noah;
6115 break;
6116
6117 case 0x01: /* read disk status */
6118 status = read_byte(0x0040, 0x0074);
6119 SET_AH(status);
6120 SET_DISK_RET_STATUS(0);
6121
6122 /* set CF if error status read */
6123 if (status) goto int13_fail_nostatus;
6124 else goto int13_success_noah;
6125 break;
6126
6127 case 0x15: /* read disk drive size */
6128 SET_AH(0x02);
6129 goto int13_fail_noah;
6130 break;
6131
6132 case 0x41: // IBM/MS installation check
6133 BX=0xaa55; // install check
6134 SET_AH(0x30); // EDD 2.1
6135 CX=0x0007; // ext disk access, removable and edd
6136 goto int13_success_noah;
6137 break;
6138
6139 case 0x42: // IBM/MS extended read
6140 case 0x44: // IBM/MS verify sectors
6141 case 0x47: // IBM/MS extended seek
6142
6143 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
6144 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
6145 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
6146
6147 // Can't use 64 bits lba
6148 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
6149 if (lba != 0L) {
6150 BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
6151 goto int13_fail;
6152 }
6153
6154 // Get 32 bits lba
6155 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
6156
6157 // If verify or seek
6158 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
6159 goto int13_success;
6160
6161 memsetb(get_SS(),atacmd,0,12);
6162 atacmd[0]=0x28; // READ command
6163 atacmd[7]=(count & 0xff00) >> 8; // Sectors
6164 atacmd[8]=(count & 0x00ff); // Sectors
6165 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
6166 atacmd[3]=(lba & 0x00ff0000) >> 16;
6167 atacmd[4]=(lba & 0x0000ff00) >> 8;
6168 atacmd[5]=(lba & 0x000000ff);
6169 status = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, count*2048L, ATA_DATA_IN, segment,offset);
6170
6171 count = (Bit16u)(read_dword(ebda_seg, &EbdaData->ata.trsfbytes) >> 11);
6172 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
6173
6174 if (status != 0) {
6175 BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status);
6176 SET_AH(0x0c);
6177 goto int13_fail_noah;
6178 }
6179
6180 goto int13_success;
6181 break;
6182
6183 case 0x45: // IBM/MS lock/unlock drive
6184 if (GET_AL() > 2) goto int13_fail;
6185
6186 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
6187
6188 switch (GET_AL()) {
6189 case 0 : // lock
6190 if (locks == 0xff) {
6191 SET_AH(0xb4);
6192 SET_AL(1);
6193 goto int13_fail_noah;
6194 }
6195 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, ++locks);
6196 SET_AL(1);
6197 break;
6198 case 1 : // unlock
6199 if (locks == 0x00) {
6200 SET_AH(0xb0);
6201 SET_AL(0);
6202 goto int13_fail_noah;
6203 }
6204 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, --locks);
6205 SET_AL(locks==0?0:1);
6206 break;
6207 case 2 : // status
6208 SET_AL(locks==0?0:1);
6209 break;
6210 }
6211 goto int13_success;
6212 break;
6213
6214 case 0x46: // IBM/MS eject media
6215 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
6216
6217 if (locks != 0) {
6218 SET_AH(0xb1); // media locked
6219 goto int13_fail_noah;
6220 }
6221 // FIXME should handle 0x31 no media in device
6222 // FIXME should handle 0xb5 valid request failed
6223
6224 // Call removable media eject
6225 ASM_START
6226 push bp
6227 mov bp, sp
6228
6229 mov ah, #0x52
6230 int #0x15
6231 mov _int13_cdrom.status + 2[bp], ah
6232 jnc int13_cdrom_rme_end
6233 mov _int13_cdrom.status, #1
6234int13_cdrom_rme_end:
6235 pop bp
6236 ASM_END
6237
6238 if (status != 0) {
6239 SET_AH(0xb1); // media locked
6240 goto int13_fail_noah;
6241 }
6242
6243 goto int13_success;
6244 break;
6245
6246 case 0x48: // IBM/MS get drive parameters
6247 size = read_word(DS,SI+(Bit16u)&Int13Ext->size);
6248
6249 // Buffer is too small
6250 if(size < 0x1a)
6251 goto int13_fail;
6252
6253 // EDD 1.x
6254 if(size >= 0x1a) {
6255 Bit16u cylinders, heads, spt, blksize;
6256
6257 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
6258
6259 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
6260 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x74); // removable, media change, lockable, max values
6261 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, 0xffffffff);
6262 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, 0xffffffff);
6263 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, 0xffffffff);
6264 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, 0xffffffff); // FIXME should be Bit64
6265 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0xffffffff);
6266 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
6267 }
6268
6269 // EDD 2.x
6270 if(size >= 0x1e) {
6271 Bit8u channel, dev, irq, mode, checksum, i;
6272 Bit16u iobase1, iobase2, options;
6273
6274 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
6275
6276 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
6277 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
6278
6279 // Fill in dpte
6280 channel = device / 2;
6281 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
6282 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
6283 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
6284 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
6285
6286 // FIXME atapi device
6287 options = (1<<4); // lba translation
6288 options |= (1<<5); // removable device
6289 options |= (1<<6); // atapi device
6290 options |= (mode==ATA_MODE_PIO32?1:0<<7);
6291
6292 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
6293 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
6294 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
6295 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
6296 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
6297 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
6298 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
6299 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
6300 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
6301 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
6302 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
6303
6304 checksum=0;
6305 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
6306 checksum = -checksum;
6307 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
6308 }
6309
6310 // EDD 3.x
6311 if(size >= 0x42) {
6312 Bit8u channel, iface, checksum, i;
6313 Bit16u iobase1;
6314
6315 channel = device / 2;
6316 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
6317 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
6318
6319 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
6320 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
6321 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
6322 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
6323 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
6324
6325 if (iface==ATA_IFACE_ISA) {
6326 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
6327 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
6328 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
6329 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
6330 }
6331 else {
6332 // FIXME PCI
6333 }
6334 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
6335 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
6336 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
6337 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
6338
6339 if (iface==ATA_IFACE_ISA) {
6340 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
6341 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
6342 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
6343 }
6344 else {
6345 // FIXME PCI
6346 }
6347 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
6348 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
6349 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
6350 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
6351
6352 checksum=0;
6353 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
6354 checksum = -checksum;
6355 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
6356 }
6357
6358 goto int13_success;
6359 break;
6360
6361 case 0x49: // IBM/MS extended media change
6362 // always send changed ??
6363 SET_AH(06);
6364 goto int13_fail_nostatus;
6365 break;
6366
6367 case 0x4e: // // IBM/MS set hardware configuration
6368 // DMA, prefetch, PIO maximum not supported
6369 switch (GET_AL()) {
6370 case 0x01:
6371 case 0x03:
6372 case 0x04:
6373 case 0x06:
6374 goto int13_success;
6375 break;
6376 default :
6377 goto int13_fail;
6378 }
6379 break;
6380
6381 // all those functions return unimplemented
6382 case 0x02: /* read sectors */
6383 case 0x04: /* verify sectors */
6384 case 0x08: /* read disk drive parameters */
6385 case 0x0a: /* read disk sectors with ECC */
6386 case 0x0b: /* write disk sectors with ECC */
6387 case 0x18: /* set media type for format */
6388 case 0x50: // ? - send packet command
6389 default:
6390 BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
6391 goto int13_fail;
6392 break;
6393 }
6394
6395int13_fail:
6396 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6397int13_fail_noah:
6398 SET_DISK_RET_STATUS(GET_AH());
6399int13_fail_nostatus:
6400 SET_CF(); // error occurred
6401 return;
6402
6403int13_success:
6404 SET_AH(0x00); // no error
6405int13_success_noah:
6406 SET_DISK_RET_STATUS(0x00);
6407 CLEAR_CF(); // no error
6408 return;
6409}
6410
6411// ---------------------------------------------------------------------------
6412// End of int13 for cdrom
6413// ---------------------------------------------------------------------------
6414
6415#if BX_ELTORITO_BOOT
6416// ---------------------------------------------------------------------------
6417// Start of int13 for eltorito functions
6418// ---------------------------------------------------------------------------
6419
6420 void
6421int13_eltorito(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
6422 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
6423{
6424 Bit16u ebda_seg=read_word(0x0040,0x000E);
6425
6426 BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6427 // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
6428
6429 switch (GET_AH()) {
6430
6431 // FIXME ElTorito Various. Should be implemented
6432 case 0x4a: // ElTorito - Initiate disk emu
6433 case 0x4c: // ElTorito - Initiate disk emu and boot
6434 case 0x4d: // ElTorito - Return Boot catalog
6435 BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX);
6436 goto int13_fail;
6437 break;
6438
6439 case 0x4b: // ElTorito - Terminate disk emu
6440 // FIXME ElTorito Hardcoded
6441 write_byte(DS,SI+0x00,0x13);
6442 write_byte(DS,SI+0x01,read_byte(ebda_seg,&EbdaData->cdemu.media));
6443 write_byte(DS,SI+0x02,read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
6444 write_byte(DS,SI+0x03,read_byte(ebda_seg,&EbdaData->cdemu.controller_index));
6445 write_dword(DS,SI+0x04,read_dword(ebda_seg,&EbdaData->cdemu.ilba));
6446 write_word(DS,SI+0x08,read_word(ebda_seg,&EbdaData->cdemu.device_spec));
6447 write_word(DS,SI+0x0a,read_word(ebda_seg,&EbdaData->cdemu.buffer_segment));
6448 write_word(DS,SI+0x0c,read_word(ebda_seg,&EbdaData->cdemu.load_segment));
6449 write_word(DS,SI+0x0e,read_word(ebda_seg,&EbdaData->cdemu.sector_count));
6450 write_byte(DS,SI+0x10,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.cylinders));
6451 write_byte(DS,SI+0x11,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.spt));
6452 write_byte(DS,SI+0x12,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.heads));
6453
6454 // If we have to terminate emulation
6455 if(GET_AL() == 0x00) {
6456 // FIXME ElTorito Various. Should be handled accordingly to spec
6457 write_byte(ebda_seg,&EbdaData->cdemu.active, 0x00); // bye bye
6458 }
6459
6460 goto int13_success;
6461 break;
6462
6463 default:
6464 BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
6465 goto int13_fail;
6466 break;
6467 }
6468
6469int13_fail:
6470 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6471 SET_DISK_RET_STATUS(GET_AH());
6472 SET_CF(); // error occurred
6473 return;
6474
6475int13_success:
6476 SET_AH(0x00); // no error
6477 SET_DISK_RET_STATUS(0x00);
6478 CLEAR_CF(); // no error
6479 return;
6480}
6481
6482// ---------------------------------------------------------------------------
6483// End of int13 for eltorito functions
6484// ---------------------------------------------------------------------------
6485
6486// ---------------------------------------------------------------------------
6487// Start of int13 when emulating a device from the cd
6488// ---------------------------------------------------------------------------
6489
6490 void
6491int13_cdemu(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
6492 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
6493{
6494 Bit16u ebda_seg=read_word(0x0040,0x000E);
6495 Bit8u device, status;
6496 Bit16u vheads, vspt, vcylinders;
6497 Bit16u head, sector, cylinder, nbsectors;
6498 Bit32u vlba, ilba, slba, elba;
6499 Bit16u before, segment, offset;
6500 Bit8u atacmd[12];
6501
6502 BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6503
6504 /* at this point, we are emulating a floppy/harddisk */
6505
6506 // Recompute the device number
6507 device = read_byte(ebda_seg,&EbdaData->cdemu.controller_index) * 2;
6508 device += read_byte(ebda_seg,&EbdaData->cdemu.device_spec);
6509
6510 SET_DISK_RET_STATUS(0x00);
6511
6512 /* basic checks : emulation should be active, dl should equal the emulated drive */
6513 if( (read_byte(ebda_seg,&EbdaData->cdemu.active) ==0 )
6514 || (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive ) != GET_DL())) {
6515 BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
6516 goto int13_fail;
6517 }
6518
6519 switch (GET_AH()) {
6520
6521 // all those functions return SUCCESS
6522 case 0x00: /* disk controller reset */
6523 case 0x09: /* initialize drive parameters */
6524 case 0x0c: /* seek to specified cylinder */
6525 case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
6526 case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
6527 case 0x11: /* recalibrate */
6528 case 0x14: /* controller internal diagnostic */
6529 case 0x16: /* detect disk change */
6530 goto int13_success;
6531 break;
6532
6533 // all those functions return disk write-protected
6534 case 0x03: /* write disk sectors */
6535 case 0x05: /* format disk track */
6536 SET_AH(0x03);
6537 goto int13_fail_noah;
6538 break;
6539
6540 case 0x01: /* read disk status */
6541 status=read_byte(0x0040, 0x0074);
6542 SET_AH(status);
6543 SET_DISK_RET_STATUS(0);
6544
6545 /* set CF if error status read */
6546 if (status) goto int13_fail_nostatus;
6547 else goto int13_success_noah;
6548 break;
6549
6550 case 0x02: // read disk sectors
6551 case 0x04: // verify disk sectors
6552 vspt = read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
6553 vcylinders = read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders);
6554 vheads = read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads);
6555
6556 ilba = read_dword(ebda_seg,&EbdaData->cdemu.ilba);
6557
6558 sector = GET_CL() & 0x003f;
6559 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
6560 head = GET_DH();
6561 nbsectors = GET_AL();
6562 segment = ES;
6563 offset = BX;
6564
6565 // no sector to read ?
6566 if(nbsectors==0) goto int13_success;
6567
6568 // sanity checks sco openserver needs this!
6569 if ((sector > vspt)
6570 || (cylinder >= vcylinders)
6571 || (head >= vheads)) {
6572 goto int13_fail;
6573 }
6574
6575 // After controls, verify do nothing
6576 if (GET_AH() == 0x04) goto int13_success;
6577
6578 segment = ES+(BX / 16);
6579 offset = BX % 16;
6580
6581 // calculate the virtual lba inside the image
6582 vlba=((((Bit32u)cylinder*(Bit32u)vheads)+(Bit32u)head)*(Bit32u)vspt)+((Bit32u)(sector-1));
6583
6584 // In advance so we don't loose the count
6585 SET_AL(nbsectors);
6586
6587 // start lba on cd
6588 slba = (Bit32u)vlba/4;
6589 before= (Bit16u)vlba%4;
6590
6591 // end lba on cd
6592 elba = (Bit32u)(vlba+nbsectors-1)/4;
6593
6594 memsetb(get_SS(),atacmd,0,12);
6595 atacmd[0]=0x28; // READ command
6596 atacmd[7]=((Bit16u)(elba-slba+1) & 0xff00) >> 8; // Sectors
6597 atacmd[8]=((Bit16u)(elba-slba+1) & 0x00ff); // Sectors
6598 atacmd[2]=(ilba+slba & 0xff000000) >> 24; // LBA
6599 atacmd[3]=(ilba+slba & 0x00ff0000) >> 16;
6600 atacmd[4]=(ilba+slba & 0x0000ff00) >> 8;
6601 atacmd[5]=(ilba+slba & 0x000000ff);
6602 if((status = ata_cmd_packet(device, 12, get_SS(), atacmd, before*512, nbsectors*512L, ATA_DATA_IN, segment,offset)) != 0) {
6603 BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status);
6604 SET_AH(0x02);
6605 SET_AL(0);
6606 goto int13_fail_noah;
6607 }
6608
6609 goto int13_success;
6610 break;
6611
6612 case 0x08: /* read disk drive parameters */
6613 vspt=read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
6614 vcylinders=read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders) - 1;
6615 vheads=read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads) - 1;
6616
6617 SET_AL( 0x00 );
6618 SET_BL( 0x00 );
6619 SET_CH( vcylinders & 0xff );
6620 SET_CL((( vcylinders >> 2) & 0xc0) | ( vspt & 0x3f ));
6621 SET_DH( vheads );
6622 SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2
6623 // FIXME ElTorito Harddisk. should send the HD count
6624
6625 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
6626 case 0x01: SET_BL( 0x02 ); break;
6627 case 0x02: SET_BL( 0x04 ); break;
6628 case 0x03: SET_BL( 0x06 ); break;
6629 }
6630
6631ASM_START
6632 push bp
6633 mov bp, sp
6634 mov ax, #diskette_param_table2
6635 mov _int13_cdemu.DI+2[bp], ax
6636 mov _int13_cdemu.ES+2[bp], cs
6637 pop bp
6638ASM_END
6639 goto int13_success;
6640 break;
6641
6642 case 0x15: /* read disk drive size */
6643 // FIXME ElTorito Harddisk. What geometry to send ?
6644 SET_AH(0x03);
6645 goto int13_success_noah;
6646 break;
6647
6648 // all those functions return unimplemented
6649 case 0x0a: /* read disk sectors with ECC */
6650 case 0x0b: /* write disk sectors with ECC */
6651 case 0x18: /* set media type for format */
6652 case 0x41: // IBM/MS installation check
6653 // FIXME ElTorito Harddisk. Darwin would like to use EDD
6654 case 0x42: // IBM/MS extended read
6655 case 0x43: // IBM/MS extended write
6656 case 0x44: // IBM/MS verify sectors
6657 case 0x45: // IBM/MS lock/unlock drive
6658 case 0x46: // IBM/MS eject media
6659 case 0x47: // IBM/MS extended seek
6660 case 0x48: // IBM/MS get drive parameters
6661 case 0x49: // IBM/MS extended media change
6662 case 0x4e: // ? - set hardware configuration
6663 case 0x50: // ? - send packet command
6664 default:
6665 BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
6666 goto int13_fail;
6667 break;
6668 }
6669
6670int13_fail:
6671 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6672int13_fail_noah:
6673 SET_DISK_RET_STATUS(GET_AH());
6674int13_fail_nostatus:
6675 SET_CF(); // error occurred
6676 return;
6677
6678int13_success:
6679 SET_AH(0x00); // no error
6680int13_success_noah:
6681 SET_DISK_RET_STATUS(0x00);
6682 CLEAR_CF(); // no error
6683 return;
6684}
6685
6686// ---------------------------------------------------------------------------
6687// End of int13 when emulating a device from the cd
6688// ---------------------------------------------------------------------------
6689
6690#endif // BX_ELTORITO_BOOT
6691
6692#else //BX_USE_ATADRV
6693
6694 void
6695outLBA(cylinder,hd_heads,head,hd_sectors,sector,dl)
6696 Bit16u cylinder;
6697 Bit16u hd_heads;
6698 Bit16u head;
6699 Bit16u hd_sectors;
6700 Bit16u sector;
6701 Bit16u dl;
6702{
6703ASM_START
6704 push bp
6705 mov bp, sp
6706 push eax
6707 push ebx
6708 push edx
6709 xor eax,eax
6710 mov ax,4[bp] // cylinder
6711 xor ebx,ebx
6712 mov bl,6[bp] // hd_heads
6713 imul ebx
6714
6715 mov bl,8[bp] // head
6716 add eax,ebx
6717 mov bl,10[bp] // hd_sectors
6718 imul ebx
6719 mov bl,12[bp] // sector
6720 add eax,ebx
6721
6722 dec eax
6723 mov dx,#0x1f3
6724 out dx,al
6725 mov dx,#0x1f4
6726 mov al,ah
6727 out dx,al
6728 shr eax,#16
6729 mov dx,#0x1f5
6730 out dx,al
6731 and ah,#0xf
6732 mov bl,14[bp] // dl
6733 and bl,#1
6734 shl bl,#4
6735 or ah,bl
6736 or ah,#0xe0
6737 mov al,ah
6738 mov dx,#0x01f6
6739 out dx,al
6740 pop edx
6741 pop ebx
6742 pop eax
6743 pop bp
6744ASM_END
6745}
6746
6747 void
6748int13_harddisk(EHBX, EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
6749 Bit16u EHBX, EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
6750{
6751 Bit8u drive, num_sectors, sector, head, status, mod;
6752 Bit8u drive_map;
6753 Bit8u n_drives;
6754 Bit16u cyl_mod, ax;
6755 Bit16u max_cylinder, cylinder, total_sectors;
6756 Bit16u hd_cylinders;
6757 Bit8u hd_heads, hd_sectors;
6758 Bit16u val16;
6759 Bit8u sector_count;
6760 unsigned int i;
6761 Bit16u tempbx;
6762 Bit16u dpsize;
6763
6764 Bit16u count, segment, offset;
6765 Bit32u lba;
6766 Bit16u error;
6767
6768 BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6769
6770 write_byte(0x0040, 0x008e, 0); // clear completion flag
6771
6772 /* at this point, DL is >= 0x80 to be passed from the floppy int13h
6773 handler code */
6774 /* check how many disks first (cmos reg 0x12), return an error if
6775 drive not present */
6776 drive_map = inb_cmos(0x12);
6777 drive_map = (((drive_map & 0xf0)==0) ? 0 : 1) |
6778 (((drive_map & 0x0f)==0) ? 0 : 2);
6779 n_drives = (drive_map==0) ? 0 :
6780 ((drive_map==3) ? 2 : 1);
6781
6782 if (!(drive_map & (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
6783 SET_AH(0x01);
6784 SET_DISK_RET_STATUS(0x01);
6785 SET_CF(); /* error occurred */
6786 return;
6787 }
6788
6789 switch (GET_AH()) {
6790
6791 case 0x00: /* disk controller reset */
6792BX_DEBUG_INT13_HD("int13_f00\n");
6793
6794 SET_AH(0);
6795 SET_DISK_RET_STATUS(0);
6796 set_diskette_ret_status(0);
6797 set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
6798 set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
6799 CLEAR_CF(); /* successful */
6800 return;
6801 break;
6802
6803 case 0x01: /* read disk status */
6804BX_DEBUG_INT13_HD("int13_f01\n");
6805 status = read_byte(0x0040, 0x0074);
6806 SET_AH(status);
6807 SET_DISK_RET_STATUS(0);
6808 /* set CF if error status read */
6809 if (status) SET_CF();
6810 else CLEAR_CF();
6811 return;
6812 break;
6813
6814 case 0x04: // verify disk sectors
6815 case 0x02: // read disk sectors
6816 drive = GET_ELDL();
6817 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6818
6819 num_sectors = GET_AL();
6820 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
6821 sector = (GET_CL() & 0x3f);
6822 head = GET_DH();
6823
6824
6825 if (hd_cylinders > 1024) {
6826 if (hd_cylinders <= 2048) {
6827 cylinder <<= 1;
6828 }
6829 else if (hd_cylinders <= 4096) {
6830 cylinder <<= 2;
6831 }
6832 else if (hd_cylinders <= 8192) {
6833 cylinder <<= 3;
6834 }
6835 else { // hd_cylinders <= 16384
6836 cylinder <<= 4;
6837 }
6838
6839 ax = head / hd_heads;
6840 cyl_mod = ax & 0xff;
6841 head = ax >> 8;
6842 cylinder |= cyl_mod;
6843 }
6844
6845 if ( (cylinder >= hd_cylinders) ||
6846 (sector > hd_sectors) ||
6847 (head >= hd_heads) ) {
6848 SET_AH(1);
6849 SET_DISK_RET_STATUS(1);
6850 SET_CF(); /* error occurred */
6851 return;
6852 }
6853
6854 if ( (num_sectors > 128) || (num_sectors == 0) )
6855 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6856
6857 if (head > 15)
6858 BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
6859
6860 if ( GET_AH() == 0x04 ) {
6861 SET_AH(0);
6862 SET_DISK_RET_STATUS(0);
6863 CLEAR_CF();
6864 return;
6865 }
6866
6867 status = inb(0x1f7);
6868 if (status & 0x80) {
6869 BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
6870 }
6871 outb(0x01f2, num_sectors);
6872 /* activate LBA? (tomv) */
6873 if (hd_heads > 16) {
6874BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder, head, sector);
6875 outLBA(cylinder,hd_heads,head,hd_sectors,sector,drive);
6876 }
6877 else {
6878 outb(0x01f3, sector);
6879 outb(0x01f4, cylinder & 0x00ff);
6880 outb(0x01f5, cylinder >> 8);
6881 outb(0x01f6, 0xa0 | ((drive & 0x01)<<4) | (head & 0x0f));
6882 }
6883 outb(0x01f7, 0x20);
6884
6885 while (1) {
6886 status = inb(0x1f7);
6887 if ( !(status & 0x80) ) break;
6888 }
6889
6890 if (status & 0x01) {
6891 BX_PANIC("hard drive BIOS:(read/verify) read error\n");
6892 } else if ( !(status & 0x08) ) {
6893 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6894 BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
6895 }
6896
6897 sector_count = 0;
6898 tempbx = BX;
6899
6900ASM_START
6901 sti ;; enable higher priority interrupts
6902ASM_END
6903
6904 while (1) {
6905ASM_START
6906 ;; store temp bx in real DI register
6907 push bp
6908 mov bp, sp
6909 mov di, _int13_harddisk.tempbx + 2 [bp]
6910 pop bp
6911
6912 ;; adjust if there will be an overrun
6913 cmp di, #0xfe00
6914 jbe i13_f02_no_adjust
6915i13_f02_adjust:
6916 sub di, #0x0200 ; sub 512 bytes from offset
6917 mov ax, es
6918 add ax, #0x0020 ; add 512 to segment
6919 mov es, ax
6920
6921i13_f02_no_adjust:
6922 mov cx, #0x0100 ;; counter (256 words = 512b)
6923 mov dx, #0x01f0 ;; AT data read port
6924
6925 rep
6926 insw ;; CX words transferred from port(DX) to ES:[DI]
6927
6928i13_f02_done:
6929 ;; store real DI register back to temp bx
6930 push bp
6931 mov bp, sp
6932 mov _int13_harddisk.tempbx + 2 [bp], di
6933 pop bp
6934ASM_END
6935
6936 sector_count++;
6937 num_sectors--;
6938 if (num_sectors == 0) {
6939 status = inb(0x1f7);
6940 if ( (status & 0xc9) != 0x40 )
6941 BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status);
6942 break;
6943 }
6944 else {
6945 status = inb(0x1f7);
6946 if ( (status & 0xc9) != 0x48 )
6947 BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status);
6948 continue;
6949 }
6950 }
6951
6952 SET_AH(0);
6953 SET_DISK_RET_STATUS(0);
6954 SET_AL(sector_count);
6955 CLEAR_CF(); /* successful */
6956 return;
6957 break;
6958
6959
6960 case 0x03: /* write disk sectors */
6961BX_DEBUG_INT13_HD("int13_f03\n");
6962 drive = GET_ELDL ();
6963 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6964
6965 num_sectors = GET_AL();
6966 cylinder = GET_CH();
6967 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
6968 sector = (GET_CL() & 0x3f);
6969 head = GET_DH();
6970
6971 if (hd_cylinders > 1024) {
6972 if (hd_cylinders <= 2048) {
6973 cylinder <<= 1;
6974 }
6975 else if (hd_cylinders <= 4096) {
6976 cylinder <<= 2;
6977 }
6978 else if (hd_cylinders <= 8192) {
6979 cylinder <<= 3;
6980 }
6981 else { // hd_cylinders <= 16384
6982 cylinder <<= 4;
6983 }
6984
6985 ax = head / hd_heads;
6986 cyl_mod = ax & 0xff;
6987 head = ax >> 8;
6988 cylinder |= cyl_mod;
6989 }
6990
6991 if ( (cylinder >= hd_cylinders) ||
6992 (sector > hd_sectors) ||
6993 (head >= hd_heads) ) {
6994 SET_AH( 1);
6995 SET_DISK_RET_STATUS(1);
6996 SET_CF(); /* error occurred */
6997 return;
6998 }
6999
7000 if ( (num_sectors > 128) || (num_sectors == 0) )
7001 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
7002
7003 if (head > 15)
7004 BX_PANIC("hard drive BIOS:(read) head > 15\n");
7005
7006 status = inb(0x1f7);
7007 if (status & 0x80) {
7008 BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
7009 }
7010// should check for Drive Ready Bit also in status reg
7011 outb(0x01f2, num_sectors);
7012
7013 /* activate LBA? (tomv) */
7014 if (hd_heads > 16) {
7015BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder, head, sector);
7016 outLBA(cylinder,hd_heads,head,hd_sectors,sector,GET_ELDL());
7017 }
7018 else {
7019 outb(0x01f3, sector);
7020 outb(0x01f4, cylinder & 0x00ff);
7021 outb(0x01f5, cylinder >> 8);
7022 outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head & 0x0f));
7023 }
7024 outb(0x01f7, 0x30);
7025
7026 // wait for busy bit to turn off after seeking
7027 while (1) {
7028 status = inb(0x1f7);
7029 if ( !(status & 0x80) ) break;
7030 }
7031
7032 if ( !(status & 0x08) ) {
7033 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
7034 BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
7035 }
7036
7037 sector_count = 0;
7038 tempbx = BX;
7039
7040ASM_START
7041 sti ;; enable higher priority interrupts
7042ASM_END
7043
7044 while (1) {
7045ASM_START
7046 ;; store temp bx in real SI register
7047 push bp
7048 mov bp, sp
7049 mov si, _int13_harddisk.tempbx + 2 [bp]
7050 pop bp
7051
7052 ;; adjust if there will be an overrun
7053 cmp si, #0xfe00
7054 jbe i13_f03_no_adjust
7055i13_f03_adjust:
7056 sub si, #0x0200 ; sub 512 bytes from offset
7057 mov ax, es
7058 add ax, #0x0020 ; add 512 to segment
7059 mov es, ax
7060
7061i13_f03_no_adjust:
7062 mov cx, #0x0100 ;; counter (256 words = 512b)
7063 mov dx, #0x01f0 ;; AT data read port
7064
7065 seg ES
7066 rep
7067 outsw ;; CX words transferred from ES:[SI] to port(DX)
7068
7069 ;; store real SI register back to temp bx
7070 push bp
7071 mov bp, sp
7072 mov _int13_harddisk.tempbx + 2 [bp], si
7073 pop bp
7074ASM_END
7075
7076 sector_count++;
7077 num_sectors--;
7078 if (num_sectors == 0) {
7079 status = inb(0x1f7);
7080 if ( (status & 0xe9) != 0x40 )
7081 BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status);
7082 break;
7083 }
7084 else {
7085 status = inb(0x1f7);
7086 if ( (status & 0xc9) != 0x48 )
7087 BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status);
7088 continue;
7089 }
7090 }
7091
7092 SET_AH(0);
7093 SET_DISK_RET_STATUS(0);
7094 SET_AL(sector_count);
7095 CLEAR_CF(); /* successful */
7096 return;
7097 break;
7098
7099 case 0x05: /* format disk track */
7100BX_DEBUG_INT13_HD("int13_f05\n");
7101 BX_PANIC("format disk track called\n");
7102 /* nop */
7103 SET_AH(0);
7104 SET_DISK_RET_STATUS(0);
7105 CLEAR_CF(); /* successful */
7106 return;
7107 break;
7108
7109 case 0x08: /* read disk drive parameters */
7110BX_DEBUG_INT13_HD("int13_f08\n");
7111
7112 drive = GET_ELDL ();
7113 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
7114
7115 // translate CHS
7116 //
7117 if (hd_cylinders <= 1024) {
7118 // hd_cylinders >>= 0;
7119 // hd_heads <<= 0;
7120 }
7121 else if (hd_cylinders <= 2048) {
7122 hd_cylinders >>= 1;
7123 hd_heads <<= 1;
7124 }
7125 else if (hd_cylinders <= 4096) {
7126 hd_cylinders >>= 2;
7127 hd_heads <<= 2;
7128 }
7129 else if (hd_cylinders <= 8192) {
7130 hd_cylinders >>= 3;
7131 hd_heads <<= 3;
7132 }
7133 else { // hd_cylinders <= 16384
7134 hd_cylinders >>= 4;
7135 hd_heads <<= 4;
7136 }
7137
7138 max_cylinder = hd_cylinders - 2; /* 0 based */
7139 SET_AL(0);
7140 SET_CH(max_cylinder & 0xff);
7141 SET_CL(((max_cylinder >> 2) & 0xc0) | (hd_sectors & 0x3f));
7142 SET_DH(hd_heads - 1);
7143 SET_DL(n_drives); /* returns 0, 1, or 2 hard drives */
7144 SET_AH(0);
7145 SET_DISK_RET_STATUS(0);
7146 CLEAR_CF(); /* successful */
7147
7148 return;
7149 break;
7150
7151 case 0x09: /* initialize drive parameters */
7152BX_DEBUG_INT13_HD("int13_f09\n");
7153 SET_AH(0);
7154 SET_DISK_RET_STATUS(0);
7155 CLEAR_CF(); /* successful */
7156 return;
7157 break;
7158
7159 case 0x0a: /* read disk sectors with ECC */
7160BX_DEBUG_INT13_HD("int13_f0a\n");
7161 case 0x0b: /* write disk sectors with ECC */
7162BX_DEBUG_INT13_HD("int13_f0b\n");
7163 BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
7164 return;
7165 break;
7166
7167 case 0x0c: /* seek to specified cylinder */
7168BX_DEBUG_INT13_HD("int13_f0c\n");
7169 BX_INFO("int13h function 0ch (seek) not implemented!\n");
7170 SET_AH(0);
7171 SET_DISK_RET_STATUS(0);
7172 CLEAR_CF(); /* successful */
7173 return;
7174 break;
7175
7176 case 0x0d: /* alternate disk reset */
7177BX_DEBUG_INT13_HD("int13_f0d\n");
7178 SET_AH(0);
7179 SET_DISK_RET_STATUS(0);
7180 CLEAR_CF(); /* successful */
7181 return;
7182 break;
7183
7184 case 0x10: /* check drive ready */
7185BX_DEBUG_INT13_HD("int13_f10\n");
7186 //SET_AH(0);
7187 //SET_DISK_RET_STATUS(0);
7188 //CLEAR_CF(); /* successful */
7189 //return;
7190 //break;
7191
7192 // should look at 40:8E also???
7193 status = inb(0x01f7);
7194 if ( (status & 0xc0) == 0x40 ) {
7195 SET_AH(0);
7196 SET_DISK_RET_STATUS(0);
7197 CLEAR_CF(); // drive ready
7198 return;
7199 }
7200 else {
7201 SET_AH(0xAA);
7202 SET_DISK_RET_STATUS(0xAA);
7203 SET_CF(); // not ready
7204 return;
7205 }
7206 break;
7207
7208 case 0x11: /* recalibrate */
7209BX_DEBUG_INT13_HD("int13_f11\n");
7210 SET_AH(0);
7211 SET_DISK_RET_STATUS(0);
7212 CLEAR_CF(); /* successful */
7213 return;
7214 break;
7215
7216 case 0x14: /* controller internal diagnostic */
7217BX_DEBUG_INT13_HD("int13_f14\n");
7218 SET_AH(0);
7219 SET_DISK_RET_STATUS(0);
7220 CLEAR_CF(); /* successful */
7221 SET_AL(0);
7222 return;
7223 break;
7224
7225 case 0x15: /* read disk drive size */
7226 drive = GET_ELDL();
7227 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
7228ASM_START
7229 push bp
7230 mov bp, sp
7231 mov al, _int13_harddisk.hd_heads + 2 [bp]
7232 mov ah, _int13_harddisk.hd_sectors + 2 [bp]
7233 mul al, ah ;; ax = heads * sectors
7234 mov bx, _int13_harddisk.hd_cylinders + 2 [bp]
7235 dec bx ;; use (cylinders - 1) ???
7236 mul ax, bx ;; dx:ax = (cylinders -1) * (heads * sectors)
7237 ;; now we need to move the 32bit result dx:ax to what the
7238 ;; BIOS wants which is cx:dx.
7239 ;; and then into CX:DX on the stack
7240 mov _int13_harddisk.CX + 2 [bp], dx
7241 mov _int13_harddisk.DX + 2 [bp], ax
7242 pop bp
7243ASM_END
7244 SET_AH(3); // hard disk accessible
7245 SET_DISK_RET_STATUS(0); // ??? should this be 0
7246 CLEAR_CF(); // successful
7247 return;
7248 break;
7249
7250 case 0x18: // set media type for format
7251 case 0x41: // IBM/MS
7252 case 0x42: // IBM/MS
7253 case 0x43: // IBM/MS
7254 case 0x44: // IBM/MS
7255 case 0x45: // IBM/MS lock/unlock drive
7256 case 0x46: // IBM/MS eject media
7257 case 0x47: // IBM/MS extended seek
7258 case 0x49: // IBM/MS extended media change
7259 case 0x50: // IBM/MS send packet command
7260 default:
7261 BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
7262
7263 SET_AH(1); // code=invalid function in AH or invalid parameter
7264 SET_DISK_RET_STATUS(1);
7265 SET_CF(); /* unsuccessful */
7266 return;
7267 break;
7268 }
7269}
7270
7271static char panic_msg_reg12h[] = "HD%d cmos reg 12h not type F\n";
7272static char panic_msg_reg19h[] = "HD%d cmos reg %02xh not user definable type 47\n";
7273
7274 void
7275get_hd_geometry(drive, hd_cylinders, hd_heads, hd_sectors)
7276 Bit8u drive;
7277 Bit16u *hd_cylinders;
7278 Bit8u *hd_heads;
7279 Bit8u *hd_sectors;
7280{
7281 Bit8u hd_type;
7282 Bit16u ss;
7283 Bit16u cylinders;
7284 Bit8u iobase;
7285
7286 ss = get_SS();
7287 if (drive == 0x80) {
7288 hd_type = inb_cmos(0x12) & 0xf0;
7289 if (hd_type != 0xf0)
7290 BX_INFO(panic_msg_reg12h,0);
7291 hd_type = inb_cmos(0x19); // HD0: extended type
7292 if (hd_type != 47)
7293 BX_INFO(panic_msg_reg19h,0,0x19);
7294 iobase = 0x1b;
7295 } else {
7296 hd_type = inb_cmos(0x12) & 0x0f;
7297 if (hd_type != 0x0f)
7298 BX_INFO(panic_msg_reg12h,1);
7299 hd_type = inb_cmos(0x1a); // HD1: extended type
7300 if (hd_type != 47)
7301 BX_INFO(panic_msg_reg19h,0,0x1a);
7302 iobase = 0x24;
7303 }
7304
7305 // cylinders
7306 cylinders = inb_cmos(iobase) | (inb_cmos(iobase+1) << 8);
7307 write_word(ss, hd_cylinders, cylinders);
7308
7309 // heads
7310 write_byte(ss, hd_heads, inb_cmos(iobase+2));
7311
7312 // sectors per track
7313 write_byte(ss, hd_sectors, inb_cmos(iobase+8));
7314}
7315
7316#endif //else BX_USE_ATADRV
7317
7318#if BX_SUPPORT_FLOPPY
7319
7320//////////////////////
7321// FLOPPY functions //
7322//////////////////////
7323
7324void floppy_reset_controller()
7325{
7326 Bit8u val8;
7327
7328 // Reset controller
7329 val8 = inb(0x03f2);
7330 outb(0x03f2, val8 & ~0x04);
7331 outb(0x03f2, val8 | 0x04);
7332
7333 // Wait for controller to come out of reset
7334 do {
7335 val8 = inb(0x3f4);
7336 } while ( (val8 & 0xc0) != 0x80 );
7337}
7338
7339void floppy_prepare_controller(drive)
7340 Bit16u drive;
7341{
7342 Bit8u val8, dor, prev_reset;
7343
7344 // set 40:3e bit 7 to 0
7345 val8 = read_byte(0x0040, 0x003e);
7346 val8 &= 0x7f;
7347 write_byte(0x0040, 0x003e, val8);
7348
7349 // turn on motor of selected drive, DMA & int enabled, normal operation
7350 prev_reset = inb(0x03f2) & 0x04;
7351 if (drive)
7352 dor = 0x20;
7353 else
7354 dor = 0x10;
7355 dor |= 0x0c;
7356 dor |= drive;
7357 outb(0x03f2, dor);
7358
7359 // reset the disk motor timeout value of INT 08
7360 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
7361
7362#ifdef VBOX
7363 // program data rate
7364 val8 = read_byte(0x0040, 0x008b);
7365 val8 >>= 6;
7366 outb(0x03f7, val8);
7367#endif
7368
7369 // wait for drive readiness
7370 do {
7371 val8 = inb(0x3f4);
7372 } while ( (val8 & 0xc0) != 0x80 );
7373
7374 if (prev_reset == 0) {
7375 // turn on interrupts
7376ASM_START
7377 sti
7378ASM_END
7379 // wait on 40:3e bit 7 to become 1
7380 do {
7381 val8 = read_byte(0x0040, 0x003e);
7382 } while ( (val8 & 0x80) == 0 );
7383 val8 &= 0x7f;
7384ASM_START
7385 cli
7386ASM_END
7387 write_byte(0x0040, 0x003e, val8);
7388 }
7389}
7390
7391 bx_bool
7392floppy_media_known(drive)
7393 Bit16u drive;
7394{
7395 Bit8u val8;
7396 Bit16u media_state_offset;
7397
7398 val8 = read_byte(0x0040, 0x003e); // diskette recal status
7399 if (drive)
7400 val8 >>= 1;
7401 val8 &= 0x01;
7402 if (val8 == 0)
7403 return(0);
7404
7405 media_state_offset = 0x0090;
7406 if (drive)
7407 media_state_offset += 1;
7408
7409 val8 = read_byte(0x0040, media_state_offset);
7410 val8 = (val8 >> 4) & 0x01;
7411 if (val8 == 0)
7412 return(0);
7413
7414 // check pass, return KNOWN
7415 return(1);
7416}
7417
7418 bx_bool
7419floppy_read_id(drive)
7420 Bit16u drive;
7421{
7422 Bit8u val8;
7423 Bit8u return_status[7];
7424
7425 floppy_prepare_controller(drive);
7426
7427 // send Read ID command (2 bytes) to controller
7428 outb(0x03f5, 0x4a); // 4a: Read ID (MFM)
7429 outb(0x03f5, drive); // 0=drive0, 1=drive1, head always 0
7430
7431 // turn on interrupts
7432ASM_START
7433 sti
7434ASM_END
7435
7436 // wait on 40:3e bit 7 to become 1
7437 do {
7438 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7439 } while ( val8 == 0 );
7440
7441 val8 = 0; // separate asm from while() loop
7442 // turn off interrupts
7443ASM_START
7444 cli
7445ASM_END
7446
7447 // read 7 return status bytes from controller
7448 return_status[0] = inb(0x3f5);
7449 return_status[1] = inb(0x3f5);
7450 return_status[2] = inb(0x3f5);
7451 return_status[3] = inb(0x3f5);
7452 return_status[4] = inb(0x3f5);
7453 return_status[5] = inb(0x3f5);
7454 return_status[6] = inb(0x3f5);
7455
7456 if ( (return_status[0] & 0xc0) != 0 )
7457 return(0);
7458 else
7459 return(1);
7460}
7461
7462 bx_bool
7463floppy_media_sense(drive)
7464 Bit16u drive;
7465{
7466 bx_bool retval;
7467 Bit16u media_state_offset;
7468 Bit8u drive_type, config_data, media_state;
7469
7470 if (floppy_drive_recal(drive) == 0) {
7471 return(0);
7472 }
7473
7474 // Try the diskette data rates in the following order:
7475 // 1 Mbps -> 500 Kbps -> 300 Kbps -> 250 Kbps
7476 // The 1 Mbps rate is only tried for 2.88M drives.
7477
7478 // ** config_data **
7479 // Bitfields for diskette media control:
7480 // Bit(s) Description (Table M0028)
7481 // 7-6 last data rate set by controller
7482 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
7483 // 5-4 last diskette drive step rate selected
7484 // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
7485 // 3-2 {data rate at start of operation}
7486 // 1-0 reserved
7487
7488 // ** media_state **
7489 // Bitfields for diskette drive media state:
7490 // Bit(s) Description (Table M0030)
7491 // 7-6 data rate
7492 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
7493 // 5 double stepping required (e.g. 360kB in 1.2MB)
7494 // 4 media type established
7495 // 3 drive capable of supporting 4MB media
7496 // 2-0 on exit from BIOS, contains
7497 // 000 trying 360kB in 360kB
7498 // 001 trying 360kB in 1.2MB
7499 // 010 trying 1.2MB in 1.2MB
7500 // 011 360kB in 360kB established
7501 // 100 360kB in 1.2MB established
7502 // 101 1.2MB in 1.2MB established
7503 // 110 reserved
7504 // 111 all other formats/drives
7505
7506 drive_type = inb_cmos(0x10);
7507 if (drive == 0)
7508 drive_type >>= 4;
7509 else
7510 drive_type &= 0x0f;
7511 if ( drive_type == 1 ) {
7512 // 360K 5.25" drive
7513 config_data = 0x00; // 0000 0000
7514 media_state = 0x15; // 0001 0101
7515 retval = 1;
7516 }
7517 else if ( drive_type == 2 ) {
7518 // 1.2 MB 5.25" drive
7519 config_data = 0x00; // 0000 0000
7520 media_state = 0x35; // 0011 0101 // need double stepping??? (bit 5)
7521 retval = 1;
7522 }
7523 else if ( drive_type == 3 ) {
7524 // 720K 3.5" drive
7525 config_data = 0x00; // 0000 0000 ???
7526 media_state = 0x17; // 0001 0111
7527 retval = 1;
7528 }
7529 else if ( drive_type == 4 ) {
7530 // 1.44 MB 3.5" drive
7531 config_data = 0x00; // 0000 0000
7532 media_state = 0x17; // 0001 0111
7533 retval = 1;
7534 }
7535 else if ( drive_type == 5 ) {
7536 // 2.88 MB 3.5" drive
7537 config_data = 0xCC; // 1100 1100
7538 media_state = 0xD7; // 1101 0111
7539 retval = 1;
7540 }
7541 //
7542 // Extended floppy size uses special cmos setting
7543 else if ( drive_type == 6 ) {
7544 // 160k 5.25" drive
7545 config_data = 0x00; // 0000 0000
7546 media_state = 0x27; // 0010 0111
7547 retval = 1;
7548 }
7549 else if ( drive_type == 7 ) {
7550 // 180k 5.25" drive
7551 config_data = 0x00; // 0000 0000
7552 media_state = 0x27; // 0010 0111
7553 retval = 1;
7554 }
7555 else if ( drive_type == 8 ) {
7556 // 320k 5.25" drive
7557 config_data = 0x00; // 0000 0000
7558 media_state = 0x27; // 0010 0111
7559 retval = 1;
7560 }
7561
7562 else {
7563 // not recognized
7564 config_data = 0x00; // 0000 0000
7565 media_state = 0x00; // 0000 0000
7566 retval = 0;
7567 }
7568
7569 write_byte(0x0040, 0x008B, config_data);
7570 while (!floppy_read_id(drive)) {
7571 if ((config_data & 0xC0) == 0x80) {
7572 // If even 250 Kbps failed, we can't do much
7573 break;
7574 }
7575 switch (config_data & 0xC0) {
7576 case 0xC0: // 1 Mbps
7577 config_data = config_data & 0x3F | 0x00;
7578 break;
7579 case 0x00: // 500 Kbps
7580 config_data = config_data & 0x3F | 0x40;
7581 break;
7582 case 0x40: // 300 Kbps
7583 config_data = config_data & 0x3F | 0x80;
7584 break;
7585 }
7586 write_byte(0x0040, 0x008B, config_data);
7587 }
7588
7589 if (drive == 0)
7590 media_state_offset = 0x0090;
7591 else
7592 media_state_offset = 0x0091;
7593 write_byte(0x0040, 0x008B, config_data);
7594 write_byte(0x0040, media_state_offset, media_state);
7595
7596 return(retval);
7597}
7598
7599 bx_bool
7600floppy_drive_recal(drive)
7601 Bit16u drive;
7602{
7603 Bit8u val8;
7604 Bit16u curr_cyl_offset;
7605
7606 floppy_prepare_controller(drive);
7607
7608 // send Recalibrate command (2 bytes) to controller
7609 outb(0x03f5, 0x07); // 07: Recalibrate
7610 outb(0x03f5, drive); // 0=drive0, 1=drive1
7611
7612 // turn on interrupts
7613ASM_START
7614 sti
7615ASM_END
7616
7617 // wait on 40:3e bit 7 to become 1
7618 do {
7619 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7620 } while ( val8 == 0 );
7621
7622 val8 = 0; // separate asm from while() loop
7623 // turn off interrupts
7624ASM_START
7625 cli
7626ASM_END
7627
7628 // set 40:3e bit 7 to 0, and calibrated bit
7629 val8 = read_byte(0x0040, 0x003e);
7630 val8 &= 0x7f;
7631 if (drive) {
7632 val8 |= 0x02; // Drive 1 calibrated
7633 curr_cyl_offset = 0x0095;
7634 } else {
7635 val8 |= 0x01; // Drive 0 calibrated
7636 curr_cyl_offset = 0x0094;
7637 }
7638 write_byte(0x0040, 0x003e, val8);
7639 write_byte(0x0040, curr_cyl_offset, 0); // current cylinder is 0
7640
7641 return(1);
7642}
7643
7644
7645
7646 bx_bool
7647floppy_drive_exists(drive)
7648 Bit16u drive;
7649{
7650 Bit8u drive_type;
7651
7652 // check CMOS to see if drive exists
7653 drive_type = inb_cmos(0x10);
7654 if (drive == 0)
7655 drive_type >>= 4;
7656 else
7657 drive_type &= 0x0f;
7658 if ( drive_type == 0 )
7659 return(0);
7660 else
7661 return(1);
7662}
7663
7664 void
7665int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
7666 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
7667{
7668 Bit8u drive, num_sectors, track, sector, head, status;
7669 Bit16u base_address, base_count, base_es;
7670 Bit8u page, mode_register, val8, dor;
7671 Bit8u return_status[7];
7672 Bit8u drive_type, num_floppies, ah;
7673 Bit16u es, last_addr;
7674
7675 BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
7676
7677 ah = GET_AH();
7678
7679 switch ( ah ) {
7680 case 0x00: // diskette controller reset
7681BX_DEBUG_INT13_FL("floppy f00\n");
7682 drive = GET_ELDL();
7683 if (drive > 1) {
7684 SET_AH(1); // invalid param
7685 set_diskette_ret_status(1);
7686 SET_CF();
7687 return;
7688 }
7689 drive_type = inb_cmos(0x10);
7690
7691 if (drive == 0)
7692 drive_type >>= 4;
7693 else
7694 drive_type &= 0x0f;
7695 if (drive_type == 0) {
7696 SET_AH(0x80); // drive not responding
7697 set_diskette_ret_status(0x80);
7698 SET_CF();
7699 return;
7700 }
7701
7702 // force re-calibration etc.
7703 write_byte(0x0040, 0x003e, 0);
7704
7705 SET_AH(0);
7706 set_diskette_ret_status(0);
7707 CLEAR_CF(); // successful
7708 set_diskette_current_cyl(drive, 0); // current cylinder
7709 return;
7710
7711 case 0x01: // Read Diskette Status
7712 CLEAR_CF();
7713 val8 = read_byte(0x0000, 0x0441);
7714 SET_AH(val8);
7715 if (val8) {
7716 SET_CF();
7717 }
7718 return;
7719
7720 case 0x02: // Read Diskette Sectors
7721 case 0x03: // Write Diskette Sectors
7722 case 0x04: // Verify Diskette Sectors
7723 num_sectors = GET_AL();
7724 track = GET_CH();
7725 sector = GET_CL();
7726 head = GET_DH();
7727 drive = GET_ELDL();
7728
7729 if ( (drive > 1) || (head > 1) ||
7730 (num_sectors == 0) || (num_sectors > 72) ) {
7731BX_INFO("floppy: drive>1 || head>1 ...\n");
7732 SET_AH(1);
7733 set_diskette_ret_status(1);
7734 SET_AL(0); // no sectors read
7735 SET_CF(); // error occurred
7736 return;
7737 }
7738
7739 // see if drive exists
7740 if (floppy_drive_exists(drive) == 0) {
7741 SET_AH(0x80); // not responding
7742 set_diskette_ret_status(0x80);
7743 SET_AL(0); // no sectors read
7744 SET_CF(); // error occurred
7745 return;
7746 }
7747
7748 // see if media in drive, and type is known
7749 if (floppy_media_known(drive) == 0) {
7750 if (floppy_media_sense(drive) == 0) {
7751 SET_AH(0x0C); // Media type not found
7752 set_diskette_ret_status(0x0C);
7753 SET_AL(0); // no sectors read
7754 SET_CF(); // error occurred
7755 return;
7756 }
7757 }
7758
7759 if (ah == 0x02) {
7760 // Read Diskette Sectors
7761
7762 //-----------------------------------
7763 // set up DMA controller for transfer
7764 //-----------------------------------
7765
7766 // es:bx = pointer to where to place information from diskette
7767 // port 04: DMA-1 base and current address, channel 2
7768 // port 05: DMA-1 base and current count, channel 2
7769 page = (ES >> 12); // upper 4 bits
7770 base_es = (ES << 4); // lower 16bits contributed by ES
7771 base_address = base_es + BX; // lower 16 bits of address
7772 // contributed by ES:BX
7773 if ( base_address < base_es ) {
7774 // in case of carry, adjust page by 1
7775 page++;
7776 }
7777 base_count = (num_sectors * 512) - 1;
7778
7779 // check for 64K boundary overrun
7780 last_addr = base_address + base_count;
7781 if (last_addr < base_address) {
7782 SET_AH(0x09);
7783 set_diskette_ret_status(0x09);
7784 SET_AL(0); // no sectors read
7785 SET_CF(); // error occurred
7786 return;
7787 }
7788
7789 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7790 outb(0x000a, 0x06);
7791
7792 BX_DEBUG_INT13_FL("clear flip-flop\n");
7793 outb(0x000c, 0x00); // clear flip-flop
7794 outb(0x0004, base_address);
7795 outb(0x0004, base_address>>8);
7796 BX_DEBUG_INT13_FL("clear flip-flop\n");
7797 outb(0x000c, 0x00); // clear flip-flop
7798 outb(0x0005, base_count);
7799 outb(0x0005, base_count>>8);
7800
7801 // port 0b: DMA-1 Mode Register
7802 mode_register = 0x46; // single mode, increment, autoinit disable,
7803 // transfer type=write, channel 2
7804 BX_DEBUG_INT13_FL("setting mode register\n");
7805 outb(0x000b, mode_register);
7806
7807 BX_DEBUG_INT13_FL("setting page register\n");
7808 // port 81: DMA-1 Page Register, channel 2
7809 outb(0x0081, page);
7810
7811 BX_DEBUG_INT13_FL("unmask chan 2\n");
7812 outb(0x000a, 0x02); // unmask channel 2
7813
7814 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7815 outb(0x000a, 0x02);
7816
7817 //--------------------------------------
7818 // set up floppy controller for transfer
7819 //--------------------------------------
7820 floppy_prepare_controller(drive);
7821
7822 // send read-normal-data command (9 bytes) to controller
7823 outb(0x03f5, 0xe6); // e6: read normal data
7824 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7825 outb(0x03f5, track);
7826 outb(0x03f5, head);
7827 outb(0x03f5, sector);
7828 outb(0x03f5, 2); // 512 byte sector size
7829 outb(0x03f5, sector + num_sectors - 1); // last sector to read on track
7830 outb(0x03f5, 0); // Gap length
7831 outb(0x03f5, 0xff); // Gap length
7832
7833 // turn on interrupts
7834 ASM_START
7835 sti
7836 ASM_END
7837
7838 // wait on 40:3e bit 7 to become 1
7839 do {
7840 val8 = read_byte(0x0040, 0x0040);
7841 if (val8 == 0) {
7842 floppy_reset_controller();
7843 SET_AH(0x80); // drive not ready (timeout)
7844 set_diskette_ret_status(0x80);
7845 SET_AL(0); // no sectors read
7846 SET_CF(); // error occurred
7847 return;
7848 }
7849 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7850 } while ( val8 == 0 );
7851
7852 val8 = 0; // separate asm from while() loop
7853 // turn off interrupts
7854 ASM_START
7855 cli
7856 ASM_END
7857
7858 // set 40:3e bit 7 to 0
7859 val8 = read_byte(0x0040, 0x003e);
7860 val8 &= 0x7f;
7861 write_byte(0x0040, 0x003e, val8);
7862
7863 // check port 3f4 for accessibility to status bytes
7864 val8 = inb(0x3f4);
7865 if ( (val8 & 0xc0) != 0xc0 )
7866 BX_PANIC("int13_diskette: ctrl not ready\n");
7867
7868 // read 7 return status bytes from controller
7869 // using loop index broken, have to unroll...
7870 return_status[0] = inb(0x3f5);
7871 return_status[1] = inb(0x3f5);
7872 return_status[2] = inb(0x3f5);
7873 return_status[3] = inb(0x3f5);
7874 return_status[4] = inb(0x3f5);
7875 return_status[5] = inb(0x3f5);
7876 return_status[6] = inb(0x3f5);
7877 // record in BIOS Data Area
7878 write_byte(0x0040, 0x0042, return_status[0]);
7879 write_byte(0x0040, 0x0043, return_status[1]);
7880 write_byte(0x0040, 0x0044, return_status[2]);
7881 write_byte(0x0040, 0x0045, return_status[3]);
7882 write_byte(0x0040, 0x0046, return_status[4]);
7883 write_byte(0x0040, 0x0047, return_status[5]);
7884 write_byte(0x0040, 0x0048, return_status[6]);
7885
7886 if ( (return_status[0] & 0xc0) != 0 ) {
7887 SET_AH(0x20);
7888 set_diskette_ret_status(0x20);
7889 SET_AL(0); // no sectors read
7890 SET_CF(); // error occurred
7891 return;
7892 }
7893
7894 // ??? should track be new val from return_status[3] ?
7895 set_diskette_current_cyl(drive, track);
7896 // AL = number of sectors read (same value as passed)
7897 SET_AH(0x00); // success
7898 CLEAR_CF(); // success
7899 return;
7900 } else if (ah == 0x03) {
7901 // Write Diskette Sectors
7902
7903 //-----------------------------------
7904 // set up DMA controller for transfer
7905 //-----------------------------------
7906
7907 // es:bx = pointer to where to place information from diskette
7908 // port 04: DMA-1 base and current address, channel 2
7909 // port 05: DMA-1 base and current count, channel 2
7910 page = (ES >> 12); // upper 4 bits
7911 base_es = (ES << 4); // lower 16bits contributed by ES
7912 base_address = base_es + BX; // lower 16 bits of address
7913 // contributed by ES:BX
7914 if ( base_address < base_es ) {
7915 // in case of carry, adjust page by 1
7916 page++;
7917 }
7918 base_count = (num_sectors * 512) - 1;
7919
7920 // check for 64K boundary overrun
7921 last_addr = base_address + base_count;
7922 if (last_addr < base_address) {
7923 SET_AH(0x09);
7924 set_diskette_ret_status(0x09);
7925 SET_AL(0); // no sectors read
7926 SET_CF(); // error occurred
7927 return;
7928 }
7929
7930 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7931 outb(0x000a, 0x06);
7932
7933 outb(0x000c, 0x00); // clear flip-flop
7934 outb(0x0004, base_address);
7935 outb(0x0004, base_address>>8);
7936 outb(0x000c, 0x00); // clear flip-flop
7937 outb(0x0005, base_count);
7938 outb(0x0005, base_count>>8);
7939
7940 // port 0b: DMA-1 Mode Register
7941 mode_register = 0x4a; // single mode, increment, autoinit disable,
7942 // transfer type=read, channel 2
7943 outb(0x000b, mode_register);
7944
7945 // port 81: DMA-1 Page Register, channel 2
7946 outb(0x0081, page);
7947
7948 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7949 outb(0x000a, 0x02);
7950
7951 //--------------------------------------
7952 // set up floppy controller for transfer
7953 //--------------------------------------
7954 floppy_prepare_controller(drive);
7955
7956 // send write-normal-data command (9 bytes) to controller
7957 outb(0x03f5, 0xc5); // c5: write normal data
7958 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7959 outb(0x03f5, track);
7960 outb(0x03f5, head);
7961 outb(0x03f5, sector);
7962 outb(0x03f5, 2); // 512 byte sector size
7963 outb(0x03f5, sector + num_sectors - 1); // last sector to write on track
7964 outb(0x03f5, 0); // Gap length
7965 outb(0x03f5, 0xff); // Gap length
7966
7967 // turn on interrupts
7968 ASM_START
7969 sti
7970 ASM_END
7971
7972 // wait on 40:3e bit 7 to become 1
7973 do {
7974 val8 = read_byte(0x0040, 0x0040);
7975 if (val8 == 0) {
7976 floppy_reset_controller();
7977 SET_AH(0x80); // drive not ready (timeout)
7978 set_diskette_ret_status(0x80);
7979 SET_AL(0); // no sectors written
7980 SET_CF(); // error occurred
7981 return;
7982 }
7983 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7984 } while ( val8 == 0 );
7985
7986 val8 = 0; // separate asm from while() loop
7987 // turn off interrupts
7988 ASM_START
7989 cli
7990 ASM_END
7991
7992 // set 40:3e bit 7 to 0
7993 val8 = read_byte(0x0040, 0x003e);
7994 val8 &= 0x7f;
7995 write_byte(0x0040, 0x003e, val8);
7996
7997 // check port 3f4 for accessibility to status bytes
7998 val8 = inb(0x3f4);
7999 if ( (val8 & 0xc0) != 0xc0 )
8000 BX_PANIC("int13_diskette: ctrl not ready\n");
8001
8002 // read 7 return status bytes from controller
8003 // using loop index broken, have to unroll...
8004 return_status[0] = inb(0x3f5);
8005 return_status[1] = inb(0x3f5);
8006 return_status[2] = inb(0x3f5);
8007 return_status[3] = inb(0x3f5);
8008 return_status[4] = inb(0x3f5);
8009 return_status[5] = inb(0x3f5);
8010 return_status[6] = inb(0x3f5);
8011 // record in BIOS Data Area
8012 write_byte(0x0040, 0x0042, return_status[0]);
8013 write_byte(0x0040, 0x0043, return_status[1]);
8014 write_byte(0x0040, 0x0044, return_status[2]);
8015 write_byte(0x0040, 0x0045, return_status[3]);
8016 write_byte(0x0040, 0x0046, return_status[4]);
8017 write_byte(0x0040, 0x0047, return_status[5]);
8018 write_byte(0x0040, 0x0048, return_status[6]);
8019
8020 if ( (return_status[0] & 0xc0) != 0 ) {
8021 if ( (return_status[1] & 0x02) != 0 ) {
8022 // diskette not writable.
8023 // AH=status code=0x03 (tried to write on write-protected disk)
8024 // AL=number of sectors written=0
8025 AX = 0x0300;
8026 SET_CF();
8027 return;
8028 } else {
8029 BX_PANIC("int13_diskette_function: read error\n");
8030 }
8031 }
8032
8033 // ??? should track be new val from return_status[3] ?
8034 set_diskette_current_cyl(drive, track);
8035 // AL = number of sectors read (same value as passed)
8036 SET_AH(0x00); // success
8037 CLEAR_CF(); // success
8038 return;
8039 } else { // if (ah == 0x04)
8040 // Verify Diskette Sectors
8041
8042 // ??? should track be new val from return_status[3] ?
8043 set_diskette_current_cyl(drive, track);
8044 // AL = number of sectors verified (same value as passed)
8045 CLEAR_CF(); // success
8046 SET_AH(0x00); // success
8047 return;
8048 }
8049 break;
8050
8051 case 0x05: // format diskette track
8052BX_DEBUG_INT13_FL("floppy f05\n");
8053
8054 num_sectors = GET_AL();
8055 track = GET_CH();
8056 head = GET_DH();
8057 drive = GET_ELDL();
8058
8059 if ((drive > 1) || (head > 1) || (track > 79) ||
8060 (num_sectors == 0) || (num_sectors > 18)) {
8061 SET_AH(1);
8062 set_diskette_ret_status(1);
8063 SET_CF(); // error occurred
8064 }
8065
8066 // see if drive exists
8067 if (floppy_drive_exists(drive) == 0) {
8068 SET_AH(0x80); // drive not responding
8069 set_diskette_ret_status(0x80);
8070 SET_CF(); // error occurred
8071 return;
8072 }
8073
8074 // see if media in drive, and type is known
8075 if (floppy_media_known(drive) == 0) {
8076 if (floppy_media_sense(drive) == 0) {
8077 SET_AH(0x0C); // Media type not found
8078 set_diskette_ret_status(0x0C);
8079 SET_AL(0); // no sectors read
8080 SET_CF(); // error occurred
8081 return;
8082 }
8083 }
8084
8085 // set up DMA controller for transfer
8086 page = (ES >> 12); // upper 4 bits
8087 base_es = (ES << 4); // lower 16bits contributed by ES
8088 base_address = base_es + BX; // lower 16 bits of address
8089 // contributed by ES:BX
8090 if ( base_address < base_es ) {
8091 // in case of carry, adjust page by 1
8092 page++;
8093 }
8094 base_count = (num_sectors * 4) - 1;
8095
8096 // check for 64K boundary overrun
8097 last_addr = base_address + base_count;
8098 if (last_addr < base_address) {
8099 SET_AH(0x09);
8100 set_diskette_ret_status(0x09);
8101 SET_AL(0); // no sectors read
8102 SET_CF(); // error occurred
8103 return;
8104 }
8105
8106 outb(0x000a, 0x06);
8107 outb(0x000c, 0x00); // clear flip-flop
8108 outb(0x0004, base_address);
8109 outb(0x0004, base_address>>8);
8110 outb(0x000c, 0x00); // clear flip-flop
8111 outb(0x0005, base_count);
8112 outb(0x0005, base_count>>8);
8113 mode_register = 0x4a; // single mode, increment, autoinit disable,
8114 // transfer type=read, channel 2
8115 outb(0x000b, mode_register);
8116 // port 81: DMA-1 Page Register, channel 2
8117 outb(0x0081, page);
8118 outb(0x000a, 0x02);
8119
8120 // set up floppy controller for transfer
8121 floppy_prepare_controller(drive);
8122
8123 // send format-track command (6 bytes) to controller
8124 outb(0x03f5, 0x4d); // 4d: format track
8125 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
8126 outb(0x03f5, 2); // 512 byte sector size
8127 outb(0x03f5, num_sectors); // number of sectors per track
8128 outb(0x03f5, 0); // Gap length
8129 outb(0x03f5, 0xf6); // Fill byte
8130 // turn on interrupts
8131 ASM_START
8132 sti
8133 ASM_END
8134
8135 // wait on 40:3e bit 7 to become 1
8136 do {
8137 val8 = read_byte(0x0040, 0x0040);
8138 if (val8 == 0) {
8139 floppy_reset_controller();
8140 SET_AH(0x80); // drive not ready (timeout)
8141 set_diskette_ret_status(0x80);
8142 SET_CF(); // error occurred
8143 return;
8144 }
8145 val8 = (read_byte(0x0040, 0x003e) & 0x80);
8146 } while ( val8 == 0 );
8147
8148 val8 = 0; // separate asm from while() loop
8149 // turn off interrupts
8150 ASM_START
8151 cli
8152 ASM_END
8153 // set 40:3e bit 7 to 0
8154 val8 = read_byte(0x0040, 0x003e);
8155 val8 &= 0x7f;
8156 write_byte(0x0040, 0x003e, val8);
8157 // check port 3f4 for accessibility to status bytes
8158 val8 = inb(0x3f4);
8159 if ( (val8 & 0xc0) != 0xc0 )
8160 BX_PANIC("int13_diskette: ctrl not ready\n");
8161
8162 // read 7 return status bytes from controller
8163 // using loop index broken, have to unroll...
8164 return_status[0] = inb(0x3f5);
8165 return_status[1] = inb(0x3f5);
8166 return_status[2] = inb(0x3f5);
8167 return_status[3] = inb(0x3f5);
8168 return_status[4] = inb(0x3f5);
8169 return_status[5] = inb(0x3f5);
8170 return_status[6] = inb(0x3f5);
8171 // record in BIOS Data Area
8172 write_byte(0x0040, 0x0042, return_status[0]);
8173 write_byte(0x0040, 0x0043, return_status[1]);
8174 write_byte(0x0040, 0x0044, return_status[2]);
8175 write_byte(0x0040, 0x0045, return_status[3]);
8176 write_byte(0x0040, 0x0046, return_status[4]);
8177 write_byte(0x0040, 0x0047, return_status[5]);
8178 write_byte(0x0040, 0x0048, return_status[6]);
8179
8180 if ( (return_status[0] & 0xc0) != 0 ) {
8181 if ( (return_status[1] & 0x02) != 0 ) {
8182 // diskette not writable.
8183 // AH=status code=0x03 (tried to write on write-protected disk)
8184 // AL=number of sectors written=0
8185 AX = 0x0300;
8186 SET_CF();
8187 return;
8188 } else {
8189 BX_PANIC("int13_diskette_function: write error\n");
8190 }
8191 }
8192
8193 SET_AH(0);
8194 set_diskette_ret_status(0);
8195 set_diskette_current_cyl(drive, 0);
8196 CLEAR_CF(); // successful
8197 return;
8198
8199
8200 case 0x08: // read diskette drive parameters
8201BX_DEBUG_INT13_FL("floppy f08\n");
8202 drive = GET_ELDL();
8203
8204 if (drive > 1) {
8205 AX = 0;
8206 BX = 0;
8207 CX = 0;
8208 DX = 0;
8209 ES = 0;
8210 DI = 0;
8211 SET_DL(num_floppies);
8212 SET_CF();
8213 return;
8214 }
8215
8216 drive_type = inb_cmos(0x10);
8217 num_floppies = 0;
8218 if (drive_type & 0xf0)
8219 num_floppies++;
8220 if (drive_type & 0x0f)
8221 num_floppies++;
8222
8223 if (drive == 0)
8224 drive_type >>= 4;
8225 else
8226 drive_type &= 0x0f;
8227
8228 SET_BH(0);
8229 SET_BL(drive_type);
8230 SET_AH(0);
8231 SET_AL(0);
8232 SET_DL(num_floppies);
8233
8234 switch (drive_type) {
8235 case 0: // none
8236 CX = 0;
8237 SET_DH(0); // max head #
8238 break;
8239
8240 case 1: // 360KB, 5.25"
8241 CX = 0x2709; // 40 tracks, 9 sectors
8242 SET_DH(1); // max head #
8243 break;
8244
8245 case 2: // 1.2MB, 5.25"
8246 CX = 0x4f0f; // 80 tracks, 15 sectors
8247 SET_DH(1); // max head #
8248 break;
8249
8250 case 3: // 720KB, 3.5"
8251 CX = 0x4f09; // 80 tracks, 9 sectors
8252 SET_DH(1); // max head #
8253 break;
8254
8255 case 4: // 1.44MB, 3.5"
8256 CX = 0x4f12; // 80 tracks, 18 sectors
8257 SET_DH(1); // max head #
8258 break;
8259
8260 case 5: // 2.88MB, 3.5"
8261 CX = 0x4f24; // 80 tracks, 36 sectors
8262 SET_DH(1); // max head #
8263 break;
8264
8265 case 6: // 160k, 5.25"
8266 CX = 0x2708; // 40 tracks, 8 sectors
8267 SET_DH(0); // max head #
8268 break;
8269
8270 case 7: // 180k, 5.25"
8271 CX = 0x2709; // 40 tracks, 9 sectors
8272 SET_DH(0); // max head #
8273 break;
8274
8275 case 8: // 320k, 5.25"
8276 CX = 0x2708; // 40 tracks, 8 sectors
8277 SET_DH(1); // max head #
8278 break;
8279
8280 default: // ?
8281 BX_PANIC("floppy: int13: bad floppy type\n");
8282 }
8283
8284 /* set es & di to point to 11 byte diskette param table in ROM */
8285ASM_START
8286 push bp
8287 mov bp, sp
8288 mov ax, #diskette_param_table2
8289 mov _int13_diskette_function.DI+2[bp], ax
8290 mov _int13_diskette_function.ES+2[bp], cs
8291 pop bp
8292ASM_END
8293 CLEAR_CF(); // success
8294 /* disk status not changed upon success */
8295 return;
8296
8297
8298 case 0x15: // read diskette drive type
8299BX_DEBUG_INT13_FL("floppy f15\n");
8300 drive = GET_ELDL();
8301 if (drive > 1) {
8302 SET_AH(0); // only 2 drives supported
8303 // set_diskette_ret_status here ???
8304 SET_CF();
8305 return;
8306 }
8307 drive_type = inb_cmos(0x10);
8308
8309 if (drive == 0)
8310 drive_type >>= 4;
8311 else
8312 drive_type &= 0x0f;
8313 CLEAR_CF(); // successful, not present
8314 if (drive_type==0) {
8315 SET_AH(0); // drive not present
8316 }
8317 else {
8318 SET_AH(1); // drive present, does not support change line
8319 }
8320
8321 return;
8322
8323 case 0x16: // get diskette change line status
8324BX_DEBUG_INT13_FL("floppy f16\n");
8325 drive = GET_ELDL();
8326 if (drive > 1) {
8327 SET_AH(0x01); // invalid drive
8328 set_diskette_ret_status(0x01);
8329 SET_CF();
8330 return;
8331 }
8332
8333 SET_AH(0x06); // change line not supported
8334 set_diskette_ret_status(0x06);
8335 SET_CF();
8336 return;
8337
8338 case 0x17: // set diskette type for format(old)
8339BX_DEBUG_INT13_FL("floppy f17\n");
8340 /* not used for 1.44M floppies */
8341 SET_AH(0x01); // not supported
8342 set_diskette_ret_status(1); /* not supported */
8343 SET_CF();
8344 return;
8345
8346 case 0x18: // set diskette type for format(new)
8347BX_DEBUG_INT13_FL("floppy f18\n");
8348 SET_AH(0x01); // do later
8349 set_diskette_ret_status(1);
8350 SET_CF();
8351 return;
8352
8353 default:
8354 BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
8355
8356 // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
8357 SET_AH(0x01); // ???
8358 set_diskette_ret_status(1);
8359 SET_CF();
8360 return;
8361 // }
8362 }
8363}
8364#else // #if BX_SUPPORT_FLOPPY
8365 void
8366int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
8367 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
8368{
8369 Bit8u val8;
8370
8371 switch ( GET_AH() ) {
8372
8373 case 0x01: // Read Diskette Status
8374 CLEAR_CF();
8375 val8 = read_byte(0x0000, 0x0441);
8376 SET_AH(val8);
8377 if (val8) {
8378 SET_CF();
8379 }
8380 return;
8381
8382 default:
8383 SET_CF();
8384 write_byte(0x0000, 0x0441, 0x01);
8385 SET_AH(0x01);
8386 }
8387}
8388#endif // #if BX_SUPPORT_FLOPPY
8389
8390 void
8391set_diskette_ret_status(value)
8392 Bit8u value;
8393{
8394 write_byte(0x0040, 0x0041, value);
8395}
8396
8397 void
8398set_diskette_current_cyl(drive, cyl)
8399 Bit8u drive;
8400 Bit8u cyl;
8401{
8402 if (drive > 1)
8403 BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
8404 write_byte(0x0040, 0x0094+drive, cyl);
8405}
8406
8407 void
8408determine_floppy_media(drive)
8409 Bit16u drive;
8410{
8411#if 0
8412 Bit8u val8, DOR, ctrl_info;
8413
8414 ctrl_info = read_byte(0x0040, 0x008F);
8415 if (drive==1)
8416 ctrl_info >>= 4;
8417 else
8418 ctrl_info &= 0x0f;
8419
8420#if 0
8421 if (drive == 0) {
8422 DOR = 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
8423 }
8424 else {
8425 DOR = 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
8426 }
8427#endif
8428
8429 if ( (ctrl_info & 0x04) != 0x04 ) {
8430 // Drive not determined means no drive exists, done.
8431 return;
8432 }
8433
8434#if 0
8435 // check Main Status Register for readiness
8436 val8 = inb(0x03f4) & 0x80; // Main Status Register
8437 if (val8 != 0x80)
8438 BX_PANIC("d_f_m: MRQ bit not set\n");
8439
8440 // change line
8441
8442 // existing BDA values
8443
8444 // turn on drive motor
8445 outb(0x03f2, DOR); // Digital Output Register
8446 //
8447#endif
8448 BX_PANIC("d_f_m: OK so far\n");
8449#endif
8450}
8451
8452 void
8453int17_function(regs, ds, iret_addr)
8454 pusha_regs_t regs; // regs pushed from PUSHA instruction
8455 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8456 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8457{
8458 Bit16u addr,timeout;
8459 Bit8u val8;
8460
8461 ASM_START
8462 sti
8463 ASM_END
8464
8465 addr = read_word(0x0040, (regs.u.r16.dx << 1) + 8);
8466 if ((regs.u.r8.ah < 3) && (regs.u.r16.dx < 3) && (addr > 0)) {
8467 timeout = read_byte(0x0040, 0x0078 + regs.u.r16.dx) << 8;
8468 if (regs.u.r8.ah == 0) {
8469 outb(addr, regs.u.r8.al);
8470 val8 = inb(addr+2);
8471 outb(addr+2, val8 | 0x01); // send strobe
8472 ASM_START
8473 nop
8474 ASM_END
8475 outb(addr+2, val8 & ~0x01);
8476 while (((inb(addr+1) & 0x40) == 0x40) && (timeout)) {
8477 timeout--;
8478 }
8479 }
8480 if (regs.u.r8.ah == 1) {
8481 val8 = inb(addr+2);
8482 outb(addr+2, val8 & ~0x04); // send init
8483 ASM_START
8484 nop
8485 ASM_END
8486 outb(addr+2, val8 | 0x04);
8487 }
8488 val8 = inb(addr+1);
8489 regs.u.r8.ah = (val8 ^ 0x48);
8490 if (!timeout) regs.u.r8.ah |= 0x01;
8491 ClearCF(iret_addr.flags);
8492 } else {
8493 SetCF(iret_addr.flags); // Unsupported
8494 }
8495}
8496
8497// returns bootsegment in ax, drive in bl
8498 Bit32u
8499int19_function(bseqnr)
8500Bit8u bseqnr;
8501{
8502 Bit16u ebda_seg=read_word(0x0040,0x000E);
8503 Bit16u bootseq;
8504 Bit8u bootdrv;
8505 Bit8u bootcd;
8506#ifdef VBOX
8507 Bit8u bootlan;
8508#endif /* VBOX */
8509 Bit8u bootchk;
8510 Bit16u bootseg;
8511 Bit16u status;
8512 Bit8u lastdrive=0;
8513
8514 // if BX_ELTORITO_BOOT is not defined, old behavior
8515 // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
8516 // in preparation for the initial INT 13h (0=floppy A:, 0x80=C:)
8517 // 0: system boot sequence, first drive C: then A:
8518 // 1: system boot sequence, first drive A: then C:
8519 // else BX_ELTORITO_BOOT is defined
8520 // CMOS regs 0x3D and 0x38 contain the boot sequence:
8521 // CMOS reg 0x3D & 0x0f : 1st boot device
8522 // CMOS reg 0x3D & 0xf0 : 2nd boot device
8523 // CMOS reg 0x38 & 0xf0 : 3rd boot device
8524#ifdef VBOX
8525 // CMOS reg 0x3C & 0x0f : 4th boot device
8526#endif /* VBOX */
8527 // boot device codes:
8528 // 0x00 : not defined
8529 // 0x01 : first floppy
8530 // 0x02 : first harddrive
8531 // 0x03 : first cdrom
8532#ifdef VBOX
8533 // 0x04 : local area network
8534#endif /* VBOX */
8535 // else : boot failure
8536
8537 // Get the boot sequence
8538#if BX_ELTORITO_BOOT
8539 bootseq=inb_cmos(0x3d);
8540 bootseq|=((inb_cmos(0x38) & 0xf0) << 4);
8541#ifdef VBOX
8542 bootseq|=((inb_cmos(0x3c) & 0x0f) << 12);
8543 if (read_byte(ebda_seg, &EbdaData->uForceBootDevice))
8544 bootseq = read_byte(ebda_seg, &EbdaData->uForceBootDevice);
8545 /* Boot delay hack. */
8546 if (bseqnr == 1)
8547 delay_boot((inb_cmos(0x3c) & 0xf0) >> 4); /* Implemented in logo.c */
8548#endif /* VBOX */
8549
8550 if (bseqnr==2) bootseq >>= 4;
8551 if (bseqnr==3) bootseq >>= 8;
8552#ifdef VBOX
8553 if (bseqnr==4) bootseq >>= 12;
8554#endif /* VBOX */
8555 if (bootseq<0x10) lastdrive = 1;
8556 bootdrv=0x00; bootcd=0;
8557#ifdef VBOX
8558 bootlan=0;
8559#endif /* VBOX */
8560
8561 switch(bootseq & 0x0f) {
8562 case 0x01:
8563 bootdrv=0x00;
8564 bootcd=0;
8565 break;
8566 case 0x02:
8567 {
8568 // Get the Boot drive.
8569 Bit8u boot_drive = read_byte(ebda_seg, &EbdaData->uForceBootDrive);
8570
8571 bootdrv = boot_drive + 0x80;
8572 bootcd=0;
8573 break;
8574 }
8575 case 0x03:
8576 bootdrv=0x00;
8577 bootcd=1;
8578 break;
8579#ifdef VBOX
8580 case 0x04: bootlan=1; break;
8581#endif /* VBOX */
8582 default: return 0x00000000;
8583 }
8584#else
8585 bootseq=inb_cmos(0x2d);
8586
8587 if (bseqnr==2) {
8588 bootseq ^= 0x20;
8589 lastdrive = 1;
8590 }
8591 bootdrv=0x00; bootcd=0;
8592 if((bootseq&0x20)==0) bootdrv=0x80;
8593#endif // BX_ELTORITO_BOOT
8594
8595#if BX_ELTORITO_BOOT
8596 // We have to boot from cd
8597 if (bootcd != 0) {
8598 status = cdrom_boot();
8599
8600 // If failure
8601 if ( (status & 0x00ff) !=0 ) {
8602 print_cdromboot_failure(status);
8603#ifdef VBOX
8604 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
8605#else /* !VBOX */
8606 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
8607#endif /* !VBOX */
8608 return 0x00000000;
8609 }
8610
8611 bootseg = read_word(ebda_seg,&EbdaData->cdemu.load_segment);
8612 bootdrv = (Bit8u)(status>>8);
8613 }
8614
8615#endif // BX_ELTORITO_BOOT
8616
8617#ifdef VBOX
8618 // Check for boot from LAN first
8619 if (bootlan == 1) {
8620 if (read_word(VBOX_LANBOOT_SEG,0) == 0xaa55) {
8621 Bit16u pnpoff;
8622 Bit32u manuf;
8623 // This is NOT a generic PnP implementation, but an Etherboot-specific hack.
8624 pnpoff = read_word(VBOX_LANBOOT_SEG,0x1a);
8625 if (read_dword(VBOX_LANBOOT_SEG,pnpoff) == 0x506e5024) {
8626 // Found PnP signature
8627 manuf = read_dword(VBOX_LANBOOT_SEG,read_word(VBOX_LANBOOT_SEG,pnpoff+0xe));
8628 if (manuf == 0x65687445) {
8629 // Found Etherboot ROM
8630 print_boot_device(bootcd, bootlan, bootdrv);
8631ASM_START
8632 push ds
8633 push es
8634 pusha
8635 calli 0x0006,VBOX_LANBOOT_SEG
8636 popa
8637 pop es
8638 pop ds
8639ASM_END
8640 } else if (manuf == 0x65746E49) {
8641 // Found Intel PXE ROM
8642 print_boot_device(bootcd, bootlan, bootdrv);
8643ASM_START
8644 push ds
8645 push es
8646 pusha
8647 sti ; Why are interrupts disabled now? Because we were called through an INT!
8648 push #VBOX_LANBOOT_SEG
8649 pop ds
8650 mov bx,#0x1a ; PnP header offset
8651 mov bx,[bx]
8652 add bx,#0x1a ; BEV offset in PnP header
8653 mov ax,[bx]
8654 test ax,ax
8655 jz no_rom
8656bev_jump:
8657 push cs
8658 push #no_rom
8659 push #VBOX_LANBOOT_SEG
8660 push ax
8661 retf ; call Boot Entry Vector
8662no_rom:
8663 popa
8664 pop es
8665 pop ds
8666ASM_END
8667 }
8668 }
8669 }
8670
8671 // boot from LAN will not return if successful.
8672 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
8673 return 0x00000000;
8674 }
8675#endif /* VBOX */
8676 // We have to boot from harddisk or floppy
8677#ifdef VBOX
8678 if (bootcd == 0 && bootlan == 0) {
8679#else /* !VBOX */
8680 if (bootcd == 0) {
8681#endif /* !VBOX */
8682 bootseg=0x07c0;
8683
8684ASM_START
8685 push bp
8686 mov bp, sp
8687
8688 xor ax, ax
8689 mov _int19_function.status + 2[bp], ax
8690 mov dl, _int19_function.bootdrv + 2[bp]
8691 mov ax, _int19_function.bootseg + 2[bp]
8692 mov es, ax ;; segment
8693 xor bx, bx ;; offset
8694 mov ah, #0x02 ;; function 2, read diskette sector
8695 mov al, #0x01 ;; read 1 sector
8696 mov ch, #0x00 ;; track 0
8697 mov cl, #0x01 ;; sector 1
8698 mov dh, #0x00 ;; head 0
8699 int #0x13 ;; read sector
8700 jnc int19_load_done
8701 mov ax, #0x0001
8702 mov _int19_function.status + 2[bp], ax
8703
8704int19_load_done:
8705 pop bp
8706ASM_END
8707
8708 if (status != 0) {
8709#ifdef VBOX
8710 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
8711#else /* !VBOX */
8712 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
8713#endif /* !VBOX */
8714 return 0x00000000;
8715 }
8716 }
8717
8718#ifdef VBOX
8719 // There is *no* requirement whatsoever for a valid floppy boot sector
8720 // to have a 55AAh signature. UNIX boot floppies typically have no such
8721 // signature. In general, it is impossible to tell a valid bootsector
8722 // from an invalid one.
8723 // NB: It is somewhat common for failed OS installs to have the
8724 // 0x55AA signature and a valid partition table but zeros in the
8725 // rest of the boot sector. We do a quick check by comparing the first
8726 // two words of boot sector; if identical, the boot sector is
8727 // extremely unlikely to be valid.
8728#endif
8729 // check signature if instructed by cmos reg 0x38, only for floppy
8730 // bootchk = 1 : signature check disabled
8731 // bootchk = 0 : signature check enabled
8732 if (bootdrv != 0) bootchk = 0;
8733#ifdef VBOX
8734 else bootchk = 1; /* disable 0x55AA signature check on drive A: */
8735#else
8736 else bootchk = inb_cmos(0x38) & 0x01;
8737#endif
8738
8739#if BX_ELTORITO_BOOT
8740 // if boot from cd, no signature check
8741 if (bootcd != 0)
8742 bootchk = 1;
8743#endif // BX_ELTORITO_BOOT
8744
8745 if (read_word(bootseg,0) == read_word(bootseg,2)
8746 || (bootchk == 0 && read_word(bootseg,0x1fe) != 0xaa55))
8747 {
8748#ifdef VBOX
8749 print_boot_failure(bootcd, bootlan, bootdrv, 0, lastdrive);
8750#else /* !VBOX */
8751 print_boot_failure(bootcd, bootdrv, 0, lastdrive);
8752#endif /* VBOX */
8753 return 0x00000000;
8754 }
8755
8756#if BX_ELTORITO_BOOT
8757 // Print out the boot string
8758#ifdef VBOX
8759 print_boot_device(bootcd, bootlan, bootdrv);
8760#else /* !VBOX */
8761 print_boot_device(bootcd, bootdrv);
8762#endif /* !VBOX */
8763#else // BX_ELTORITO_BOOT
8764#ifdef VBOX
8765 print_boot_device(0, bootlan, bootdrv);
8766#else /* !VBOX */
8767 print_boot_device(0, bootdrv);
8768#endif /* !VBOX */
8769#endif // BX_ELTORITO_BOOT
8770
8771 // return the boot segment
8772 return (((Bit32u)bootdrv) << 16) + bootseg;
8773}
8774
8775 void
8776int1a_function(regs, ds, iret_addr)
8777 pusha_regs_t regs; // regs pushed from PUSHA instruction
8778 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8779 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8780{
8781 Bit8u val8;
8782
8783 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);
8784
8785 ASM_START
8786 sti
8787 ASM_END
8788
8789 switch (regs.u.r8.ah) {
8790 case 0: // get current clock count
8791 ASM_START
8792 cli
8793 ASM_END
8794 regs.u.r16.cx = BiosData->ticks_high;
8795 regs.u.r16.dx = BiosData->ticks_low;
8796 regs.u.r8.al = BiosData->midnight_flag;
8797 BiosData->midnight_flag = 0; // reset flag
8798 ASM_START
8799 sti
8800 ASM_END
8801 // AH already 0
8802 ClearCF(iret_addr.flags); // OK
8803 break;
8804
8805 case 1: // Set Current Clock Count
8806 ASM_START
8807 cli
8808 ASM_END
8809 BiosData->ticks_high = regs.u.r16.cx;
8810 BiosData->ticks_low = regs.u.r16.dx;
8811 BiosData->midnight_flag = 0; // reset flag
8812 ASM_START
8813 sti
8814 ASM_END
8815 regs.u.r8.ah = 0;
8816 ClearCF(iret_addr.flags); // OK
8817 break;
8818
8819
8820 case 2: // Read CMOS Time
8821 if (rtc_updating()) {
8822 SetCF(iret_addr.flags);
8823 break;
8824 }
8825
8826 regs.u.r8.dh = inb_cmos(0x00); // Seconds
8827 regs.u.r8.cl = inb_cmos(0x02); // Minutes
8828 regs.u.r8.ch = inb_cmos(0x04); // Hours
8829 regs.u.r8.dl = inb_cmos(0x0b) & 0x01; // Stat Reg B
8830 regs.u.r8.ah = 0;
8831 regs.u.r8.al = regs.u.r8.ch;
8832 ClearCF(iret_addr.flags); // OK
8833 break;
8834
8835 case 3: // Set CMOS Time
8836 // Using a debugger, I notice the following masking/setting
8837 // of bits in Status Register B, by setting Reg B to
8838 // a few values and getting its value after INT 1A was called.
8839 //
8840 // try#1 try#2 try#3
8841 // before 1111 1101 0111 1101 0000 0000
8842 // after 0110 0010 0110 0010 0000 0010
8843 //
8844 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8845 // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
8846 if (rtc_updating()) {
8847 init_rtc();
8848 // fall through as if an update were not in progress
8849 }
8850 outb_cmos(0x00, regs.u.r8.dh); // Seconds
8851 outb_cmos(0x02, regs.u.r8.cl); // Minutes
8852 outb_cmos(0x04, regs.u.r8.ch); // Hours
8853 // Set Daylight Savings time enabled bit to requested value
8854 val8 = (inb_cmos(0x0b) & 0x60) | 0x02 | (regs.u.r8.dl & 0x01);
8855 // (reg B already selected)
8856 outb_cmos(0x0b, val8);
8857 regs.u.r8.ah = 0;
8858 regs.u.r8.al = val8; // val last written to Reg B
8859 ClearCF(iret_addr.flags); // OK
8860 break;
8861
8862 case 4: // Read CMOS Date
8863 regs.u.r8.ah = 0;
8864 if (rtc_updating()) {
8865 SetCF(iret_addr.flags);
8866 break;
8867 }
8868 regs.u.r8.cl = inb_cmos(0x09); // Year
8869 regs.u.r8.dh = inb_cmos(0x08); // Month
8870 regs.u.r8.dl = inb_cmos(0x07); // Day of Month
8871 regs.u.r8.ch = inb_cmos(0x32); // Century
8872 regs.u.r8.al = regs.u.r8.ch;
8873 ClearCF(iret_addr.flags); // OK
8874 break;
8875
8876 case 5: // Set CMOS Date
8877 // Using a debugger, I notice the following masking/setting
8878 // of bits in Status Register B, by setting Reg B to
8879 // a few values and getting its value after INT 1A was called.
8880 //
8881 // try#1 try#2 try#3 try#4
8882 // before 1111 1101 0111 1101 0000 0010 0000 0000
8883 // after 0110 1101 0111 1101 0000 0010 0000 0000
8884 //
8885 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8886 // My assumption: RegB = (RegB & 01111111b)
8887 if (rtc_updating()) {
8888 init_rtc();
8889 SetCF(iret_addr.flags);
8890 break;
8891 }
8892 outb_cmos(0x09, regs.u.r8.cl); // Year
8893 outb_cmos(0x08, regs.u.r8.dh); // Month
8894 outb_cmos(0x07, regs.u.r8.dl); // Day of Month
8895 outb_cmos(0x32, regs.u.r8.ch); // Century
8896 val8 = inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
8897 outb_cmos(0x0b, val8);
8898 regs.u.r8.ah = 0;
8899 regs.u.r8.al = val8; // AL = val last written to Reg B
8900 ClearCF(iret_addr.flags); // OK
8901 break;
8902
8903 case 6: // Set Alarm Time in CMOS
8904 // Using a debugger, I notice the following masking/setting
8905 // of bits in Status Register B, by setting Reg B to
8906 // a few values and getting its value after INT 1A was called.
8907 //
8908 // try#1 try#2 try#3
8909 // before 1101 1111 0101 1111 0000 0000
8910 // after 0110 1111 0111 1111 0010 0000
8911 //
8912 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8913 // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
8914 val8 = inb_cmos(0x0b); // Get Status Reg B
8915 regs.u.r16.ax = 0;
8916 if (val8 & 0x20) {
8917 // Alarm interrupt enabled already
8918 SetCF(iret_addr.flags); // Error: alarm in use
8919 break;
8920 }
8921 if (rtc_updating()) {
8922 init_rtc();
8923 // fall through as if an update were not in progress
8924 }
8925 outb_cmos(0x01, regs.u.r8.dh); // Seconds alarm
8926 outb_cmos(0x03, regs.u.r8.cl); // Minutes alarm
8927 outb_cmos(0x05, regs.u.r8.ch); // Hours alarm
8928 outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
8929 // enable Status Reg B alarm bit, clear halt clock bit
8930 outb_cmos(0x0b, (val8 & 0x7f) | 0x20);
8931 ClearCF(iret_addr.flags); // OK
8932 break;
8933
8934 case 7: // Turn off Alarm
8935 // Using a debugger, I notice the following masking/setting
8936 // of bits in Status Register B, by setting Reg B to
8937 // a few values and getting its value after INT 1A was called.
8938 //
8939 // try#1 try#2 try#3 try#4
8940 // before 1111 1101 0111 1101 0010 0000 0010 0010
8941 // after 0100 0101 0101 0101 0000 0000 0000 0010
8942 //
8943 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8944 // My assumption: RegB = (RegB & 01010111b)
8945 val8 = inb_cmos(0x0b); // Get Status Reg B
8946 // clear clock-halt bit, disable alarm bit
8947 outb_cmos(0x0b, val8 & 0x57); // disable alarm bit
8948 regs.u.r8.ah = 0;
8949 regs.u.r8.al = val8; // val last written to Reg B
8950 ClearCF(iret_addr.flags); // OK
8951 break;
8952#if BX_PCIBIOS
8953 case 0xb1:
8954 // real mode PCI BIOS functions now handled in assembler code
8955 // this C code handles the error code for information only
8956 if (regs.u.r8.bl == 0xff) {
8957 BX_INFO("PCI BIOS: PCI not present\n");
8958 } else if (regs.u.r8.bl == 0x81) {
8959 BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs.u.r8.al);
8960 } else if (regs.u.r8.bl == 0x83) {
8961 BX_INFO("bad PCI vendor ID %04x\n", regs.u.r16.dx);
8962 } else if (regs.u.r8.bl == 0x86) {
8963 if (regs.u.r8.al == 0x02) {
8964 BX_INFO("PCI device %04x:%04x not found at index %d\n", regs.u.r16.dx, regs.u.r16.cx, regs.u.r16.si);
8965 } else {
8966 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);
8967 }
8968 }
8969 regs.u.r8.ah = regs.u.r8.bl;
8970 SetCF(iret_addr.flags);
8971 break;
8972#endif
8973
8974 default:
8975 SetCF(iret_addr.flags); // Unsupported
8976 }
8977}
8978
8979 void
8980int70_function(regs, ds, iret_addr)
8981 pusha_regs_t regs; // regs pushed from PUSHA instruction
8982 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8983 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8984{
8985 // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
8986 Bit8u registerB = 0, registerC = 0;
8987
8988 // Check which modes are enabled and have occurred.
8989 registerB = inb_cmos( 0xB );
8990 registerC = inb_cmos( 0xC );
8991
8992 if( ( registerB & 0x60 ) != 0 ) {
8993 if( ( registerC & 0x20 ) != 0 ) {
8994 // Handle Alarm Interrupt.
8995ASM_START
8996 sti
8997 int #0x4a
8998 cli
8999ASM_END
9000 }
9001 if( ( registerC & 0x40 ) != 0 ) {
9002 // Handle Periodic Interrupt.
9003
9004 if( read_byte( 0x40, 0xA0 ) != 0 ) {
9005 // Wait Interval (Int 15, AH=83) active.
9006 Bit32u time, toggle;
9007
9008 time = read_dword( 0x40, 0x9C ); // Time left in microseconds.
9009 if( time < 0x3D1 ) {
9010 // Done waiting.
9011 Bit16u segment, offset;
9012
9013 segment = read_word( 0x40, 0x98 );
9014 offset = read_word( 0x40, 0x9A );
9015 write_byte( 0x40, 0xA0, 0 ); // Turn of status byte.
9016 outb_cmos( 0xB, registerB & 0x37 ); // Clear the Periodic Interrupt.
9017 write_byte(segment, offset, read_byte(segment, offset) | 0x80 ); // Write to specified flag byte.
9018 } else {
9019 // Continue waiting.
9020 time -= 0x3D1;
9021 write_dword( 0x40, 0x9C, time );
9022 }
9023 }
9024 }
9025 }
9026
9027ASM_START
9028 call eoi_both_pics
9029ASM_END
9030}
9031
9032 void
9033dummy_isr_function(regs, ds, iret_addr)
9034 pusha_regs_t regs; // regs pushed from PUSHA instruction
9035 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
9036 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
9037{
9038 // Interrupt handler for unexpected hardware interrupts. We have to clear
9039 // the PIC because if we don't, the next EOI will clear the wrong interrupt
9040 // and all hell will break loose! This routine also masks the unexpected
9041 // interrupt so it will generally be called only once for each unexpected
9042 // interrupt level.
9043 Bit8u isrA, isrB, imr, last_int = 0xFF;
9044
9045 outb( 0x20, 0x0B );
9046 isrA = inb( 0x20 );
9047 if (isrA) {
9048 outb( 0xA0, 0x0B );
9049 isrB = inb( 0xA0 );
9050 if (isrB) {
9051 imr = inb( 0xA1 );
9052 outb( 0xA1, imr | isrB ); // Mask this interrupt
9053 outb( 0xA0, 0x20 ); // Send EOI on slave PIC
9054 } else {
9055 imr = inb( 0x21 );
9056 isrA &= 0xFB; // Never mask the cascade interrupt
9057 outb( 0x21, imr | isrA); // Mask this interrupt
9058 }
9059 outb( 0x20, 0x20 ); // Send EOI on master PIC
9060 last_int = isrA;
9061 }
9062 write_byte( 0x40, 0x6B, last_int ); // Write INTR_FLAG
9063}
9064
9065ASM_START
9066;------------------------------------------
9067;- INT74h : PS/2 mouse hardware interrupt -
9068;------------------------------------------
9069int74_handler:
9070 sti
9071 pusha
9072 push ds ;; save DS
9073 push #0x00 ;; placeholder for status
9074 push #0x00 ;; placeholder for X
9075 push #0x00 ;; placeholder for Y
9076 push #0x00 ;; placeholder for Z
9077 push #0x00 ;; placeholder for make_far_call boolean
9078 call _int74_function
9079 pop cx ;; remove make_far_call from stack
9080 jcxz int74_done
9081
9082 ;; make far call to EBDA:0022
9083 push #0x00
9084 pop ds
9085 push 0x040E ;; push 0000:040E (opcodes 0xff, 0x36, 0x0E, 0x04)
9086 pop ds
9087 //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
9088 call far ptr[0x22]
9089int74_done:
9090 cli
9091 call eoi_both_pics
9092 add sp, #8 ;; pop status, x, y, z
9093
9094 pop ds ;; restore DS
9095 popa
9096 iret
9097
9098
9099;; This will perform an IRET, but will retain value of current CF
9100;; by altering flags on stack. Better than RETF #02.
9101iret_modify_cf:
9102 jc carry_set
9103 push bp
9104 mov bp, sp
9105 and BYTE [bp + 0x06], #0xfe
9106 pop bp
9107 iret
9108carry_set:
9109 push bp
9110 mov bp, sp
9111 or BYTE [bp + 0x06], #0x01
9112 pop bp
9113 iret
9114
9115
9116;----------------------
9117;- INT13h (relocated) -
9118;----------------------
9119;
9120; int13_relocated is a little bit messed up since I played with it
9121; I have to rewrite it:
9122; - call a function that detect which function to call
9123; - make all called C function get the same parameters list
9124;
9125int13_relocated:
9126 cld ;; we will be doing some string I/O
9127
9128#if BX_ELTORITO_BOOT
9129 ;; check for an eltorito function
9130 cmp ah,#0x4a
9131 jb int13_not_eltorito
9132 cmp ah,#0x4d
9133 ja int13_not_eltorito
9134
9135 pusha
9136 push es
9137 push ds
9138 push ss
9139 pop ds
9140
9141 push #int13_out
9142 jmp _int13_eltorito ;; ELDX not used
9143
9144int13_not_eltorito:
9145 push ax
9146 push bx
9147 push cx
9148 push dx
9149
9150 ;; check if emulation active
9151 call _cdemu_isactive
9152 cmp al,#0x00
9153 je int13_cdemu_inactive
9154
9155 ;; check if access to the emulated drive
9156 call _cdemu_emulated_drive
9157 pop dx
9158 push dx
9159 cmp al,dl ;; int13 on emulated drive
9160 jne int13_nocdemu
9161
9162 pop dx
9163 pop cx
9164 pop bx
9165 pop ax
9166
9167 pusha
9168 push es
9169 push ds
9170 push ss
9171 pop ds
9172
9173 push #int13_out
9174 jmp _int13_cdemu ;; ELDX not used
9175
9176int13_nocdemu:
9177 and dl,#0xE0 ;; mask to get device class, including cdroms
9178 cmp al,dl ;; al is 0x00 or 0x80
9179 jne int13_cdemu_inactive ;; inactive for device class
9180
9181 pop dx
9182 pop cx
9183 pop bx
9184 pop ax
9185
9186 push ax
9187 push cx
9188 push dx
9189 push bx
9190
9191 dec dl ;; real drive is dl - 1
9192 jmp int13_legacy
9193
9194int13_cdemu_inactive:
9195 pop dx
9196 pop cx
9197 pop bx
9198 pop ax
9199
9200#endif // BX_ELTORITO_BOOT
9201
9202int13_noeltorito:
9203
9204 push ax
9205 push cx
9206 push dx
9207 push bx
9208
9209int13_legacy:
9210
9211 push dx ;; push eltorito value of dx instead of sp
9212
9213 push bp
9214 push si
9215 push di
9216
9217 push es
9218 push ds
9219 push ss
9220 pop ds
9221
9222 ;; now the 16-bit registers can be restored with:
9223 ;; pop ds; pop es; popa; iret
9224 ;; arguments passed to functions should be
9225 ;; DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS
9226
9227 test dl, #0x80
9228 jnz int13_notfloppy
9229
9230 push #int13_out
9231 jmp _int13_diskette_function
9232
9233int13_notfloppy:
9234
9235#if BX_USE_ATADRV
9236
9237 cmp dl, #0xE0
9238 jb int13_notcdrom
9239
9240 // ebx is modified: BSD 5.2.1 boot loader problem
9241 // someone should figure out which 32 bit register that actually are used
9242
9243 shr ebx, #16
9244 push bx
9245
9246 call _int13_cdrom
9247
9248 pop bx
9249 shl ebx, #16
9250
9251 jmp int13_out
9252
9253int13_notcdrom:
9254
9255#endif
9256
9257int13_disk:
9258 ;; int13_harddisk modifies high word of EAX and EBX
9259 shr eax, #16
9260 push ax
9261 shr ebx, #16
9262 push bx
9263 call _int13_harddisk
9264 pop bx
9265 shl ebx, #16
9266 pop ax
9267 shl eax, #16
9268
9269int13_out:
9270 pop ds
9271 pop es
9272 popa
9273 iret
9274
9275;----------
9276;- INT18h -
9277;----------
9278int18_handler: ;; Boot Failure routing
9279 call _int18_panic_msg
9280 hlt
9281 iret
9282
9283;----------
9284;- INT19h -
9285;----------
9286int19_relocated: ;; Boot function, relocated
9287
9288#ifdef VBOX
9289 // If an already booted OS calls int 0x19 to reboot, it is not sufficient
9290 // just to try booting from the configured drives. All BIOS variables and
9291 // interrupt vectors need to be reset, otherwise strange things may happen.
9292 // The approach used is faking a warm reboot (which just skips showing the
9293 // logo), which is a bit more than what we need, but hey, it's fast.
9294 mov bp, sp
9295 mov ax, 2[bp]
9296 cmp ax, #0xf000
9297 jz bios_initiated_boot
9298 xor ax, ax
9299 mov ds, ax
9300 mov ax, #0x1234
9301 mov 0x472, ax
9302 jmp post
9303bios_initiated_boot:
9304#endif /* VBOX */
9305
9306 ;; int19 was beginning to be really complex, so now it
9307 ;; just calls a C function that does the work
9308 ;; it returns in BL the boot drive, and in AX the boot segment
9309 ;; the boot segment will be 0x0000 if something has failed
9310
9311 push bp
9312 mov bp, sp
9313
9314 ;; drop ds
9315 xor ax, ax
9316 mov ds, ax
9317
9318 ;; 1st boot device
9319 mov ax, #0x0001
9320 push ax
9321 call _int19_function
9322 inc sp
9323 inc sp
9324 ;; bl contains the boot drive
9325 ;; ax contains the boot segment or 0 if failure
9326
9327 test ax, ax ;; if ax is 0 try next boot device
9328 jnz boot_setup
9329
9330 ;; 2nd boot device
9331 mov ax, #0x0002
9332 push ax
9333 call _int19_function
9334 inc sp
9335 inc sp
9336 test ax, ax ;; if ax is 0 try next boot device
9337 jnz boot_setup
9338
9339 ;; 3rd boot device
9340 mov ax, #0x0003
9341 push ax
9342 call _int19_function
9343 inc sp
9344 inc sp
9345#ifdef VBOX
9346 test ax, ax ;; if ax is 0 try next boot device
9347 jnz boot_setup
9348
9349 ;; 4th boot device
9350 mov ax, #0x0004
9351 push ax
9352 call _int19_function
9353 inc sp
9354 inc sp
9355#endif /* VBOX */
9356 test ax, ax ;; if ax is 0 call int18
9357 jz int18_handler
9358
9359boot_setup:
9360 mov dl, bl ;; set drive so guest os find it
9361 shl eax, #0x04 ;; convert seg to ip
9362 mov 2[bp], ax ;; set ip
9363
9364 shr eax, #0x04 ;; get cs back
9365 and ax, #0xF000 ;; remove what went in ip
9366 mov 4[bp], ax ;; set cs
9367 xor ax, ax
9368 mov es, ax ;; set es to zero fixes [ 549815 ]
9369 mov [bp], ax ;; set bp to zero
9370 mov ax, #0xaa55 ;; set ok flag
9371
9372 pop bp
9373 iret ;; Beam me up Scotty
9374
9375;----------
9376;- INT1Ch -
9377;----------
9378int1c_handler: ;; User Timer Tick
9379 iret
9380
9381
9382;----------------------
9383;- POST: Floppy Drive -
9384;----------------------
9385floppy_drive_post:
9386 xor ax, ax
9387 mov ds, ax
9388
9389 mov al, #0x00
9390 mov 0x043e, al ;; drive 0 & 1 uncalibrated, no interrupt has occurred
9391
9392 mov 0x043f, al ;; diskette motor status: read op, drive0, motors off
9393
9394 mov 0x0440, al ;; diskette motor timeout counter: not active
9395 mov 0x0441, al ;; diskette controller status return code
9396
9397 mov 0x0442, al ;; disk & diskette controller status register 0
9398 mov 0x0443, al ;; diskette controller status register 1
9399 mov 0x0444, al ;; diskette controller status register 2
9400 mov 0x0445, al ;; diskette controller cylinder number
9401 mov 0x0446, al ;; diskette controller head number
9402 mov 0x0447, al ;; diskette controller sector number
9403 mov 0x0448, al ;; diskette controller bytes written
9404
9405 mov 0x048b, al ;; diskette configuration data
9406
9407 ;; -----------------------------------------------------------------
9408 ;; (048F) diskette controller information
9409 ;;
9410 mov al, #0x10 ;; get CMOS diskette drive type
9411 out 0x70, AL
9412 in AL, 0x71
9413 mov ah, al ;; save byte to AH
9414
9415look_drive0:
9416 shr al, #4 ;; look at top 4 bits for drive 0
9417 jz f0_missing ;; jump if no drive0
9418 mov bl, #0x07 ;; drive0 determined, multi-rate, has changed line
9419 jmp look_drive1
9420f0_missing:
9421 mov bl, #0x00 ;; no drive0
9422
9423look_drive1:
9424 mov al, ah ;; restore from AH
9425 and al, #0x0f ;; look at bottom 4 bits for drive 1
9426 jz f1_missing ;; jump if no drive1
9427 or bl, #0x70 ;; drive1 determined, multi-rate, has changed line
9428f1_missing:
9429 ;; leave high bits in BL zerod
9430 mov 0x048f, bl ;; put new val in BDA (diskette controller information)
9431 ;; -----------------------------------------------------------------
9432
9433 mov al, #0x00
9434 mov 0x0490, al ;; diskette 0 media state
9435 mov 0x0491, al ;; diskette 1 media state
9436
9437 ;; diskette 0,1 operational starting state
9438 ;; drive type has not been determined,
9439 ;; has no changed detection line
9440 mov 0x0492, al
9441 mov 0x0493, al
9442
9443 mov 0x0494, al ;; diskette 0 current cylinder
9444 mov 0x0495, al ;; diskette 1 current cylinder
9445
9446 mov al, #0x02
9447 out #0x0a, al ;; clear DMA-1 channel 2 mask bit
9448
9449 SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
9450 SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
9451 SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
9452
9453 ret
9454
9455
9456;--------------------
9457;- POST: HARD DRIVE -
9458;--------------------
9459; relocated here because the primary POST area isnt big enough.
9460hard_drive_post:
9461 // IRQ 14 = INT 76h
9462 // INT 76h calls INT 15h function ax=9100
9463
9464 mov al, #0x0a ; 0000 1010 = reserved, disable IRQ 14
9465 mov dx, #0x03f6
9466 out dx, al
9467
9468 xor ax, ax
9469 mov ds, ax
9470 mov 0x0474, al /* hard disk status of last operation */
9471 mov 0x0477, al /* hard disk port offset (XT only ???) */
9472 mov 0x048c, al /* hard disk status register */
9473 mov 0x048d, al /* hard disk error register */
9474 mov 0x048e, al /* hard disk task complete flag */
9475#ifndef VBOX /* Why is this hardcoded to 1? */
9476 mov al, #0x01
9477 mov 0x0475, al /* hard disk number attached */
9478#endif
9479 mov al, #0xc0
9480 mov 0x0476, al /* hard disk control byte */
9481 SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
9482 SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
9483 ;; INT 41h: hard disk 0 configuration pointer
9484 ;; INT 46h: hard disk 1 configuration pointer
9485 SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D)
9486 SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D)
9487
9488#ifndef VBOX /* This is done later (and the CMOS format is now different). */
9489 ;; move disk geometry data from CMOS to EBDA disk parameter table(s)
9490 mov al, #0x12
9491 out #0x70, al
9492 in al, #0x71
9493 and al, #0xf0
9494 cmp al, #0xf0
9495 je post_d0_extended
9496 jmp check_for_hd1
9497post_d0_extended:
9498 mov al, #0x19
9499 out #0x70, al
9500 in al, #0x71
9501 cmp al, #47 ;; decimal 47 - user definable
9502 je post_d0_type47
9503 HALT(__LINE__)
9504post_d0_type47:
9505 ;; CMOS purpose param table offset
9506 ;; 1b cylinders low 0
9507 ;; 1c cylinders high 1
9508 ;; 1d heads 2
9509 ;; 1e write pre-comp low 5
9510 ;; 1f write pre-comp high 6
9511 ;; 20 retries/bad map/heads>8 8
9512 ;; 21 landing zone low C
9513 ;; 22 landing zone high D
9514 ;; 23 sectors/track E
9515
9516 mov ax, #EBDA_SEG
9517 mov ds, ax
9518
9519 ;;; Filling EBDA table for hard disk 0.
9520 mov al, #0x1f
9521 out #0x70, al
9522 in al, #0x71
9523 mov ah, al
9524 mov al, #0x1e
9525 out #0x70, al
9526 in al, #0x71
9527 mov (0x003d + 0x05), ax ;; write precomp word
9528
9529 mov al, #0x20
9530 out #0x70, al
9531 in al, #0x71
9532 mov (0x003d + 0x08), al ;; drive control byte
9533
9534 mov al, #0x22
9535 out #0x70, al
9536 in al, #0x71
9537 mov ah, al
9538 mov al, #0x21
9539 out #0x70, al
9540 in al, #0x71
9541 mov (0x003d + 0x0C), ax ;; landing zone word
9542
9543 mov al, #0x1c ;; get cylinders word in AX
9544 out #0x70, al
9545 in al, #0x71 ;; high byte
9546 mov ah, al
9547 mov al, #0x1b
9548 out #0x70, al
9549 in al, #0x71 ;; low byte
9550 mov bx, ax ;; BX = cylinders
9551
9552 mov al, #0x1d
9553 out #0x70, al
9554 in al, #0x71
9555 mov cl, al ;; CL = heads
9556
9557 mov al, #0x23
9558 out #0x70, al
9559 in al, #0x71
9560 mov dl, al ;; DL = sectors
9561
9562 cmp bx, #1024
9563 jnbe hd0_post_logical_chs ;; if cylinders > 1024, use translated style CHS
9564
9565hd0_post_physical_chs:
9566 ;; no logical CHS mapping used, just physical CHS
9567 ;; use Standard Fixed Disk Parameter Table (FDPT)
9568 mov (0x003d + 0x00), bx ;; number of physical cylinders
9569 mov (0x003d + 0x02), cl ;; number of physical heads
9570 mov (0x003d + 0x0E), dl ;; number of physical sectors
9571 jmp check_for_hd1
9572
9573hd0_post_logical_chs:
9574 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
9575 mov (0x003d + 0x09), bx ;; number of physical cylinders
9576 mov (0x003d + 0x0b), cl ;; number of physical heads
9577 mov (0x003d + 0x04), dl ;; number of physical sectors
9578 mov (0x003d + 0x0e), dl ;; number of logical sectors (same)
9579 mov al, #0xa0
9580 mov (0x003d + 0x03), al ;; A0h signature, indicates translated table
9581
9582 cmp bx, #2048
9583 jnbe hd0_post_above_2048
9584 ;; 1024 < c <= 2048 cylinders
9585 shr bx, #0x01
9586 shl cl, #0x01
9587 jmp hd0_post_store_logical
9588
9589hd0_post_above_2048:
9590 cmp bx, #4096
9591 jnbe hd0_post_above_4096
9592 ;; 2048 < c <= 4096 cylinders
9593 shr bx, #0x02
9594 shl cl, #0x02
9595 jmp hd0_post_store_logical
9596
9597hd0_post_above_4096:
9598 cmp bx, #8192
9599 jnbe hd0_post_above_8192
9600 ;; 4096 < c <= 8192 cylinders
9601 shr bx, #0x03
9602 shl cl, #0x03
9603 jmp hd0_post_store_logical
9604
9605hd0_post_above_8192:
9606 ;; 8192 < c <= 16384 cylinders
9607 shr bx, #0x04
9608 shl cl, #0x04
9609
9610hd0_post_store_logical:
9611 mov (0x003d + 0x00), bx ;; number of physical cylinders
9612 mov (0x003d + 0x02), cl ;; number of physical heads
9613 ;; checksum
9614 mov cl, #0x0f ;; repeat count
9615 mov si, #0x003d ;; offset to disk0 FDPT
9616 mov al, #0x00 ;; sum
9617hd0_post_checksum_loop:
9618 add al, [si]
9619 inc si
9620 dec cl
9621 jnz hd0_post_checksum_loop
9622 not al ;; now take 2s complement
9623 inc al
9624 mov [si], al
9625;;; Done filling EBDA table for hard disk 0.
9626
9627
9628check_for_hd1:
9629 ;; is there really a second hard disk? if not, return now
9630 mov al, #0x12
9631 out #0x70, al
9632 in al, #0x71
9633 and al, #0x0f
9634 jnz post_d1_exists
9635 ret
9636post_d1_exists:
9637 ;; check that the hd type is really 0x0f.
9638 cmp al, #0x0f
9639 jz post_d1_extended
9640 HALT(__LINE__)
9641post_d1_extended:
9642 ;; check that the extended type is 47 - user definable
9643 mov al, #0x1a
9644 out #0x70, al
9645 in al, #0x71
9646 cmp al, #47 ;; decimal 47 - user definable
9647 je post_d1_type47
9648 HALT(__LINE__)
9649post_d1_type47:
9650 ;; Table for disk1.
9651 ;; CMOS purpose param table offset
9652 ;; 0x24 cylinders low 0
9653 ;; 0x25 cylinders high 1
9654 ;; 0x26 heads 2
9655 ;; 0x27 write pre-comp low 5
9656 ;; 0x28 write pre-comp high 6
9657 ;; 0x29 heads>8 8
9658 ;; 0x2a landing zone low C
9659 ;; 0x2b landing zone high D
9660 ;; 0x2c sectors/track E
9661;;; Fill EBDA table for hard disk 1.
9662 mov ax, #EBDA_SEG
9663 mov ds, ax
9664 mov al, #0x28
9665 out #0x70, al
9666 in al, #0x71
9667 mov ah, al
9668 mov al, #0x27
9669 out #0x70, al
9670 in al, #0x71
9671 mov (0x004d + 0x05), ax ;; write precomp word
9672
9673 mov al, #0x29
9674 out #0x70, al
9675 in al, #0x71
9676 mov (0x004d + 0x08), al ;; drive control byte
9677
9678 mov al, #0x2b
9679 out #0x70, al
9680 in al, #0x71
9681 mov ah, al
9682 mov al, #0x2a
9683 out #0x70, al
9684 in al, #0x71
9685 mov (0x004d + 0x0C), ax ;; landing zone word
9686
9687 mov al, #0x25 ;; get cylinders word in AX
9688 out #0x70, al
9689 in al, #0x71 ;; high byte
9690 mov ah, al
9691 mov al, #0x24
9692 out #0x70, al
9693 in al, #0x71 ;; low byte
9694 mov bx, ax ;; BX = cylinders
9695
9696 mov al, #0x26
9697 out #0x70, al
9698 in al, #0x71
9699 mov cl, al ;; CL = heads
9700
9701 mov al, #0x2c
9702 out #0x70, al
9703 in al, #0x71
9704 mov dl, al ;; DL = sectors
9705
9706 cmp bx, #1024
9707 jnbe hd1_post_logical_chs ;; if cylinders > 1024, use translated style CHS
9708
9709hd1_post_physical_chs:
9710 ;; no logical CHS mapping used, just physical CHS
9711 ;; use Standard Fixed Disk Parameter Table (FDPT)
9712 mov (0x004d + 0x00), bx ;; number of physical cylinders
9713 mov (0x004d + 0x02), cl ;; number of physical heads
9714 mov (0x004d + 0x0E), dl ;; number of physical sectors
9715 ret
9716
9717hd1_post_logical_chs:
9718 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
9719 mov (0x004d + 0x09), bx ;; number of physical cylinders
9720 mov (0x004d + 0x0b), cl ;; number of physical heads
9721 mov (0x004d + 0x04), dl ;; number of physical sectors
9722 mov (0x004d + 0x0e), dl ;; number of logical sectors (same)
9723 mov al, #0xa0
9724 mov (0x004d + 0x03), al ;; A0h signature, indicates translated table
9725
9726 cmp bx, #2048
9727 jnbe hd1_post_above_2048
9728 ;; 1024 < c <= 2048 cylinders
9729 shr bx, #0x01
9730 shl cl, #0x01
9731 jmp hd1_post_store_logical
9732
9733hd1_post_above_2048:
9734 cmp bx, #4096
9735 jnbe hd1_post_above_4096
9736 ;; 2048 < c <= 4096 cylinders
9737 shr bx, #0x02
9738 shl cl, #0x02
9739 jmp hd1_post_store_logical
9740
9741hd1_post_above_4096:
9742 cmp bx, #8192
9743 jnbe hd1_post_above_8192
9744 ;; 4096 < c <= 8192 cylinders
9745 shr bx, #0x03
9746 shl cl, #0x03
9747 jmp hd1_post_store_logical
9748
9749hd1_post_above_8192:
9750 ;; 8192 < c <= 16384 cylinders
9751 shr bx, #0x04
9752 shl cl, #0x04
9753
9754hd1_post_store_logical:
9755 mov (0x004d + 0x00), bx ;; number of physical cylinders
9756 mov (0x004d + 0x02), cl ;; number of physical heads
9757 ;; checksum
9758 mov cl, #0x0f ;; repeat count
9759 mov si, #0x004d ;; offset to disk0 FDPT
9760 mov al, #0x00 ;; sum
9761hd1_post_checksum_loop:
9762 add al, [si]
9763 inc si
9764 dec cl
9765 jnz hd1_post_checksum_loop
9766 not al ;; now take 2s complement
9767 inc al
9768 mov [si], al
9769;;; Done filling EBDA table for hard disk 1.
9770#endif /* !VBOX */
9771
9772 ret
9773
9774;--------------------
9775;- POST: EBDA segment
9776;--------------------
9777; relocated here because the primary POST area isnt big enough.
9778; the SET_INT_VECTORs have nothing to do with EBDA but do not
9779; fit into the primary POST area either
9780ebda_post:
9781 SET_INT_VECTOR(0x0D, #0xF000, #dummy_isr); IRQ 5
9782 SET_INT_VECTOR(0x0F, #0xF000, #dummy_isr); IRQ 7
9783 SET_INT_VECTOR(0x72, #0xF000, #dummy_isr); IRQ 11
9784 SET_INT_VECTOR(0x77, #0xF000, #dummy_isr); IRQ 15
9785
9786#if BX_USE_EBDA
9787 mov ax, #EBDA_SEG
9788 mov ds, ax
9789 mov byte ptr [0x0], #EBDA_SIZE
9790#endif
9791 xor ax, ax ; mov EBDA seg into 40E
9792 mov ds, ax
9793 mov word ptr [0x40E], #EBDA_SEG
9794 ret;;
9795
9796;--------------------
9797;- POST: EOI + jmp via [0x40:67)
9798;--------------------
9799; relocated here because the primary POST area isnt big enough.
9800eoi_jmp_post:
9801 call eoi_both_pics
9802
9803 xor ax, ax
9804 mov ds, ax
9805
9806 jmp far ptr [0x467]
9807
9808
9809;--------------------
9810eoi_both_pics:
9811 mov al, #0x20
9812 out #0xA0, al ;; slave PIC EOI
9813eoi_master_pic:
9814 mov al, #0x20
9815 out #0x20, al ;; master PIC EOI
9816 ret
9817
9818;--------------------
9819BcdToBin:
9820 ;; in: AL in BCD format
9821 ;; out: AL in binary format, AH will always be 0
9822 ;; trashes BX
9823 mov bl, al
9824 and bl, #0x0f ;; bl has low digit
9825 shr al, #4 ;; al has high digit
9826 mov bh, #10
9827 mul al, bh ;; multiply high digit by 10 (result in AX)
9828 add al, bl ;; then add low digit
9829 ret
9830
9831;--------------------
9832timer_tick_post:
9833 ;; Setup the Timer Ticks Count (0x46C:dword) and
9834 ;; Timer Ticks Roller Flag (0x470:byte)
9835 ;; The Timer Ticks Count needs to be set according to
9836 ;; the current CMOS time, as if ticks have been occurring
9837 ;; at 18.2hz since midnight up to this point. Calculating
9838 ;; this is a little complicated. Here are the factors I gather
9839 ;; regarding this. 14,318,180 hz was the original clock speed,
9840 ;; chosen so it could be divided by either 3 to drive the 5Mhz CPU
9841 ;; at the time, or 4 to drive the CGA video adapter. The div3
9842 ;; source was divided again by 4 to feed a 1.193Mhz signal to
9843 ;; the timer. With a maximum 16bit timer count, this is again
9844 ;; divided down by 65536 to 18.2hz.
9845 ;;
9846 ;; 14,318,180 Hz clock
9847 ;; /3 = 4,772,726 Hz fed to original 5Mhz CPU
9848 ;; /4 = 1,193,181 Hz fed to timer
9849 ;; /65536 (maximum timer count) = 18.20650736 ticks/second
9850 ;; 1 second = 18.20650736 ticks
9851 ;; 1 minute = 1092.390442 ticks
9852 ;; 1 hour = 65543.42651 ticks
9853 ;;
9854 ;; Given the values in the CMOS clock, one could calculate
9855 ;; the number of ticks by the following:
9856 ;; ticks = (BcdToBin(seconds) * 18.206507) +
9857 ;; (BcdToBin(minutes) * 1092.3904)
9858 ;; (BcdToBin(hours) * 65543.427)
9859 ;; To get a little more accuracy, since Im using integer
9860 ;; arithmetic, I use:
9861 ;; ticks = (BcdToBin(seconds) * 18206507) / 1000000 +
9862 ;; (BcdToBin(minutes) * 10923904) / 10000 +
9863 ;; (BcdToBin(hours) * 65543427) / 1000
9864
9865 ;; assuming DS=0000
9866
9867 ;; get CMOS seconds
9868 xor eax, eax ;; clear EAX
9869 mov al, #0x00
9870 out #0x70, al
9871 in al, #0x71 ;; AL has CMOS seconds in BCD
9872 call BcdToBin ;; EAX now has seconds in binary
9873 mov edx, #18206507
9874 mul eax, edx
9875 mov ebx, #1000000
9876 xor edx, edx
9877 div eax, ebx
9878 mov ecx, eax ;; ECX will accumulate total ticks
9879
9880 ;; get CMOS minutes
9881 xor eax, eax ;; clear EAX
9882 mov al, #0x02
9883 out #0x70, al
9884 in al, #0x71 ;; AL has CMOS minutes in BCD
9885 call BcdToBin ;; EAX now has minutes in binary
9886 mov edx, #10923904
9887 mul eax, edx
9888 mov ebx, #10000
9889 xor edx, edx
9890 div eax, ebx
9891 add ecx, eax ;; add to total ticks
9892
9893 ;; get CMOS hours
9894 xor eax, eax ;; clear EAX
9895 mov al, #0x04
9896 out #0x70, al
9897 in al, #0x71 ;; AL has CMOS hours in BCD
9898 call BcdToBin ;; EAX now has hours in binary
9899 mov edx, #65543427
9900 mul eax, edx
9901 mov ebx, #1000
9902 xor edx, edx
9903 div eax, ebx
9904 add ecx, eax ;; add to total ticks
9905
9906 mov 0x46C, ecx ;; Timer Ticks Count
9907 xor al, al
9908 mov 0x470, al ;; Timer Ticks Rollover Flag
9909 ret
9910
9911;--------------------
9912int76_handler:
9913 ;; record completion in BIOS task complete flag
9914 push ax
9915 push ds
9916 mov ax, #0x0040
9917 mov ds, ax
9918 mov 0x008E, #0xff
9919 call eoi_both_pics
9920 pop ds
9921 pop ax
9922 iret
9923
9924
9925;--------------------
9926#ifdef VBOX
9927init_pic:
9928 ;; init PIC
9929 mov al, #0x11 ; send initialisation commands
9930 out 0x20, al
9931 out 0xa0, al
9932 mov al, #0x08
9933 out 0x21, al
9934 mov al, #0x70
9935 out 0xa1, al
9936 mov al, #0x04
9937 out 0x21, al
9938 mov al, #0x02
9939 out 0xa1, al
9940 mov al, #0x01
9941 out 0x21, al
9942 out 0xa1, al
9943 mov al, #0xb8
9944 out 0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6
9945#if BX_USE_PS2_MOUSE
9946 mov al, #0x8f
9947#else
9948 mov al, #0x9f
9949#endif
9950 out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14
9951 ret
9952#endif /* VBOX */
9953
9954;--------------------
9955#if BX_APM
9956
9957use32 386
9958#define APM_PROT32
9959#include "apmbios.S"
9960
9961use16 386
9962#define APM_PROT16
9963#include "apmbios.S"
9964
9965#define APM_REAL
9966#include "apmbios.S"
9967
9968#endif
9969
9970;--------------------
9971#if BX_PCIBIOS
9972use32 386
9973.align 16
9974bios32_structure:
9975 db 0x5f, 0x33, 0x32, 0x5f ;; "_32_" signature
9976 dw bios32_entry_point, 0xf ;; 32 bit physical address
9977 db 0 ;; revision level
9978 ;; length in paragraphs and checksum stored in a word to prevent errors
9979 dw (~(((bios32_entry_point >> 8) + (bios32_entry_point & 0xff) + 0x32) \
9980 & 0xff) << 8) + 0x01
9981 db 0,0,0,0,0 ;; reserved
9982
9983.align 16
9984bios32_entry_point:
9985 pushfd
9986 cmp eax, #0x49435024 ;; "$PCI"
9987 jne unknown_service
9988
9989#ifdef PCI_FIXED_HOST_BRIDGE_1
9990 mov eax, #0x80000000
9991 mov dx, #0x0cf8
9992 out dx, eax
9993 mov dx, #0x0cfc
9994 in eax, dx
9995 cmp eax, #PCI_FIXED_HOST_BRIDGE_1
9996 je device_ok
9997#endif
9998
9999#ifdef PCI_FIXED_HOST_BRIDGE_2
10000 /* 0x1e << 11 */
10001 mov eax, #0x8000f000
10002 mov dx, #0x0cf8
10003 out dx, eax
10004 mov dx, #0x0cfc
10005 in eax, dx
10006 cmp eax, #PCI_FIXED_HOST_BRIDGE_2
10007 je device_ok
10008#endif
10009 jmp unknown_service
10010device_ok:
10011 mov ebx, #0x000f0000
10012 mov ecx, #0
10013 mov edx, #pcibios_protected
10014 xor al, al
10015 jmp bios32_end
10016unknown_service:
10017 mov al, #0x80
10018bios32_end:
10019#ifdef BX_QEMU
10020 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
10021#endif
10022 popfd
10023 retf
10024
10025.align 16
10026pcibios_protected:
10027 pushfd
10028 cli
10029 push esi
10030 push edi
10031 cmp al, #0x01 ;; installation check
10032 jne pci_pro_f02
10033 mov bx, #0x0210
10034 mov cx, #0
10035 mov edx, #0x20494350 ;; "PCI "
10036 mov al, #0x01
10037 jmp pci_pro_ok
10038pci_pro_f02: ;; find pci device
10039 cmp al, #0x02
10040 jne pci_pro_f03
10041 shl ecx, #16
10042 mov cx, dx
10043 xor ebx, ebx
10044 mov di, #0x00
10045pci_pro_devloop:
10046 call pci_pro_select_reg
10047 mov dx, #0x0cfc
10048 in eax, dx
10049 cmp eax, ecx
10050 jne pci_pro_nextdev
10051 cmp si, #0
10052 je pci_pro_ok
10053 dec si
10054pci_pro_nextdev:
10055 inc ebx
10056 cmp ebx, #0x10000
10057 jne pci_pro_devloop
10058 mov ah, #0x86
10059 jmp pci_pro_fail
10060pci_pro_f03: ;; find class code
10061 cmp al, #0x03
10062 jne pci_pro_f08
10063 xor ebx, ebx
10064 mov di, #0x08
10065pci_pro_devloop2:
10066 call pci_pro_select_reg
10067 mov dx, #0x0cfc
10068 in eax, dx
10069 shr eax, #8
10070 cmp eax, ecx
10071 jne pci_pro_nextdev2
10072 cmp si, #0
10073 je pci_pro_ok
10074 dec si
10075pci_pro_nextdev2:
10076 inc ebx
10077 cmp ebx, #0x10000
10078 jne pci_pro_devloop2
10079 mov ah, #0x86
10080 jmp pci_pro_fail
10081pci_pro_f08: ;; read configuration byte
10082 cmp al, #0x08
10083 jne pci_pro_f09
10084 call pci_pro_select_reg
10085 push edx
10086 mov dx, di
10087 and dx, #0x03
10088 add dx, #0x0cfc
10089 in al, dx
10090 pop edx
10091 mov cl, al
10092 jmp pci_pro_ok
10093pci_pro_f09: ;; read configuration word
10094 cmp al, #0x09
10095 jne pci_pro_f0a
10096 call pci_pro_select_reg
10097 push edx
10098 mov dx, di
10099 and dx, #0x02
10100 add dx, #0x0cfc
10101 in ax, dx
10102 pop edx
10103 mov cx, ax
10104 jmp pci_pro_ok
10105pci_pro_f0a: ;; read configuration dword
10106 cmp al, #0x0a
10107 jne pci_pro_f0b
10108 call pci_pro_select_reg
10109 push edx
10110 mov dx, #0x0cfc
10111 in eax, dx
10112 pop edx
10113 mov ecx, eax
10114 jmp pci_pro_ok
10115pci_pro_f0b: ;; write configuration byte
10116 cmp al, #0x0b
10117 jne pci_pro_f0c
10118 call pci_pro_select_reg
10119 push edx
10120 mov dx, di
10121 and dx, #0x03
10122 add dx, #0x0cfc
10123 mov al, cl
10124 out dx, al
10125 pop edx
10126 jmp pci_pro_ok
10127pci_pro_f0c: ;; write configuration word
10128 cmp al, #0x0c
10129 jne pci_pro_f0d
10130 call pci_pro_select_reg
10131 push edx
10132 mov dx, di
10133 and dx, #0x02
10134 add dx, #0x0cfc
10135 mov ax, cx
10136 out dx, ax
10137 pop edx
10138 jmp pci_pro_ok
10139pci_pro_f0d: ;; write configuration dword
10140 cmp al, #0x0d
10141 jne pci_pro_unknown
10142 call pci_pro_select_reg
10143 push edx
10144 mov dx, #0x0cfc
10145 mov eax, ecx
10146 out dx, eax
10147 pop edx
10148 jmp pci_pro_ok
10149pci_pro_unknown:
10150 mov ah, #0x81
10151pci_pro_fail:
10152 pop edi
10153 pop esi
10154#ifdef BX_QEMU
10155 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
10156#endif
10157 popfd
10158 stc
10159 retf
10160pci_pro_ok:
10161 xor ah, ah
10162 pop edi
10163 pop esi
10164#ifdef BX_QEMU
10165 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
10166#endif
10167 popfd
10168 clc
10169 retf
10170
10171pci_pro_select_reg:
10172 push edx
10173 mov eax, #0x800000
10174 mov ax, bx
10175 shl eax, #8
10176 and di, #0xff
10177 or ax, di
10178 and al, #0xfc
10179 mov dx, #0x0cf8
10180 out dx, eax
10181 pop edx
10182 ret
10183
10184use16 386
10185
10186pcibios_real:
10187 push eax
10188 push dx
10189#ifdef PCI_FIXED_HOST_BRIDGE_1
10190 mov eax, #0x80000000
10191 mov dx, #0x0cf8
10192 out dx, eax
10193 mov dx, #0x0cfc
10194 in eax, dx
10195 cmp eax, #PCI_FIXED_HOST_BRIDGE_1
10196 je pci_present
10197#endif
10198
10199#ifdef PCI_FIXED_HOST_BRIDGE_2
10200 /* 0x1e << 11 */
10201 mov eax, #0x8000f000
10202 mov dx, #0x0cf8
10203 out dx, eax
10204 mov dx, #0x0cfc
10205 in eax, dx
10206 cmp eax, #PCI_FIXED_HOST_BRIDGE_2
10207 je pci_present
10208#endif
10209 pop dx
10210 pop eax
10211 mov ah, #0xff
10212 stc
10213 ret
10214pci_present:
10215 pop dx
10216 pop eax
10217 cmp al, #0x01 ;; installation check
10218 jne pci_real_f02
10219 mov ax, #0x0001
10220 mov bx, #0x0210
10221 mov cx, #0
10222 mov edx, #0x20494350 ;; "PCI "
10223 mov edi, #0xf0000
10224 mov di, #pcibios_protected
10225 clc
10226 ret
10227pci_real_f02: ;; find pci device
10228 push esi
10229 push edi
10230 push edx
10231 cmp al, #0x02
10232 jne pci_real_f03
10233 shl ecx, #16
10234 mov cx, dx
10235 xor ebx, ebx
10236 mov di, #0x00
10237pci_real_devloop:
10238 call pci_real_select_reg
10239 mov dx, #0x0cfc
10240 in eax, dx
10241 cmp eax, ecx
10242 jne pci_real_nextdev
10243 cmp si, #0
10244 je pci_real_ok
10245 dec si
10246pci_real_nextdev:
10247 inc ebx
10248 cmp ebx, #0x10000
10249 jne pci_real_devloop
10250 mov dx, cx
10251 shr ecx, #16
10252 mov ax, #0x8602
10253 jmp pci_real_fail
10254pci_real_f03: ;; find class code
10255 cmp al, #0x03
10256 jne pci_real_f08
10257 xor ebx, ebx
10258 mov di, #0x08
10259pci_real_devloop2:
10260 call pci_real_select_reg
10261 mov dx, #0x0cfc
10262 in eax, dx
10263 shr eax, #8
10264 cmp eax, ecx
10265 jne pci_real_nextdev2
10266 cmp si, #0
10267 je pci_real_ok
10268 dec si
10269pci_real_nextdev2:
10270 inc ebx
10271 cmp ebx, #0x10000
10272 jne pci_real_devloop2
10273 mov ax, #0x8603
10274 jmp pci_real_fail
10275pci_real_f08: ;; read configuration byte
10276 cmp al, #0x08
10277 jne pci_real_f09
10278 call pci_real_select_reg
10279 push dx
10280 mov dx, di
10281 and dx, #0x03
10282 add dx, #0x0cfc
10283 in al, dx
10284 pop dx
10285 mov cl, al
10286 jmp pci_real_ok
10287pci_real_f09: ;; read configuration word
10288 cmp al, #0x09
10289 jne pci_real_f0a
10290 call pci_real_select_reg
10291 push dx
10292 mov dx, di
10293 and dx, #0x02
10294 add dx, #0x0cfc
10295 in ax, dx
10296 pop dx
10297 mov cx, ax
10298 jmp pci_real_ok
10299pci_real_f0a: ;; read configuration dword
10300 cmp al, #0x0a
10301 jne pci_real_f0b
10302 call pci_real_select_reg
10303 push dx
10304 mov dx, #0x0cfc
10305 in eax, dx
10306 pop dx
10307 mov ecx, eax
10308 jmp pci_real_ok
10309pci_real_f0b: ;; write configuration byte
10310 cmp al, #0x0b
10311 jne pci_real_f0c
10312 call pci_real_select_reg
10313 push dx
10314 mov dx, di
10315 and dx, #0x03
10316 add dx, #0x0cfc
10317 mov al, cl
10318 out dx, al
10319 pop dx
10320 jmp pci_real_ok
10321pci_real_f0c: ;; write configuration word
10322 cmp al, #0x0c
10323 jne pci_real_f0d
10324 call pci_real_select_reg
10325 push dx
10326 mov dx, di
10327 and dx, #0x02
10328 add dx, #0x0cfc
10329 mov ax, cx
10330 out dx, ax
10331 pop dx
10332 jmp pci_real_ok
10333pci_real_f0d: ;; write configuration dword
10334 cmp al, #0x0d
10335 jne pci_real_f0e
10336 call pci_real_select_reg
10337 push dx
10338 mov dx, #0x0cfc
10339 mov eax, ecx
10340 out dx, eax
10341 pop dx
10342 jmp pci_real_ok
10343pci_real_f0e: ;; get irq routing options
10344 cmp al, #0x0e
10345 jne pci_real_unknown
10346 SEG ES
10347 cmp word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
10348 jb pci_real_too_small
10349 SEG ES
10350 mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
10351 pushf
10352 push ds
10353 push es
10354 push cx
10355 push si
10356 push di
10357 cld
10358 mov si, #pci_routing_table_structure_start
10359 push cs
10360 pop ds
10361 SEG ES
10362 mov cx, [di+2]
10363 SEG ES
10364 mov es, [di+4]
10365 mov di, cx
10366 mov cx, #pci_routing_table_structure_end - pci_routing_table_structure_start
10367 rep
10368 movsb
10369 pop di
10370 pop si
10371 pop cx
10372 pop es
10373 pop ds
10374 popf
10375 mov bx, #(1 << 9) | (1 << 11) ;; irq 9 and 11 are used
10376 jmp pci_real_ok
10377pci_real_too_small:
10378 SEG ES
10379 mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
10380 mov ah, #0x89
10381 jmp pci_real_fail
10382
10383pci_real_unknown:
10384 mov ah, #0x81
10385pci_real_fail:
10386 pop edx
10387 pop edi
10388 pop esi
10389 stc
10390 ret
10391pci_real_ok:
10392 xor ah, ah
10393 pop edx
10394 pop edi
10395 pop esi
10396 clc
10397 ret
10398
10399;; prepare from reading the PCI config space; on input:
10400;; bx = bus/dev/fn
10401;; di = offset into config space header
10402;; destroys eax and may modify di
10403pci_real_select_reg:
10404 push dx
10405 mov eax, #0x800000
10406 mov ax, bx
10407 shl eax, #8
10408 and di, #0xff
10409 or ax, di
10410 and al, #0xfc
10411 mov dx, #0x0cf8
10412 out dx, eax
10413 pop dx
10414 ret
10415
10416.align 16
10417pci_routing_table_structure:
10418 db 0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature
10419 db 0, 1 ;; version
10420#ifdef VBOX
10421 dw 32 + (30 * 16) ;; table size
10422#else /* !VBOX */
10423 dw 32 + (6 * 16) ;; table size
10424#endif /* !VBOX */
10425 db 0 ;; PCI interrupt router bus
10426 db 0x08 ;; PCI interrupt router DevFunc
10427 dw 0x0000 ;; PCI exclusive IRQs
10428 dw 0x8086 ;; compatible PCI interrupt router vendor ID
10429 dw 0x7000 ;; compatible PCI interrupt router device ID
10430 dw 0,0 ;; Miniport data
10431 db 0,0,0,0,0,0,0,0,0,0,0 ;; reserved
10432#ifdef VBOX
10433 db 0x00 ;; checksum (set by biossums)
10434#else /* !VBOX */
10435 db 0x07 ;; checksum
10436#endif /* !VBOX */
10437pci_routing_table_structure_start:
10438 ;; first slot entry PCI-to-ISA (embedded)
10439 db 0 ;; pci bus number
10440 db 0x08 ;; pci device number (bit 7-3)
10441 db 0x60 ;; link value INTA#: pointer into PCI2ISA config space
10442 dw 0xdef8 ;; IRQ bitmap INTA#
10443 db 0x61 ;; link value INTB#
10444 dw 0xdef8 ;; IRQ bitmap INTB#
10445 db 0x62 ;; link value INTC#
10446 dw 0xdef8 ;; IRQ bitmap INTC#
10447 db 0x63 ;; link value INTD#
10448 dw 0xdef8 ;; IRQ bitmap INTD#
10449 db 0 ;; physical slot (0 = embedded)
10450 db 0 ;; reserved
10451 ;; second slot entry: 1st PCI slot
10452 db 0 ;; pci bus number
10453 db 0x10 ;; pci device number (bit 7-3)
10454 db 0x61 ;; link value INTA#
10455 dw 0xdef8 ;; IRQ bitmap INTA#
10456 db 0x62 ;; link value INTB#
10457 dw 0xdef8 ;; IRQ bitmap INTB#
10458 db 0x63 ;; link value INTC#
10459 dw 0xdef8 ;; IRQ bitmap INTC#
10460 db 0x60 ;; link value INTD#
10461 dw 0xdef8 ;; IRQ bitmap INTD#
10462 db 1 ;; physical slot (0 = embedded)
10463 db 0 ;; reserved
10464 ;; third slot entry: 2nd PCI slot
10465 db 0 ;; pci bus number
10466 db 0x18 ;; pci device number (bit 7-3)
10467 db 0x62 ;; link value INTA#
10468 dw 0xdef8 ;; IRQ bitmap INTA#
10469 db 0x63 ;; link value INTB#
10470 dw 0xdef8 ;; IRQ bitmap INTB#
10471 db 0x60 ;; link value INTC#
10472 dw 0xdef8 ;; IRQ bitmap INTC#
10473 db 0x61 ;; link value INTD#
10474 dw 0xdef8 ;; IRQ bitmap INTD#
10475 db 2 ;; physical slot (0 = embedded)
10476 db 0 ;; reserved
10477 ;; 4th slot entry: 3rd PCI slot
10478 db 0 ;; pci bus number
10479 db 0x20 ;; pci device number (bit 7-3)
10480 db 0x63 ;; link value INTA#
10481 dw 0xdef8 ;; IRQ bitmap INTA#
10482 db 0x60 ;; link value INTB#
10483 dw 0xdef8 ;; IRQ bitmap INTB#
10484 db 0x61 ;; link value INTC#
10485 dw 0xdef8 ;; IRQ bitmap INTC#
10486 db 0x62 ;; link value INTD#
10487 dw 0xdef8 ;; IRQ bitmap INTD#
10488 db 3 ;; physical slot (0 = embedded)
10489 db 0 ;; reserved
10490 ;; 5th slot entry: 4rd PCI slot
10491 db 0 ;; pci bus number
10492 db 0x28 ;; pci device number (bit 7-3)
10493 db 0x60 ;; link value INTA#
10494 dw 0xdef8 ;; IRQ bitmap INTA#
10495 db 0x61 ;; link value INTB#
10496 dw 0xdef8 ;; IRQ bitmap INTB#
10497 db 0x62 ;; link value INTC#
10498 dw 0xdef8 ;; IRQ bitmap INTC#
10499 db 0x63 ;; link value INTD#
10500 dw 0xdef8 ;; IRQ bitmap INTD#
10501 db 4 ;; physical slot (0 = embedded)
10502 db 0 ;; reserved
10503 ;; 6th slot entry: 5rd PCI slot
10504 db 0 ;; pci bus number
10505 db 0x30 ;; pci device number (bit 7-3)
10506 db 0x61 ;; link value INTA#
10507 dw 0xdef8 ;; IRQ bitmap INTA#
10508 db 0x62 ;; link value INTB#
10509 dw 0xdef8 ;; IRQ bitmap INTB#
10510 db 0x63 ;; link value INTC#
10511 dw 0xdef8 ;; IRQ bitmap INTC#
10512 db 0x60 ;; link value INTD#
10513 dw 0xdef8 ;; IRQ bitmap INTD#
10514 db 5 ;; physical slot (0 = embedded)
10515 db 0 ;; reserved
10516#ifdef VBOX
10517 ;; 7th slot entry: 6th PCI slot
10518 db 0 ;; pci bus number
10519 db 0x38 ;; pci device number (bit 7-3)
10520 db 0x62 ;; link value INTA#
10521 dw 0xdef8 ;; IRQ bitmap INTA#
10522 db 0x63 ;; link value INTB#
10523 dw 0xdef8 ;; IRQ bitmap INTB#
10524 db 0x60 ;; link value INTC#
10525 dw 0xdef8 ;; IRQ bitmap INTC#
10526 db 0x61 ;; link value INTD#
10527 dw 0xdef8 ;; IRQ bitmap INTD#
10528 db 6 ;; physical slot (0 = embedded)
10529 db 0 ;; reserved
10530 ;; 8th slot entry: 7th PCI slot
10531 db 0 ;; pci bus number
10532 db 0x40 ;; pci device number (bit 7-3)
10533 db 0x63 ;; link value INTA#
10534 dw 0xdef8 ;; IRQ bitmap INTA#
10535 db 0x60 ;; link value INTB#
10536 dw 0xdef8 ;; IRQ bitmap INTB#
10537 db 0x61 ;; link value INTC#
10538 dw 0xdef8 ;; IRQ bitmap INTC#
10539 db 0x62 ;; link value INTD#
10540 dw 0xdef8 ;; IRQ bitmap INTD#
10541 db 7 ;; physical slot (0 = embedded)
10542 db 0 ;; reserved
10543 ;; 9th slot entry: 8th PCI slot
10544 db 0 ;; pci bus number
10545 db 0x48 ;; pci device number (bit 7-3)
10546 db 0x60 ;; link value INTA#
10547 dw 0xdef8 ;; IRQ bitmap INTA#
10548 db 0x61 ;; link value INTB#
10549 dw 0xdef8 ;; IRQ bitmap INTB#
10550 db 0x62 ;; link value INTC#
10551 dw 0xdef8 ;; IRQ bitmap INTC#
10552 db 0x63 ;; link value INTD#
10553 dw 0xdef8 ;; IRQ bitmap INTD#
10554 db 8 ;; physical slot (0 = embedded)
10555 db 0 ;; reserved
10556 ;; 10th slot entry: 9th PCI slot
10557 db 0 ;; pci bus number
10558 db 0x50 ;; pci device number (bit 7-3)
10559 db 0x61 ;; link value INTA#
10560 dw 0xdef8 ;; IRQ bitmap INTA#
10561 db 0x62 ;; link value INTB#
10562 dw 0xdef8 ;; IRQ bitmap INTB#
10563 db 0x63 ;; link value INTC#
10564 dw 0xdef8 ;; IRQ bitmap INTC#
10565 db 0x60 ;; link value INTD#
10566 dw 0xdef8 ;; IRQ bitmap INTD#
10567 db 9 ;; physical slot (0 = embedded)
10568 db 0 ;; reserved
10569 ;; 11th slot entry: 10th PCI slot
10570 db 0 ;; pci bus number
10571 db 0x58 ;; pci device number (bit 7-3)
10572 db 0x62 ;; link value INTA#
10573 dw 0xdef8 ;; IRQ bitmap INTA#
10574 db 0x63 ;; link value INTB#
10575 dw 0xdef8 ;; IRQ bitmap INTB#
10576 db 0x60 ;; link value INTC#
10577 dw 0xdef8 ;; IRQ bitmap INTC#
10578 db 0x61 ;; link value INTD#
10579 dw 0xdef8 ;; IRQ bitmap INTD#
10580 db 10 ;; physical slot (0 = embedded)
10581 db 0 ;; reserved
10582 ;; 12th slot entry: 11th PCI slot
10583 db 0 ;; pci bus number
10584 db 0x60 ;; pci device number (bit 7-3)
10585 db 0x63 ;; link value INTA#
10586 dw 0xdef8 ;; IRQ bitmap INTA#
10587 db 0x60 ;; link value INTB#
10588 dw 0xdef8 ;; IRQ bitmap INTB#
10589 db 0x61 ;; link value INTC#
10590 dw 0xdef8 ;; IRQ bitmap INTC#
10591 db 0x62 ;; link value INTD#
10592 dw 0xdef8 ;; IRQ bitmap INTD#
10593 db 11 ;; physical slot (0 = embedded)
10594 db 0 ;; reserved
10595 ;; 13th slot entry: 12th PCI slot
10596 db 0 ;; pci bus number
10597 db 0x68 ;; pci device number (bit 7-3)
10598 db 0x60 ;; link value INTA#
10599 dw 0xdef8 ;; IRQ bitmap INTA#
10600 db 0x61 ;; link value INTB#
10601 dw 0xdef8 ;; IRQ bitmap INTB#
10602 db 0x62 ;; link value INTC#
10603 dw 0xdef8 ;; IRQ bitmap INTC#
10604 db 0x63 ;; link value INTD#
10605 dw 0xdef8 ;; IRQ bitmap INTD#
10606 db 12 ;; physical slot (0 = embedded)
10607 db 0 ;; reserved
10608 ;; 14th slot entry: 13th PCI slot
10609 db 0 ;; pci bus number
10610 db 0x70 ;; pci device number (bit 7-3)
10611 db 0x61 ;; link value INTA#
10612 dw 0xdef8 ;; IRQ bitmap INTA#
10613 db 0x62 ;; link value INTB#
10614 dw 0xdef8 ;; IRQ bitmap INTB#
10615 db 0x63 ;; link value INTC#
10616 dw 0xdef8 ;; IRQ bitmap INTC#
10617 db 0x60 ;; link value INTD#
10618 dw 0xdef8 ;; IRQ bitmap INTD#
10619 db 13 ;; physical slot (0 = embedded)
10620 db 0 ;; reserved
10621 ;; 15th slot entry: 14th PCI slot
10622 db 0 ;; pci bus number
10623 db 0x78 ;; pci device number (bit 7-3)
10624 db 0x62 ;; link value INTA#
10625 dw 0xdef8 ;; IRQ bitmap INTA#
10626 db 0x63 ;; link value INTB#
10627 dw 0xdef8 ;; IRQ bitmap INTB#
10628 db 0x60 ;; link value INTC#
10629 dw 0xdef8 ;; IRQ bitmap INTC#
10630 db 0x61 ;; link value INTD#
10631 dw 0xdef8 ;; IRQ bitmap INTD#
10632 db 14 ;; physical slot (0 = embedded)
10633 db 0 ;; reserved
10634 ;; 16th slot entry: 15th PCI slot
10635 db 0 ;; pci bus number
10636 db 0x80 ;; pci device number (bit 7-3)
10637 db 0x63 ;; link value INTA#
10638 dw 0xdef8 ;; IRQ bitmap INTA#
10639 db 0x60 ;; link value INTB#
10640 dw 0xdef8 ;; IRQ bitmap INTB#
10641 db 0x61 ;; link value INTC#
10642 dw 0xdef8 ;; IRQ bitmap INTC#
10643 db 0x62 ;; link value INTD#
10644 dw 0xdef8 ;; IRQ bitmap INTD#
10645 db 15 ;; physical slot (0 = embedded)
10646 db 0 ;; reserved
10647 ;; 17th slot entry: 16th PCI slot
10648 db 0 ;; pci bus number
10649 db 0x88 ;; pci device number (bit 7-3)
10650 db 0x60 ;; link value INTA#
10651 dw 0xdef8 ;; IRQ bitmap INTA#
10652 db 0x61 ;; link value INTB#
10653 dw 0xdef8 ;; IRQ bitmap INTB#
10654 db 0x62 ;; link value INTC#
10655 dw 0xdef8 ;; IRQ bitmap INTC#
10656 db 0x63 ;; link value INTD#
10657 dw 0xdef8 ;; IRQ bitmap INTD#
10658 db 16 ;; physical slot (0 = embedded)
10659 db 0 ;; reserved
10660 ;; 18th slot entry: 17th PCI slot
10661 db 0 ;; pci bus number
10662 db 0x90 ;; pci device number (bit 7-3)
10663 db 0x61 ;; link value INTA#
10664 dw 0xdef8 ;; IRQ bitmap INTA#
10665 db 0x62 ;; link value INTB#
10666 dw 0xdef8 ;; IRQ bitmap INTB#
10667 db 0x63 ;; link value INTC#
10668 dw 0xdef8 ;; IRQ bitmap INTC#
10669 db 0x60 ;; link value INTD#
10670 dw 0xdef8 ;; IRQ bitmap INTD#
10671 db 17 ;; physical slot (0 = embedded)
10672 db 0 ;; reserved
10673 ;; 19th slot entry: 18th PCI slot
10674 db 0 ;; pci bus number
10675 db 0x98 ;; pci device number (bit 7-3)
10676 db 0x62 ;; link value INTA#
10677 dw 0xdef8 ;; IRQ bitmap INTA#
10678 db 0x63 ;; link value INTB#
10679 dw 0xdef8 ;; IRQ bitmap INTB#
10680 db 0x60 ;; link value INTC#
10681 dw 0xdef8 ;; IRQ bitmap INTC#
10682 db 0x61 ;; link value INTD#
10683 dw 0xdef8 ;; IRQ bitmap INTD#
10684 db 18 ;; physical slot (0 = embedded)
10685 db 0 ;; reserved
10686 ;; 20th slot entry: 19th PCI slot
10687 db 0 ;; pci bus number
10688 db 0xa0 ;; pci device number (bit 7-3)
10689 db 0x63 ;; link value INTA#
10690 dw 0xdef8 ;; IRQ bitmap INTA#
10691 db 0x60 ;; link value INTB#
10692 dw 0xdef8 ;; IRQ bitmap INTB#
10693 db 0x61 ;; link value INTC#
10694 dw 0xdef8 ;; IRQ bitmap INTC#
10695 db 0x62 ;; link value INTD#
10696 dw 0xdef8 ;; IRQ bitmap INTD#
10697 db 19 ;; physical slot (0 = embedded)
10698 db 0 ;; reserved
10699 ;; 21st slot entry: 20th PCI slot
10700 db 0 ;; pci bus number
10701 db 0xa8 ;; pci device number (bit 7-3)
10702 db 0x60 ;; link value INTA#
10703 dw 0xdef8 ;; IRQ bitmap INTA#
10704 db 0x61 ;; link value INTB#
10705 dw 0xdef8 ;; IRQ bitmap INTB#
10706 db 0x62 ;; link value INTC#
10707 dw 0xdef8 ;; IRQ bitmap INTC#
10708 db 0x63 ;; link value INTD#
10709 dw 0xdef8 ;; IRQ bitmap INTD#
10710 db 20 ;; physical slot (0 = embedded)
10711 db 0 ;; reserved
10712 ;; 22nd slot entry: 21st PCI slot
10713 db 0 ;; pci bus number
10714 db 0xb0 ;; pci device number (bit 7-3)
10715 db 0x61 ;; link value INTA#
10716 dw 0xdef8 ;; IRQ bitmap INTA#
10717 db 0x62 ;; link value INTB#
10718 dw 0xdef8 ;; IRQ bitmap INTB#
10719 db 0x63 ;; link value INTC#
10720 dw 0xdef8 ;; IRQ bitmap INTC#
10721 db 0x60 ;; link value INTD#
10722 dw 0xdef8 ;; IRQ bitmap INTD#
10723 db 21 ;; physical slot (0 = embedded)
10724 db 0 ;; reserved
10725 ;; 23rd slot entry: 22nd PCI slot
10726 db 0 ;; pci bus number
10727 db 0xb8 ;; pci device number (bit 7-3)
10728 db 0x62 ;; link value INTA#
10729 dw 0xdef8 ;; IRQ bitmap INTA#
10730 db 0x63 ;; link value INTB#
10731 dw 0xdef8 ;; IRQ bitmap INTB#
10732 db 0x60 ;; link value INTC#
10733 dw 0xdef8 ;; IRQ bitmap INTC#
10734 db 0x61 ;; link value INTD#
10735 dw 0xdef8 ;; IRQ bitmap INTD#
10736 db 22 ;; physical slot (0 = embedded)
10737 db 0 ;; reserved
10738 ;; 24th slot entry: 23rd PCI slot
10739 db 0 ;; pci bus number
10740 db 0xc0 ;; pci device number (bit 7-3)
10741 db 0x63 ;; link value INTA#
10742 dw 0xdef8 ;; IRQ bitmap INTA#
10743 db 0x60 ;; link value INTB#
10744 dw 0xdef8 ;; IRQ bitmap INTB#
10745 db 0x61 ;; link value INTC#
10746 dw 0xdef8 ;; IRQ bitmap INTC#
10747 db 0x62 ;; link value INTD#
10748 dw 0xdef8 ;; IRQ bitmap INTD#
10749 db 23 ;; physical slot (0 = embedded)
10750 db 0 ;; reserved
10751 ;; 25th slot entry: 24th PCI slot
10752 db 0 ;; pci bus number
10753 db 0xc8 ;; pci device number (bit 7-3)
10754 db 0x60 ;; link value INTA#
10755 dw 0xdef8 ;; IRQ bitmap INTA#
10756 db 0x61 ;; link value INTB#
10757 dw 0xdef8 ;; IRQ bitmap INTB#
10758 db 0x62 ;; link value INTC#
10759 dw 0xdef8 ;; IRQ bitmap INTC#
10760 db 0x63 ;; link value INTD#
10761 dw 0xdef8 ;; IRQ bitmap INTD#
10762 db 24 ;; physical slot (0 = embedded)
10763 db 0 ;; reserved
10764 ;; 26th slot entry: 25th PCI slot
10765 db 0 ;; pci bus number
10766 db 0xd0 ;; pci device number (bit 7-3)
10767 db 0x61 ;; link value INTA#
10768 dw 0xdef8 ;; IRQ bitmap INTA#
10769 db 0x62 ;; link value INTB#
10770 dw 0xdef8 ;; IRQ bitmap INTB#
10771 db 0x63 ;; link value INTC#
10772 dw 0xdef8 ;; IRQ bitmap INTC#
10773 db 0x60 ;; link value INTD#
10774 dw 0xdef8 ;; IRQ bitmap INTD#
10775 db 25 ;; physical slot (0 = embedded)
10776 db 0 ;; reserved
10777 ;; 27th slot entry: 26th PCI slot
10778 db 0 ;; pci bus number
10779 db 0xd8 ;; pci device number (bit 7-3)
10780 db 0x62 ;; link value INTA#
10781 dw 0xdef8 ;; IRQ bitmap INTA#
10782 db 0x63 ;; link value INTB#
10783 dw 0xdef8 ;; IRQ bitmap INTB#
10784 db 0x60 ;; link value INTC#
10785 dw 0xdef8 ;; IRQ bitmap INTC#
10786 db 0x61 ;; link value INTD#
10787 dw 0xdef8 ;; IRQ bitmap INTD#
10788 db 26 ;; physical slot (0 = embedded)
10789 db 0 ;; reserved
10790 ;; 28th slot entry: 27th PCI slot
10791 db 0 ;; pci bus number
10792 db 0xe0 ;; pci device number (bit 7-3)
10793 db 0x63 ;; link value INTA#
10794 dw 0xdef8 ;; IRQ bitmap INTA#
10795 db 0x60 ;; link value INTB#
10796 dw 0xdef8 ;; IRQ bitmap INTB#
10797 db 0x61 ;; link value INTC#
10798 dw 0xdef8 ;; IRQ bitmap INTC#
10799 db 0x62 ;; link value INTD#
10800 dw 0xdef8 ;; IRQ bitmap INTD#
10801 db 27 ;; physical slot (0 = embedded)
10802 db 0 ;; reserved
10803 ;; 29th slot entry: 28th PCI slot
10804 db 0 ;; pci bus number
10805 db 0xe8 ;; pci device number (bit 7-3)
10806 db 0x60 ;; link value INTA#
10807 dw 0xdef8 ;; IRQ bitmap INTA#
10808 db 0x61 ;; link value INTB#
10809 dw 0xdef8 ;; IRQ bitmap INTB#
10810 db 0x62 ;; link value INTC#
10811 dw 0xdef8 ;; IRQ bitmap INTC#
10812 db 0x63 ;; link value INTD#
10813 dw 0xdef8 ;; IRQ bitmap INTD#
10814 db 28 ;; physical slot (0 = embedded)
10815 db 0 ;; reserved
10816 ;; 30th slot entry: 29th PCI slot
10817 db 0 ;; pci bus number
10818 db 0xf0 ;; pci device number (bit 7-3)
10819 db 0x61 ;; link value INTA#
10820 dw 0xdef8 ;; IRQ bitmap INTA#
10821 db 0x62 ;; link value INTB#
10822 dw 0xdef8 ;; IRQ bitmap INTB#
10823 db 0x63 ;; link value INTC#
10824 dw 0xdef8 ;; IRQ bitmap INTC#
10825 db 0x60 ;; link value INTD#
10826 dw 0xdef8 ;; IRQ bitmap INTD#
10827 db 29 ;; physical slot (0 = embedded)
10828 db 0 ;; reserved
10829#endif /* VBOX */
10830pci_routing_table_structure_end:
10831
10832#if !BX_ROMBIOS32
10833pci_irq_list:
10834 db 11, 10, 9, 5;
10835
10836pcibios_init_sel_reg:
10837 push eax
10838 mov eax, #0x800000
10839 mov ax, bx
10840 shl eax, #8
10841 and dl, #0xfc
10842 or al, dl
10843 mov dx, #0x0cf8
10844 out dx, eax
10845 pop eax
10846 ret
10847
10848pcibios_init_iomem_bases:
10849 push bp
10850 mov bp, sp
10851 mov eax, #0xe0000000 ;; base for memory init
10852 push eax
10853 mov ax, #0xc000 ;; base for i/o init
10854 push ax
10855 mov ax, #0x0010 ;; start at base address #0
10856 push ax
10857 mov bx, #0x0008
10858pci_init_io_loop1:
10859 mov dl, #0x00
10860 call pcibios_init_sel_reg
10861 mov dx, #0x0cfc
10862 in ax, dx
10863 cmp ax, #0xffff
10864 jz next_pci_dev
10865#ifndef VBOX /* This currently breaks restoring a previously saved state. */
10866 mov dl, #0x04 ;; disable i/o and memory space access
10867 call pcibios_init_sel_reg
10868 mov dx, #0x0cfc
10869 in al, dx
10870 and al, #0xfc
10871 out dx, al
10872pci_init_io_loop2:
10873 mov dl, [bp-8]
10874 call pcibios_init_sel_reg
10875 mov dx, #0x0cfc
10876 in eax, dx
10877 test al, #0x01
10878 jnz init_io_base
10879 mov ecx, eax
10880 mov eax, #0xffffffff
10881 out dx, eax
10882 in eax, dx
10883 cmp eax, ecx
10884 je next_pci_base
10885 xor eax, #0xffffffff
10886 mov ecx, eax
10887 mov eax, [bp-4]
10888 out dx, eax
10889 add eax, ecx ;; calculate next free mem base
10890 add eax, #0x01000000
10891 and eax, #0xff000000
10892 mov [bp-4], eax
10893 jmp next_pci_base
10894init_io_base:
10895 mov cx, ax
10896 mov ax, #0xffff
10897 out dx, ax
10898 in ax, dx
10899 cmp ax, cx
10900 je next_pci_base
10901 xor ax, #0xfffe
10902 mov cx, ax
10903 mov ax, [bp-6]
10904 out dx, ax
10905 add ax, cx ;; calculate next free i/o base
10906 add ax, #0x0100
10907 and ax, #0xff00
10908 mov [bp-6], ax
10909next_pci_base:
10910 mov al, [bp-8]
10911 add al, #0x04
10912 cmp al, #0x28
10913 je enable_iomem_space
10914 mov byte ptr[bp-8], al
10915 jmp pci_init_io_loop2
10916#endif /* !VBOX */
10917enable_iomem_space:
10918 mov dl, #0x04 ;; enable i/o and memory space access if available
10919 call pcibios_init_sel_reg
10920 mov dx, #0x0cfc
10921 in al, dx
10922 or al, #0x07
10923 out dx, al
10924#ifdef VBOX
10925 mov dl, #0x00 ;; check if PCI device is AMD PCNet
10926 call pcibios_init_sel_reg
10927 mov dx, #0x0cfc
10928 in eax, dx
10929 cmp eax, #0x20001022
10930 jne next_pci_dev
10931 mov dl, #0x10 ;; get I/O address
10932 call pcibios_init_sel_reg
10933 mov dx, #0x0cfc
10934 in ax, dx
10935 and ax, #0xfffc
10936 mov cx, ax
10937 mov dx, cx
10938 add dx, #0x14 ;; reset register if PCNet is in word I/O mode
10939 in ax, dx ;; reset is performed by reading the reset register
10940 mov dx, cx
10941 add dx, #0x18 ;; reset register if PCNet is in word I/O mode
10942 in eax, dx ;; reset is performed by reading the reset register
10943#endif /* VBOX */
10944next_pci_dev:
10945 mov byte ptr[bp-8], #0x10
10946 inc bx
10947 cmp bx, #0x0100
10948 jne pci_init_io_loop1
10949 mov sp, bp
10950 pop bp
10951 ret
10952
10953pcibios_init_set_elcr:
10954 push ax
10955 push cx
10956 mov dx, #0x04d0
10957 test al, #0x08
10958 jz is_master_pic
10959 inc dx
10960 and al, #0x07
10961is_master_pic:
10962 mov cl, al
10963 mov bl, #0x01
10964 shl bl, cl
10965 in al, dx
10966 or al, bl
10967 out dx, al
10968 pop cx
10969 pop ax
10970 ret
10971
10972pcibios_init_irqs:
10973 push ds
10974 push bp
10975 mov ax, #0xf000
10976 mov ds, ax
10977 mov dx, #0x04d0 ;; reset ELCR1 + ELCR2
10978 mov al, #0x00
10979 out dx, al
10980 inc dx
10981 out dx, al
10982 mov si, #pci_routing_table_structure
10983 mov bh, [si+8]
10984 mov bl, [si+9]
10985 mov dl, #0x00
10986 call pcibios_init_sel_reg
10987 mov dx, #0x0cfc
10988 in eax, dx
10989 cmp eax, [si+12] ;; check irq router
10990 jne pci_init_end
10991 mov dl, [si+34]
10992 call pcibios_init_sel_reg
10993 push bx ;; save irq router bus + devfunc
10994 mov dx, #0x0cfc
10995 mov ax, #0x8080
10996 out dx, ax ;; reset PIRQ route control
10997 add dx, #2
10998 out dx, ax
10999 mov ax, [si+6]
11000 sub ax, #0x20
11001 shr ax, #4
11002 mov cx, ax
11003 add si, #0x20 ;; set pointer to 1st entry
11004 mov bp, sp
11005 mov ax, #pci_irq_list
11006 push ax
11007 xor ax, ax
11008 push ax
11009pci_init_irq_loop1:
11010 mov bh, [si]
11011 mov bl, [si+1]
11012pci_init_irq_loop2:
11013 mov dl, #0x00
11014 call pcibios_init_sel_reg
11015 mov dx, #0x0cfc
11016 in ax, dx
11017 cmp ax, #0xffff
11018 jnz pci_test_int_pin
11019 test bl, #0x07
11020 jz next_pir_entry
11021 jmp next_pci_func
11022pci_test_int_pin:
11023 mov dl, #0x3c
11024 call pcibios_init_sel_reg
11025 mov dx, #0x0cfd
11026 in al, dx
11027 and al, #0x07
11028 jz next_pci_func
11029 dec al ;; determine pirq reg
11030 mov dl, #0x03
11031 mul al, dl
11032 add al, #0x02
11033 xor ah, ah
11034 mov bx, ax
11035 mov al, [si+bx]
11036 mov dl, al
11037 mov bx, [bp]
11038 call pcibios_init_sel_reg
11039 mov dx, #0x0cfc
11040 and al, #0x03
11041 add dl, al
11042 in al, dx
11043 cmp al, #0x80
11044 jb pirq_found
11045 mov bx, [bp-2] ;; pci irq list pointer
11046 mov al, [bx]
11047 out dx, al
11048 inc bx
11049 mov [bp-2], bx
11050 call pcibios_init_set_elcr
11051pirq_found:
11052 mov bh, [si]
11053 mov bl, [si+1]
11054 add bl, [bp-3] ;; pci function number
11055 mov dl, #0x3c
11056 call pcibios_init_sel_reg
11057 mov dx, #0x0cfc
11058 out dx, al
11059next_pci_func:
11060 inc byte ptr[bp-3]
11061 inc bl
11062 test bl, #0x07
11063 jnz pci_init_irq_loop2
11064next_pir_entry:
11065 add si, #0x10
11066 mov byte ptr[bp-3], #0x00
11067 loop pci_init_irq_loop1
11068 mov sp, bp
11069 pop bx
11070pci_init_end:
11071 pop bp
11072 pop ds
11073 ret
11074#endif // !BX_ROMBIOS32
11075#endif // BX_PCIBIOS
11076
11077#if BX_ROMBIOS32
11078rombios32_init:
11079 ;; save a20 and enable it
11080 in al, 0x92
11081 push ax
11082 or al, #0x02
11083 out 0x92, al
11084
11085 ;; save SS:SP to the BDA
11086 xor ax, ax
11087 mov ds, ax
11088 mov 0x0469, ss
11089 mov 0x0467, sp
11090
11091 SEG CS
11092 lidt [pmode_IDT_info]
11093 SEG CS
11094 lgdt [rombios32_gdt_48]
11095 ;; set PE bit in CR0
11096 mov eax, cr0
11097 or al, #0x01
11098 mov cr0, eax
11099 ;; start protected mode code: ljmpl 0x10:rombios32_init1
11100 db 0x66, 0xea
11101 dw rombios32_05
11102 dw 0x000f ;; high 16 bit address
11103 dw 0x0010
11104
11105use32 386
11106rombios32_05:
11107 ;; init data segments
11108 mov eax, #0x18
11109 mov ds, ax
11110 mov es, ax
11111 mov ss, ax
11112 xor eax, eax
11113 mov fs, ax
11114 mov gs, ax
11115 cld
11116
11117 ;; copy rombios32 code to ram (ram offset = 1MB)
11118 mov esi, #0xfffe0000
11119 mov edi, #0x00040000
11120 mov ecx, #0x10000 / 4
11121 rep
11122 movsd
11123
11124 ;; init the stack pointer
11125 mov esp, #0x00080000
11126
11127 ;; call rombios32 code
11128 mov eax, #0x00040000
11129 call eax
11130
11131 ;; return to 16 bit protected mode first
11132 db 0xea
11133 dd rombios32_10
11134 dw 0x20
11135
11136use16 386
11137rombios32_10:
11138 ;; restore data segment limits to 0xffff
11139 mov ax, #0x28
11140 mov ds, ax
11141 mov es, ax
11142 mov ss, ax
11143 mov fs, ax
11144 mov gs, ax
11145
11146 ;; reset PE bit in CR0
11147 mov eax, cr0
11148 and al, #0xFE
11149 mov cr0, eax
11150
11151 ;; far jump to flush CPU queue after transition to real mode
11152 JMP_AP(0xf000, rombios32_real_mode)
11153
11154rombios32_real_mode:
11155 ;; restore IDT to normal real-mode defaults
11156 SEG CS
11157 lidt [rmode_IDT_info]
11158
11159 xor ax, ax
11160 mov ds, ax
11161 mov es, ax
11162 mov fs, ax
11163 mov gs, ax
11164
11165 ;; restore SS:SP from the BDA
11166 mov ss, 0x0469
11167 xor esp, esp
11168 mov sp, 0x0467
11169 ;; restore a20
11170 pop ax
11171 out 0x92, al
11172 ret
11173
11174rombios32_gdt_48:
11175 dw 0x30
11176 dw rombios32_gdt
11177 dw 0x000f
11178
11179rombios32_gdt:
11180 dw 0, 0, 0, 0
11181 dw 0, 0, 0, 0
11182 dw 0xffff, 0, 0x9b00, 0x00cf ; 32 bit flat code segment (0x10)
11183 dw 0xffff, 0, 0x9300, 0x00cf ; 32 bit flat data segment (0x18)
11184 dw 0xffff, 0, 0x9b0f, 0x0000 ; 16 bit code segment base=0xf0000 limit=0xffff
11185 dw 0xffff, 0, 0x9300, 0x0000 ; 16 bit data segment base=0x0 limit=0xffff
11186#endif // BX_ROMBIOS32
11187
11188
11189; parallel port detection: base address in DX, index in BX, timeout in CL
11190detect_parport:
11191 push dx
11192 add dx, #2
11193 in al, dx
11194 and al, #0xdf ; clear input mode
11195 out dx, al
11196 pop dx
11197 mov al, #0xaa
11198 out dx, al
11199 in al, dx
11200 cmp al, #0xaa
11201 jne no_parport
11202 push bx
11203 shl bx, #1
11204 mov [bx+0x408], dx ; Parallel I/O address
11205 pop bx
11206 mov [bx+0x478], cl ; Parallel printer timeout
11207 inc bx
11208no_parport:
11209 ret
11210
11211; serial port detection: base address in DX, index in BX, timeout in CL
11212detect_serial:
11213 push dx
11214 inc dx
11215 mov al, #0x02
11216 out dx, al
11217 in al, dx
11218 cmp al, #0x02
11219 jne no_serial
11220 inc dx
11221 in al, dx
11222 cmp al, #0x02
11223 jne no_serial
11224 dec dx
11225 xor al, al
11226 out dx, al
11227 pop dx
11228 push bx
11229 shl bx, #1
11230 mov [bx+0x400], dx ; Serial I/O address
11231 pop bx
11232 mov [bx+0x47c], cl ; Serial timeout
11233 inc bx
11234 ret
11235no_serial:
11236 pop dx
11237 ret
11238
11239rom_checksum:
11240 push ax
11241#ifdef NO_ROM_CHECKSUM
11242 xor ax, ax
11243#else
11244 push bx
11245 push cx
11246 xor ax, ax
11247 xor bx, bx
11248 xor cx, cx
11249 mov ch, [2]
11250 shl cx, #1
11251checksum_loop:
11252 add al, [bx]
11253 inc bx
11254 loop checksum_loop
11255 and al, #0xff
11256 pop cx
11257 pop bx
11258#endif
11259 pop ax
11260 ret
11261
11262rom_scan:
11263 ;; Scan for existence of valid expansion ROMS.
11264 ;; Video ROM: from 0xC0000..0xC7FFF in 2k increments
11265 ;; General ROM: from 0xC8000..0xDFFFF in 2k increments
11266 ;; System ROM: only 0xE0000
11267 ;;
11268 ;; Header:
11269 ;; Offset Value
11270 ;; 0 0x55
11271 ;; 1 0xAA
11272 ;; 2 ROM length in 512-byte blocks
11273 ;; 3 ROM initialization entry point (FAR CALL)
11274
11275 mov cx, #0xc000
11276rom_scan_loop:
11277 mov ds, cx
11278 mov ax, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
11279 cmp [0], #0xAA55 ;; look for signature
11280 jne rom_scan_increment
11281 call rom_checksum
11282 jnz rom_scan_increment
11283 mov al, [2] ;; change increment to ROM length in 512-byte blocks
11284
11285 ;; We want our increment in 512-byte quantities, rounded to
11286 ;; the nearest 2k quantity, since we only scan at 2k intervals.
11287 test al, #0x03
11288 jz block_count_rounded
11289 and al, #0xfc ;; needs rounding up
11290 add al, #0x04
11291block_count_rounded:
11292
11293 xor bx, bx ;; Restore DS back to 0000:
11294 mov ds, bx
11295 push ax ;; Save AX
11296 ;; Push addr of ROM entry point
11297 push cx ;; Push seg
11298 push #0x0003 ;; Push offset
11299 mov bp, sp ;; Call ROM init routine using seg:off on stack
11300 db 0xff ;; call_far ss:[bp+0]
11301 db 0x5e
11302 db 0
11303 cli ;; In case expansion ROM BIOS turns IF on
11304 add sp, #2 ;; Pop offset value
11305 pop cx ;; Pop seg value (restore CX)
11306 pop ax ;; Restore AX
11307rom_scan_increment:
11308 shl ax, #5 ;; convert 512-bytes blocks to 16-byte increments
11309 ;; because the segment selector is shifted left 4 bits.
11310 add cx, ax
11311 cmp cx, #0xe800 ;; Must encompass VBOX_LANBOOT_SEG!
11312 jbe rom_scan_loop
11313
11314 xor ax, ax ;; Restore DS back to 0000:
11315 mov ds, ax
11316 ret
11317
11318#define LVT0 0xFEE00350
11319#define LVT1 0xFEE00360
11320
11321;; Run initialization steps which must be performed in protected mode.
11322;; - Program LVT0/LVT1 entries in the local APIC. Some Linux kernels (e.g., RHEL4
11323;; SMP 32-bit) expect the entries to be unmasked in virtual wire mode.
11324;; - Clear the CD and NW bits in CR0; these are not relevant (except possibly
11325;; under AMD-V with nested paging) but the guest should see the right state.
11326
11327pmode_setup:
11328 push eax
11329 push esi
11330 pushf
11331 cli ;; Interrupts would kill us!
11332 call pmode_enter
11333 mov esi, #LVT0 ;; Program LVT0 to ExtINT and unmask
11334 mov eax, [esi]
11335 and eax, #0xfffe00ff
11336 or ah, #0x07
11337 mov [esi], eax
11338 mov esi, #LVT1 ;; Program LVT1 to NMI and unmask
11339 mov eax, [esi]
11340 and eax, #0xfffe00ff
11341 or ah, #0x04
11342 mov [esi], eax
11343 mov eax, cr0 ;; Clear CR0.CD and CR0.NW
11344 and eax, #0x9fffffff
11345 mov cr0, eax
11346 call pmode_exit
11347 popf
11348 pop esi
11349 pop eax
11350 ret
11351
11352;; Enter and exit minimal protected-mode environment. May only be called from
11353;; the F000 segment (16-bit). Does not switch stacks. Must be run with disabled
11354;; interrupts(!). On return from pmode_enter, DS contains a selector which can
11355;; address the entire 4GB address space.
11356
11357pmode_enter:
11358 push cs
11359 pop ds
11360 lgdt [pmbios_gdt_desc]
11361 mov eax, cr0
11362 or al, #0x1
11363 mov cr0, eax
11364 JMP_AP(0x20, really_enter_pm)
11365really_enter_pm:
11366 mov ax, #0x18
11367 mov ds, ax
11368 ret
11369
11370pmode_exit:
11371 mov ax, #0x28
11372 mov ds, ax
11373 mov eax, cr0
11374 and al, #0xfe
11375 mov cr0, eax
11376 JMP_AP(0xF000, really_exit_pm)
11377really_exit_pm:
11378 ret
11379
11380pmbios_gdt_desc:
11381 dw 0x30
11382 dw pmbios_gdt
11383 dw 0x000f
11384
11385pmbios_gdt:
11386 dw 0, 0, 0, 0
11387 dw 0, 0, 0, 0
11388 dw 0xffff, 0, 0x9b00, 0x00cf ; 32 bit flat code segment (0x10)
11389 dw 0xffff, 0, 0x9300, 0x00cf ; 32 bit flat data segment (0x18)
11390 dw 0xffff, 0, 0x9b0f, 0x0000 ; 16 bit code segment base=0xf0000 limit=0xffff
11391 dw 0xffff, 0, 0x9300, 0x0000 ; 16 bit data segment base=0x0 limit=0xffff
11392
11393;; for 'C' strings and other data, insert them here with
11394;; a the following hack:
11395;; DATA_SEG_DEFS_HERE
11396
11397
11398;; the following area can be used to write dynamically generated tables
11399 .align 16
11400bios_table_area_start:
11401 dd 0xaafb4442
11402 dd bios_table_area_end - bios_table_area_start - 8;
11403
11404;--------
11405;- POST -
11406;--------
11407.org 0xe05b ; POST Entry Point
11408bios_table_area_end:
11409post:
11410
11411 xor ax, ax
11412
11413 ;; first reset the DMA controllers
11414 out 0x0d,al
11415 out 0xda,al
11416
11417 ;; then initialize the DMA controllers
11418 mov al, #0xC0
11419 out 0xD6, al ; cascade mode of channel 4 enabled
11420 mov al, #0x00
11421 out 0xD4, al ; unmask channel 4
11422
11423 ;; Examine CMOS shutdown status.
11424 mov AL, #0x0f
11425 out 0x70, AL
11426 in AL, 0x71
11427
11428 ;; backup status
11429 mov bl, al
11430
11431 ;; Reset CMOS shutdown status.
11432 mov AL, #0x0f
11433 out 0x70, AL ; select CMOS register Fh
11434 mov AL, #0x00
11435 out 0x71, AL ; set shutdown action to normal
11436
11437 ;; Examine CMOS shutdown status.
11438 mov al, bl
11439
11440 ;; 0x00, 0x09, 0x0D+ = normal startup
11441 cmp AL, #0x00
11442 jz normal_post
11443 cmp AL, #0x0d
11444 jae normal_post
11445 cmp AL, #0x09
11446 je normal_post
11447
11448 ;; 0x05 = eoi + jmp via [0x40:0x67] jump
11449 cmp al, #0x05
11450 je eoi_jmp_post
11451
11452#ifdef VBOX
11453 ;; just ignore all other CMOS shutdown status values (OpenSolaris sets it to 0xA for some reason in certain cases)
11454 ;; (shutdown_status_panic just crashes the VM as it calls int 0x10 before the IDT table has been initialized)
11455 jmp normal_post
11456#else
11457 ;; Examine CMOS shutdown status.
11458 ;; 0x01,0x02,0x03,0x04,0x06,0x07,0x08, 0x0a, 0x0b, 0x0c = Unimplemented shutdown status.
11459 push bx
11460 call _shutdown_status_panic
11461#endif
11462
11463#if 0
11464 HALT(__LINE__)
11465 ;
11466 ;#if 0
11467 ; 0xb0, 0x20, /* mov al, #0x20 */
11468 ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */
11469 ;#endif
11470 ;
11471 pop es
11472 pop ds
11473 popa
11474 iret
11475#endif
11476
11477normal_post:
11478 ; case 0: normal startup
11479
11480 cli
11481 mov ax, #0x7C00
11482 mov sp, ax
11483 xor ax, ax
11484 mov ds, ax
11485 mov ss, ax
11486
11487#ifndef VBOX
11488 ;; zero out BIOS data area (40:00..40:ff)
11489 mov es, ax
11490 mov cx, #0x0080 ;; 128 words
11491 mov di, #0x0400
11492 cld
11493 rep
11494 stosw
11495#else /* VBOX */
11496 ;; zero out segment 0 (includes BIOS data area) except word at 40:72
11497 mov es, ax
11498 xor di, di
11499 cld
11500 mov cx, #0x0239 ;; 569 words
11501 rep
11502 stosw
11503 inc di
11504 inc di
11505 mov cx, #0x7dc6 ;; 32198 words
11506 rep
11507 stosw
11508 ;; zero out remaining base memory except the last 16 bytes of the EBDA
11509 ;; because we store the MP table there
11510 xor eax, eax
11511 xor bx, bx
11512memory_zero_loop:
11513 add bx, #0x1000
11514 cmp bx, #0x9000
11515 jae memory_cleared
11516 mov es, bx
11517 xor di, di
11518 mov cx, #0x4000
11519 rep
11520 stosd
11521 jmp memory_zero_loop
11522memory_cleared:
11523 mov es, bx
11524 xor di, di
11525 mov cx, #0x3f00
11526 rep
11527 stosd
11528 xor bx, bx
11529#endif
11530
11531 call _log_bios_start
11532
11533 call pmode_setup
11534
11535 ;; set all interrupts to default handler
11536 xor bx, bx ;; offset index
11537 mov cx, #0x0078 ;; leave the rest as zeros
11538 mov ax, #dummy_iret_handler
11539 mov dx, #0xF000
11540
11541post_default_ints:
11542 mov [bx], ax
11543 add bx, #2
11544 mov [bx], dx
11545 add bx, #2
11546 loop post_default_ints
11547
11548 ;; set vector 0x79 to zero
11549 ;; this is used by 'guardian angel' protection system
11550 SET_INT_VECTOR(0x79, #0, #0)
11551
11552 ;; base memory in K 40:13 (word)
11553 mov ax, #BASE_MEM_IN_K
11554 mov 0x0413, ax
11555
11556
11557 ;; Manufacturing Test 40:12
11558 ;; zerod out above
11559
11560#ifndef VBOX
11561 ;; Warm Boot Flag 0040:0072
11562 ;; value of 1234h = skip memory checks
11563 ;; zerod out above
11564#endif /* !VBOX */
11565
11566
11567 ;; Printer Services vector
11568 SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
11569
11570 ;; Bootstrap failure vector
11571 SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
11572
11573 ;; Bootstrap Loader vector
11574 SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
11575
11576 ;; User Timer Tick vector
11577 SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
11578
11579 ;; Memory Size Check vector
11580 SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
11581
11582 ;; Equipment Configuration Check vector
11583 SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
11584
11585 ;; System Services
11586 SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
11587
11588 ;; EBDA setup
11589 call ebda_post
11590
11591 ;; PIT setup
11592 SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
11593 ;; int 1C already points at dummy_iret_handler (above)
11594 mov al, #0x34 ; timer0: binary count, 16bit count, mode 2
11595 out 0x43, al
11596 mov al, #0x00 ; maximum count of 0000H = 18.2Hz
11597 out 0x40, al
11598 out 0x40, al
11599
11600 ;; Keyboard
11601 SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
11602 SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
11603
11604 xor ax, ax
11605 mov ds, ax
11606 mov 0x0417, al /* keyboard shift flags, set 1 */
11607 mov 0x0418, al /* keyboard shift flags, set 2 */
11608 mov 0x0419, al /* keyboard alt-numpad work area */
11609 mov 0x0471, al /* keyboard ctrl-break flag */
11610 mov 0x0497, al /* keyboard status flags 4 */
11611 mov al, #0x10
11612 mov 0x0496, al /* keyboard status flags 3 */
11613
11614
11615 /* keyboard head of buffer pointer */
11616 mov bx, #0x001E
11617 mov 0x041A, bx
11618
11619 /* keyboard end of buffer pointer */
11620 mov 0x041C, bx
11621
11622 /* keyboard pointer to start of buffer */
11623 mov bx, #0x001E
11624 mov 0x0480, bx
11625
11626 /* keyboard pointer to end of buffer */
11627 mov bx, #0x003E
11628 mov 0x0482, bx
11629
11630 /* init the keyboard */
11631 call _keyboard_init
11632
11633 ;; mov CMOS Equipment Byte to BDA Equipment Word
11634 mov ax, 0x0410
11635 mov al, #0x14
11636 out 0x70, al
11637 in al, 0x71
11638 mov 0x0410, ax
11639
11640
11641 ;; Parallel setup
11642 SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
11643 xor ax, ax
11644 mov ds, ax
11645 xor bx, bx
11646 mov cl, #0x14 ; timeout value
11647 mov dx, #0x378 ; Parallel I/O address, port 1
11648 call detect_parport
11649 mov dx, #0x278 ; Parallel I/O address, port 2
11650 call detect_parport
11651 shl bx, #0x0e
11652 mov ax, 0x410 ; Equipment word bits 14..15 determine # parallel ports
11653 and ax, #0x3fff
11654 or ax, bx ; set number of parallel ports
11655 mov 0x410, ax
11656
11657 ;; Serial setup
11658 SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
11659 SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
11660 xor bx, bx
11661 mov cl, #0x0a ; timeout value
11662 mov dx, #0x03f8 ; Serial I/O address, port 1
11663 call detect_serial
11664 mov dx, #0x02f8 ; Serial I/O address, port 2
11665 call detect_serial
11666 mov dx, #0x03e8 ; Serial I/O address, port 3
11667 call detect_serial
11668 mov dx, #0x02e8 ; Serial I/O address, port 4
11669 call detect_serial
11670 shl bx, #0x09
11671 mov ax, 0x410 ; Equipment word bits 9..11 determine # serial ports
11672 and ax, #0xf1ff
11673 or ax, bx ; set number of serial port
11674 mov 0x410, ax
11675
11676 ;; CMOS RTC
11677 SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
11678 SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
11679 SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
11680 ;; BIOS DATA AREA 0x4CE ???
11681 call timer_tick_post
11682
11683 ;; PS/2 mouse setup
11684 SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
11685
11686 ;; IRQ13 (FPU exception) setup
11687 SET_INT_VECTOR(0x75, #0xF000, #int75_handler)
11688
11689 ;; Video setup
11690 SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
11691
11692#ifdef VBOX
11693 ;; moved the PIC initialization to another place as we need
11694 ;; some space for additions init calls. Otherwise this code
11695 ;; overlaps with the NMI handler at 0xe2c3 (fixed BIOS entry)
11696 call init_pic
11697#else /* !VBOX */
11698 ;; PIC
11699 mov al, #0x11 ; send initialisation commands
11700 out 0x20, al
11701 out 0xa0, al
11702 mov al, #0x08
11703 out 0x21, al
11704 mov al, #0x70
11705 out 0xa1, al
11706 mov al, #0x04
11707 out 0x21, al
11708 mov al, #0x02
11709 out 0xa1, al
11710 mov al, #0x01
11711 out 0x21, al
11712 out 0xa1, al
11713 mov al, #0xb8
11714 out 0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6
11715#if BX_USE_PS2_MOUSE
11716 mov al, #0x8f
11717#else
11718 mov al, #0x9f
11719#endif
11720 out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14
11721#endif /* !VBOX */
11722
11723#if BX_ROMBIOS32
11724 call rombios32_init
11725#else
11726 call pcibios_init_iomem_bases
11727 call pcibios_init_irqs
11728#endif
11729 call rom_scan
11730
11731#if BX_USE_ATADRV
11732 ;;
11733 ;; ATA/ATAPI driver setup
11734 ;;
11735 call _ata_init
11736 call _ata_detect
11737 ;;
11738#endif
11739
11740#ifdef VBOX_WITH_SCSI
11741 ;;
11742 ;; SCSI driver setup
11743 ;;
11744 call _scsi_init
11745 ;;
11746#endif
11747
11748 call _print_bios_banner
11749
11750 ;;
11751 ;; Floppy setup
11752 ;;
11753 call floppy_drive_post
11754
11755 ;;
11756 ;; Hard Drive setup
11757 ;;
11758 call hard_drive_post
11759
11760#ifdef VBOX_WITH_BIOS_AHCI
11761 ;;
11762 ;; AHCI driver setup
11763 ;;
11764 call _ahci_init
11765 ;;
11766#endif
11767
11768#if BX_ELTORITO_BOOT
11769 ;;
11770 ;; eltorito floppy/harddisk emulation from cd
11771 ;;
11772 call _cdemu_init
11773 ;;
11774#endif // BX_ELTORITO_BOOT
11775
11776 sti ;; enable interrupts
11777 int #0x19
11778
11779.org 0xe2c3 ; NMI Handler Entry Point
11780nmi:
11781 ;; FIXME the NMI handler should not panic
11782 ;; but iret when called from int75 (fpu exception)
11783 call _nmi_handler_msg
11784 iret
11785
11786int75_handler:
11787 out 0xf0, al // clear irq13
11788 call eoi_both_pics // clear interrupt
11789 int 2 // legacy nmi call
11790 iret
11791
11792;-------------------------------------------
11793;- INT 13h Fixed Disk Services Entry Point -
11794;-------------------------------------------
11795.org 0xe3fe ; INT 13h Fixed Disk Services Entry Point
11796int13_handler:
11797 //JMPL(int13_relocated)
11798 jmp int13_relocated
11799
11800.org 0xe401 ; Fixed Disk Parameter Table
11801
11802;----------
11803;- INT19h -
11804;----------
11805.org 0xe6f2 ; INT 19h Boot Load Service Entry Point
11806int19_handler:
11807
11808 jmp int19_relocated
11809;-------------------------------------------
11810;- System BIOS Configuration Data Table
11811;-------------------------------------------
11812.org BIOS_CONFIG_TABLE
11813db 0x08 ; Table size (bytes) -Lo
11814db 0x00 ; Table size (bytes) -Hi
11815db SYS_MODEL_ID
11816db SYS_SUBMODEL_ID
11817db BIOS_REVISION
11818; Feature byte 1
11819; b7: 1=DMA channel 3 used by hard disk
11820; b6: 1=2 interrupt controllers present
11821; b5: 1=RTC present
11822; b4: 1=BIOS calls int 15h/4Fh every key
11823; b3: 1=wait for extern event supported (Int 15h/41h)
11824; b2: 1=extended BIOS data area used
11825; b1: 0=AT or ESDI bus, 1=MicroChannel
11826; b0: 1=Dual bus (MicroChannel + ISA)
11827db (0 << 7) | \
11828 (1 << 6) | \
11829 (1 << 5) | \
11830 (BX_CALL_INT15_4F << 4) | \
11831 (0 << 3) | \
11832 (BX_USE_EBDA << 2) | \
11833 (0 << 1) | \
11834 (0 << 0)
11835; Feature byte 2
11836; b7: 1=32-bit DMA supported
11837; b6: 1=int16h, function 9 supported
11838; b5: 1=int15h/C6h (get POS data) supported
11839; b4: 1=int15h/C7h (get mem map info) supported
11840; b3: 1=int15h/C8h (en/dis CPU) supported
11841; b2: 1=non-8042 kb controller
11842; b1: 1=data streaming supported
11843; b0: reserved
11844db (0 << 7) | \
11845 (1 << 6) | \
11846 (0 << 5) | \
11847 (0 << 4) | \
11848 (0 << 3) | \
11849 (0 << 2) | \
11850 (0 << 1) | \
11851 (0 << 0)
11852; Feature byte 3
11853; b7: not used
11854; b6: reserved
11855; b5: reserved
11856; b4: POST supports ROM-to-RAM enable/disable
11857; b3: SCSI on system board
11858; b2: info panel installed
11859; b1: Initial Machine Load (IML) system - BIOS on disk
11860; b0: SCSI supported in IML
11861db 0x00
11862; Feature byte 4
11863; b7: IBM private
11864; b6: EEPROM present
11865; b5-3: ABIOS presence (011 = not supported)
11866; b2: private
11867; b1: memory split above 16Mb supported
11868; b0: POSTEXT directly supported by POST
11869db 0x00
11870; Feature byte 5 (IBM)
11871; b1: enhanced mouse
11872; b0: flash EPROM
11873db 0x00
11874
11875
11876
11877.org 0xe729 ; Baud Rate Generator Table
11878
11879;----------
11880;- INT14h -
11881;----------
11882.org 0xe739 ; INT 14h Serial Communications Service Entry Point
11883int14_handler:
11884 push ds
11885 pusha
11886 xor ax, ax
11887 mov ds, ax
11888 call _int14_function
11889 popa
11890 pop ds
11891 iret
11892
11893
11894;----------------------------------------
11895;- INT 16h Keyboard Service Entry Point -
11896;----------------------------------------
11897.org 0xe82e
11898int16_handler:
11899
11900 sti
11901 push ds
11902 pushf
11903 pusha
11904
11905 cmp ah, #0x00
11906 je int16_F00
11907 cmp ah, #0x10
11908 je int16_F00
11909
11910 mov bx, #0xf000
11911 mov ds, bx
11912 call _int16_function
11913 popa
11914 popf
11915 pop ds
11916 jz int16_zero_set
11917
11918int16_zero_clear:
11919 push bp
11920 mov bp, sp
11921 //SEG SS
11922 and BYTE [bp + 0x06], #0xbf
11923 pop bp
11924 iret
11925
11926int16_zero_set:
11927 push bp
11928 mov bp, sp
11929 //SEG SS
11930 or BYTE [bp + 0x06], #0x40
11931 pop bp
11932 iret
11933
11934int16_F00:
11935 mov bx, #0x0040
11936 mov ds, bx
11937
11938int16_wait_for_key:
11939 cli
11940 mov bx, 0x001a
11941 cmp bx, 0x001c
11942 jne int16_key_found
11943 sti
11944 nop
11945#if 0
11946 /* no key yet, call int 15h, function AX=9002 */
11947 0x50, /* push AX */
11948 0xb8, 0x02, 0x90, /* mov AX, #0x9002 */
11949 0xcd, 0x15, /* int 15h */
11950 0x58, /* pop AX */
11951 0xeb, 0xea, /* jmp WAIT_FOR_KEY */
11952#endif
11953 jmp int16_wait_for_key
11954
11955int16_key_found:
11956 mov bx, #0xf000
11957 mov ds, bx
11958 call _int16_function
11959 popa
11960 popf
11961 pop ds
11962#if 0
11963 /* notify int16 complete w/ int 15h, function AX=9102 */
11964 0x50, /* push AX */
11965 0xb8, 0x02, 0x91, /* mov AX, #0x9102 */
11966 0xcd, 0x15, /* int 15h */
11967 0x58, /* pop AX */
11968#endif
11969 iret
11970
11971
11972
11973;-------------------------------------------------
11974;- INT09h : Keyboard Hardware Service Entry Point -
11975;-------------------------------------------------
11976.org 0xe987
11977int09_handler:
11978 cli
11979 push ax
11980
11981 mov al, #0xAD ;;disable keyboard
11982 out #0x64, al
11983
11984 mov al, #0x0B
11985 out #0x20, al
11986 in al, #0x20
11987 and al, #0x02
11988 jz int09_finish
11989
11990 in al, #0x60 ;;read key from keyboard controller
11991 sti
11992 push ds
11993 pusha
11994#ifdef BX_CALL_INT15_4F
11995 mov ah, #0x4f ;; allow for keyboard intercept
11996 stc
11997 int #0x15
11998 jnc int09_done
11999#endif
12000
12001 ;; check for extended key
12002 cmp al, #0xe0
12003 jne int09_check_pause
12004 xor ax, ax
12005 mov ds, ax
12006 mov al, BYTE [0x496] ;; mf2_state |= 0x02
12007 or al, #0x02
12008 mov BYTE [0x496], al
12009 jmp int09_done
12010
12011int09_check_pause: ;; check for pause key
12012 cmp al, #0xe1
12013 jne int09_process_key
12014 xor ax, ax
12015 mov ds, ax
12016 mov al, BYTE [0x496] ;; mf2_state |= 0x01
12017 or al, #0x01
12018 mov BYTE [0x496], al
12019 jmp int09_done
12020
12021int09_process_key:
12022 mov bx, #0xf000
12023 mov ds, bx
12024 call _int09_function
12025
12026int09_done:
12027 popa
12028 pop ds
12029 cli
12030 call eoi_master_pic
12031
12032int09_finish:
12033 mov al, #0xAE ;;enable keyboard
12034 out #0x64, al
12035 pop ax
12036 iret
12037
12038
12039;----------------------------------------
12040;- INT 13h Diskette Service Entry Point -
12041;----------------------------------------
12042.org 0xec59
12043int13_diskette:
12044 jmp int13_noeltorito
12045
12046;---------------------------------------------
12047;- INT 0Eh Diskette Hardware ISR Entry Point -
12048;---------------------------------------------
12049.org 0xef57 ; INT 0Eh Diskette Hardware ISR Entry Point
12050int0e_handler:
12051 push ax
12052 push dx
12053 mov dx, #0x03f4
12054 in al, dx
12055 and al, #0xc0
12056 cmp al, #0xc0
12057 je int0e_normal
12058 mov dx, #0x03f5
12059 mov al, #0x08 ; sense interrupt status
12060 out dx, al
12061int0e_loop1:
12062 mov dx, #0x03f4
12063 in al, dx
12064 and al, #0xc0
12065 cmp al, #0xc0
12066 jne int0e_loop1
12067int0e_loop2:
12068 mov dx, #0x03f5
12069 in al, dx
12070 mov dx, #0x03f4
12071 in al, dx
12072 and al, #0xc0
12073 cmp al, #0xc0
12074 je int0e_loop2
12075int0e_normal:
12076 push ds
12077 xor ax, ax ;; segment 0000
12078 mov ds, ax
12079 call eoi_master_pic
12080 mov al, 0x043e
12081 or al, #0x80 ;; diskette interrupt has occurred
12082 mov 0x043e, al
12083 pop ds
12084 pop dx
12085 pop ax
12086 iret
12087
12088
12089.org 0xefc7 ; Diskette Controller Parameter Table
12090diskette_param_table:
12091;; Since no provisions are made for multiple drive types, most
12092;; values in this table are ignored. I set parameters for 1.44M
12093;; floppy here
12094db 0xAF
12095db 0x02 ;; head load time 0000001, DMA used
12096db 0x25
12097db 0x02
12098db 18
12099db 0x1B
12100db 0xFF
12101db 0x6C
12102db 0xF6
12103db 0x0F
12104db 0x08
12105
12106
12107;----------------------------------------
12108;- INT17h : Printer Service Entry Point -
12109;----------------------------------------
12110.org 0xefd2
12111int17_handler:
12112 push ds
12113 pusha
12114 xor ax, ax
12115 mov ds, ax
12116 call _int17_function
12117 popa
12118 pop ds
12119 iret
12120
12121diskette_param_table2:
12122;; New diskette parameter table adding 3 parameters from IBM
12123;; Since no provisions are made for multiple drive types, most
12124;; values in this table are ignored. I set parameters for 1.44M
12125;; floppy here
12126db 0xAF
12127db 0x02 ;; head load time 0000001, DMA used
12128db 0x25
12129db 0x02
12130db 18
12131db 0x1B
12132db 0xFF
12133db 0x6C
12134db 0xF6
12135db 0x0F
12136db 0x08
12137db 79 ;; maximum track
12138db 0 ;; data transfer rate
12139db 4 ;; drive type in cmos
12140
12141.org 0xf045 ; INT 10 Functions 0-Fh Entry Point
12142 HALT(__LINE__)
12143 iret
12144
12145;----------
12146;- INT10h -
12147;----------
12148.org 0xf065 ; INT 10h Video Support Service Entry Point
12149int10_handler:
12150 ;; dont do anything, since the VGA BIOS handles int10h requests
12151 iret
12152
12153.org 0xf0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
12154
12155;----------
12156;- INT12h -
12157;----------
12158.org 0xf841 ; INT 12h Memory Size Service Entry Point
12159; ??? different for Pentium (machine check)?
12160int12_handler:
12161 push ds
12162 mov ax, #0x0040
12163 mov ds, ax
12164 mov ax, 0x0013
12165 pop ds
12166 iret
12167
12168;----------
12169;- INT11h -
12170;----------
12171.org 0xf84d ; INT 11h Equipment List Service Entry Point
12172int11_handler:
12173 push ds
12174 mov ax, #0x0040
12175 mov ds, ax
12176 mov ax, 0x0010
12177 pop ds
12178 iret
12179
12180;----------
12181;- INT15h -
12182;----------
12183.org 0xf859 ; INT 15h System Services Entry Point
12184int15_handler:
12185 pushf
12186#if BX_APM
12187 cmp ah, #0x53
12188 je apm_call
12189#endif
12190 push ds
12191 push es
12192 cmp ah, #0x86
12193 je int15_handler32
12194 cmp ah, #0xE8
12195 je int15_handler32
12196 pusha
12197#if BX_USE_PS2_MOUSE
12198 cmp ah, #0xC2
12199 je int15_handler_mouse
12200#endif
12201 call _int15_function
12202int15_handler_mouse_ret:
12203 popa
12204int15_handler32_ret:
12205 pop es
12206 pop ds
12207 popf
12208 jmp iret_modify_cf
12209#if BX_APM
12210apm_call:
12211 jmp _apmreal_entry
12212#endif
12213
12214#if BX_USE_PS2_MOUSE
12215int15_handler_mouse:
12216 call _int15_function_mouse
12217 jmp int15_handler_mouse_ret
12218#endif
12219
12220int15_handler32:
12221 pushad
12222 call _int15_function32
12223 popad
12224 jmp int15_handler32_ret
12225
12226;; Protected mode IDT descriptor
12227;;
12228;; I just make the limit 0, so the machine will shutdown
12229;; if an exception occurs during protected mode memory
12230;; transfers.
12231;;
12232;; Set base to f0000 to correspond to beginning of BIOS,
12233;; in case I actually define an IDT later
12234;; Set limit to 0
12235
12236pmode_IDT_info:
12237dw 0x0000 ;; limit 15:00
12238dw 0x0000 ;; base 15:00
12239dw 0x0f ;; base 23:16
12240
12241;; Real mode IDT descriptor
12242;;
12243;; Set to typical real-mode values.
12244;; base = 000000
12245;; limit = 03ff
12246
12247rmode_IDT_info:
12248dw 0x03ff ;; limit 15:00
12249dw 0x0000 ;; base 15:00
12250dw 0x00 ;; base 23:16
12251
12252;;
12253;; Handler for unexpected hardware interrupts
12254;;
12255dummy_isr:
12256 push ds
12257 pushad
12258 xor ax, ax
12259 mov ds, ax
12260 call _dummy_isr_function
12261 popad
12262 pop ds
12263 iret
12264
12265;----------
12266;- INT1Ah -
12267;----------
12268.org 0xfe6e ; INT 1Ah Time-of-day Service Entry Point
12269int1a_handler:
12270#if BX_PCIBIOS
12271 cmp ah, #0xb1
12272 jne int1a_normal
12273 call pcibios_real
12274 jc pcibios_error
12275 jmp iret_modify_cf ; preserve old flags!
12276pcibios_error:
12277 mov bl, ah
12278 mov ah, #0xb1
12279 push ds
12280 pusha
12281 mov ax, ss ; set readable descriptor to ds, for calling pcibios
12282 mov ds, ax ; on 16bit protected mode.
12283 jmp int1a_callfunction
12284int1a_normal:
12285#endif
12286 push ds
12287 pusha
12288 xor ax, ax
12289 mov ds, ax
12290int1a_callfunction:
12291 call _int1a_function
12292 popa
12293 pop ds
12294 iret
12295
12296;;
12297;; int70h: IRQ8 - CMOS RTC
12298;;
12299int70_handler:
12300 push ds
12301 pushad
12302 xor ax, ax
12303 mov ds, ax
12304 call _int70_function
12305 popad
12306 pop ds
12307 iret
12308
12309;---------
12310;- INT08 -
12311;---------
12312.org 0xfea5 ; INT 08h System Timer ISR Entry Point
12313int08_handler:
12314 sti
12315 push eax
12316 push ds
12317 xor ax, ax
12318 mov ds, ax
12319
12320 ;; time to turn off drive(s)?
12321 mov al,0x0440
12322 or al,al
12323 jz int08_floppy_off
12324 dec al
12325 mov 0x0440,al
12326 jnz int08_floppy_off
12327 ;; turn motor(s) off
12328 push dx
12329 mov dx,#0x03f2
12330 in al,dx
12331 and al,#0xcf
12332 out dx,al
12333 pop dx
12334int08_floppy_off:
12335
12336 mov eax, 0x046c ;; get ticks dword
12337 inc eax
12338
12339 ;; compare eax to one days worth of timer ticks at 18.2 hz
12340 cmp eax, #0x001800B0
12341 jb int08_store_ticks
12342 ;; there has been a midnight rollover at this point
12343 xor eax, eax ;; zero out counter
12344 inc BYTE 0x0470 ;; increment rollover flag
12345
12346int08_store_ticks:
12347 mov 0x046c, eax ;; store new ticks dword
12348 ;; chain to user timer tick INT #0x1c
12349 //pushf
12350 //;; call_ep [ds:loc]
12351 //CALL_EP( 0x1c << 2 )
12352 int #0x1c
12353 cli
12354 call eoi_master_pic
12355 pop ds
12356 pop eax
12357 iret
12358
12359.org 0xfef3 ; Initial Interrupt Vector Offsets Loaded by POST
12360
12361
12362.org 0xff00
12363.ascii BIOS_COPYRIGHT_STRING
12364
12365#ifdef VBOX
12366// The SMBIOS header
12367.org 0xff30
12368.align 16
12369 db 0x5f, 0x53, 0x4d, 0x5f ; "_SM_" signature
12370 db 0x00 ; checksum (set by biossums)
12371 db 0x1f ; EPS length, defined by standard
12372 db VBOX_SMBIOS_MAJOR_VER ; SMBIOS major version
12373 db VBOX_SMBIOS_MINOR_VER ; SMBIOS minor version
12374 dw VBOX_SMBIOS_MAXSS ; Maximum structure size
12375 db 0x00 ; Entry point revision
12376 db 0x00, 0x00, 0x00, 0x00, 0x00
12377
12378// The DMI header
12379 db 0x5f, 0x44, 0x4d, 0x49, 0x5f ; "_DMI_" signature
12380 db 0x00 ; checksum (set by biossums)
12381 dw VBOX_DMI_TABLE_SIZE ; DMI tables length
12382 dd VBOX_DMI_TABLE_BASE ; DMI tables base
12383 dw VBOX_DMI_TABLE_ENTR ; DMI tables entries
12384 db VBOX_DMI_TABLE_VER ; DMI version
12385 db 0x00 ; Just for alignment
12386#endif
12387
12388;------------------------------------------------
12389;- IRET Instruction for Dummy Interrupt Handler -
12390;------------------------------------------------
12391.org 0xff53 ; IRET Instruction for Dummy Interrupt Handler
12392dummy_iret_handler:
12393 iret
12394
12395.org 0xff54 ; INT 05h Print Screen Service Entry Point
12396 HALT(__LINE__)
12397 iret
12398
12399.org 0xfff0 ; Power-up Entry Point
12400 jmp 0xf000:post
12401
12402.org 0xfff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
12403.ascii BIOS_BUILD_DATE
12404
12405.org 0xfffe ; System Model ID
12406db SYS_MODEL_ID
12407db 0x00 ; filler
12408
12409.org 0xfa6e ;; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
12410ASM_END
12411/*
12412 * This font comes from the fntcol16.zip package (c) by Joseph Gil
12413 * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
12414 * This font is public domain
12415 */
12416static Bit8u vgafont8[128*8]=
12417{
12418 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
12419 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
12420 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
12421 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
12422 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
12423 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
12424 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
12425 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
12426 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
12427 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
12428 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
12429 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
12430 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
12431 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
12432 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
12433 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
12434 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
12435 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
12436 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
12437 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
12438 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
12439 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
12440 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
12441 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
12442 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
12443 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
12444 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
12445 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
12446 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
12447 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
12448 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
12449 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
12450 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
12451 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
12452 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
12453 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
12454 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
12455 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
12456 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
12457 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
12458 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
12459 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
12460 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
12461 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
12462 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
12463 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
12464 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
12465 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
12466 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
12467 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
12468 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
12469 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
12470 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
12471 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
12472 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
12473 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
12474 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
12475 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
12476 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
12477 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
12478 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
12479 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
12480 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
12481 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
12482 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
12483 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
12484 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
12485 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
12486 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
12487 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
12488 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
12489 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
12490 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
12491 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
12492 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
12493 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
12494 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
12495 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
12496 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
12497 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
12498 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
12499 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
12500 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
12501 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
12502 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
12503 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
12504 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
12505 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
12506 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
12507 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
12508 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
12509 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
12510 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
12511 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
12512 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
12513 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
12514 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
12515 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
12516 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
12517 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
12518 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
12519 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
12520 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
12521 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
12522 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
12523 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
12524 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
12525 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
12526 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
12527 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
12528 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
12529 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
12530 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
12531 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
12532 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
12533 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
12534 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
12535 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
12536 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
12537 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
12538 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
12539 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
12540 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
12541 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
12542 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
12543 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
12544 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
12545 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
12546};
12547
12548ASM_START
12549.org 0xcc00
12550// bcc-generated data will be placed here
12551ASM_END
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use