VirtualBox

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

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

BIOS: properly detect the ICH9 bridge (fixes PXE with ICH9)

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

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