VirtualBox

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

Last change on this file since 1531 was 1531, checked in by vboxsync, 18 years ago

Implemented INT15h, fn 0xC2 (mouse), subfn 3 - set resolution. MSD and Windows 3.x
setup no longer misdetect mouse as Logitech and properly report generic PS/2.

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

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