VirtualBox

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

Last change on this file since 12649 was 12630, checked in by vboxsync, 16 years ago

SCSI: Add write support for the BIOS (Grub makes use of it if there is a savedefault command in the config)

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