VirtualBox

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

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

Clean up a few BIOS log/error messages.

  • Property svn:eol-style set to native
File size: 317.6 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#ifdef VBOX
3747 case 0x00: /* assorted functions */
3748 if (regs.u.r8.al != 0xc0)
3749 goto undecoded;
3750 /* GRUB calls int15 with ax=0x00c0 to get the ROM configuration table,
3751 * which we don't support, but logging that event is annoying. In fact
3752 * it is likely that they just misread some specs, because there is a
3753 * int15 BIOS function AH=0xc0 which sounds quite similar to what GRUB
3754 * wants to achieve. */
3755 SET_CF();
3756 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3757 break;
3758#endif
3759 case 0x24: /* A20 Control */
3760 switch (regs.u.r8.al) {
3761 case 0x00:
3762 set_enable_a20(0);
3763 CLEAR_CF();
3764 regs.u.r8.ah = 0;
3765 break;
3766 case 0x01:
3767 set_enable_a20(1);
3768 CLEAR_CF();
3769 regs.u.r8.ah = 0;
3770 break;
3771 case 0x02:
3772 regs.u.r8.al = (inb(0x92) >> 1) & 0x01;
3773 CLEAR_CF();
3774 regs.u.r8.ah = 0;
3775 break;
3776 case 0x03:
3777 CLEAR_CF();
3778 regs.u.r8.ah = 0;
3779 regs.u.r16.bx = 3;
3780 break;
3781 default:
3782 BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs.u.r8.al);
3783 SET_CF();
3784 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3785 }
3786 break;
3787
3788 case 0x41:
3789 SET_CF();
3790 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3791 break;
3792
3793 case 0x4f:
3794 /* keyboard intercept */
3795#if BX_CPU < 2
3796 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3797#else
3798 // nop
3799#endif
3800 SET_CF();
3801 break;
3802
3803 case 0x52: // removable media eject
3804 CLEAR_CF();
3805 regs.u.r8.ah = 0; // "ok ejection may proceed"
3806 break;
3807
3808 case 0x83: {
3809 if( regs.u.r8.al == 0 ) {
3810 // Set Interval requested.
3811 if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
3812 // Interval not already set.
3813 write_byte( 0x40, 0xA0, 1 ); // Set status byte.
3814 write_word( 0x40, 0x98, ES ); // Byte location, segment
3815 write_word( 0x40, 0x9A, regs.u.r16.bx ); // Byte location, offset
3816 write_word( 0x40, 0x9C, regs.u.r16.dx ); // Low word, delay
3817 write_word( 0x40, 0x9E, regs.u.r16.cx ); // High word, delay.
3818 CLEAR_CF( );
3819 irqDisable = inb( 0xA1 );
3820 outb( 0xA1, irqDisable & 0xFE );
3821 bRegister = inb_cmos( 0xB ); // Unmask IRQ8 so INT70 will get through.
3822 outb_cmos( 0xB, bRegister | 0x40 ); // Turn on the Periodic Interrupt timer
3823 } else {
3824 // Interval already set.
3825 BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
3826 SET_CF();
3827 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3828 }
3829 } else if( regs.u.r8.al == 1 ) {
3830 // Clear Interval requested
3831 write_byte( 0x40, 0xA0, 0 ); // Clear status byte
3832 CLEAR_CF( );
3833 bRegister = inb_cmos( 0xB );
3834 outb_cmos( 0xB, bRegister & ~0x40 ); // Turn off the Periodic Interrupt timer
3835 } else {
3836 BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
3837 SET_CF();
3838 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3839 regs.u.r8.al--;
3840 }
3841
3842 break;
3843 }
3844
3845 case 0x87:
3846#if BX_CPU < 3
3847# error "Int15 function 87h not supported on < 80386"
3848#endif
3849 // +++ should probably have descriptor checks
3850 // +++ should have exception handlers
3851
3852 // turn off interrupts
3853ASM_START
3854 cli
3855ASM_END
3856
3857 prev_a20_enable = set_enable_a20(1); // enable A20 line
3858
3859 // 128K max of transfer on 386+ ???
3860 // source == destination ???
3861
3862 // ES:SI points to descriptor table
3863 // offset use initially comments
3864 // ==============================================
3865 // 00..07 Unused zeros Null descriptor
3866 // 08..0f GDT zeros filled in by BIOS
3867 // 10..17 source ssssssss source of data
3868 // 18..1f dest dddddddd destination of data
3869 // 20..27 CS zeros filled in by BIOS
3870 // 28..2f SS zeros filled in by BIOS
3871
3872 //es:si
3873 //eeee0
3874 //0ssss
3875 //-----
3876
3877// check for access rights of source & dest here
3878
3879 // Initialize GDT descriptor
3880 base15_00 = (ES << 4) + regs.u.r16.si;
3881 base23_16 = ES >> 12;
3882 if (base15_00 < (ES<<4))
3883 base23_16++;
3884 write_word(ES, regs.u.r16.si+0x08+0, 47); // limit 15:00 = 6 * 8bytes/descriptor
3885 write_word(ES, regs.u.r16.si+0x08+2, base15_00);// base 15:00
3886 write_byte(ES, regs.u.r16.si+0x08+4, base23_16);// base 23:16
3887 write_byte(ES, regs.u.r16.si+0x08+5, 0x93); // access
3888 write_word(ES, regs.u.r16.si+0x08+6, 0x0000); // base 31:24/reserved/limit 19:16
3889
3890 // Initialize CS descriptor
3891 write_word(ES, regs.u.r16.si+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
3892 write_word(ES, regs.u.r16.si+0x20+2, 0x0000);// base 15:00
3893 write_byte(ES, regs.u.r16.si+0x20+4, 0x000f);// base 23:16
3894 write_byte(ES, regs.u.r16.si+0x20+5, 0x9b); // access
3895 write_word(ES, regs.u.r16.si+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
3896
3897 // Initialize SS descriptor
3898 ss = get_SS();
3899 base15_00 = ss << 4;
3900 base23_16 = ss >> 12;
3901 write_word(ES, regs.u.r16.si+0x28+0, 0xffff); // limit 15:00 = normal 64K limit
3902 write_word(ES, regs.u.r16.si+0x28+2, base15_00);// base 15:00
3903 write_byte(ES, regs.u.r16.si+0x28+4, base23_16);// base 23:16
3904 write_byte(ES, regs.u.r16.si+0x28+5, 0x93); // access
3905 write_word(ES, regs.u.r16.si+0x28+6, 0x0000); // base 31:24/reserved/limit 19:16
3906
3907 CX = regs.u.r16.cx;
3908ASM_START
3909 // Compile generates locals offset info relative to SP.
3910 // Get CX (word count) from stack.
3911 mov bx, sp
3912 SEG SS
3913 mov cx, _int15_function.CX [bx]
3914
3915 // since we need to set SS:SP, save them to the BDA
3916 // for future restore
3917 push eax
3918 xor eax, eax
3919 mov ds, ax
3920 mov 0x0469, ss
3921 mov 0x0467, sp
3922
3923 SEG ES
3924 lgdt [si + 0x08]
3925 SEG CS
3926 lidt [pmode_IDT_info]
3927 ;; perhaps do something with IDT here
3928
3929 ;; set PE bit in CR0
3930 mov eax, cr0
3931 or al, #0x01
3932 mov cr0, eax
3933 ;; far jump to flush CPU queue after transition to protected mode
3934 JMP_AP(0x0020, protected_mode)
3935
3936protected_mode:
3937 ;; GDT points to valid descriptor table, now load SS, DS, ES
3938 mov ax, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
3939 mov ss, ax
3940 mov ax, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
3941 mov ds, ax
3942 mov ax, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
3943 mov es, ax
3944 xor si, si
3945 xor di, di
3946 cld
3947 rep
3948 movsw ;; move CX words from DS:SI to ES:DI
3949
3950 ;; make sure DS and ES limits are 64KB
3951 mov ax, #0x28
3952 mov ds, ax
3953 mov es, ax
3954
3955 ;; reset PG bit in CR0 ???
3956 mov eax, cr0
3957 and al, #0xFE
3958 mov cr0, eax
3959
3960 ;; far jump to flush CPU queue after transition to real mode
3961 JMP_AP(0xf000, real_mode)
3962
3963real_mode:
3964 ;; restore IDT to normal real-mode defaults
3965 SEG CS
3966 lidt [rmode_IDT_info]
3967
3968 // restore SS:SP from the BDA
3969 xor ax, ax
3970 mov ds, ax
3971 mov ss, 0x0469
3972 mov sp, 0x0467
3973 pop eax
3974ASM_END
3975
3976 set_enable_a20(prev_a20_enable);
3977
3978 // turn back on interrupts
3979ASM_START
3980 sti
3981ASM_END
3982
3983 regs.u.r8.ah = 0;
3984 CLEAR_CF();
3985 break;
3986
3987
3988 case 0x88:
3989 // Get the amount of extended memory (above 1M)
3990#if BX_CPU < 2
3991 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3992 SET_CF();
3993#else
3994 regs.u.r8.al = inb_cmos(0x30);
3995 regs.u.r8.ah = inb_cmos(0x31);
3996
3997 // According to Ralf Brown's interrupt the limit should be 15M,
3998 // but real machines mostly return max. 63M.
3999 if(regs.u.r16.ax > 0xffc0)
4000 regs.u.r16.ax = 0xffc0;
4001
4002 CLEAR_CF();
4003#endif
4004 break;
4005
4006 case 0x90:
4007 /* Device busy interrupt. Called by Int 16h when no key available */
4008 break;
4009
4010 case 0x91:
4011 /* Interrupt complete. Called by Int 16h when key becomes available */
4012 break;
4013
4014 case 0xbf:
4015 BX_INFO("*** int 15h function AH=bf not yet supported!\n");
4016 SET_CF();
4017 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4018 break;
4019
4020 case 0xC0:
4021#if 0
4022 SET_CF();
4023 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4024 break;
4025#endif
4026 CLEAR_CF();
4027 regs.u.r8.ah = 0;
4028 regs.u.r16.bx = BIOS_CONFIG_TABLE;
4029 ES = 0xF000;
4030 break;
4031
4032 case 0xc1:
4033 ES = ebda_seg;
4034 CLEAR_CF();
4035 break;
4036
4037 case 0xd8:
4038 bios_printf(BIOS_PRINTF_DEBUG, "EISA BIOS not present\n");
4039 SET_CF();
4040 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4041 break;
4042
4043#ifdef VBOX
4044 /* Make the BIOS warning for pretty much every Linux kernel start
4045 * disappear - it calls with ax=0xe980 to figure out SMI info. */
4046 case 0xe9: /* SMI functions (SpeedStep and similar things) */
4047 SET_CF();
4048 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4049 break;
4050undecoded:
4051#endif /* VBOX */
4052 default:
4053 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4054 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4055 SET_CF();
4056 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4057 break;
4058 }
4059}
4060
4061#if BX_USE_PS2_MOUSE
4062 void
4063int15_function_mouse(regs, ES, DS, FLAGS)
4064 pusha_regs_t regs; // REGS pushed via pusha
4065 Bit16u ES, DS, FLAGS;
4066{
4067 Bit16u ebda_seg=read_word(0x0040,0x000E);
4068 Bit8u mouse_flags_1, mouse_flags_2;
4069 Bit16u mouse_driver_seg;
4070 Bit16u mouse_driver_offset;
4071 Bit8u comm_byte, prev_command_byte;
4072 Bit8u ret, mouse_data1, mouse_data2, mouse_data3;
4073
4074BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4075
4076 switch (regs.u.r8.ah) {
4077 case 0xC2:
4078 // Return Codes status in AH
4079 // =========================
4080 // 00: success
4081 // 01: invalid subfunction (AL > 7)
4082 // 02: invalid input value (out of allowable range)
4083 // 03: interface error
4084 // 04: resend command received from mouse controller,
4085 // device driver should attempt command again
4086 // 05: cannot enable mouse, since no far call has been installed
4087 // 80/86: mouse service not implemented
4088
4089 switch (regs.u.r8.al) {
4090 case 0: // Disable/Enable Mouse
4091BX_DEBUG_INT15("case 0:\n");
4092 switch (regs.u.r8.bh) {
4093 case 0: // Disable Mouse
4094BX_DEBUG_INT15("case 0: disable mouse\n");
4095 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4096 ret = send_to_mouse_ctrl(0xF5); // disable mouse command
4097 if (ret == 0) {
4098 ret = get_mouse_data(&mouse_data1);
4099 if ( (ret == 0) || (mouse_data1 == 0xFA) ) {
4100 CLEAR_CF();
4101 regs.u.r8.ah = 0;
4102 return;
4103 }
4104 }
4105
4106 // error
4107 SET_CF();
4108 regs.u.r8.ah = ret;
4109 return;
4110 break;
4111
4112 case 1: // Enable Mouse
4113BX_DEBUG_INT15("case 1: enable mouse\n");
4114 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4115 if ( (mouse_flags_2 & 0x80) == 0 ) {
4116 BX_DEBUG_INT15("INT 15h C2 Enable Mouse, no far call handler\n");
4117 SET_CF(); // error
4118 regs.u.r8.ah = 5; // no far call installed
4119 return;
4120 }
4121 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4122 ret = send_to_mouse_ctrl(0xF4); // enable mouse command
4123 if (ret == 0) {
4124 ret = get_mouse_data(&mouse_data1);
4125 if ( (ret == 0) && (mouse_data1 == 0xFA) ) {
4126 enable_mouse_int_and_events(); // turn IRQ12 and packet generation on
4127 CLEAR_CF();
4128 regs.u.r8.ah = 0;
4129 return;
4130 }
4131 }
4132 SET_CF();
4133 regs.u.r8.ah = ret;
4134 return;
4135
4136 default: // invalid subfunction
4137 BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs.u.r8.bh);
4138 SET_CF(); // error
4139 regs.u.r8.ah = 1; // invalid subfunction
4140 return;
4141 }
4142 break;
4143
4144 case 1: // Reset Mouse
4145 case 5: // Initialize Mouse
4146BX_DEBUG_INT15("case 1 or 5:\n");
4147 if (regs.u.r8.al == 5) {
4148 if (regs.u.r8.bh != 3) {
4149 SET_CF();
4150 regs.u.r8.ah = 0x02; // invalid input
4151 return;
4152 }
4153#ifndef VBOX
4154 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4155 mouse_flags_2 = (mouse_flags_2 & 0x00) | regs.u.r8.bh;
4156 mouse_flags_1 = 0x00;
4157 write_byte(ebda_seg, 0x0026, mouse_flags_1);
4158 write_byte(ebda_seg, 0x0027, mouse_flags_2);
4159#endif /* !VBOX */
4160 }
4161
4162 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4163#ifdef VBOX
4164 /* Moved here to eliminate the race with the IRQ12 handler
4165 * concurrently accessing the EBDA values. It also makes no
4166 * sense to reset the mouse and leave the mouse flags as is. */
4167 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4168 if (regs.u.r8.al == 5)
4169 mouse_flags_2 = (mouse_flags_2 & 0x00) | regs.u.r8.bh;
4170 mouse_flags_1 = 0x00;
4171 write_byte(ebda_seg, 0x0026, mouse_flags_1);
4172 write_byte(ebda_seg, 0x0027, mouse_flags_2);
4173#endif /* VBOX */
4174 ret = send_to_mouse_ctrl(0xFF); // reset mouse command
4175 if (ret == 0) {
4176 ret = get_mouse_data(&mouse_data3);
4177 // if no mouse attached, it will return RESEND
4178 if (mouse_data3 == 0xfe) {
4179 SET_CF();
4180 return;
4181 }
4182 if (mouse_data3 != 0xfa)
4183 BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3);
4184 if ( ret == 0 ) {
4185 ret = get_mouse_data(&mouse_data1);
4186 if ( ret == 0 ) {
4187 ret = get_mouse_data(&mouse_data2);
4188 if ( ret == 0 ) {
4189 // turn IRQ12 and packet generation on
4190 enable_mouse_int_and_events();
4191 CLEAR_CF();
4192 regs.u.r8.ah = 0;
4193 regs.u.r8.bl = mouse_data1;
4194 regs.u.r8.bh = mouse_data2;
4195 return;
4196 }
4197 }
4198 }
4199 }
4200
4201 // error
4202 SET_CF();
4203 regs.u.r8.ah = ret;
4204 return;
4205
4206 case 2: // Set Sample Rate
4207BX_DEBUG_INT15("case 2:\n");
4208 switch (regs.u.r8.bh) {
4209 case 0: mouse_data1 = 10; break; // 10 reports/sec
4210 case 1: mouse_data1 = 20; break; // 20 reports/sec
4211 case 2: mouse_data1 = 40; break; // 40 reports/sec
4212 case 3: mouse_data1 = 60; break; // 60 reports/sec
4213 case 4: mouse_data1 = 80; break; // 80 reports/sec
4214 case 5: mouse_data1 = 100; break; // 100 reports/sec (default)
4215 case 6: mouse_data1 = 200; break; // 200 reports/sec
4216 default: mouse_data1 = 0;
4217 }
4218#ifdef VBOX
4219 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4220#endif /* VBOX */
4221 if (mouse_data1 > 0) {
4222 ret = send_to_mouse_ctrl(0xF3); // set sample rate command
4223 if (ret == 0) {
4224 ret = get_mouse_data(&mouse_data2);
4225 ret = send_to_mouse_ctrl(mouse_data1);
4226 ret = get_mouse_data(&mouse_data2);
4227 CLEAR_CF();
4228 regs.u.r8.ah = 0;
4229 } else {
4230 // error
4231 SET_CF();
4232 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4233 }
4234 } else {
4235 // error
4236 SET_CF();
4237 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4238 }
4239#ifdef VBOX
4240 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
4241#endif /* VBOX */
4242 break;
4243
4244 case 3: // Set Resolution
4245BX_DEBUG_INT15("case 3:\n");
4246 // BX:
4247 // 0 = 25 dpi, 1 count per millimeter
4248 // 1 = 50 dpi, 2 counts per millimeter
4249 // 2 = 100 dpi, 4 counts per millimeter
4250 // 3 = 200 dpi, 8 counts per millimeter
4251#ifdef VBOX
4252 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4253 if (regs.u.r8.bh < 4) {
4254 ret = send_to_mouse_ctrl(0xE8); // set resolution command
4255 if (ret == 0) {
4256 ret = get_mouse_data(&mouse_data1);
4257 if (mouse_data1 != 0xfa)
4258 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4259 ret = send_to_mouse_ctrl(regs.u.r8.bh);
4260 ret = get_mouse_data(&mouse_data1);
4261 if (mouse_data1 != 0xfa)
4262 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4263 CLEAR_CF();
4264 regs.u.r8.ah = 0;
4265 } else {
4266 // error
4267 SET_CF();
4268 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4269 }
4270 } else {
4271 // error
4272 SET_CF();
4273 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4274 }
4275 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
4276#else
4277 CLEAR_CF();
4278 regs.u.r8.ah = 0;
4279#endif /* VBOX */
4280 break;
4281
4282 case 4: // Get Device ID
4283BX_DEBUG_INT15("case 4:\n");
4284#ifdef VBOX
4285 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4286#else /* !VBOX */
4287 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4288#endif /* !VBOX */
4289 ret = send_to_mouse_ctrl(0xF2); // get mouse ID command
4290 if (ret == 0) {
4291 ret = get_mouse_data(&mouse_data1);
4292 ret = get_mouse_data(&mouse_data2);
4293 CLEAR_CF();
4294 regs.u.r8.ah = 0;
4295 regs.u.r8.bh = mouse_data2;
4296 } else {
4297 // error
4298 SET_CF();
4299 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4300 }
4301#ifdef VBOX
4302 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
4303#endif /* VBOX */
4304 break;
4305
4306 case 6: // Return Status & Set Scaling Factor...
4307BX_DEBUG_INT15("case 6:\n");
4308 switch (regs.u.r8.bh) {
4309 case 0: // Return Status
4310 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4311 ret = send_to_mouse_ctrl(0xE9); // get mouse info command
4312 if (ret == 0) {
4313 ret = get_mouse_data(&mouse_data1);
4314 if (mouse_data1 != 0xfa)
4315 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4316 if (ret == 0) {
4317 ret = get_mouse_data(&mouse_data1);
4318 if ( ret == 0 ) {
4319 ret = get_mouse_data(&mouse_data2);
4320 if ( ret == 0 ) {
4321 ret = get_mouse_data(&mouse_data3);
4322 if ( ret == 0 ) {
4323 CLEAR_CF();
4324 regs.u.r8.ah = 0;
4325 regs.u.r8.bl = mouse_data1;
4326 regs.u.r8.cl = mouse_data2;
4327 regs.u.r8.dl = mouse_data3;
4328 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
4329 return;
4330 }
4331 }
4332 }
4333 }
4334 }
4335
4336 // error
4337 SET_CF();
4338 regs.u.r8.ah = ret;
4339 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
4340 return;
4341
4342 case 1: // Set Scaling Factor to 1:1
4343 case 2: // Set Scaling Factor to 2:1
4344 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4345 if (regs.u.r8.bh == 1) {
4346 ret = send_to_mouse_ctrl(0xE6);
4347 } else {
4348 ret = send_to_mouse_ctrl(0xE7);
4349 }
4350 if (ret == 0) {
4351 get_mouse_data(&mouse_data1);
4352 ret = (mouse_data1 != 0xFA);
4353 }
4354 if (ret == 0) {
4355 CLEAR_CF();
4356 regs.u.r8.ah = 0;
4357 } else {
4358 // error
4359 SET_CF();
4360 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4361 }
4362 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
4363 break;
4364
4365 default:
4366 BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs.u.r8.bh);
4367 }
4368 break;
4369
4370 case 7: // Set Mouse Handler Address
4371BX_DEBUG_INT15("case 7:\n");
4372 mouse_driver_seg = ES;
4373 mouse_driver_offset = regs.u.r16.bx;
4374 write_word(ebda_seg, 0x0022, mouse_driver_offset);
4375 write_word(ebda_seg, 0x0024, mouse_driver_seg);
4376 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4377 if (mouse_driver_offset == 0 && mouse_driver_seg == 0) {
4378 /* remove handler */
4379 if ( (mouse_flags_2 & 0x80) != 0 ) {
4380 mouse_flags_2 &= ~0x80;
4381 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4382 }
4383 }
4384 else {
4385 /* install handler */
4386 mouse_flags_2 |= 0x80;
4387 }
4388 write_byte(ebda_seg, 0x0027, mouse_flags_2);
4389 CLEAR_CF();
4390 regs.u.r8.ah = 0;
4391 break;
4392
4393 default:
4394BX_DEBUG_INT15("case default:\n");
4395 regs.u.r8.ah = 1; // invalid function
4396 SET_CF();
4397 }
4398 break;
4399
4400 default:
4401 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4402 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4403 SET_CF();
4404 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4405 break;
4406 }
4407}
4408#endif
4409
4410
4411void set_e820_range(ES, DI, start, end, type)
4412 Bit16u ES;
4413 Bit16u DI;
4414 Bit32u start;
4415 Bit32u end;
4416 Bit16u type;
4417{
4418 write_word(ES, DI, start);
4419 write_word(ES, DI+2, start >> 16);
4420 write_word(ES, DI+4, 0x00);
4421 write_word(ES, DI+6, 0x00);
4422
4423 end -= start;
4424 write_word(ES, DI+8, end);
4425 write_word(ES, DI+10, end >> 16);
4426#ifdef VBOX
4427 if (end == 0)
4428 write_word(ES, DI+12, 0x0001);
4429 else
4430 write_word(ES, DI+12, 0x0000);
4431#else /* !VBOX */
4432 write_word(ES, DI+12, 0x0000);
4433#endif /* !VBOX */
4434 write_word(ES, DI+14, 0x0000);
4435
4436 write_word(ES, DI+16, type);
4437 write_word(ES, DI+18, 0x0);
4438}
4439
4440 void
4441int15_function32(regs, ES, DS, FLAGS)
4442 pushad_regs_t regs; // REGS pushed via pushad
4443 Bit16u ES, DS, FLAGS;
4444{
4445 Bit32u extended_memory_size=0; // 64bits long
4446 Bit16u CX,DX;
4447
4448BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4449
4450 switch (regs.u.r8.ah) {
4451 case 0x86:
4452 // Wait for CX:DX microseconds. currently using the
4453 // refresh request port 0x61 bit4, toggling every 15usec
4454
4455 CX = regs.u.r16.cx;
4456 DX = regs.u.r16.dx;
4457
4458ASM_START
4459 sti
4460
4461 ;; Get the count in eax
4462 mov bx, sp
4463 SEG SS
4464 mov ax, _int15_function.CX [bx]
4465 shl eax, #16
4466 SEG SS
4467 mov ax, _int15_function.DX [bx]
4468
4469 ;; convert to numbers of 15usec ticks
4470 mov ebx, #15
4471 xor edx, edx
4472 div eax, ebx
4473 mov ecx, eax
4474
4475 ;; wait for ecx number of refresh requests
4476 in al, #0x61
4477 and al,#0x10
4478 mov ah, al
4479
4480 or ecx, ecx
4481 je int1586_tick_end
4482int1586_tick:
4483 in al, #0x61
4484 and al,#0x10
4485 cmp al, ah
4486 je int1586_tick
4487 mov ah, al
4488 dec ecx
4489 jnz int1586_tick
4490int1586_tick_end:
4491ASM_END
4492
4493 break;
4494
4495 case 0xe8:
4496 switch(regs.u.r8.al)
4497 {
4498 case 0x20: // coded by osmaker aka K.J.
4499 if(regs.u.r32.edx == 0x534D4150)
4500 {
4501 extended_memory_size = inb_cmos(0x35);
4502 extended_memory_size <<= 8;
4503 extended_memory_size |= inb_cmos(0x34);
4504 extended_memory_size *= 64;
4505 // greater than EFF00000???
4506 if(extended_memory_size > 0x3bc000) {
4507 extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4508 }
4509 extended_memory_size *= 1024;
4510 extended_memory_size += (16L * 1024 * 1024);
4511
4512 if(extended_memory_size <= (16L * 1024 * 1024)) {
4513 extended_memory_size = inb_cmos(0x31);
4514 extended_memory_size <<= 8;
4515 extended_memory_size |= inb_cmos(0x30);
4516 extended_memory_size *= 1024;
4517 }
4518
4519 switch(regs.u.r16.bx)
4520 {
4521 case 0:
4522 set_e820_range(ES, regs.u.r16.di,
4523 0x0000000L, 0x0009fc00L, 1);
4524 regs.u.r32.ebx = 1;
4525 regs.u.r32.eax = 0x534D4150;
4526 regs.u.r32.ecx = 0x14;
4527 CLEAR_CF();
4528 return;
4529 break;
4530 case 1:
4531 set_e820_range(ES, regs.u.r16.di,
4532 0x0009fc00L, 0x000a0000L, 2);
4533 regs.u.r32.ebx = 2;
4534 regs.u.r32.eax = 0x534D4150;
4535 regs.u.r32.ecx = 0x14;
4536 CLEAR_CF();
4537 return;
4538 break;
4539 case 2:
4540#ifdef VBOX
4541 /* Mark the BIOS as reserved. VBox doesn't currently
4542 * use the 0xe0000-0xeffff area. It does use the
4543 * 0xd0000-0xdffff area for the BIOS logo, but it's
4544 * not worth marking it as reserved. Note that various
4545 * Windows versions don't accept (read: in debug builds
4546 * they trigger the "Too many similar traps" assertion)
4547 * a single reserved range from 0xd0000 to 0xffffff.
4548 * A 128K area starting from 0xd0000 works. */
4549 set_e820_range(ES, regs.u.r16.di,
4550 0x000f0000L, 0x00100000L, 2);
4551#else /* !VBOX */
4552 set_e820_range(ES, regs.u.r16.di,
4553 0x000e8000L, 0x00100000L, 2);
4554#endif /* !VBOX */
4555 regs.u.r32.ebx = 3;
4556 regs.u.r32.eax = 0x534D4150;
4557 regs.u.r32.ecx = 0x14;
4558 CLEAR_CF();
4559 return;
4560 break;
4561 case 3:
4562 set_e820_range(ES, regs.u.r16.di,
4563 0x00100000L,
4564 extended_memory_size - ACPI_DATA_SIZE, 1);
4565 regs.u.r32.ebx = 4;
4566 regs.u.r32.eax = 0x534D4150;
4567 regs.u.r32.ecx = 0x14;
4568 CLEAR_CF();
4569 return;
4570 break;
4571 case 4:
4572 set_e820_range(ES, regs.u.r16.di,
4573 extended_memory_size - ACPI_DATA_SIZE,
4574 extended_memory_size, 3); // ACPI RAM
4575 regs.u.r32.ebx = 5;
4576 regs.u.r32.eax = 0x534D4150;
4577 regs.u.r32.ecx = 0x14;
4578 CLEAR_CF();
4579 return;
4580 break;
4581 case 5:
4582 /* 256KB BIOS area at the end of 4 GB */
4583 set_e820_range(ES, regs.u.r16.di,
4584 0xfffc0000L, 0x00000000L, 2);
4585 regs.u.r32.ebx = 0;
4586 regs.u.r32.eax = 0x534D4150;
4587 regs.u.r32.ecx = 0x14;
4588 CLEAR_CF();
4589 return;
4590 default: /* AX=E820, DX=534D4150, BX unrecognized */
4591 goto int15_unimplemented;
4592 break;
4593 }
4594 } else {
4595 // if DX != 0x534D4150)
4596 goto int15_unimplemented;
4597 }
4598 break;
4599
4600 case 0x01:
4601 // do we have any reason to fail here ?
4602 CLEAR_CF();
4603
4604 // my real system sets ax and bx to 0
4605 // this is confirmed by Ralph Brown list
4606 // but syslinux v1.48 is known to behave
4607 // strangely if ax is set to 0
4608 // regs.u.r16.ax = 0;
4609 // regs.u.r16.bx = 0;
4610
4611 // Get the amount of extended memory (above 1M)
4612 regs.u.r8.cl = inb_cmos(0x30);
4613 regs.u.r8.ch = inb_cmos(0x31);
4614
4615 // limit to 15M
4616 if(regs.u.r16.cx > 0x3c00)
4617 {
4618 regs.u.r16.cx = 0x3c00;
4619 }
4620
4621 // Get the amount of extended memory above 16M in 64k blocs
4622 regs.u.r8.dl = inb_cmos(0x34);
4623 regs.u.r8.dh = inb_cmos(0x35);
4624
4625 // Set configured memory equal to extended memory
4626 regs.u.r16.ax = regs.u.r16.cx;
4627 regs.u.r16.bx = regs.u.r16.dx;
4628 break;
4629 default: /* AH=0xE8?? but not implemented */
4630 goto int15_unimplemented;
4631 }
4632 break;
4633 int15_unimplemented:
4634 // fall into the default
4635 default:
4636 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4637 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4638 SET_CF();
4639 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4640 break;
4641 }
4642}
4643
4644 void
4645int16_function(DI, SI, BP, SP, BX, DX, CX, AX, FLAGS)
4646 Bit16u DI, SI, BP, SP, BX, DX, CX, AX, FLAGS;
4647{
4648 Bit8u scan_code, ascii_code, shift_flags, led_flags, count;
4649 Bit16u kbd_code, max;
4650
4651 BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX, BX, CX, DX);
4652
4653 shift_flags = read_byte(0x0040, 0x17);
4654 led_flags = read_byte(0x0040, 0x97);
4655 if ((((shift_flags >> 4) & 0x07) ^ (led_flags & 0x07)) != 0) {
4656ASM_START
4657 cli
4658ASM_END
4659 outb(0x60, 0xed);
4660 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
4661 if ((inb(0x60) == 0xfa)) {
4662 led_flags &= 0xf8;
4663 led_flags |= ((shift_flags >> 4) & 0x07);
4664 outb(0x60, led_flags & 0x07);
4665 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
4666 inb(0x60);
4667 write_byte(0x0040, 0x97, led_flags);
4668 }
4669ASM_START
4670 sti
4671ASM_END
4672 }
4673
4674 switch (GET_AH()) {
4675 case 0x00: /* read keyboard input */
4676
4677 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4678 BX_PANIC("KBD: int16h: out of keyboard input\n");
4679 }
4680 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4681 else if (ascii_code == 0xE0) ascii_code = 0;
4682 AX = (scan_code << 8) | ascii_code;
4683 break;
4684
4685 case 0x01: /* check keyboard status */
4686 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4687 SET_ZF();
4688 return;
4689 }
4690 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4691 else if (ascii_code == 0xE0) ascii_code = 0;
4692 AX = (scan_code << 8) | ascii_code;
4693 CLEAR_ZF();
4694 break;
4695
4696 case 0x02: /* get shift flag status */
4697 shift_flags = read_byte(0x0040, 0x17);
4698 SET_AL(shift_flags);
4699 break;
4700
4701 case 0x05: /* store key-stroke into buffer */
4702 if ( !enqueue_key(GET_CH(), GET_CL()) ) {
4703 SET_AL(1);
4704 }
4705 else {
4706 SET_AL(0);
4707 }
4708 break;
4709
4710 case 0x09: /* GET KEYBOARD FUNCTIONALITY */
4711 // bit Bochs Description
4712 // 7 0 reserved
4713 // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
4714 // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
4715 // 4 1 INT 16/AH=0Ah supported
4716 // 3 0 INT 16/AX=0306h supported
4717 // 2 0 INT 16/AX=0305h supported
4718 // 1 0 INT 16/AX=0304h supported
4719 // 0 0 INT 16/AX=0300h supported
4720 //
4721 SET_AL(0x30);
4722 break;
4723
4724 case 0x0A: /* GET KEYBOARD ID */
4725 count = 2;
4726 kbd_code = 0x0;
4727 outb(0x60, 0xf2);
4728 /* Wait for data */
4729 max=0xffff;
4730 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4731 if (max>0x0) {
4732 if ((inb(0x60) == 0xfa)) {
4733 do {
4734 max=0xffff;
4735 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4736 if (max>0x0) {
4737 kbd_code >>= 8;
4738 kbd_code |= (inb(0x60) << 8);
4739 }
4740 } while (--count>0);
4741 }
4742 }
4743 BX=kbd_code;
4744 break;
4745
4746 case 0x10: /* read MF-II keyboard input */
4747
4748 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4749 BX_PANIC("KBD: int16h: out of keyboard input\n");
4750 }
4751 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4752 AX = (scan_code << 8) | ascii_code;
4753 break;
4754
4755 case 0x11: /* check MF-II keyboard status */
4756 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4757 SET_ZF();
4758 return;
4759 }
4760 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4761 AX = (scan_code << 8) | ascii_code;
4762 CLEAR_ZF();
4763 break;
4764
4765 case 0x12: /* get extended keyboard status */
4766 shift_flags = read_byte(0x0040, 0x17);
4767 SET_AL(shift_flags);
4768 shift_flags = read_byte(0x0040, 0x18) & 0x73;
4769 shift_flags |= read_byte(0x0040, 0x96) & 0x0c;
4770 SET_AH(shift_flags);
4771 BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX);
4772 break;
4773
4774 case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
4775 SET_AH(0x80); // function int16 ah=0x10-0x12 supported
4776 break;
4777
4778 case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
4779 // don't change AH : function int16 ah=0x20-0x22 NOT supported
4780 break;
4781
4782 case 0x6F:
4783 if (GET_AL() == 0x08)
4784 SET_AH(0x02); // unsupported, aka normal keyboard
4785
4786 default:
4787 BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
4788 }
4789}
4790
4791 unsigned int
4792dequeue_key(scan_code, ascii_code, incr)
4793 Bit8u *scan_code;
4794 Bit8u *ascii_code;
4795 unsigned int incr;
4796{
4797 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail;
4798 Bit16u ss;
4799 Bit8u acode, scode;
4800
4801#if BX_CPU < 2
4802 buffer_start = 0x001E;
4803 buffer_end = 0x003E;
4804#else
4805 buffer_start = read_word(0x0040, 0x0080);
4806 buffer_end = read_word(0x0040, 0x0082);
4807#endif
4808
4809 buffer_head = read_word(0x0040, 0x001a);
4810 buffer_tail = read_word(0x0040, 0x001c);
4811
4812 if (buffer_head != buffer_tail) {
4813 ss = get_SS();
4814 acode = read_byte(0x0040, buffer_head);
4815 scode = read_byte(0x0040, buffer_head+1);
4816 write_byte(ss, ascii_code, acode);
4817 write_byte(ss, scan_code, scode);
4818
4819 if (incr) {
4820 buffer_head += 2;
4821 if (buffer_head >= buffer_end)
4822 buffer_head = buffer_start;
4823 write_word(0x0040, 0x001a, buffer_head);
4824 }
4825 return(1);
4826 }
4827 else {
4828 return(0);
4829 }
4830}
4831
4832static char panic_msg_keyb_buffer_full[] = "%s: keyboard input buffer full\n";
4833
4834 Bit8u
4835inhibit_mouse_int_and_events()
4836{
4837 Bit8u command_byte, prev_command_byte;
4838
4839 // Turn off IRQ generation and aux data line
4840 if ( inb(0x64) & 0x02 )
4841 BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
4842 outb(0x64, 0x20); // get command byte
4843 while ( (inb(0x64) & 0x01) != 0x01 );
4844 prev_command_byte = inb(0x60);
4845 command_byte = prev_command_byte;
4846 //while ( (inb(0x64) & 0x02) );
4847 if ( inb(0x64) & 0x02 )
4848 BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
4849 command_byte &= 0xfd; // turn off IRQ 12 generation
4850 command_byte |= 0x20; // disable mouse serial clock line
4851 outb(0x64, 0x60); // write command byte
4852 outb(0x60, command_byte);
4853 return(prev_command_byte);
4854}
4855
4856 void
4857enable_mouse_int_and_events()
4858{
4859 Bit8u command_byte;
4860
4861 // Turn on IRQ generation and aux data line
4862 if ( inb(0x64) & 0x02 )
4863 BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
4864 outb(0x64, 0x20); // get command byte
4865 while ( (inb(0x64) & 0x01) != 0x01 );
4866 command_byte = inb(0x60);
4867 //while ( (inb(0x64) & 0x02) );
4868 if ( inb(0x64) & 0x02 )
4869 BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
4870 command_byte |= 0x02; // turn on IRQ 12 generation
4871 command_byte &= 0xdf; // enable mouse serial clock line
4872 outb(0x64, 0x60); // write command byte
4873 outb(0x60, command_byte);
4874}
4875
4876 Bit8u
4877send_to_mouse_ctrl(sendbyte)
4878 Bit8u sendbyte;
4879{
4880 Bit8u response;
4881
4882 // wait for chance to write to ctrl
4883 if ( inb(0x64) & 0x02 )
4884 BX_PANIC(panic_msg_keyb_buffer_full,"sendmouse");
4885 outb(0x64, 0xD4);
4886 outb(0x60, sendbyte);
4887 return(0);
4888}
4889
4890
4891 Bit8u
4892get_mouse_data(data)
4893 Bit8u *data;
4894{
4895 Bit8u response;
4896 Bit16u ss;
4897
4898 while ( (inb(0x64) & 0x21) != 0x21 ) {
4899 }
4900
4901 response = inb(0x60);
4902
4903 ss = get_SS();
4904 write_byte(ss, data, response);
4905 return(0);
4906}
4907
4908 void
4909set_kbd_command_byte(command_byte)
4910 Bit8u command_byte;
4911{
4912 if ( inb(0x64) & 0x02 )
4913 BX_PANIC(panic_msg_keyb_buffer_full,"setkbdcomm");
4914 outb(0x64, 0xD4);
4915
4916 outb(0x64, 0x60); // write command byte
4917 outb(0x60, command_byte);
4918}
4919
4920 void
4921int09_function(DI, SI, BP, SP, BX, DX, CX, AX)
4922 Bit16u DI, SI, BP, SP, BX, DX, CX, AX;
4923{
4924 Bit8u scancode, asciicode, shift_flags;
4925 Bit8u mf2_flags, mf2_state;
4926
4927 //
4928 // DS has been set to F000 before call
4929 //
4930
4931
4932 scancode = GET_AL();
4933
4934 if (scancode == 0) {
4935 BX_INFO("KBD: int09 handler: AL=0\n");
4936 return;
4937 }
4938
4939
4940 shift_flags = read_byte(0x0040, 0x17);
4941 mf2_flags = read_byte(0x0040, 0x18);
4942 mf2_state = read_byte(0x0040, 0x96);
4943 asciicode = 0;
4944
4945 switch (scancode) {
4946 case 0x3a: /* Caps Lock press */
4947 shift_flags ^= 0x40;
4948 write_byte(0x0040, 0x17, shift_flags);
4949 mf2_flags |= 0x40;
4950 write_byte(0x0040, 0x18, mf2_flags);
4951 break;
4952 case 0xba: /* Caps Lock release */
4953 mf2_flags &= ~0x40;
4954 write_byte(0x0040, 0x18, mf2_flags);
4955 break;
4956
4957 case 0x2a: /* L Shift press */
4958 shift_flags |= 0x02;
4959 write_byte(0x0040, 0x17, shift_flags);
4960 break;
4961 case 0xaa: /* L Shift release */
4962 shift_flags &= ~0x02;
4963 write_byte(0x0040, 0x17, shift_flags);
4964 break;
4965
4966 case 0x36: /* R Shift press */
4967 shift_flags |= 0x01;
4968 write_byte(0x0040, 0x17, shift_flags);
4969 break;
4970 case 0xb6: /* R Shift release */
4971 shift_flags &= ~0x01;
4972 write_byte(0x0040, 0x17, shift_flags);
4973 break;
4974
4975 case 0x1d: /* Ctrl press */
4976 if ((mf2_state & 0x01) == 0) {
4977 shift_flags |= 0x04;
4978 write_byte(0x0040, 0x17, shift_flags);
4979 if (mf2_state & 0x02) {
4980 mf2_state |= 0x04;
4981 write_byte(0x0040, 0x96, mf2_state);
4982 } else {
4983 mf2_flags |= 0x01;
4984 write_byte(0x0040, 0x18, mf2_flags);
4985 }
4986 }
4987 break;
4988 case 0x9d: /* Ctrl release */
4989 if ((mf2_state & 0x01) == 0) {
4990 shift_flags &= ~0x04;
4991 write_byte(0x0040, 0x17, shift_flags);
4992 if (mf2_state & 0x02) {
4993 mf2_state &= ~0x04;
4994 write_byte(0x0040, 0x96, mf2_state);
4995 } else {
4996 mf2_flags &= ~0x01;
4997 write_byte(0x0040, 0x18, mf2_flags);
4998 }
4999 }
5000 break;
5001
5002 case 0x38: /* Alt press */
5003 shift_flags |= 0x08;
5004 write_byte(0x0040, 0x17, shift_flags);
5005 if (mf2_state & 0x02) {
5006 mf2_state |= 0x08;
5007 write_byte(0x0040, 0x96, mf2_state);
5008 } else {
5009 mf2_flags |= 0x02;
5010 write_byte(0x0040, 0x18, mf2_flags);
5011 }
5012 break;
5013 case 0xb8: /* Alt release */
5014 shift_flags &= ~0x08;
5015 write_byte(0x0040, 0x17, shift_flags);
5016 if (mf2_state & 0x02) {
5017 mf2_state &= ~0x08;
5018 write_byte(0x0040, 0x96, mf2_state);
5019 } else {
5020 mf2_flags &= ~0x02;
5021 write_byte(0x0040, 0x18, mf2_flags);
5022 }
5023 break;
5024
5025 case 0x45: /* Num Lock press */
5026 if ((mf2_state & 0x03) == 0) {
5027 mf2_flags |= 0x20;
5028 write_byte(0x0040, 0x18, mf2_flags);
5029 shift_flags ^= 0x20;
5030 write_byte(0x0040, 0x17, shift_flags);
5031 }
5032 break;
5033 case 0xc5: /* Num Lock release */
5034 if ((mf2_state & 0x03) == 0) {
5035 mf2_flags &= ~0x20;
5036 write_byte(0x0040, 0x18, mf2_flags);
5037 }
5038 break;
5039
5040 case 0x46: /* Scroll Lock press */
5041 mf2_flags |= 0x10;
5042 write_byte(0x0040, 0x18, mf2_flags);
5043 shift_flags ^= 0x10;
5044 write_byte(0x0040, 0x17, shift_flags);
5045 break;
5046
5047 case 0xc6: /* Scroll Lock release */
5048 mf2_flags &= ~0x10;
5049 write_byte(0x0040, 0x18, mf2_flags);
5050 break;
5051
5052 default:
5053 if (scancode & 0x80) {
5054 break; /* toss key releases ... */
5055 }
5056 if (scancode > MAX_SCAN_CODE) {
5057 BX_INFO("KBD: int09h_handler(): unknown scancode read: 0x%02x!\n", scancode);
5058 return;
5059 }
5060 if (shift_flags & 0x08) { /* ALT */
5061 asciicode = scan_to_scanascii[scancode].alt;
5062 scancode = scan_to_scanascii[scancode].alt >> 8;
5063 } else if (shift_flags & 0x04) { /* CONTROL */
5064 asciicode = scan_to_scanascii[scancode].control;
5065 scancode = scan_to_scanascii[scancode].control >> 8;
5066 } else if (((mf2_state & 0x02) > 0) && ((scancode >= 0x47) && (scancode <= 0x53))) {
5067 /* extended keys handling */
5068 asciicode = 0xe0;
5069 scancode = scan_to_scanascii[scancode].normal >> 8;
5070 } else if (shift_flags & 0x03) { /* LSHIFT + RSHIFT */
5071 /* check if lock state should be ignored
5072 * because a SHIFT key are pressed */
5073
5074 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
5075 asciicode = scan_to_scanascii[scancode].normal;
5076 scancode = scan_to_scanascii[scancode].normal >> 8;
5077 } else {
5078 asciicode = scan_to_scanascii[scancode].shift;
5079 scancode = scan_to_scanascii[scancode].shift >> 8;
5080 }
5081 } else {
5082 /* check if lock is on */
5083 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
5084 asciicode = scan_to_scanascii[scancode].shift;
5085 scancode = scan_to_scanascii[scancode].shift >> 8;
5086 } else {
5087 asciicode = scan_to_scanascii[scancode].normal;
5088 scancode = scan_to_scanascii[scancode].normal >> 8;
5089 }
5090 }
5091 if (scancode==0 && asciicode==0) {
5092 BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
5093 }
5094 enqueue_key(scancode, asciicode);
5095 break;
5096 }
5097 if ((scancode & 0x7f) != 0x1d) {
5098 mf2_state &= ~0x01;
5099 }
5100 mf2_state &= ~0x02;
5101 write_byte(0x0040, 0x96, mf2_state);
5102}
5103
5104 unsigned int
5105enqueue_key(scan_code, ascii_code)
5106 Bit8u scan_code, ascii_code;
5107{
5108 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail, temp_tail;
5109
5110#if BX_CPU < 2
5111 buffer_start = 0x001E;
5112 buffer_end = 0x003E;
5113#else
5114 buffer_start = read_word(0x0040, 0x0080);
5115 buffer_end = read_word(0x0040, 0x0082);
5116#endif
5117
5118 buffer_head = read_word(0x0040, 0x001A);
5119 buffer_tail = read_word(0x0040, 0x001C);
5120
5121 temp_tail = buffer_tail;
5122 buffer_tail += 2;
5123 if (buffer_tail >= buffer_end)
5124 buffer_tail = buffer_start;
5125
5126 if (buffer_tail == buffer_head) {
5127 return(0);
5128 }
5129
5130 write_byte(0x0040, temp_tail, ascii_code);
5131 write_byte(0x0040, temp_tail+1, scan_code);
5132 write_word(0x0040, 0x001C, buffer_tail);
5133 return(1);
5134}
5135
5136
5137 void
5138int74_function(make_farcall, Z, Y, X, status)
5139 Bit16u make_farcall, Z, Y, X, status;
5140{
5141 Bit16u ebda_seg=read_word(0x0040,0x000E);
5142 Bit8u in_byte, index, package_count;
5143 Bit8u mouse_flags_1, mouse_flags_2;
5144
5145BX_DEBUG_INT74("entering int74_function\n");
5146 make_farcall = 0;
5147
5148 in_byte = inb(0x64);
5149 if ( (in_byte & 0x21) != 0x21 ) {
5150 return;
5151 }
5152 in_byte = inb(0x60);
5153BX_DEBUG_INT74("int74: read byte %02x\n", in_byte);
5154
5155 mouse_flags_1 = read_byte(ebda_seg, 0x0026);
5156 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
5157
5158 if ( (mouse_flags_2 & 0x80) != 0x80 ) {
5159 return;
5160 }
5161
5162 package_count = mouse_flags_2 & 0x07;
5163 index = mouse_flags_1 & 0x07;
5164 write_byte(ebda_seg, 0x28 + index, in_byte);
5165
5166 if ( (index+1) >= package_count ) {
5167BX_DEBUG_INT74("int74_function: make_farcall=1\n");
5168 status = read_byte(ebda_seg, 0x0028 + 0);
5169 X = read_byte(ebda_seg, 0x0028 + 1);
5170 Y = read_byte(ebda_seg, 0x0028 + 2);
5171 Z = 0;
5172 mouse_flags_1 = 0;
5173 // check if far call handler installed
5174 if (mouse_flags_2 & 0x80)
5175 make_farcall = 1;
5176 }
5177 else {
5178 mouse_flags_1++;
5179 }
5180 write_byte(ebda_seg, 0x0026, mouse_flags_1);
5181}
5182
5183#define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
5184
5185#if BX_USE_ATADRV
5186
5187 void
5188int13_harddisk(EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5189 Bit16u EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5190{
5191 Bit32u lba;
5192 Bit16u ebda_seg=read_word(0x0040,0x000E);
5193 Bit16u cylinder, head, sector;
5194 Bit16u segment, offset;
5195 Bit16u npc, nph, npspt, nlc, nlh, nlspt;
5196 Bit16u size, count;
5197 Bit8u device, status;
5198
5199 BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5200
5201 write_byte(0x0040, 0x008e, 0); // clear completion flag
5202
5203 // basic check : device has to be defined
5204 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES) ) {
5205 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5206 goto int13_fail;
5207 }
5208
5209 // Get the ata channel
5210 device=read_byte(ebda_seg,&EbdaData->ata.hdidmap[GET_ELDL()-0x80]);
5211
5212 // basic check : device has to be valid
5213 if (device >= BX_MAX_ATA_DEVICES) {
5214 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5215 goto int13_fail;
5216 }
5217
5218 switch (GET_AH()) {
5219
5220 case 0x00: /* disk controller reset */
5221 ata_reset (device);
5222 goto int13_success;
5223 break;
5224
5225 case 0x01: /* read disk status */
5226 status = read_byte(0x0040, 0x0074);
5227 SET_AH(status);
5228 SET_DISK_RET_STATUS(0);
5229 /* set CF if error status read */
5230 if (status) goto int13_fail_nostatus;
5231 else goto int13_success_noah;
5232 break;
5233
5234 case 0x02: // read disk sectors
5235 case 0x03: // write disk sectors
5236 case 0x04: // verify disk sectors
5237
5238 count = GET_AL();
5239 cylinder = GET_CH();
5240 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
5241 sector = (GET_CL() & 0x3f);
5242 head = GET_DH();
5243
5244 segment = ES;
5245 offset = BX;
5246
5247 if ( (count > 128) || (count == 0) ) {
5248 BX_INFO("int13_harddisk: function %02x, count out of range!\n",GET_AH());
5249 goto int13_fail;
5250 }
5251
5252 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
5253 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
5254 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
5255
5256 // sanity check on cyl heads, sec
5257 if( (cylinder >= nlc) || (head >= nlh) || (sector > nlspt )) {
5258 BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder, head, sector);
5259 goto int13_fail;
5260 }
5261
5262 // FIXME verify
5263 if ( GET_AH() == 0x04 ) goto int13_success;
5264
5265 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5266 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5267
5268 // if needed, translate lchs to lba, and execute command
5269 if ( (nph != nlh) || (npspt != nlspt)) {
5270 lba = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
5271 sector = 0; // this forces the command to be lba
5272 }
5273
5274 if ( GET_AH() == 0x02 )
5275 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, cylinder, head, sector, lba, segment, offset);
5276 else
5277 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, cylinder, head, sector, lba, segment, offset);
5278
5279 // Set nb of sector transferred
5280 SET_AL(read_word(ebda_seg, &EbdaData->ata.trsfsectors));
5281
5282 if (status != 0) {
5283 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5284 SET_AH(0x0c);
5285 goto int13_fail_noah;
5286 }
5287
5288 goto int13_success;
5289 break;
5290
5291 case 0x05: /* format disk track */
5292 BX_INFO("format disk track called\n");
5293 goto int13_success;
5294 return;
5295 break;
5296
5297 case 0x08: /* read disk drive parameters */
5298
5299 // Get logical geometry from table
5300 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
5301 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
5302 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
5303 count = read_byte(ebda_seg, &EbdaData->ata.hdcount);
5304
5305#ifndef VBOX
5306 nlc = nlc - 2; /* 0 based , last sector not used */
5307#else /* VBOX */
5308 /* Maximum cylinder number is just one less than the number of cylinders. */
5309 nlc = nlc - 1; /* 0 based , last sector not used */
5310#endif /* VBOX */
5311 SET_AL(0);
5312 SET_CH(nlc & 0xff);
5313 SET_CL(((nlc >> 2) & 0xc0) | (nlspt & 0x3f));
5314 SET_DH(nlh - 1);
5315 SET_DL(count); /* FIXME returns 0, 1, or n hard drives */
5316
5317 // FIXME should set ES & DI
5318
5319 goto int13_success;
5320 break;
5321
5322 case 0x10: /* check drive ready */
5323 // should look at 40:8E also???
5324
5325 // Read the status from controller
5326 status = inb(read_word(ebda_seg, &EbdaData->ata.channels[device/2].iobase1) + ATA_CB_STAT);
5327 if ( (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY ) {
5328 goto int13_success;
5329 }
5330 else {
5331 SET_AH(0xAA);
5332 goto int13_fail_noah;
5333 }
5334 break;
5335
5336 case 0x15: /* read disk drive size */
5337
5338 // Get physical geometry from table
5339 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5340 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5341 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5342
5343 // Compute sector count seen by int13
5344#ifndef VBOX
5345 lba = (Bit32u)(npc - 1) * (Bit32u)nph * (Bit32u)npspt;
5346#else /* VBOX */
5347 /* Is it so hard to multiply a couple of counts (without introducing
5348 * arbitrary off by one errors)? */
5349 lba = (Bit32u)npc * (Bit32u)nph * (Bit32u)npspt;
5350#endif /* VBOX */
5351 CX = lba >> 16;
5352 DX = lba & 0xffff;
5353
5354 SET_AH(3); // hard disk accessible
5355 goto int13_success_noah;
5356 break;
5357
5358 case 0x41: // IBM/MS installation check
5359 BX=0xaa55; // install check
5360 SET_AH(0x30); // EDD 3.0
5361 CX=0x0007; // ext disk access and edd, removable supported
5362 goto int13_success_noah;
5363 break;
5364
5365 case 0x42: // IBM/MS extended read
5366 case 0x43: // IBM/MS extended write
5367 case 0x44: // IBM/MS verify
5368 case 0x47: // IBM/MS extended seek
5369
5370 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5371 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5372 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5373
5374 // Can't use 64 bits lba
5375 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5376 if (lba != 0L) {
5377 BX_PANIC("int13_harddisk: function %02x. Can't use 64bits lba\n",GET_AH());
5378 goto int13_fail;
5379 }
5380
5381 // Get 32 bits lba and check
5382 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5383 if (lba >= read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors) ) {
5384 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5385 goto int13_fail;
5386 }
5387
5388 // If verify or seek
5389 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5390 goto int13_success;
5391
5392 // Execute the command
5393 if ( GET_AH() == 0x42 )
5394#ifdef VBOX
5395 {
5396 if (count >= 256 || lba + count >= 268435456)
5397 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS_EXT, count, 0, 0, 0, lba, segment, offset);
5398 else
5399 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba, segment, offset);
5400 }
5401#else /* !VBOX */
5402 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba, segment, offset);
5403#endif /* VBOX */
5404 else
5405#ifdef VBOX
5406 {
5407 if (count >= 256 || lba + count >= 268435456)
5408 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS_EXT, count, 0, 0, 0, lba, segment, offset);
5409 else
5410 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
5411 }
5412#else /* !VBOX */
5413 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
5414#endif /* VBOX */
5415
5416 count=read_word(ebda_seg, &EbdaData->ata.trsfsectors);
5417 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5418
5419 if (status != 0) {
5420 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5421 SET_AH(0x0c);
5422 goto int13_fail_noah;
5423 }
5424
5425 goto int13_success;
5426 break;
5427
5428 case 0x45: // IBM/MS lock/unlock drive
5429 case 0x49: // IBM/MS extended media change
5430 goto int13_success; // Always success for HD
5431 break;
5432
5433 case 0x46: // IBM/MS eject media
5434 SET_AH(0xb2); // Volume Not Removable
5435 goto int13_fail_noah; // Always fail for HD
5436 break;
5437
5438 case 0x48: // IBM/MS get drive parameters
5439 size=read_word(DS,SI+(Bit16u)&Int13DPT->size);
5440
5441 // Buffer is too small
5442 if(size < 0x1a)
5443 goto int13_fail;
5444
5445 // EDD 1.x
5446 if(size >= 0x1a) {
5447 Bit16u blksize;
5448
5449 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5450 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5451 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5452 lba = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors);
5453 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5454
5455 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5456 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x02); // geometry is valid
5457 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, (Bit32u)npc);
5458 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, (Bit32u)nph);
5459 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, (Bit32u)npspt);
5460 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, lba); // FIXME should be Bit64
5461 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0L);
5462 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5463 }
5464
5465 // EDD 2.x
5466 if(size >= 0x1e) {
5467 Bit8u channel, dev, irq, mode, checksum, i, translation;
5468 Bit16u iobase1, iobase2, options;
5469
5470 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5471
5472 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5473 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5474
5475 // Fill in dpte
5476 channel = device / 2;
5477 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5478 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5479 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5480 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5481 translation = read_byte(ebda_seg, &EbdaData->ata.devices[device].translation);
5482
5483 options = (translation==ATA_TRANSLATION_NONE?0:1<<3); // chs translation
5484 options |= (1<<4); // lba translation
5485 options |= (mode==ATA_MODE_PIO32?1:0<<7);
5486 options |= (translation==ATA_TRANSLATION_LBA?1:0<<9);
5487 options |= (translation==ATA_TRANSLATION_RECHS?3:0<<9);
5488
5489 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5490 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5491 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5492 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5493 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5494 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5495 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5496 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5497 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5498 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5499 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5500
5501 checksum=0;
5502 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5503 checksum = ~checksum;
5504 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5505 }
5506
5507 // EDD 3.x
5508 if(size >= 0x42) {
5509 Bit8u channel, iface, checksum, i;
5510 Bit16u iobase1;
5511
5512 channel = device / 2;
5513 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5514 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5515
5516 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5517 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5518 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5519 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5520 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5521
5522 if (iface==ATA_IFACE_ISA) {
5523 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5524 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5525 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5526 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5527 }
5528 else {
5529 // FIXME PCI
5530 }
5531 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5532 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5533 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5534 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5535
5536 if (iface==ATA_IFACE_ISA) {
5537 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5538 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5539 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5540 }
5541 else {
5542 // FIXME PCI
5543 }
5544 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5545 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5546 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5547 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5548
5549 checksum=0;
5550 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5551 checksum = ~checksum;
5552 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5553 }
5554
5555 goto int13_success;
5556 break;
5557
5558 case 0x4e: // // IBM/MS set hardware configuration
5559 // DMA, prefetch, PIO maximum not supported
5560 switch (GET_AL()) {
5561 case 0x01:
5562 case 0x03:
5563 case 0x04:
5564 case 0x06:
5565 goto int13_success;
5566 break;
5567 default :
5568 goto int13_fail;
5569 }
5570 break;
5571
5572 case 0x09: /* initialize drive parameters */
5573 case 0x0c: /* seek to specified cylinder */
5574 case 0x0d: /* alternate disk reset */
5575 case 0x11: /* recalibrate */
5576 case 0x14: /* controller internal diagnostic */
5577 BX_INFO("int13_harddisk: function %02xh unimplemented, returns success\n", GET_AH());
5578 goto int13_success;
5579 break;
5580
5581 case 0x0a: /* read disk sectors with ECC */
5582 case 0x0b: /* write disk sectors with ECC */
5583 case 0x18: // set media type for format
5584 case 0x50: // IBM/MS send packet command
5585 default:
5586 BX_INFO("int13_harddisk: function %02xh unsupported, returns fail\n", GET_AH());
5587 goto int13_fail;
5588 break;
5589 }
5590
5591int13_fail:
5592 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5593int13_fail_noah:
5594 SET_DISK_RET_STATUS(GET_AH());
5595int13_fail_nostatus:
5596 SET_CF(); // error occurred
5597 return;
5598
5599int13_success:
5600 SET_AH(0x00); // no error
5601int13_success_noah:
5602 SET_DISK_RET_STATUS(0x00);
5603 CLEAR_CF(); // no error
5604 return;
5605}
5606
5607// ---------------------------------------------------------------------------
5608// Start of int13 for cdrom
5609// ---------------------------------------------------------------------------
5610
5611 void
5612int13_cdrom(EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5613 Bit16u EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5614{
5615 Bit16u ebda_seg=read_word(0x0040,0x000E);
5616 Bit8u device, status, locks;
5617 Bit8u atacmd[12];
5618 Bit32u lba;
5619 Bit16u count, segment, offset, i, size;
5620
5621 BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5622
5623 SET_DISK_RET_STATUS(0x00);
5624
5625 /* basic check : device should be 0xE0+ */
5626 if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES) ) {
5627 BX_INFO("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5628 goto int13_fail;
5629 }
5630
5631 // Get the ata channel
5632 device=read_byte(ebda_seg,&EbdaData->ata.cdidmap[GET_ELDL()-0xE0]);
5633
5634 /* basic check : device has to be valid */
5635 if (device >= BX_MAX_ATA_DEVICES) {
5636 BX_INFO("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5637 goto int13_fail;
5638 }
5639
5640 switch (GET_AH()) {
5641
5642 // all those functions return SUCCESS
5643 case 0x00: /* disk controller reset */
5644 case 0x09: /* initialize drive parameters */
5645 case 0x0c: /* seek to specified cylinder */
5646 case 0x0d: /* alternate disk reset */
5647 case 0x10: /* check drive ready */
5648 case 0x11: /* recalibrate */
5649 case 0x14: /* controller internal diagnostic */
5650 case 0x16: /* detect disk change */
5651 goto int13_success;
5652 break;
5653
5654 // all those functions return disk write-protected
5655 case 0x03: /* write disk sectors */
5656 case 0x05: /* format disk track */
5657 case 0x43: // IBM/MS extended write
5658 SET_AH(0x03);
5659 goto int13_fail_noah;
5660 break;
5661
5662 case 0x01: /* read disk status */
5663 status = read_byte(0x0040, 0x0074);
5664 SET_AH(status);
5665 SET_DISK_RET_STATUS(0);
5666
5667 /* set CF if error status read */
5668 if (status) goto int13_fail_nostatus;
5669 else goto int13_success_noah;
5670 break;
5671
5672 case 0x15: /* read disk drive size */
5673 SET_AH(0x02);
5674 goto int13_fail_noah;
5675 break;
5676
5677 case 0x41: // IBM/MS installation check
5678 BX=0xaa55; // install check
5679 SET_AH(0x30); // EDD 2.1
5680 CX=0x0007; // ext disk access, removable and edd
5681 goto int13_success_noah;
5682 break;
5683
5684 case 0x42: // IBM/MS extended read
5685 case 0x44: // IBM/MS verify sectors
5686 case 0x47: // IBM/MS extended seek
5687
5688 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5689 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5690 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5691
5692 // Can't use 64 bits lba
5693 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5694 if (lba != 0L) {
5695 BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
5696 goto int13_fail;
5697 }
5698
5699 // Get 32 bits lba
5700 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5701
5702 // If verify or seek
5703 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5704 goto int13_success;
5705
5706 memsetb(get_SS(),atacmd,0,12);
5707 atacmd[0]=0x28; // READ command
5708 atacmd[7]=(count & 0xff00) >> 8; // Sectors
5709 atacmd[8]=(count & 0x00ff); // Sectors
5710 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
5711 atacmd[3]=(lba & 0x00ff0000) >> 16;
5712 atacmd[4]=(lba & 0x0000ff00) >> 8;
5713 atacmd[5]=(lba & 0x000000ff);
5714 status = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, count*2048L, ATA_DATA_IN, segment,offset);
5715
5716 count = (Bit16u)(read_dword(ebda_seg, &EbdaData->ata.trsfbytes) >> 11);
5717 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5718
5719 if (status != 0) {
5720 BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status);
5721 SET_AH(0x0c);
5722 goto int13_fail_noah;
5723 }
5724
5725 goto int13_success;
5726 break;
5727
5728 case 0x45: // IBM/MS lock/unlock drive
5729 if (GET_AL() > 2) goto int13_fail;
5730
5731 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
5732
5733 switch (GET_AL()) {
5734 case 0 : // lock
5735 if (locks == 0xff) {
5736 SET_AH(0xb4);
5737 SET_AL(1);
5738 goto int13_fail_noah;
5739 }
5740 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, ++locks);
5741 SET_AL(1);
5742 break;
5743 case 1 : // unlock
5744 if (locks == 0x00) {
5745 SET_AH(0xb0);
5746 SET_AL(0);
5747 goto int13_fail_noah;
5748 }
5749 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, --locks);
5750 SET_AL(locks==0?0:1);
5751 break;
5752 case 2 : // status
5753 SET_AL(locks==0?0:1);
5754 break;
5755 }
5756 goto int13_success;
5757 break;
5758
5759 case 0x46: // IBM/MS eject media
5760 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
5761
5762 if (locks != 0) {
5763 SET_AH(0xb1); // media locked
5764 goto int13_fail_noah;
5765 }
5766 // FIXME should handle 0x31 no media in device
5767 // FIXME should handle 0xb5 valid request failed
5768
5769 // Call removable media eject
5770 ASM_START
5771 push bp
5772 mov bp, sp
5773
5774 mov ah, #0x52
5775 int 15
5776 mov _int13_cdrom.status + 2[bp], ah
5777 jnc int13_cdrom_rme_end
5778 mov _int13_cdrom.status, #1
5779int13_cdrom_rme_end:
5780 pop bp
5781 ASM_END
5782
5783 if (status != 0) {
5784 SET_AH(0xb1); // media locked
5785 goto int13_fail_noah;
5786 }
5787
5788 goto int13_success;
5789 break;
5790
5791 case 0x48: // IBM/MS get drive parameters
5792 size = read_word(DS,SI+(Bit16u)&Int13Ext->size);
5793
5794 // Buffer is too small
5795 if(size < 0x1a)
5796 goto int13_fail;
5797
5798 // EDD 1.x
5799 if(size >= 0x1a) {
5800 Bit16u cylinders, heads, spt, blksize;
5801
5802 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5803
5804 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5805 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x74); // removable, media change, lockable, max values
5806 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, 0xffffffff);
5807 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, 0xffffffff);
5808 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, 0xffffffff);
5809 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, 0xffffffff); // FIXME should be Bit64
5810 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0xffffffff);
5811 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5812 }
5813
5814 // EDD 2.x
5815 if(size >= 0x1e) {
5816 Bit8u channel, dev, irq, mode, checksum, i;
5817 Bit16u iobase1, iobase2, options;
5818
5819 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5820
5821 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5822 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5823
5824 // Fill in dpte
5825 channel = device / 2;
5826 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5827 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5828 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5829 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5830
5831 // FIXME atapi device
5832 options = (1<<4); // lba translation
5833 options |= (1<<5); // removable device
5834 options |= (1<<6); // atapi device
5835 options |= (mode==ATA_MODE_PIO32?1:0<<7);
5836
5837 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5838 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5839 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5840 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5841 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5842 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5843 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5844 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5845 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5846 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5847 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5848
5849 checksum=0;
5850 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5851 checksum = ~checksum;
5852 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5853 }
5854
5855 // EDD 3.x
5856 if(size >= 0x42) {
5857 Bit8u channel, iface, checksum, i;
5858 Bit16u iobase1;
5859
5860 channel = device / 2;
5861 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5862 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5863
5864 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5865 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5866 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5867 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5868 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5869
5870 if (iface==ATA_IFACE_ISA) {
5871 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5872 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5873 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5874 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5875 }
5876 else {
5877 // FIXME PCI
5878 }
5879 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5880 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5881 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5882 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5883
5884 if (iface==ATA_IFACE_ISA) {
5885 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5886 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5887 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5888 }
5889 else {
5890 // FIXME PCI
5891 }
5892 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5893 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5894 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5895 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5896
5897 checksum=0;
5898 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5899 checksum = ~checksum;
5900 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5901 }
5902
5903 goto int13_success;
5904 break;
5905
5906 case 0x49: // IBM/MS extended media change
5907 // always send changed ??
5908 SET_AH(06);
5909 goto int13_fail_nostatus;
5910 break;
5911
5912 case 0x4e: // // IBM/MS set hardware configuration
5913 // DMA, prefetch, PIO maximum not supported
5914 switch (GET_AL()) {
5915 case 0x01:
5916 case 0x03:
5917 case 0x04:
5918 case 0x06:
5919 goto int13_success;
5920 break;
5921 default :
5922 goto int13_fail;
5923 }
5924 break;
5925
5926 // all those functions return unimplemented
5927 case 0x02: /* read sectors */
5928 case 0x04: /* verify sectors */
5929 case 0x08: /* read disk drive parameters */
5930 case 0x0a: /* read disk sectors with ECC */
5931 case 0x0b: /* write disk sectors with ECC */
5932 case 0x18: /* set media type for format */
5933 case 0x50: // ? - send packet command
5934 default:
5935 BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
5936 goto int13_fail;
5937 break;
5938 }
5939
5940int13_fail:
5941 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5942int13_fail_noah:
5943 SET_DISK_RET_STATUS(GET_AH());
5944int13_fail_nostatus:
5945 SET_CF(); // error occurred
5946 return;
5947
5948int13_success:
5949 SET_AH(0x00); // no error
5950int13_success_noah:
5951 SET_DISK_RET_STATUS(0x00);
5952 CLEAR_CF(); // no error
5953 return;
5954}
5955
5956// ---------------------------------------------------------------------------
5957// End of int13 for cdrom
5958// ---------------------------------------------------------------------------
5959
5960#if BX_ELTORITO_BOOT
5961// ---------------------------------------------------------------------------
5962// Start of int13 for eltorito functions
5963// ---------------------------------------------------------------------------
5964
5965 void
5966int13_eltorito(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
5967 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
5968{
5969 Bit16u ebda_seg=read_word(0x0040,0x000E);
5970
5971 BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5972 // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
5973
5974 switch (GET_AH()) {
5975
5976 // FIXME ElTorito Various. Should be implemented
5977 case 0x4a: // ElTorito - Initiate disk emu
5978 case 0x4c: // ElTorito - Initiate disk emu and boot
5979 case 0x4d: // ElTorito - Return Boot catalog
5980 BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX);
5981 goto int13_fail;
5982 break;
5983
5984 case 0x4b: // ElTorito - Terminate disk emu
5985 // FIXME ElTorito Hardcoded
5986 write_byte(DS,SI+0x00,0x13);
5987 write_byte(DS,SI+0x01,read_byte(ebda_seg,&EbdaData->cdemu.media));
5988 write_byte(DS,SI+0x02,read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
5989 write_byte(DS,SI+0x03,read_byte(ebda_seg,&EbdaData->cdemu.controller_index));
5990 write_dword(DS,SI+0x04,read_dword(ebda_seg,&EbdaData->cdemu.ilba));
5991 write_word(DS,SI+0x08,read_word(ebda_seg,&EbdaData->cdemu.device_spec));
5992 write_word(DS,SI+0x0a,read_word(ebda_seg,&EbdaData->cdemu.buffer_segment));
5993 write_word(DS,SI+0x0c,read_word(ebda_seg,&EbdaData->cdemu.load_segment));
5994 write_word(DS,SI+0x0e,read_word(ebda_seg,&EbdaData->cdemu.sector_count));
5995 write_byte(DS,SI+0x10,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.cylinders));
5996 write_byte(DS,SI+0x11,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.spt));
5997 write_byte(DS,SI+0x12,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.heads));
5998
5999 // If we have to terminate emulation
6000 if(GET_AL() == 0x00) {
6001 // FIXME ElTorito Various. Should be handled accordingly to spec
6002 write_byte(ebda_seg,&EbdaData->cdemu.active, 0x00); // bye bye
6003 }
6004
6005 goto int13_success;
6006 break;
6007
6008 default:
6009 BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
6010 goto int13_fail;
6011 break;
6012 }
6013
6014int13_fail:
6015 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6016 SET_DISK_RET_STATUS(GET_AH());
6017 SET_CF(); // error occurred
6018 return;
6019
6020int13_success:
6021 SET_AH(0x00); // no error
6022 SET_DISK_RET_STATUS(0x00);
6023 CLEAR_CF(); // no error
6024 return;
6025}
6026
6027// ---------------------------------------------------------------------------
6028// End of int13 for eltorito functions
6029// ---------------------------------------------------------------------------
6030
6031// ---------------------------------------------------------------------------
6032// Start of int13 when emulating a device from the cd
6033// ---------------------------------------------------------------------------
6034
6035 void
6036int13_cdemu(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
6037 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
6038{
6039 Bit16u ebda_seg=read_word(0x0040,0x000E);
6040 Bit8u device, status;
6041 Bit16u vheads, vspt, vcylinders;
6042 Bit16u head, sector, cylinder, nbsectors;
6043 Bit32u vlba, ilba, slba, elba;
6044 Bit16u before, segment, offset;
6045 Bit8u atacmd[12];
6046
6047 BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6048
6049 /* at this point, we are emulating a floppy/harddisk */
6050
6051 // Recompute the device number
6052 device = read_byte(ebda_seg,&EbdaData->cdemu.controller_index) * 2;
6053 device += read_byte(ebda_seg,&EbdaData->cdemu.device_spec);
6054
6055 SET_DISK_RET_STATUS(0x00);
6056
6057 /* basic checks : emulation should be active, dl should equal the emulated drive */
6058 if( (read_byte(ebda_seg,&EbdaData->cdemu.active) ==0 )
6059 || (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive ) != GET_DL())) {
6060 BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
6061 goto int13_fail;
6062 }
6063
6064 switch (GET_AH()) {
6065
6066 // all those functions return SUCCESS
6067 case 0x00: /* disk controller reset */
6068 case 0x09: /* initialize drive parameters */
6069 case 0x0c: /* seek to specified cylinder */
6070 case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
6071 case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
6072 case 0x11: /* recalibrate */
6073 case 0x14: /* controller internal diagnostic */
6074 case 0x16: /* detect disk change */
6075 goto int13_success;
6076 break;
6077
6078 // all those functions return disk write-protected
6079 case 0x03: /* write disk sectors */
6080 case 0x05: /* format disk track */
6081 SET_AH(0x03);
6082 goto int13_fail_noah;
6083 break;
6084
6085 case 0x01: /* read disk status */
6086 status=read_byte(0x0040, 0x0074);
6087 SET_AH(status);
6088 SET_DISK_RET_STATUS(0);
6089
6090 /* set CF if error status read */
6091 if (status) goto int13_fail_nostatus;
6092 else goto int13_success_noah;
6093 break;
6094
6095 case 0x02: // read disk sectors
6096 case 0x04: // verify disk sectors
6097 vspt = read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
6098 vcylinders = read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders);
6099 vheads = read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads);
6100
6101 ilba = read_dword(ebda_seg,&EbdaData->cdemu.ilba);
6102
6103 sector = GET_CL() & 0x003f;
6104 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
6105 head = GET_DH();
6106 nbsectors = GET_AL();
6107 segment = ES;
6108 offset = BX;
6109
6110 // no sector to read ?
6111 if(nbsectors==0) goto int13_success;
6112
6113 // sanity checks sco openserver needs this!
6114 if ((sector > vspt)
6115 || (cylinder >= vcylinders)
6116 || (head >= vheads)) {
6117 goto int13_fail;
6118 }
6119
6120 // After controls, verify do nothing
6121 if (GET_AH() == 0x04) goto int13_success;
6122
6123 segment = ES+(BX / 16);
6124 offset = BX % 16;
6125
6126 // calculate the virtual lba inside the image
6127 vlba=((((Bit32u)cylinder*(Bit32u)vheads)+(Bit32u)head)*(Bit32u)vspt)+((Bit32u)(sector-1));
6128
6129 // In advance so we don't loose the count
6130 SET_AL(nbsectors);
6131
6132 // start lba on cd
6133 slba = (Bit32u)vlba/4;
6134 before= (Bit16u)vlba%4;
6135
6136 // end lba on cd
6137 elba = (Bit32u)(vlba+nbsectors-1)/4;
6138
6139 memsetb(get_SS(),atacmd,0,12);
6140 atacmd[0]=0x28; // READ command
6141 atacmd[7]=((Bit16u)(elba-slba+1) & 0xff00) >> 8; // Sectors
6142 atacmd[8]=((Bit16u)(elba-slba+1) & 0x00ff); // Sectors
6143 atacmd[2]=(ilba+slba & 0xff000000) >> 24; // LBA
6144 atacmd[3]=(ilba+slba & 0x00ff0000) >> 16;
6145 atacmd[4]=(ilba+slba & 0x0000ff00) >> 8;
6146 atacmd[5]=(ilba+slba & 0x000000ff);
6147 if((status = ata_cmd_packet(device, 12, get_SS(), atacmd, before*512, nbsectors*512L, ATA_DATA_IN, segment,offset)) != 0) {
6148 BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status);
6149 SET_AH(0x02);
6150 SET_AL(0);
6151 goto int13_fail_noah;
6152 }
6153
6154 goto int13_success;
6155 break;
6156
6157 case 0x08: /* read disk drive parameters */
6158 vspt=read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
6159 vcylinders=read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders) - 1;
6160 vheads=read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads) - 1;
6161
6162 SET_AL( 0x00 );
6163 SET_BL( 0x00 );
6164 SET_CH( vcylinders & 0xff );
6165 SET_CL((( vcylinders >> 2) & 0xc0) | ( vspt & 0x3f ));
6166 SET_DH( vheads );
6167 SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2
6168 // FIXME ElTorito Harddisk. should send the HD count
6169
6170 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
6171 case 0x01: SET_BL( 0x02 ); break;
6172 case 0x02: SET_BL( 0x04 ); break;
6173 case 0x03: SET_BL( 0x06 ); break;
6174 }
6175
6176ASM_START
6177 push bp
6178 mov bp, sp
6179 mov ax, #diskette_param_table2
6180 mov _int13_cdemu.DI+2[bp], ax
6181 mov _int13_cdemu.ES+2[bp], cs
6182 pop bp
6183ASM_END
6184 goto int13_success;
6185 break;
6186
6187 case 0x15: /* read disk drive size */
6188 // FIXME ElTorito Harddisk. What geometry to send ?
6189 SET_AH(0x03);
6190 goto int13_success_noah;
6191 break;
6192
6193 // all those functions return unimplemented
6194 case 0x0a: /* read disk sectors with ECC */
6195 case 0x0b: /* write disk sectors with ECC */
6196 case 0x18: /* set media type for format */
6197 case 0x41: // IBM/MS installation check
6198 // FIXME ElTorito Harddisk. Darwin would like to use EDD
6199 case 0x42: // IBM/MS extended read
6200 case 0x43: // IBM/MS extended write
6201 case 0x44: // IBM/MS verify sectors
6202 case 0x45: // IBM/MS lock/unlock drive
6203 case 0x46: // IBM/MS eject media
6204 case 0x47: // IBM/MS extended seek
6205 case 0x48: // IBM/MS get drive parameters
6206 case 0x49: // IBM/MS extended media change
6207 case 0x4e: // ? - set hardware configuration
6208 case 0x50: // ? - send packet command
6209 default:
6210 BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
6211 goto int13_fail;
6212 break;
6213 }
6214
6215int13_fail:
6216 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6217int13_fail_noah:
6218 SET_DISK_RET_STATUS(GET_AH());
6219int13_fail_nostatus:
6220 SET_CF(); // error occurred
6221 return;
6222
6223int13_success:
6224 SET_AH(0x00); // no error
6225int13_success_noah:
6226 SET_DISK_RET_STATUS(0x00);
6227 CLEAR_CF(); // no error
6228 return;
6229}
6230
6231// ---------------------------------------------------------------------------
6232// End of int13 when emulating a device from the cd
6233// ---------------------------------------------------------------------------
6234
6235#endif // BX_ELTORITO_BOOT
6236
6237#else //BX_USE_ATADRV
6238
6239 void
6240outLBA(cylinder,hd_heads,head,hd_sectors,sector,dl)
6241 Bit16u cylinder;
6242 Bit16u hd_heads;
6243 Bit16u head;
6244 Bit16u hd_sectors;
6245 Bit16u sector;
6246 Bit16u dl;
6247{
6248ASM_START
6249 push bp
6250 mov bp, sp
6251 push eax
6252 push ebx
6253 push edx
6254 xor eax,eax
6255 mov ax,4[bp] // cylinder
6256 xor ebx,ebx
6257 mov bl,6[bp] // hd_heads
6258 imul ebx
6259
6260 mov bl,8[bp] // head
6261 add eax,ebx
6262 mov bl,10[bp] // hd_sectors
6263 imul ebx
6264 mov bl,12[bp] // sector
6265 add eax,ebx
6266
6267 dec eax
6268 mov dx,#0x1f3
6269 out dx,al
6270 mov dx,#0x1f4
6271 mov al,ah
6272 out dx,al
6273 shr eax,#16
6274 mov dx,#0x1f5
6275 out dx,al
6276 and ah,#0xf
6277 mov bl,14[bp] // dl
6278 and bl,#1
6279 shl bl,#4
6280 or ah,bl
6281 or ah,#0xe0
6282 mov al,ah
6283 mov dx,#0x01f6
6284 out dx,al
6285 pop edx
6286 pop ebx
6287 pop eax
6288 pop bp
6289ASM_END
6290}
6291
6292 void
6293int13_harddisk(EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
6294 Bit16u EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
6295{
6296 Bit8u drive, num_sectors, sector, head, status, mod;
6297 Bit8u drive_map;
6298 Bit8u n_drives;
6299 Bit16u cyl_mod, ax;
6300 Bit16u max_cylinder, cylinder, total_sectors;
6301 Bit16u hd_cylinders;
6302 Bit8u hd_heads, hd_sectors;
6303 Bit16u val16;
6304 Bit8u sector_count;
6305 unsigned int i;
6306 Bit16u tempbx;
6307 Bit16u dpsize;
6308
6309 Bit16u count, segment, offset;
6310 Bit32u lba;
6311 Bit16u error;
6312
6313 BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6314
6315 write_byte(0x0040, 0x008e, 0); // clear completion flag
6316
6317 /* at this point, DL is >= 0x80 to be passed from the floppy int13h
6318 handler code */
6319 /* check how many disks first (cmos reg 0x12), return an error if
6320 drive not present */
6321 drive_map = inb_cmos(0x12);
6322 drive_map = (((drive_map & 0xf0)==0) ? 0 : 1) |
6323 (((drive_map & 0x0f)==0) ? 0 : 2);
6324 n_drives = (drive_map==0) ? 0 :
6325 ((drive_map==3) ? 2 : 1);
6326
6327 if (!(drive_map & (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
6328 SET_AH(0x01);
6329 SET_DISK_RET_STATUS(0x01);
6330 SET_CF(); /* error occurred */
6331 return;
6332 }
6333
6334 switch (GET_AH()) {
6335
6336 case 0x00: /* disk controller reset */
6337BX_DEBUG_INT13_HD("int13_f00\n");
6338
6339 SET_AH(0);
6340 SET_DISK_RET_STATUS(0);
6341 set_diskette_ret_status(0);
6342 set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
6343 set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
6344 CLEAR_CF(); /* successful */
6345 return;
6346 break;
6347
6348 case 0x01: /* read disk status */
6349BX_DEBUG_INT13_HD("int13_f01\n");
6350 status = read_byte(0x0040, 0x0074);
6351 SET_AH(status);
6352 SET_DISK_RET_STATUS(0);
6353 /* set CF if error status read */
6354 if (status) SET_CF();
6355 else CLEAR_CF();
6356 return;
6357 break;
6358
6359 case 0x04: // verify disk sectors
6360 case 0x02: // read disk sectors
6361 drive = GET_ELDL();
6362 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6363
6364 num_sectors = GET_AL();
6365 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
6366 sector = (GET_CL() & 0x3f);
6367 head = GET_DH();
6368
6369
6370 if (hd_cylinders > 1024) {
6371 if (hd_cylinders <= 2048) {
6372 cylinder <<= 1;
6373 }
6374 else if (hd_cylinders <= 4096) {
6375 cylinder <<= 2;
6376 }
6377 else if (hd_cylinders <= 8192) {
6378 cylinder <<= 3;
6379 }
6380 else { // hd_cylinders <= 16384
6381 cylinder <<= 4;
6382 }
6383
6384 ax = head / hd_heads;
6385 cyl_mod = ax & 0xff;
6386 head = ax >> 8;
6387 cylinder |= cyl_mod;
6388 }
6389
6390 if ( (cylinder >= hd_cylinders) ||
6391 (sector > hd_sectors) ||
6392 (head >= hd_heads) ) {
6393 SET_AH(1);
6394 SET_DISK_RET_STATUS(1);
6395 SET_CF(); /* error occurred */
6396 return;
6397 }
6398
6399 if ( (num_sectors > 128) || (num_sectors == 0) )
6400 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6401
6402 if (head > 15)
6403 BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
6404
6405 if ( GET_AH() == 0x04 ) {
6406 SET_AH(0);
6407 SET_DISK_RET_STATUS(0);
6408 CLEAR_CF();
6409 return;
6410 }
6411
6412 status = inb(0x1f7);
6413 if (status & 0x80) {
6414 BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
6415 }
6416 outb(0x01f2, num_sectors);
6417 /* activate LBA? (tomv) */
6418 if (hd_heads > 16) {
6419BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder, head, sector);
6420 outLBA(cylinder,hd_heads,head,hd_sectors,sector,drive);
6421 }
6422 else {
6423 outb(0x01f3, sector);
6424 outb(0x01f4, cylinder & 0x00ff);
6425 outb(0x01f5, cylinder >> 8);
6426 outb(0x01f6, 0xa0 | ((drive & 0x01)<<4) | (head & 0x0f));
6427 }
6428 outb(0x01f7, 0x20);
6429
6430 while (1) {
6431 status = inb(0x1f7);
6432 if ( !(status & 0x80) ) break;
6433 }
6434
6435 if (status & 0x01) {
6436 BX_PANIC("hard drive BIOS:(read/verify) read error\n");
6437 } else if ( !(status & 0x08) ) {
6438 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6439 BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
6440 }
6441
6442 sector_count = 0;
6443 tempbx = BX;
6444
6445ASM_START
6446 sti ;; enable higher priority interrupts
6447ASM_END
6448
6449 while (1) {
6450ASM_START
6451 ;; store temp bx in real DI register
6452 push bp
6453 mov bp, sp
6454 mov di, _int13_harddisk.tempbx + 2 [bp]
6455 pop bp
6456
6457 ;; adjust if there will be an overrun
6458 cmp di, #0xfe00
6459 jbe i13_f02_no_adjust
6460i13_f02_adjust:
6461 sub di, #0x0200 ; sub 512 bytes from offset
6462 mov ax, es
6463 add ax, #0x0020 ; add 512 to segment
6464 mov es, ax
6465
6466i13_f02_no_adjust:
6467 mov cx, #0x0100 ;; counter (256 words = 512b)
6468 mov dx, #0x01f0 ;; AT data read port
6469
6470 rep
6471 insw ;; CX words transfered from port(DX) to ES:[DI]
6472
6473i13_f02_done:
6474 ;; store real DI register back to temp bx
6475 push bp
6476 mov bp, sp
6477 mov _int13_harddisk.tempbx + 2 [bp], di
6478 pop bp
6479ASM_END
6480
6481 sector_count++;
6482 num_sectors--;
6483 if (num_sectors == 0) {
6484 status = inb(0x1f7);
6485 if ( (status & 0xc9) != 0x40 )
6486 BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status);
6487 break;
6488 }
6489 else {
6490 status = inb(0x1f7);
6491 if ( (status & 0xc9) != 0x48 )
6492 BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status);
6493 continue;
6494 }
6495 }
6496
6497 SET_AH(0);
6498 SET_DISK_RET_STATUS(0);
6499 SET_AL(sector_count);
6500 CLEAR_CF(); /* successful */
6501 return;
6502 break;
6503
6504
6505 case 0x03: /* write disk sectors */
6506BX_DEBUG_INT13_HD("int13_f03\n");
6507 drive = GET_ELDL ();
6508 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6509
6510 num_sectors = GET_AL();
6511 cylinder = GET_CH();
6512 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
6513 sector = (GET_CL() & 0x3f);
6514 head = GET_DH();
6515
6516 if (hd_cylinders > 1024) {
6517 if (hd_cylinders <= 2048) {
6518 cylinder <<= 1;
6519 }
6520 else if (hd_cylinders <= 4096) {
6521 cylinder <<= 2;
6522 }
6523 else if (hd_cylinders <= 8192) {
6524 cylinder <<= 3;
6525 }
6526 else { // hd_cylinders <= 16384
6527 cylinder <<= 4;
6528 }
6529
6530 ax = head / hd_heads;
6531 cyl_mod = ax & 0xff;
6532 head = ax >> 8;
6533 cylinder |= cyl_mod;
6534 }
6535
6536 if ( (cylinder >= hd_cylinders) ||
6537 (sector > hd_sectors) ||
6538 (head >= hd_heads) ) {
6539 SET_AH( 1);
6540 SET_DISK_RET_STATUS(1);
6541 SET_CF(); /* error occurred */
6542 return;
6543 }
6544
6545 if ( (num_sectors > 128) || (num_sectors == 0) )
6546 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6547
6548 if (head > 15)
6549 BX_PANIC("hard drive BIOS:(read) head > 15\n");
6550
6551 status = inb(0x1f7);
6552 if (status & 0x80) {
6553 BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
6554 }
6555// should check for Drive Ready Bit also in status reg
6556 outb(0x01f2, num_sectors);
6557
6558 /* activate LBA? (tomv) */
6559 if (hd_heads > 16) {
6560BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder, head, sector);
6561 outLBA(cylinder,hd_heads,head,hd_sectors,sector,GET_ELDL());
6562 }
6563 else {
6564 outb(0x01f3, sector);
6565 outb(0x01f4, cylinder & 0x00ff);
6566 outb(0x01f5, cylinder >> 8);
6567 outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head & 0x0f));
6568 }
6569 outb(0x01f7, 0x30);
6570
6571 // wait for busy bit to turn off after seeking
6572 while (1) {
6573 status = inb(0x1f7);
6574 if ( !(status & 0x80) ) break;
6575 }
6576
6577 if ( !(status & 0x08) ) {
6578 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6579 BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
6580 }
6581
6582 sector_count = 0;
6583 tempbx = BX;
6584
6585ASM_START
6586 sti ;; enable higher priority interrupts
6587ASM_END
6588
6589 while (1) {
6590ASM_START
6591 ;; store temp bx in real SI register
6592 push bp
6593 mov bp, sp
6594 mov si, _int13_harddisk.tempbx + 2 [bp]
6595 pop bp
6596
6597 ;; adjust if there will be an overrun
6598 cmp si, #0xfe00
6599 jbe i13_f03_no_adjust
6600i13_f03_adjust:
6601 sub si, #0x0200 ; sub 512 bytes from offset
6602 mov ax, es
6603 add ax, #0x0020 ; add 512 to segment
6604 mov es, ax
6605
6606i13_f03_no_adjust:
6607 mov cx, #0x0100 ;; counter (256 words = 512b)
6608 mov dx, #0x01f0 ;; AT data read port
6609
6610 seg ES
6611 rep
6612 outsw ;; CX words tranfered from ES:[SI] to port(DX)
6613
6614 ;; store real SI register back to temp bx
6615 push bp
6616 mov bp, sp
6617 mov _int13_harddisk.tempbx + 2 [bp], si
6618 pop bp
6619ASM_END
6620
6621 sector_count++;
6622 num_sectors--;
6623 if (num_sectors == 0) {
6624 status = inb(0x1f7);
6625 if ( (status & 0xe9) != 0x40 )
6626 BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status);
6627 break;
6628 }
6629 else {
6630 status = inb(0x1f7);
6631 if ( (status & 0xc9) != 0x48 )
6632 BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status);
6633 continue;
6634 }
6635 }
6636
6637 SET_AH(0);
6638 SET_DISK_RET_STATUS(0);
6639 SET_AL(sector_count);
6640 CLEAR_CF(); /* successful */
6641 return;
6642 break;
6643
6644 case 0x05: /* format disk track */
6645BX_DEBUG_INT13_HD("int13_f05\n");
6646 BX_PANIC("format disk track called\n");
6647 /* nop */
6648 SET_AH(0);
6649 SET_DISK_RET_STATUS(0);
6650 CLEAR_CF(); /* successful */
6651 return;
6652 break;
6653
6654 case 0x08: /* read disk drive parameters */
6655BX_DEBUG_INT13_HD("int13_f08\n");
6656
6657 drive = GET_ELDL ();
6658 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6659
6660 // translate CHS
6661 //
6662 if (hd_cylinders <= 1024) {
6663 // hd_cylinders >>= 0;
6664 // hd_heads <<= 0;
6665 }
6666 else if (hd_cylinders <= 2048) {
6667 hd_cylinders >>= 1;
6668 hd_heads <<= 1;
6669 }
6670 else if (hd_cylinders <= 4096) {
6671 hd_cylinders >>= 2;
6672 hd_heads <<= 2;
6673 }
6674 else if (hd_cylinders <= 8192) {
6675 hd_cylinders >>= 3;
6676 hd_heads <<= 3;
6677 }
6678 else { // hd_cylinders <= 16384
6679 hd_cylinders >>= 4;
6680 hd_heads <<= 4;
6681 }
6682
6683 max_cylinder = hd_cylinders - 2; /* 0 based */
6684 SET_AL(0);
6685 SET_CH(max_cylinder & 0xff);
6686 SET_CL(((max_cylinder >> 2) & 0xc0) | (hd_sectors & 0x3f));
6687 SET_DH(hd_heads - 1);
6688 SET_DL(n_drives); /* returns 0, 1, or 2 hard drives */
6689 SET_AH(0);
6690 SET_DISK_RET_STATUS(0);
6691 CLEAR_CF(); /* successful */
6692
6693 return;
6694 break;
6695
6696 case 0x09: /* initialize drive parameters */
6697BX_DEBUG_INT13_HD("int13_f09\n");
6698 SET_AH(0);
6699 SET_DISK_RET_STATUS(0);
6700 CLEAR_CF(); /* successful */
6701 return;
6702 break;
6703
6704 case 0x0a: /* read disk sectors with ECC */
6705BX_DEBUG_INT13_HD("int13_f0a\n");
6706 case 0x0b: /* write disk sectors with ECC */
6707BX_DEBUG_INT13_HD("int13_f0b\n");
6708 BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
6709 return;
6710 break;
6711
6712 case 0x0c: /* seek to specified cylinder */
6713BX_DEBUG_INT13_HD("int13_f0c\n");
6714 BX_INFO("int13h function 0ch (seek) not implemented!\n");
6715 SET_AH(0);
6716 SET_DISK_RET_STATUS(0);
6717 CLEAR_CF(); /* successful */
6718 return;
6719 break;
6720
6721 case 0x0d: /* alternate disk reset */
6722BX_DEBUG_INT13_HD("int13_f0d\n");
6723 SET_AH(0);
6724 SET_DISK_RET_STATUS(0);
6725 CLEAR_CF(); /* successful */
6726 return;
6727 break;
6728
6729 case 0x10: /* check drive ready */
6730BX_DEBUG_INT13_HD("int13_f10\n");
6731 //SET_AH(0);
6732 //SET_DISK_RET_STATUS(0);
6733 //CLEAR_CF(); /* successful */
6734 //return;
6735 //break;
6736
6737 // should look at 40:8E also???
6738 status = inb(0x01f7);
6739 if ( (status & 0xc0) == 0x40 ) {
6740 SET_AH(0);
6741 SET_DISK_RET_STATUS(0);
6742 CLEAR_CF(); // drive ready
6743 return;
6744 }
6745 else {
6746 SET_AH(0xAA);
6747 SET_DISK_RET_STATUS(0xAA);
6748 SET_CF(); // not ready
6749 return;
6750 }
6751 break;
6752
6753 case 0x11: /* recalibrate */
6754BX_DEBUG_INT13_HD("int13_f11\n");
6755 SET_AH(0);
6756 SET_DISK_RET_STATUS(0);
6757 CLEAR_CF(); /* successful */
6758 return;
6759 break;
6760
6761 case 0x14: /* controller internal diagnostic */
6762BX_DEBUG_INT13_HD("int13_f14\n");
6763 SET_AH(0);
6764 SET_DISK_RET_STATUS(0);
6765 CLEAR_CF(); /* successful */
6766 SET_AL(0);
6767 return;
6768 break;
6769
6770 case 0x15: /* read disk drive size */
6771 drive = GET_ELDL();
6772 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6773ASM_START
6774 push bp
6775 mov bp, sp
6776 mov al, _int13_harddisk.hd_heads + 2 [bp]
6777 mov ah, _int13_harddisk.hd_sectors + 2 [bp]
6778 mul al, ah ;; ax = heads * sectors
6779 mov bx, _int13_harddisk.hd_cylinders + 2 [bp]
6780 dec bx ;; use (cylinders - 1) ???
6781 mul ax, bx ;; dx:ax = (cylinders -1) * (heads * sectors)
6782 ;; now we need to move the 32bit result dx:ax to what the
6783 ;; BIOS wants which is cx:dx.
6784 ;; and then into CX:DX on the stack
6785 mov _int13_harddisk.CX + 2 [bp], dx
6786 mov _int13_harddisk.DX + 2 [bp], ax
6787 pop bp
6788ASM_END
6789 SET_AH(3); // hard disk accessible
6790 SET_DISK_RET_STATUS(0); // ??? should this be 0
6791 CLEAR_CF(); // successful
6792 return;
6793 break;
6794
6795 case 0x18: // set media type for format
6796 case 0x41: // IBM/MS
6797 case 0x42: // IBM/MS
6798 case 0x43: // IBM/MS
6799 case 0x44: // IBM/MS
6800 case 0x45: // IBM/MS lock/unlock drive
6801 case 0x46: // IBM/MS eject media
6802 case 0x47: // IBM/MS extended seek
6803 case 0x49: // IBM/MS extended media change
6804 case 0x50: // IBM/MS send packet command
6805 default:
6806 BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
6807
6808 SET_AH(1); // code=invalid function in AH or invalid parameter
6809 SET_DISK_RET_STATUS(1);
6810 SET_CF(); /* unsuccessful */
6811 return;
6812 break;
6813 }
6814}
6815
6816static char panic_msg_reg12h[] = "HD%d cmos reg 12h not type F\n";
6817static char panic_msg_reg19h[] = "HD%d cmos reg %02xh not user definable type 47\n";
6818
6819 void
6820get_hd_geometry(drive, hd_cylinders, hd_heads, hd_sectors)
6821 Bit8u drive;
6822 Bit16u *hd_cylinders;
6823 Bit8u *hd_heads;
6824 Bit8u *hd_sectors;
6825{
6826 Bit8u hd_type;
6827 Bit16u ss;
6828 Bit16u cylinders;
6829 Bit8u iobase;
6830
6831 ss = get_SS();
6832 if (drive == 0x80) {
6833 hd_type = inb_cmos(0x12) & 0xf0;
6834 if (hd_type != 0xf0)
6835 BX_INFO(panic_msg_reg12h,0);
6836 hd_type = inb_cmos(0x19); // HD0: extended type
6837 if (hd_type != 47)
6838 BX_INFO(panic_msg_reg19h,0,0x19);
6839 iobase = 0x1b;
6840 } else {
6841 hd_type = inb_cmos(0x12) & 0x0f;
6842 if (hd_type != 0x0f)
6843 BX_INFO(panic_msg_reg12h,1);
6844 hd_type = inb_cmos(0x1a); // HD0: extended type
6845 if (hd_type != 47)
6846 BX_INFO(panic_msg_reg19h,0,0x1a);
6847 iobase = 0x24;
6848 }
6849
6850 // cylinders
6851 cylinders = inb_cmos(iobase) | (inb_cmos(iobase+1) << 8);
6852 write_word(ss, hd_cylinders, cylinders);
6853
6854 // heads
6855 write_byte(ss, hd_heads, inb_cmos(iobase+2));
6856
6857 // sectors per track
6858 write_byte(ss, hd_sectors, inb_cmos(iobase+8));
6859}
6860
6861#endif //else BX_USE_ATADRV
6862
6863
6864//////////////////////
6865// FLOPPY functions //
6866//////////////////////
6867
6868void floppy_reset_controller()
6869{
6870 Bit8u val8;
6871
6872 // Reset controller
6873 val8 = inb(0x03f2);
6874 outb(0x03f2, val8 & ~0x04);
6875 outb(0x03f2, val8 | 0x04);
6876
6877 // Wait for controller to come out of reset
6878 do {
6879 val8 = inb(0x3f4);
6880 } while ( (val8 & 0xc0) != 0x80 );
6881}
6882
6883void floppy_prepare_controller(drive)
6884 Bit16u drive;
6885{
6886 Bit8u val8, dor, prev_reset;
6887
6888 // set 40:3e bit 7 to 0
6889 val8 = read_byte(0x0040, 0x003e);
6890 val8 &= 0x7f;
6891 write_byte(0x0040, 0x003e, val8);
6892
6893 // turn on motor of selected drive, DMA & int enabled, normal operation
6894 prev_reset = inb(0x03f2) & 0x04;
6895 if (drive)
6896 dor = 0x20;
6897 else
6898 dor = 0x10;
6899 dor |= 0x0c;
6900 dor |= drive;
6901 outb(0x03f2, dor);
6902
6903 // reset the disk motor timeout value of INT 08
6904 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
6905
6906 // wait for drive readiness
6907 do {
6908 val8 = inb(0x3f4);
6909 } while ( (val8 & 0xc0) != 0x80 );
6910
6911 if (prev_reset == 0) {
6912 // turn on interrupts
6913ASM_START
6914 sti
6915ASM_END
6916 // wait on 40:3e bit 7 to become 1
6917 do {
6918 val8 = read_byte(0x0040, 0x003e);
6919 } while ( (val8 & 0x80) == 0 );
6920 val8 &= 0x7f;
6921ASM_START
6922 cli
6923ASM_END
6924 write_byte(0x0040, 0x003e, val8);
6925 }
6926}
6927
6928 bx_bool
6929floppy_media_known(drive)
6930 Bit16u drive;
6931{
6932 Bit8u val8;
6933 Bit16u media_state_offset;
6934
6935 val8 = read_byte(0x0040, 0x003e); // diskette recal status
6936 if (drive)
6937 val8 >>= 1;
6938 val8 &= 0x01;
6939 if (val8 == 0)
6940 return(0);
6941
6942 media_state_offset = 0x0090;
6943 if (drive)
6944 media_state_offset += 1;
6945
6946 val8 = read_byte(0x0040, media_state_offset);
6947 val8 = (val8 >> 4) & 0x01;
6948 if (val8 == 0)
6949 return(0);
6950
6951 // check pass, return KNOWN
6952 return(1);
6953}
6954
6955 bx_bool
6956floppy_media_sense(drive)
6957 Bit16u drive;
6958{
6959 bx_bool retval;
6960 Bit16u media_state_offset;
6961 Bit8u drive_type, config_data, media_state;
6962
6963 if (floppy_drive_recal(drive) == 0) {
6964 return(0);
6965 }
6966
6967 // for now cheat and get drive type from CMOS,
6968 // assume media is same as drive type
6969
6970 // ** config_data **
6971 // Bitfields for diskette media control:
6972 // Bit(s) Description (Table M0028)
6973 // 7-6 last data rate set by controller
6974 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6975 // 5-4 last diskette drive step rate selected
6976 // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
6977 // 3-2 {data rate at start of operation}
6978 // 1-0 reserved
6979
6980 // ** media_state **
6981 // Bitfields for diskette drive media state:
6982 // Bit(s) Description (Table M0030)
6983 // 7-6 data rate
6984 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6985 // 5 double stepping required (e.g. 360kB in 1.2MB)
6986 // 4 media type established
6987 // 3 drive capable of supporting 4MB media
6988 // 2-0 on exit from BIOS, contains
6989 // 000 trying 360kB in 360kB
6990 // 001 trying 360kB in 1.2MB
6991 // 010 trying 1.2MB in 1.2MB
6992 // 011 360kB in 360kB established
6993 // 100 360kB in 1.2MB established
6994 // 101 1.2MB in 1.2MB established
6995 // 110 reserved
6996 // 111 all other formats/drives
6997
6998 drive_type = inb_cmos(0x10);
6999 if (drive == 0)
7000 drive_type >>= 4;
7001 else
7002 drive_type &= 0x0f;
7003 if ( drive_type == 1 ) {
7004 // 360K 5.25" drive
7005 config_data = 0x00; // 0000 0000
7006 media_state = 0x25; // 0010 0101
7007 retval = 1;
7008 }
7009 else if ( drive_type == 2 ) {
7010 // 1.2 MB 5.25" drive
7011 config_data = 0x00; // 0000 0000
7012 media_state = 0x25; // 0010 0101 // need double stepping??? (bit 5)
7013 retval = 1;
7014 }
7015 else if ( drive_type == 3 ) {
7016 // 720K 3.5" drive
7017 config_data = 0x00; // 0000 0000 ???
7018 media_state = 0x17; // 0001 0111
7019 retval = 1;
7020 }
7021 else if ( drive_type == 4 ) {
7022 // 1.44 MB 3.5" drive
7023 config_data = 0x00; // 0000 0000
7024 media_state = 0x17; // 0001 0111
7025 retval = 1;
7026 }
7027 else if ( drive_type == 5 ) {
7028 // 2.88 MB 3.5" drive
7029 config_data = 0xCC; // 1100 1100
7030 media_state = 0xD7; // 1101 0111
7031 retval = 1;
7032 }
7033 //
7034 // Extended floppy size uses special cmos setting
7035 else if ( drive_type == 6 ) {
7036 // 160k 5.25" drive
7037 config_data = 0x00; // 0000 0000
7038 media_state = 0x27; // 0010 0111
7039 retval = 1;
7040 }
7041 else if ( drive_type == 7 ) {
7042 // 180k 5.25" drive
7043 config_data = 0x00; // 0000 0000
7044 media_state = 0x27; // 0010 0111
7045 retval = 1;
7046 }
7047 else if ( drive_type == 8 ) {
7048 // 320k 5.25" drive
7049 config_data = 0x00; // 0000 0000
7050 media_state = 0x27; // 0010 0111
7051 retval = 1;
7052 }
7053
7054 else {
7055 // not recognized
7056 config_data = 0x00; // 0000 0000
7057 media_state = 0x00; // 0000 0000
7058 retval = 0;
7059 }
7060
7061 if (drive == 0)
7062 media_state_offset = 0x90;
7063 else
7064 media_state_offset = 0x91;
7065 write_byte(0x0040, 0x008B, config_data);
7066 write_byte(0x0040, media_state_offset, media_state);
7067
7068 return(retval);
7069}
7070
7071 bx_bool
7072floppy_drive_recal(drive)
7073 Bit16u drive;
7074{
7075 Bit8u val8;
7076 Bit16u curr_cyl_offset;
7077
7078 floppy_prepare_controller(drive);
7079
7080 // send Recalibrate command (2 bytes) to controller
7081 outb(0x03f5, 0x07); // 07: Recalibrate
7082 outb(0x03f5, drive); // 0=drive0, 1=drive1
7083
7084 // turn on interrupts
7085ASM_START
7086 sti
7087ASM_END
7088
7089 // wait on 40:3e bit 7 to become 1
7090 do {
7091 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7092 } while ( val8 == 0 );
7093
7094 val8 = 0; // separate asm from while() loop
7095 // turn off interrupts
7096ASM_START
7097 cli
7098ASM_END
7099
7100 // set 40:3e bit 7 to 0, and calibrated bit
7101 val8 = read_byte(0x0040, 0x003e);
7102 val8 &= 0x7f;
7103 if (drive) {
7104 val8 |= 0x02; // Drive 1 calibrated
7105 curr_cyl_offset = 0x0095;
7106 } else {
7107 val8 |= 0x01; // Drive 0 calibrated
7108 curr_cyl_offset = 0x0094;
7109 }
7110 write_byte(0x0040, 0x003e, val8);
7111 write_byte(0x0040, curr_cyl_offset, 0); // current cylinder is 0
7112
7113 return(1);
7114}
7115
7116
7117
7118 bx_bool
7119floppy_drive_exists(drive)
7120 Bit16u drive;
7121{
7122 Bit8u drive_type;
7123
7124 // check CMOS to see if drive exists
7125 drive_type = inb_cmos(0x10);
7126 if (drive == 0)
7127 drive_type >>= 4;
7128 else
7129 drive_type &= 0x0f;
7130 if ( drive_type == 0 )
7131 return(0);
7132 else
7133 return(1);
7134}
7135
7136#if BX_SUPPORT_FLOPPY
7137 void
7138int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
7139 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
7140{
7141 Bit8u drive, num_sectors, track, sector, head, status;
7142 Bit16u base_address, base_count, base_es;
7143 Bit8u page, mode_register, val8, dor;
7144 Bit8u return_status[7];
7145 Bit8u drive_type, num_floppies, ah;
7146 Bit16u es, last_addr;
7147
7148 BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
7149
7150 ah = GET_AH();
7151
7152 switch ( ah ) {
7153 case 0x00: // diskette controller reset
7154BX_DEBUG_INT13_FL("floppy f00\n");
7155 drive = GET_ELDL();
7156 if (drive > 1) {
7157 SET_AH(1); // invalid param
7158 set_diskette_ret_status(1);
7159 SET_CF();
7160 return;
7161 }
7162 drive_type = inb_cmos(0x10);
7163
7164 if (drive == 0)
7165 drive_type >>= 4;
7166 else
7167 drive_type &= 0x0f;
7168 if (drive_type == 0) {
7169 SET_AH(0x80); // drive not responding
7170 set_diskette_ret_status(0x80);
7171 SET_CF();
7172 return;
7173 }
7174 SET_AH(0);
7175 set_diskette_ret_status(0);
7176 CLEAR_CF(); // successful
7177 set_diskette_current_cyl(drive, 0); // current cylinder
7178 return;
7179
7180 case 0x01: // Read Diskette Status
7181 CLEAR_CF();
7182 val8 = read_byte(0x0000, 0x0441);
7183 SET_AH(val8);
7184 if (val8) {
7185 SET_CF();
7186 }
7187 return;
7188
7189 case 0x02: // Read Diskette Sectors
7190 case 0x03: // Write Diskette Sectors
7191 case 0x04: // Verify Diskette Sectors
7192 num_sectors = GET_AL();
7193 track = GET_CH();
7194 sector = GET_CL();
7195 head = GET_DH();
7196 drive = GET_ELDL();
7197
7198 if ( (drive > 1) || (head > 1) ||
7199 (num_sectors == 0) || (num_sectors > 72) ) {
7200BX_INFO("floppy: drive>1 || head>1 ...\n");
7201 SET_AH(1);
7202 set_diskette_ret_status(1);
7203 SET_AL(0); // no sectors read
7204 SET_CF(); // error occurred
7205 return;
7206 }
7207
7208 // see if drive exists
7209 if (floppy_drive_exists(drive) == 0) {
7210 SET_AH(0x80); // not responding
7211 set_diskette_ret_status(0x80);
7212 SET_AL(0); // no sectors read
7213 SET_CF(); // error occurred
7214 return;
7215 }
7216
7217 // see if media in drive, and type is known
7218 if (floppy_media_known(drive) == 0) {
7219 if (floppy_media_sense(drive) == 0) {
7220 SET_AH(0x0C); // Media type not found
7221 set_diskette_ret_status(0x0C);
7222 SET_AL(0); // no sectors read
7223 SET_CF(); // error occurred
7224 return;
7225 }
7226 }
7227
7228 if (ah == 0x02) {
7229 // Read Diskette Sectors
7230
7231 //-----------------------------------
7232 // set up DMA controller for transfer
7233 //-----------------------------------
7234
7235 // es:bx = pointer to where to place information from diskette
7236 // port 04: DMA-1 base and current address, channel 2
7237 // port 05: DMA-1 base and current count, channel 2
7238 page = (ES >> 12); // upper 4 bits
7239 base_es = (ES << 4); // lower 16bits contributed by ES
7240 base_address = base_es + BX; // lower 16 bits of address
7241 // contributed by ES:BX
7242 if ( base_address < base_es ) {
7243 // in case of carry, adjust page by 1
7244 page++;
7245 }
7246 base_count = (num_sectors * 512) - 1;
7247
7248 // check for 64K boundary overrun
7249 last_addr = base_address + base_count;
7250 if (last_addr < base_address) {
7251 SET_AH(0x09);
7252 set_diskette_ret_status(0x09);
7253 SET_AL(0); // no sectors read
7254 SET_CF(); // error occurred
7255 return;
7256 }
7257
7258 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7259 outb(0x000a, 0x06);
7260
7261 BX_DEBUG_INT13_FL("clear flip-flop\n");
7262 outb(0x000c, 0x00); // clear flip-flop
7263 outb(0x0004, base_address);
7264 outb(0x0004, base_address>>8);
7265 BX_DEBUG_INT13_FL("clear flip-flop\n");
7266 outb(0x000c, 0x00); // clear flip-flop
7267 outb(0x0005, base_count);
7268 outb(0x0005, base_count>>8);
7269
7270 // port 0b: DMA-1 Mode Register
7271 mode_register = 0x46; // single mode, increment, autoinit disable,
7272 // transfer type=write, channel 2
7273 BX_DEBUG_INT13_FL("setting mode register\n");
7274 outb(0x000b, mode_register);
7275
7276 BX_DEBUG_INT13_FL("setting page register\n");
7277 // port 81: DMA-1 Page Register, channel 2
7278 outb(0x0081, page);
7279
7280 BX_DEBUG_INT13_FL("unmask chan 2\n");
7281 outb(0x000a, 0x02); // unmask channel 2
7282
7283 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7284 outb(0x000a, 0x02);
7285
7286 //--------------------------------------
7287 // set up floppy controller for transfer
7288 //--------------------------------------
7289 floppy_prepare_controller(drive);
7290
7291 // send read-normal-data command (9 bytes) to controller
7292 outb(0x03f5, 0xe6); // e6: read normal data
7293 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7294 outb(0x03f5, track);
7295 outb(0x03f5, head);
7296 outb(0x03f5, sector);
7297 outb(0x03f5, 2); // 512 byte sector size
7298 outb(0x03f5, sector + num_sectors - 1); // last sector to read on track
7299 outb(0x03f5, 0); // Gap length
7300 outb(0x03f5, 0xff); // Gap length
7301
7302 // turn on interrupts
7303 ASM_START
7304 sti
7305 ASM_END
7306
7307 // wait on 40:3e bit 7 to become 1
7308 do {
7309 val8 = read_byte(0x0040, 0x0040);
7310 if (val8 == 0) {
7311 floppy_reset_controller();
7312 SET_AH(0x80); // drive not ready (timeout)
7313 set_diskette_ret_status(0x80);
7314 SET_AL(0); // no sectors read
7315 SET_CF(); // error occurred
7316 return;
7317 }
7318 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7319 } while ( val8 == 0 );
7320
7321 val8 = 0; // separate asm from while() loop
7322 // turn off interrupts
7323 ASM_START
7324 cli
7325 ASM_END
7326
7327 // set 40:3e bit 7 to 0
7328 val8 = read_byte(0x0040, 0x003e);
7329 val8 &= 0x7f;
7330 write_byte(0x0040, 0x003e, val8);
7331
7332 // check port 3f4 for accessibility to status bytes
7333 val8 = inb(0x3f4);
7334 if ( (val8 & 0xc0) != 0xc0 )
7335 BX_PANIC("int13_diskette: ctrl not ready\n");
7336
7337 // read 7 return status bytes from controller
7338 // using loop index broken, have to unroll...
7339 return_status[0] = inb(0x3f5);
7340 return_status[1] = inb(0x3f5);
7341 return_status[2] = inb(0x3f5);
7342 return_status[3] = inb(0x3f5);
7343 return_status[4] = inb(0x3f5);
7344 return_status[5] = inb(0x3f5);
7345 return_status[6] = inb(0x3f5);
7346 // record in BIOS Data Area
7347 write_byte(0x0040, 0x0042, return_status[0]);
7348 write_byte(0x0040, 0x0043, return_status[1]);
7349 write_byte(0x0040, 0x0044, return_status[2]);
7350 write_byte(0x0040, 0x0045, return_status[3]);
7351 write_byte(0x0040, 0x0046, return_status[4]);
7352 write_byte(0x0040, 0x0047, return_status[5]);
7353 write_byte(0x0040, 0x0048, return_status[6]);
7354
7355 if ( (return_status[0] & 0xc0) != 0 ) {
7356 SET_AH(0x20);
7357 set_diskette_ret_status(0x20);
7358 SET_AL(0); // no sectors read
7359 SET_CF(); // error occurred
7360 return;
7361 }
7362
7363 // ??? should track be new val from return_status[3] ?
7364 set_diskette_current_cyl(drive, track);
7365 // AL = number of sectors read (same value as passed)
7366 SET_AH(0x00); // success
7367 CLEAR_CF(); // success
7368 return;
7369 } else if (ah == 0x03) {
7370 // Write Diskette Sectors
7371
7372 //-----------------------------------
7373 // set up DMA controller for transfer
7374 //-----------------------------------
7375
7376 // es:bx = pointer to where to place information from diskette
7377 // port 04: DMA-1 base and current address, channel 2
7378 // port 05: DMA-1 base and current count, channel 2
7379 page = (ES >> 12); // upper 4 bits
7380 base_es = (ES << 4); // lower 16bits contributed by ES
7381 base_address = base_es + BX; // lower 16 bits of address
7382 // contributed by ES:BX
7383 if ( base_address < base_es ) {
7384 // in case of carry, adjust page by 1
7385 page++;
7386 }
7387 base_count = (num_sectors * 512) - 1;
7388
7389 // check for 64K boundary overrun
7390 last_addr = base_address + base_count;
7391 if (last_addr < base_address) {
7392 SET_AH(0x09);
7393 set_diskette_ret_status(0x09);
7394 SET_AL(0); // no sectors read
7395 SET_CF(); // error occurred
7396 return;
7397 }
7398
7399 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7400 outb(0x000a, 0x06);
7401
7402 outb(0x000c, 0x00); // clear flip-flop
7403 outb(0x0004, base_address);
7404 outb(0x0004, base_address>>8);
7405 outb(0x000c, 0x00); // clear flip-flop
7406 outb(0x0005, base_count);
7407 outb(0x0005, base_count>>8);
7408
7409 // port 0b: DMA-1 Mode Register
7410 mode_register = 0x4a; // single mode, increment, autoinit disable,
7411 // transfer type=read, channel 2
7412 outb(0x000b, mode_register);
7413
7414 // port 81: DMA-1 Page Register, channel 2
7415 outb(0x0081, page);
7416
7417 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7418 outb(0x000a, 0x02);
7419
7420 //--------------------------------------
7421 // set up floppy controller for transfer
7422 //--------------------------------------
7423 floppy_prepare_controller(drive);
7424
7425 // send write-normal-data command (9 bytes) to controller
7426 outb(0x03f5, 0xc5); // c5: write normal data
7427 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7428 outb(0x03f5, track);
7429 outb(0x03f5, head);
7430 outb(0x03f5, sector);
7431 outb(0x03f5, 2); // 512 byte sector size
7432 outb(0x03f5, sector + num_sectors - 1); // last sector to write on track
7433 outb(0x03f5, 0); // Gap length
7434 outb(0x03f5, 0xff); // Gap length
7435
7436 // turn on interrupts
7437 ASM_START
7438 sti
7439 ASM_END
7440
7441 // wait on 40:3e bit 7 to become 1
7442 do {
7443 val8 = read_byte(0x0040, 0x0040);
7444 if (val8 == 0) {
7445 floppy_reset_controller();
7446 SET_AH(0x80); // drive not ready (timeout)
7447 set_diskette_ret_status(0x80);
7448 SET_AL(0); // no sectors written
7449 SET_CF(); // error occurred
7450 return;
7451 }
7452 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7453 } while ( val8 == 0 );
7454
7455 val8 = 0; // separate asm from while() loop
7456 // turn off interrupts
7457 ASM_START
7458 cli
7459 ASM_END
7460
7461 // set 40:3e bit 7 to 0
7462 val8 = read_byte(0x0040, 0x003e);
7463 val8 &= 0x7f;
7464 write_byte(0x0040, 0x003e, val8);
7465
7466 // check port 3f4 for accessibility to status bytes
7467 val8 = inb(0x3f4);
7468 if ( (val8 & 0xc0) != 0xc0 )
7469 BX_PANIC("int13_diskette: ctrl not ready\n");
7470
7471 // read 7 return status bytes from controller
7472 // using loop index broken, have to unroll...
7473 return_status[0] = inb(0x3f5);
7474 return_status[1] = inb(0x3f5);
7475 return_status[2] = inb(0x3f5);
7476 return_status[3] = inb(0x3f5);
7477 return_status[4] = inb(0x3f5);
7478 return_status[5] = inb(0x3f5);
7479 return_status[6] = inb(0x3f5);
7480 // record in BIOS Data Area
7481 write_byte(0x0040, 0x0042, return_status[0]);
7482 write_byte(0x0040, 0x0043, return_status[1]);
7483 write_byte(0x0040, 0x0044, return_status[2]);
7484 write_byte(0x0040, 0x0045, return_status[3]);
7485 write_byte(0x0040, 0x0046, return_status[4]);
7486 write_byte(0x0040, 0x0047, return_status[5]);
7487 write_byte(0x0040, 0x0048, return_status[6]);
7488
7489 if ( (return_status[0] & 0xc0) != 0 ) {
7490 if ( (return_status[1] & 0x02) != 0 ) {
7491 // diskette not writable.
7492 // AH=status code=0x03 (tried to write on write-protected disk)
7493 // AL=number of sectors written=0
7494 AX = 0x0300;
7495 SET_CF();
7496 return;
7497 } else {
7498 BX_PANIC("int13_diskette_function: read error\n");
7499 }
7500 }
7501
7502 // ??? should track be new val from return_status[3] ?
7503 set_diskette_current_cyl(drive, track);
7504 // AL = number of sectors read (same value as passed)
7505 SET_AH(0x00); // success
7506 CLEAR_CF(); // success
7507 return;
7508 } else { // if (ah == 0x04)
7509 // Verify Diskette Sectors
7510
7511 // ??? should track be new val from return_status[3] ?
7512 set_diskette_current_cyl(drive, track);
7513 // AL = number of sectors verified (same value as passed)
7514 CLEAR_CF(); // success
7515 SET_AH(0x00); // success
7516 return;
7517 }
7518 break;
7519
7520 case 0x05: // format diskette track
7521BX_DEBUG_INT13_FL("floppy f05\n");
7522
7523 num_sectors = GET_AL();
7524 track = GET_CH();
7525 head = GET_DH();
7526 drive = GET_ELDL();
7527
7528 if ((drive > 1) || (head > 1) || (track > 79) ||
7529 (num_sectors == 0) || (num_sectors > 18)) {
7530 SET_AH(1);
7531 set_diskette_ret_status(1);
7532 SET_CF(); // error occurred
7533 }
7534
7535 // see if drive exists
7536 if (floppy_drive_exists(drive) == 0) {
7537 SET_AH(0x80); // drive not responding
7538 set_diskette_ret_status(0x80);
7539 SET_CF(); // error occurred
7540 return;
7541 }
7542
7543 // see if media in drive, and type is known
7544 if (floppy_media_known(drive) == 0) {
7545 if (floppy_media_sense(drive) == 0) {
7546 SET_AH(0x0C); // Media type not found
7547 set_diskette_ret_status(0x0C);
7548 SET_AL(0); // no sectors read
7549 SET_CF(); // error occurred
7550 return;
7551 }
7552 }
7553
7554 // set up DMA controller for transfer
7555 page = (ES >> 12); // upper 4 bits
7556 base_es = (ES << 4); // lower 16bits contributed by ES
7557 base_address = base_es + BX; // lower 16 bits of address
7558 // contributed by ES:BX
7559 if ( base_address < base_es ) {
7560 // in case of carry, adjust page by 1
7561 page++;
7562 }
7563 base_count = (num_sectors * 4) - 1;
7564
7565 // check for 64K boundary overrun
7566 last_addr = base_address + base_count;
7567 if (last_addr < base_address) {
7568 SET_AH(0x09);
7569 set_diskette_ret_status(0x09);
7570 SET_AL(0); // no sectors read
7571 SET_CF(); // error occurred
7572 return;
7573 }
7574
7575 outb(0x000a, 0x06);
7576 outb(0x000c, 0x00); // clear flip-flop
7577 outb(0x0004, base_address);
7578 outb(0x0004, base_address>>8);
7579 outb(0x000c, 0x00); // clear flip-flop
7580 outb(0x0005, base_count);
7581 outb(0x0005, base_count>>8);
7582 mode_register = 0x4a; // single mode, increment, autoinit disable,
7583 // transfer type=read, channel 2
7584 outb(0x000b, mode_register);
7585 // port 81: DMA-1 Page Register, channel 2
7586 outb(0x0081, page);
7587 outb(0x000a, 0x02);
7588
7589 // set up floppy controller for transfer
7590 floppy_prepare_controller(drive);
7591
7592 // send format-track command (6 bytes) to controller
7593 outb(0x03f5, 0x4d); // 4d: format track
7594 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7595 outb(0x03f5, 2); // 512 byte sector size
7596 outb(0x03f5, num_sectors); // number of sectors per track
7597 outb(0x03f5, 0); // Gap length
7598 outb(0x03f5, 0xf6); // Fill byte
7599 // turn on interrupts
7600 ASM_START
7601 sti
7602 ASM_END
7603
7604 // wait on 40:3e bit 7 to become 1
7605 do {
7606 val8 = read_byte(0x0040, 0x0040);
7607 if (val8 == 0) {
7608 floppy_reset_controller();
7609 SET_AH(0x80); // drive not ready (timeout)
7610 set_diskette_ret_status(0x80);
7611 SET_CF(); // error occurred
7612 return;
7613 }
7614 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7615 } while ( val8 == 0 );
7616
7617 val8 = 0; // separate asm from while() loop
7618 // turn off interrupts
7619 ASM_START
7620 cli
7621 ASM_END
7622 // set 40:3e bit 7 to 0
7623 val8 = read_byte(0x0040, 0x003e);
7624 val8 &= 0x7f;
7625 write_byte(0x0040, 0x003e, val8);
7626 // check port 3f4 for accessibility to status bytes
7627 val8 = inb(0x3f4);
7628 if ( (val8 & 0xc0) != 0xc0 )
7629 BX_PANIC("int13_diskette: ctrl not ready\n");
7630
7631 // read 7 return status bytes from controller
7632 // using loop index broken, have to unroll...
7633 return_status[0] = inb(0x3f5);
7634 return_status[1] = inb(0x3f5);
7635 return_status[2] = inb(0x3f5);
7636 return_status[3] = inb(0x3f5);
7637 return_status[4] = inb(0x3f5);
7638 return_status[5] = inb(0x3f5);
7639 return_status[6] = inb(0x3f5);
7640 // record in BIOS Data Area
7641 write_byte(0x0040, 0x0042, return_status[0]);
7642 write_byte(0x0040, 0x0043, return_status[1]);
7643 write_byte(0x0040, 0x0044, return_status[2]);
7644 write_byte(0x0040, 0x0045, return_status[3]);
7645 write_byte(0x0040, 0x0046, return_status[4]);
7646 write_byte(0x0040, 0x0047, return_status[5]);
7647 write_byte(0x0040, 0x0048, return_status[6]);
7648
7649 if ( (return_status[0] & 0xc0) != 0 ) {
7650 if ( (return_status[1] & 0x02) != 0 ) {
7651 // diskette not writable.
7652 // AH=status code=0x03 (tried to write on write-protected disk)
7653 // AL=number of sectors written=0
7654 AX = 0x0300;
7655 SET_CF();
7656 return;
7657 } else {
7658 BX_PANIC("int13_diskette_function: write error\n");
7659 }
7660 }
7661
7662 SET_AH(0);
7663 set_diskette_ret_status(0);
7664 set_diskette_current_cyl(drive, 0);
7665 CLEAR_CF(); // successful
7666 return;
7667
7668
7669 case 0x08: // read diskette drive parameters
7670BX_DEBUG_INT13_FL("floppy f08\n");
7671 drive = GET_ELDL();
7672
7673 if (drive > 1) {
7674 AX = 0;
7675 BX = 0;
7676 CX = 0;
7677 DX = 0;
7678 ES = 0;
7679 DI = 0;
7680 SET_DL(num_floppies);
7681 SET_CF();
7682 return;
7683 }
7684
7685 drive_type = inb_cmos(0x10);
7686 num_floppies = 0;
7687 if (drive_type & 0xf0)
7688 num_floppies++;
7689 if (drive_type & 0x0f)
7690 num_floppies++;
7691
7692 if (drive == 0)
7693 drive_type >>= 4;
7694 else
7695 drive_type &= 0x0f;
7696
7697 SET_BH(0);
7698 SET_BL(drive_type);
7699 SET_AH(0);
7700 SET_AL(0);
7701 SET_DL(num_floppies);
7702
7703 switch (drive_type) {
7704 case 0: // none
7705 CX = 0;
7706 SET_DH(0); // max head #
7707 break;
7708
7709 case 1: // 360KB, 5.25"
7710 CX = 0x2709; // 40 tracks, 9 sectors
7711 SET_DH(1); // max head #
7712 break;
7713
7714 case 2: // 1.2MB, 5.25"
7715 CX = 0x4f0f; // 80 tracks, 15 sectors
7716 SET_DH(1); // max head #
7717 break;
7718
7719 case 3: // 720KB, 3.5"
7720 CX = 0x4f09; // 80 tracks, 9 sectors
7721 SET_DH(1); // max head #
7722 break;
7723
7724 case 4: // 1.44MB, 3.5"
7725 CX = 0x4f12; // 80 tracks, 18 sectors
7726 SET_DH(1); // max head #
7727 break;
7728
7729 case 5: // 2.88MB, 3.5"
7730 CX = 0x4f24; // 80 tracks, 36 sectors
7731 SET_DH(1); // max head #
7732 break;
7733
7734 case 6: // 160k, 5.25"
7735 CX = 0x2708; // 40 tracks, 8 sectors
7736 SET_DH(0); // max head #
7737 break;
7738
7739 case 7: // 180k, 5.25"
7740 CX = 0x2709; // 40 tracks, 9 sectors
7741 SET_DH(0); // max head #
7742 break;
7743
7744 case 8: // 320k, 5.25"
7745 CX = 0x2708; // 40 tracks, 8 sectors
7746 SET_DH(1); // max head #
7747 break;
7748
7749 default: // ?
7750 BX_PANIC("floppy: int13: bad floppy type\n");
7751 }
7752
7753 /* set es & di to point to 11 byte diskette param table in ROM */
7754ASM_START
7755 push bp
7756 mov bp, sp
7757 mov ax, #diskette_param_table2
7758 mov _int13_diskette_function.DI+2[bp], ax
7759 mov _int13_diskette_function.ES+2[bp], cs
7760 pop bp
7761ASM_END
7762 CLEAR_CF(); // success
7763 /* disk status not changed upon success */
7764 return;
7765
7766
7767 case 0x15: // read diskette drive type
7768BX_DEBUG_INT13_FL("floppy f15\n");
7769 drive = GET_ELDL();
7770 if (drive > 1) {
7771 SET_AH(0); // only 2 drives supported
7772 // set_diskette_ret_status here ???
7773 SET_CF();
7774 return;
7775 }
7776 drive_type = inb_cmos(0x10);
7777
7778 if (drive == 0)
7779 drive_type >>= 4;
7780 else
7781 drive_type &= 0x0f;
7782 CLEAR_CF(); // successful, not present
7783 if (drive_type==0) {
7784 SET_AH(0); // drive not present
7785 }
7786 else {
7787 SET_AH(1); // drive present, does not support change line
7788 }
7789
7790 return;
7791
7792 case 0x16: // get diskette change line status
7793BX_DEBUG_INT13_FL("floppy f16\n");
7794 drive = GET_ELDL();
7795 if (drive > 1) {
7796 SET_AH(0x01); // invalid drive
7797 set_diskette_ret_status(0x01);
7798 SET_CF();
7799 return;
7800 }
7801
7802 SET_AH(0x06); // change line not supported
7803 set_diskette_ret_status(0x06);
7804 SET_CF();
7805 return;
7806
7807 case 0x17: // set diskette type for format(old)
7808BX_DEBUG_INT13_FL("floppy f17\n");
7809 /* not used for 1.44M floppies */
7810 SET_AH(0x01); // not supported
7811 set_diskette_ret_status(1); /* not supported */
7812 SET_CF();
7813 return;
7814
7815 case 0x18: // set diskette type for format(new)
7816BX_DEBUG_INT13_FL("floppy f18\n");
7817 SET_AH(0x01); // do later
7818 set_diskette_ret_status(1);
7819 SET_CF();
7820 return;
7821
7822 default:
7823 BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
7824
7825 // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
7826 SET_AH(0x01); // ???
7827 set_diskette_ret_status(1);
7828 SET_CF();
7829 return;
7830 // }
7831 }
7832}
7833#else // #if BX_SUPPORT_FLOPPY
7834 void
7835int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
7836 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
7837{
7838 Bit8u val8;
7839
7840 switch ( GET_AH() ) {
7841
7842 case 0x01: // Read Diskette Status
7843 CLEAR_CF();
7844 val8 = read_byte(0x0000, 0x0441);
7845 SET_AH(val8);
7846 if (val8) {
7847 SET_CF();
7848 }
7849 return;
7850
7851 default:
7852 SET_CF();
7853 write_byte(0x0000, 0x0441, 0x01);
7854 SET_AH(0x01);
7855 }
7856}
7857#endif // #if BX_SUPPORT_FLOPPY
7858
7859 void
7860set_diskette_ret_status(value)
7861 Bit8u value;
7862{
7863 write_byte(0x0040, 0x0041, value);
7864}
7865
7866 void
7867set_diskette_current_cyl(drive, cyl)
7868 Bit8u drive;
7869 Bit8u cyl;
7870{
7871 if (drive > 1)
7872 BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
7873 write_byte(0x0040, 0x0094+drive, cyl);
7874}
7875
7876 void
7877determine_floppy_media(drive)
7878 Bit16u drive;
7879{
7880#if 0
7881 Bit8u val8, DOR, ctrl_info;
7882
7883 ctrl_info = read_byte(0x0040, 0x008F);
7884 if (drive==1)
7885 ctrl_info >>= 4;
7886 else
7887 ctrl_info &= 0x0f;
7888
7889#if 0
7890 if (drive == 0) {
7891 DOR = 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
7892 }
7893 else {
7894 DOR = 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
7895 }
7896#endif
7897
7898 if ( (ctrl_info & 0x04) != 0x04 ) {
7899 // Drive not determined means no drive exists, done.
7900 return;
7901 }
7902
7903#if 0
7904 // check Main Status Register for readiness
7905 val8 = inb(0x03f4) & 0x80; // Main Status Register
7906 if (val8 != 0x80)
7907 BX_PANIC("d_f_m: MRQ bit not set\n");
7908
7909 // change line
7910
7911 // existing BDA values
7912
7913 // turn on drive motor
7914 outb(0x03f2, DOR); // Digital Output Register
7915 //
7916#endif
7917 BX_PANIC("d_f_m: OK so far\n");
7918#endif
7919}
7920
7921 void
7922int17_function(regs, ds, iret_addr)
7923 pusha_regs_t regs; // regs pushed from PUSHA instruction
7924 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
7925 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
7926{
7927 Bit16u addr,timeout;
7928 Bit8u val8;
7929
7930 ASM_START
7931 sti
7932 ASM_END
7933
7934 addr = read_word(0x0040, (regs.u.r16.dx << 1) + 8);
7935 if ((regs.u.r8.ah < 3) && (regs.u.r16.dx < 3) && (addr > 0)) {
7936 timeout = read_byte(0x0040, 0x0078 + regs.u.r16.dx) << 8;
7937 if (regs.u.r8.ah == 0) {
7938 outb(addr, regs.u.r8.al);
7939 val8 = inb(addr+2);
7940 outb(addr+2, val8 | 0x01); // send strobe
7941 ASM_START
7942 nop
7943 ASM_END
7944 outb(addr+2, val8 & ~0x01);
7945 while (((inb(addr+1) & 0x40) == 0x40) && (timeout)) {
7946 timeout--;
7947 }
7948 }
7949 if (regs.u.r8.ah == 1) {
7950 val8 = inb(addr+2);
7951 outb(addr+2, val8 & ~0x04); // send init
7952 ASM_START
7953 nop
7954 ASM_END
7955 outb(addr+2, val8 | 0x04);
7956 }
7957 val8 = inb(addr+1);
7958 regs.u.r8.ah = (val8 ^ 0x48);
7959 if (!timeout) regs.u.r8.ah |= 0x01;
7960 ClearCF(iret_addr.flags);
7961 } else {
7962 SetCF(iret_addr.flags); // Unsupported
7963 }
7964}
7965
7966// returns bootsegment in ax, drive in bl
7967 Bit32u
7968int19_function(bseqnr)
7969Bit8u bseqnr;
7970{
7971 Bit16u ebda_seg=read_word(0x0040,0x000E);
7972 Bit16u bootseq;
7973 Bit8u bootdrv;
7974 Bit8u bootcd;
7975#ifdef VBOX
7976 Bit8u bootlan;
7977#endif /* VBOX */
7978 Bit8u bootchk;
7979 Bit16u bootseg;
7980 Bit16u status;
7981 Bit8u lastdrive=0;
7982
7983 // if BX_ELTORITO_BOOT is not defined, old behavior
7984 // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
7985 // in preparation for the intial INT 13h (0=floppy A:, 0x80=C:)
7986 // 0: system boot sequence, first drive C: then A:
7987 // 1: system boot sequence, first drive A: then C:
7988 // else BX_ELTORITO_BOOT is defined
7989 // CMOS regs 0x3D and 0x38 contain the boot sequence:
7990 // CMOS reg 0x3D & 0x0f : 1st boot device
7991 // CMOS reg 0x3D & 0xf0 : 2nd boot device
7992 // CMOS reg 0x38 & 0xf0 : 3rd boot device
7993#ifdef VBOX
7994 // CMOS reg 0x3C & 0x0f : 4th boot device
7995#endif /* VBOX */
7996 // boot device codes:
7997 // 0x00 : not defined
7998 // 0x01 : first floppy
7999 // 0x02 : first harddrive
8000 // 0x03 : first cdrom
8001#ifdef VBOX
8002 // 0x04 : local area network
8003#endif /* VBOX */
8004 // else : boot failure
8005
8006 // Get the boot sequence
8007#if BX_ELTORITO_BOOT
8008 bootseq=inb_cmos(0x3d);
8009 bootseq|=((inb_cmos(0x38) & 0xf0) << 4);
8010#ifdef VBOX
8011 bootseq|=((inb_cmos(0x3c) & 0x0f) << 12);
8012 if (read_byte(ebda_seg, &EbdaData->uForceBootDrive))
8013 bootseq = read_byte(ebda_seg, &EbdaData->uForceBootDrive);
8014 /* Boot delay hack. */
8015 if (bseqnr == 1)
8016 delay_boot((inb_cmos(0x3c) & 0xf0) >> 4); /* Implemented in logo.c */
8017#endif /* VBOX */
8018
8019 if (bseqnr==2) bootseq >>= 4;
8020 if (bseqnr==3) bootseq >>= 8;
8021#ifdef VBOX
8022 if (bseqnr==4) bootseq >>= 12;
8023#endif /* VBOX */
8024 if (bootseq<0x10) lastdrive = 1;
8025 bootdrv=0x00; bootcd=0;
8026#ifdef VBOX
8027 bootlan=0;
8028#endif /* VBOX */
8029 switch(bootseq & 0x0f) {
8030 case 0x01: bootdrv=0x00; bootcd=0; break;
8031 case 0x02: bootdrv=0x80; bootcd=0; break;
8032 case 0x03: bootdrv=0x00; bootcd=1; break;
8033#ifdef VBOX
8034 case 0x04: bootlan=1; break;
8035#endif /* VBOX */
8036 default: return 0x00000000;
8037 }
8038#else
8039 bootseq=inb_cmos(0x2d);
8040
8041 if (bseqnr==2) {
8042 bootseq ^= 0x20;
8043 lastdrive = 1;
8044 }
8045 bootdrv=0x00; bootcd=0;
8046 if((bootseq&0x20)==0) bootdrv=0x80;
8047#endif // BX_ELTORITO_BOOT
8048
8049#if BX_ELTORITO_BOOT
8050 // We have to boot from cd
8051 if (bootcd != 0) {
8052 status = cdrom_boot();
8053
8054 // If failure
8055 if ( (status & 0x00ff) !=0 ) {
8056 print_cdromboot_failure(status);
8057#ifdef VBOX
8058 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
8059#else /* !VBOX */
8060 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
8061#endif /* !VBOX */
8062 return 0x00000000;
8063 }
8064
8065 bootseg = read_word(ebda_seg,&EbdaData->cdemu.load_segment);
8066 bootdrv = (Bit8u)(status>>8);
8067 }
8068
8069#endif // BX_ELTORITO_BOOT
8070
8071#ifdef VBOX
8072 // Check for boot from LAN first
8073 if (bootlan == 1) {
8074 if (read_word(VBOX_LANBOOT_SEG,0) == 0xaa55) {
8075 Bit16u pnpoff;
8076 // This is NOT a generic PnP implementation, but an Etherboot-specific hack.
8077 pnpoff = read_word(VBOX_LANBOOT_SEG,0x1a);
8078 if (read_dword(VBOX_LANBOOT_SEG,pnpoff) == 0x506e5024 &&
8079 read_dword(VBOX_LANBOOT_SEG,read_word(VBOX_LANBOOT_SEG,pnpoff+0xe)) == 0x65687445) {
8080 // Found PnP signature and Etherboot manufacturer string.
8081 print_boot_device(bootcd, bootlan, bootdrv);
8082ASM_START
8083 push ds
8084 push es
8085 pusha
8086 calli 0x0006,VBOX_LANBOOT_SEG
8087 popa
8088 pop es
8089 pop ds
8090ASM_END
8091 }
8092 }
8093
8094 // boot from LAN will not return if successful.
8095 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
8096 return 0x00000000;
8097 }
8098#endif /* VBOX */
8099 // We have to boot from harddisk or floppy
8100#ifdef VBOX
8101 if (bootcd == 0 && bootlan == 0) {
8102#else /* !VBOX */
8103 if (bootcd == 0) {
8104#endif /* !VBOX */
8105 bootseg=0x07c0;
8106
8107ASM_START
8108 push bp
8109 mov bp, sp
8110
8111 xor ax, ax
8112 mov _int19_function.status + 2[bp], ax
8113 mov dl, _int19_function.bootdrv + 2[bp]
8114 mov ax, _int19_function.bootseg + 2[bp]
8115 mov es, ax ;; segment
8116 xor bx, bx ;; offset
8117 mov ah, #0x02 ;; function 2, read diskette sector
8118 mov al, #0x01 ;; read 1 sector
8119 mov ch, #0x00 ;; track 0
8120 mov cl, #0x01 ;; sector 1
8121 mov dh, #0x00 ;; head 0
8122 int #0x13 ;; read sector
8123 jnc int19_load_done
8124 mov ax, #0x0001
8125 mov _int19_function.status + 2[bp], ax
8126
8127int19_load_done:
8128 pop bp
8129ASM_END
8130
8131 if (status != 0) {
8132#ifdef VBOX
8133 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
8134#else /* !VBOX */
8135 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
8136#endif /* !VBOX */
8137 return 0x00000000;
8138 }
8139 }
8140
8141 // check signature if instructed by cmos reg 0x38, only for floppy
8142 // bootchk = 1 : signature check disabled
8143 // bootchk = 0 : signature check enabled
8144 if (bootdrv != 0) bootchk = 0;
8145 else bootchk = inb_cmos(0x38) & 0x01;
8146
8147#if BX_ELTORITO_BOOT
8148 // if boot from cd, no signature check
8149 if (bootcd != 0)
8150 bootchk = 1;
8151#endif // BX_ELTORITO_BOOT
8152
8153 if (bootchk == 0) {
8154 if (read_word(bootseg,0x1fe) != 0xaa55) {
8155#ifdef VBOX
8156 print_boot_failure(bootcd, bootlan, bootdrv, 0, lastdrive);
8157#else /* !VBOX */
8158 print_boot_failure(bootcd, bootdrv, 0, lastdrive);
8159#endif /* VBOX */
8160 return 0x00000000;
8161 }
8162 }
8163
8164#if BX_ELTORITO_BOOT
8165 // Print out the boot string
8166#ifdef VBOX
8167 print_boot_device(bootcd, bootlan, bootdrv);
8168#else /* !VBOX */
8169 print_boot_device(bootcd, bootdrv);
8170#endif /* !VBOX */
8171#else // BX_ELTORITO_BOOT
8172#ifdef VBOX
8173 print_boot_device(0, bootlan, bootdrv);
8174#else /* !VBOX */
8175 print_boot_device(0, bootdrv);
8176#endif /* !VBOX */
8177#endif // BX_ELTORITO_BOOT
8178
8179 // return the boot segment
8180 return (((Bit32u)bootdrv) << 16) + bootseg;
8181}
8182
8183 void
8184int1a_function(regs, ds, iret_addr)
8185 pusha_regs_t regs; // regs pushed from PUSHA instruction
8186 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8187 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8188{
8189 Bit8u val8;
8190
8191 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);
8192
8193 ASM_START
8194 sti
8195 ASM_END
8196
8197 switch (regs.u.r8.ah) {
8198 case 0: // get current clock count
8199 ASM_START
8200 cli
8201 ASM_END
8202 regs.u.r16.cx = BiosData->ticks_high;
8203 regs.u.r16.dx = BiosData->ticks_low;
8204 regs.u.r8.al = BiosData->midnight_flag;
8205 BiosData->midnight_flag = 0; // reset flag
8206 ASM_START
8207 sti
8208 ASM_END
8209 // AH already 0
8210 ClearCF(iret_addr.flags); // OK
8211 break;
8212
8213 case 1: // Set Current Clock Count
8214 ASM_START
8215 cli
8216 ASM_END
8217 BiosData->ticks_high = regs.u.r16.cx;
8218 BiosData->ticks_low = regs.u.r16.dx;
8219 BiosData->midnight_flag = 0; // reset flag
8220 ASM_START
8221 sti
8222 ASM_END
8223 regs.u.r8.ah = 0;
8224 ClearCF(iret_addr.flags); // OK
8225 break;
8226
8227
8228 case 2: // Read CMOS Time
8229 if (rtc_updating()) {
8230 SetCF(iret_addr.flags);
8231 break;
8232 }
8233
8234 regs.u.r8.dh = inb_cmos(0x00); // Seconds
8235 regs.u.r8.cl = inb_cmos(0x02); // Minutes
8236 regs.u.r8.ch = inb_cmos(0x04); // Hours
8237 regs.u.r8.dl = inb_cmos(0x0b) & 0x01; // Stat Reg B
8238 regs.u.r8.ah = 0;
8239 regs.u.r8.al = regs.u.r8.ch;
8240 ClearCF(iret_addr.flags); // OK
8241 break;
8242
8243 case 3: // Set CMOS Time
8244 // Using a debugger, I notice the following masking/setting
8245 // of bits in Status Register B, by setting Reg B to
8246 // a few values and getting its value after INT 1A was called.
8247 //
8248 // try#1 try#2 try#3
8249 // before 1111 1101 0111 1101 0000 0000
8250 // after 0110 0010 0110 0010 0000 0010
8251 //
8252 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8253 // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
8254 if (rtc_updating()) {
8255 init_rtc();
8256 // fall through as if an update were not in progress
8257 }
8258 outb_cmos(0x00, regs.u.r8.dh); // Seconds
8259 outb_cmos(0x02, regs.u.r8.cl); // Minutes
8260 outb_cmos(0x04, regs.u.r8.ch); // Hours
8261 // Set Daylight Savings time enabled bit to requested value
8262 val8 = (inb_cmos(0x0b) & 0x60) | 0x02 | (regs.u.r8.dl & 0x01);
8263 // (reg B already selected)
8264 outb_cmos(0x0b, val8);
8265 regs.u.r8.ah = 0;
8266 regs.u.r8.al = val8; // val last written to Reg B
8267 ClearCF(iret_addr.flags); // OK
8268 break;
8269
8270 case 4: // Read CMOS Date
8271 regs.u.r8.ah = 0;
8272 if (rtc_updating()) {
8273 SetCF(iret_addr.flags);
8274 break;
8275 }
8276 regs.u.r8.cl = inb_cmos(0x09); // Year
8277 regs.u.r8.dh = inb_cmos(0x08); // Month
8278 regs.u.r8.dl = inb_cmos(0x07); // Day of Month
8279 regs.u.r8.ch = inb_cmos(0x32); // Century
8280 regs.u.r8.al = regs.u.r8.ch;
8281 ClearCF(iret_addr.flags); // OK
8282 break;
8283
8284 case 5: // Set CMOS Date
8285 // Using a debugger, I notice the following masking/setting
8286 // of bits in Status Register B, by setting Reg B to
8287 // a few values and getting its value after INT 1A was called.
8288 //
8289 // try#1 try#2 try#3 try#4
8290 // before 1111 1101 0111 1101 0000 0010 0000 0000
8291 // after 0110 1101 0111 1101 0000 0010 0000 0000
8292 //
8293 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8294 // My assumption: RegB = (RegB & 01111111b)
8295 if (rtc_updating()) {
8296 init_rtc();
8297 SetCF(iret_addr.flags);
8298 break;
8299 }
8300 outb_cmos(0x09, regs.u.r8.cl); // Year
8301 outb_cmos(0x08, regs.u.r8.dh); // Month
8302 outb_cmos(0x07, regs.u.r8.dl); // Day of Month
8303 outb_cmos(0x32, regs.u.r8.ch); // Century
8304 val8 = inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
8305 outb_cmos(0x0b, val8);
8306 regs.u.r8.ah = 0;
8307 regs.u.r8.al = val8; // AL = val last written to Reg B
8308 ClearCF(iret_addr.flags); // OK
8309 break;
8310
8311 case 6: // Set Alarm Time in CMOS
8312 // Using a debugger, I notice the following masking/setting
8313 // of bits in Status Register B, by setting Reg B to
8314 // a few values and getting its value after INT 1A was called.
8315 //
8316 // try#1 try#2 try#3
8317 // before 1101 1111 0101 1111 0000 0000
8318 // after 0110 1111 0111 1111 0010 0000
8319 //
8320 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8321 // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
8322 val8 = inb_cmos(0x0b); // Get Status Reg B
8323 regs.u.r16.ax = 0;
8324 if (val8 & 0x20) {
8325 // Alarm interrupt enabled already
8326 SetCF(iret_addr.flags); // Error: alarm in use
8327 break;
8328 }
8329 if (rtc_updating()) {
8330 init_rtc();
8331 // fall through as if an update were not in progress
8332 }
8333 outb_cmos(0x01, regs.u.r8.dh); // Seconds alarm
8334 outb_cmos(0x03, regs.u.r8.cl); // Minutes alarm
8335 outb_cmos(0x05, regs.u.r8.ch); // Hours alarm
8336 outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
8337 // enable Status Reg B alarm bit, clear halt clock bit
8338 outb_cmos(0x0b, (val8 & 0x7f) | 0x20);
8339 ClearCF(iret_addr.flags); // OK
8340 break;
8341
8342 case 7: // Turn off Alarm
8343 // Using a debugger, I notice the following masking/setting
8344 // of bits in Status Register B, by setting Reg B to
8345 // a few values and getting its value after INT 1A was called.
8346 //
8347 // try#1 try#2 try#3 try#4
8348 // before 1111 1101 0111 1101 0010 0000 0010 0010
8349 // after 0100 0101 0101 0101 0000 0000 0000 0010
8350 //
8351 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8352 // My assumption: RegB = (RegB & 01010111b)
8353 val8 = inb_cmos(0x0b); // Get Status Reg B
8354 // clear clock-halt bit, disable alarm bit
8355 outb_cmos(0x0b, val8 & 0x57); // disable alarm bit
8356 regs.u.r8.ah = 0;
8357 regs.u.r8.al = val8; // val last written to Reg B
8358 ClearCF(iret_addr.flags); // OK
8359 break;
8360#if BX_PCIBIOS
8361 case 0xb1:
8362 // real mode PCI BIOS functions now handled in assembler code
8363 // this C code handles the error code for information only
8364 if (regs.u.r8.bl == 0xff) {
8365 BX_INFO("PCI BIOS: PCI not present\n");
8366 } else if (regs.u.r8.bl == 0x81) {
8367 BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs.u.r8.al);
8368 } else if (regs.u.r8.bl == 0x83) {
8369 BX_INFO("bad PCI vendor ID %04x\n", regs.u.r16.dx);
8370 } else if (regs.u.r8.bl == 0x86) {
8371 if (regs.u.r8.al == 0x02) {
8372 BX_INFO("PCI device %04x:%04x not found at index %d\n", regs.u.r16.dx, regs.u.r16.cx, regs.u.r16.si);
8373 } else {
8374 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);
8375 }
8376 }
8377 regs.u.r8.ah = regs.u.r8.bl;
8378 SetCF(iret_addr.flags);
8379 break;
8380#endif
8381
8382 default:
8383 SetCF(iret_addr.flags); // Unsupported
8384 }
8385}
8386
8387 void
8388int70_function(regs, ds, iret_addr)
8389 pusha_regs_t regs; // regs pushed from PUSHA instruction
8390 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8391 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8392{
8393 // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
8394 Bit8u registerB = 0, registerC = 0;
8395
8396 // Check which modes are enabled and have occurred.
8397 registerB = inb_cmos( 0xB );
8398 registerC = inb_cmos( 0xC );
8399
8400 if( ( registerB & 0x60 ) != 0 ) {
8401 if( ( registerC & 0x20 ) != 0 ) {
8402 // Handle Alarm Interrupt.
8403ASM_START
8404 sti
8405 int #0x4a
8406 cli
8407ASM_END
8408 }
8409 if( ( registerC & 0x40 ) != 0 ) {
8410 // Handle Periodic Interrupt.
8411
8412 if( read_byte( 0x40, 0xA0 ) != 0 ) {
8413 // Wait Interval (Int 15, AH=83) active.
8414 Bit32u time, toggle;
8415
8416 time = read_dword( 0x40, 0x9C ); // Time left in microseconds.
8417 if( time < 0x3D1 ) {
8418 // Done waiting.
8419 Bit16u segment, offset;
8420
8421 segment = read_word( 0x40, 0x98 );
8422 offset = read_word( 0x40, 0x9A );
8423 write_byte( 0x40, 0xA0, 0 ); // Turn of status byte.
8424 outb_cmos( 0xB, registerB & 0x37 ); // Clear the Periodic Interrupt.
8425 write_byte(segment, offset, read_byte(segment, offset) | 0x80 ); // Write to specified flag byte.
8426 } else {
8427 // Continue waiting.
8428 time -= 0x3D1;
8429 write_dword( 0x40, 0x9C, time );
8430 }
8431 }
8432 }
8433 }
8434
8435ASM_START
8436 call eoi_both_pics
8437ASM_END
8438}
8439
8440
8441ASM_START
8442;------------------------------------------
8443;- INT74h : PS/2 mouse hardware interrupt -
8444;------------------------------------------
8445int74_handler:
8446 sti
8447 pusha
8448 push ds ;; save DS
8449 push #0x00 ;; placeholder for status
8450 push #0x00 ;; placeholder for X
8451 push #0x00 ;; placeholder for Y
8452 push #0x00 ;; placeholder for Z
8453 push #0x00 ;; placeholder for make_far_call boolean
8454 call _int74_function
8455 pop cx ;; remove make_far_call from stack
8456 jcxz int74_done
8457
8458 ;; make far call to EBDA:0022
8459 push #0x00
8460 pop ds
8461 push 0x040E ;; push 0000:040E (opcodes 0xff, 0x36, 0x0E, 0x04)
8462 pop ds
8463 //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
8464 call far ptr[0x22]
8465int74_done:
8466 cli
8467 call eoi_both_pics
8468 add sp, #8 ;; pop status, x, y, z
8469
8470 pop ds ;; restore DS
8471 popa
8472 iret
8473
8474
8475;; This will perform an IRET, but will retain value of current CF
8476;; by altering flags on stack. Better than RETF #02.
8477iret_modify_cf:
8478 jc carry_set
8479 push bp
8480 mov bp, sp
8481 and BYTE [bp + 0x06], #0xfe
8482 pop bp
8483 iret
8484carry_set:
8485 push bp
8486 mov bp, sp
8487 or BYTE [bp + 0x06], #0x01
8488 pop bp
8489 iret
8490
8491
8492;----------------------
8493;- INT13h (relocated) -
8494;----------------------
8495;
8496; int13_relocated is a little bit messed up since I played with it
8497; I have to rewrite it:
8498; - call a function that detect which function to call
8499; - make all called C function get the same parameters list
8500;
8501int13_relocated:
8502
8503#if BX_ELTORITO_BOOT
8504 ;; check for an eltorito function
8505 cmp ah,#0x4a
8506 jb int13_not_eltorito
8507 cmp ah,#0x4d
8508 ja int13_not_eltorito
8509
8510 pusha
8511 push es
8512 push ds
8513 push ss
8514 pop ds
8515
8516 push #int13_out
8517 jmp _int13_eltorito ;; ELDX not used
8518
8519int13_not_eltorito:
8520 push ax
8521 push bx
8522 push cx
8523 push dx
8524
8525 ;; check if emulation active
8526 call _cdemu_isactive
8527 cmp al,#0x00
8528 je int13_cdemu_inactive
8529
8530 ;; check if access to the emulated drive
8531 call _cdemu_emulated_drive
8532 pop dx
8533 push dx
8534 cmp al,dl ;; int13 on emulated drive
8535 jne int13_nocdemu
8536
8537 pop dx
8538 pop cx
8539 pop bx
8540 pop ax
8541
8542 pusha
8543 push es
8544 push ds
8545 push ss
8546 pop ds
8547
8548 push #int13_out
8549 jmp _int13_cdemu ;; ELDX not used
8550
8551int13_nocdemu:
8552 and dl,#0xE0 ;; mask to get device class, including cdroms
8553 cmp al,dl ;; al is 0x00 or 0x80
8554 jne int13_cdemu_inactive ;; inactive for device class
8555
8556 pop dx
8557 pop cx
8558 pop bx
8559 pop ax
8560
8561 push ax
8562 push cx
8563 push dx
8564 push bx
8565
8566 dec dl ;; real drive is dl - 1
8567 jmp int13_legacy
8568
8569int13_cdemu_inactive:
8570 pop dx
8571 pop cx
8572 pop bx
8573 pop ax
8574
8575#endif // BX_ELTORITO_BOOT
8576
8577int13_noeltorito:
8578
8579 push ax
8580 push cx
8581 push dx
8582 push bx
8583
8584int13_legacy:
8585
8586 push dx ;; push eltorito value of dx instead of sp
8587
8588 push bp
8589 push si
8590 push di
8591
8592 push es
8593 push ds
8594 push ss
8595 pop ds
8596
8597 ;; now the 16-bit registers can be restored with:
8598 ;; pop ds; pop es; popa; iret
8599 ;; arguments passed to functions should be
8600 ;; DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS
8601
8602 test dl, #0x80
8603 jnz int13_notfloppy
8604
8605 push #int13_out
8606 jmp _int13_diskette_function
8607
8608int13_notfloppy:
8609
8610#if BX_USE_ATADRV
8611
8612 cmp dl, #0xE0
8613 jb int13_notcdrom
8614
8615 // ebx is modified: BSD 5.2.1 boot loader problem
8616 // someone should figure out which 32 bit register that actually are used
8617
8618 shr ebx, #16
8619 push bx
8620
8621 call _int13_cdrom
8622
8623 pop bx
8624 shl ebx, #16
8625
8626 jmp int13_out
8627
8628int13_notcdrom:
8629
8630#endif
8631
8632int13_disk:
8633 ;; int13_harddisk modifies high word of EAX
8634 shr eax, #16
8635 push ax
8636 call _int13_harddisk
8637 pop ax
8638 shl eax, #16
8639
8640int13_out:
8641 pop ds
8642 pop es
8643 popa
8644 iret
8645
8646
8647;----------
8648;- INT18h -
8649;----------
8650int18_handler: ;; Boot Failure routing
8651 call _int18_panic_msg
8652 hlt
8653 iret
8654
8655;----------
8656;- INT19h -
8657;----------
8658int19_relocated: ;; Boot function, relocated
8659
8660#ifdef VBOX
8661 // If an already booted OS calls int 0x19 to reboot, it is not sufficient
8662 // just to try booting from the configured drives. All BIOS variables and
8663 // interrupt vectors need to be reset, otherwise strange things may happen.
8664 // The approach used is faking a warm reboot (which just skips showing the
8665 // logo), which is a bit more than what we need, but hey, it's fast.
8666 mov bp, sp
8667 mov ax, 2[bp]
8668 cmp ax, #0xf000
8669 jz bios_initiated_boot
8670 xor ax, ax
8671 mov ds, ax
8672 mov ax, #0x1234
8673 mov 0x472, ax
8674 jmp post
8675bios_initiated_boot:
8676#endif /* VBOX */
8677
8678 ;; int19 was beginning to be really complex, so now it
8679 ;; just calls an C function, that does the work
8680 ;; it returns in BL the boot drive, and in AX the boot segment
8681 ;; the boot segment will be 0x0000 if something has failed
8682
8683 push bp
8684 mov bp, sp
8685
8686 ;; drop ds
8687 xor ax, ax
8688 mov ds, ax
8689
8690 ;; 1st boot device
8691 mov ax, #0x0001
8692 push ax
8693 call _int19_function
8694 inc sp
8695 inc sp
8696 ;; bl contains the boot drive
8697 ;; ax contains the boot segment or 0 if failure
8698
8699 test ax, ax ;; if ax is 0 try next boot device
8700 jnz boot_setup
8701
8702 ;; 2nd boot device
8703 mov ax, #0x0002
8704 push ax
8705 call _int19_function
8706 inc sp
8707 inc sp
8708 test ax, ax ;; if ax is 0 try next boot device
8709 jnz boot_setup
8710
8711 ;; 3rd boot device
8712 mov ax, #0x0003
8713 push ax
8714 call _int19_function
8715 inc sp
8716 inc sp
8717#ifdef VBOX
8718 test ax, ax ;; if ax is 0 try next boot device
8719 jnz boot_setup
8720
8721 ;; 4th boot device
8722 mov ax, #0x0004
8723 push ax
8724 call _int19_function
8725 inc sp
8726 inc sp
8727#endif /* VBOX */
8728 test ax, ax ;; if ax is 0 call int18
8729 jz int18_handler
8730
8731boot_setup:
8732 mov dl, bl ;; set drive so guest os find it
8733 shl eax, #0x04 ;; convert seg to ip
8734 mov 2[bp], ax ;; set ip
8735
8736 shr eax, #0x04 ;; get cs back
8737 and ax, #0xF000 ;; remove what went in ip
8738 mov 4[bp], ax ;; set cs
8739 xor ax, ax
8740 mov es, ax ;; set es to zero fixes [ 549815 ]
8741 mov [bp], ax ;; set bp to zero
8742 mov ax, #0xaa55 ;; set ok flag
8743
8744 pop bp
8745 iret ;; Beam me up Scotty
8746
8747;----------
8748;- INT1Ch -
8749;----------
8750int1c_handler: ;; User Timer Tick
8751 iret
8752
8753
8754;----------------------
8755;- POST: Floppy Drive -
8756;----------------------
8757floppy_drive_post:
8758 xor ax, ax
8759 mov ds, ax
8760
8761 mov al, #0x00
8762 mov 0x043e, al ;; drive 0 & 1 uncalibrated, no interrupt has occurred
8763
8764 mov 0x043f, al ;; diskette motor status: read op, drive0, motors off
8765
8766 mov 0x0440, al ;; diskette motor timeout counter: not active
8767 mov 0x0441, al ;; diskette controller status return code
8768
8769 mov 0x0442, al ;; disk & diskette controller status register 0
8770 mov 0x0443, al ;; diskette controller status register 1
8771 mov 0x0444, al ;; diskette controller status register 2
8772 mov 0x0445, al ;; diskette controller cylinder number
8773 mov 0x0446, al ;; diskette controller head number
8774 mov 0x0447, al ;; diskette controller sector number
8775 mov 0x0448, al ;; diskette controller bytes written
8776
8777 mov 0x048b, al ;; diskette configuration data
8778
8779 ;; -----------------------------------------------------------------
8780 ;; (048F) diskette controller information
8781 ;;
8782 mov al, #0x10 ;; get CMOS diskette drive type
8783 out 0x70, AL
8784 in AL, 0x71
8785 mov ah, al ;; save byte to AH
8786
8787look_drive0:
8788 shr al, #4 ;; look at top 4 bits for drive 0
8789 jz f0_missing ;; jump if no drive0
8790 mov bl, #0x07 ;; drive0 determined, multi-rate, has changed line
8791 jmp look_drive1
8792f0_missing:
8793 mov bl, #0x00 ;; no drive0
8794
8795look_drive1:
8796 mov al, ah ;; restore from AH
8797 and al, #0x0f ;; look at bottom 4 bits for drive 1
8798 jz f1_missing ;; jump if no drive1
8799 or bl, #0x70 ;; drive1 determined, multi-rate, has changed line
8800f1_missing:
8801 ;; leave high bits in BL zerod
8802 mov 0x048f, bl ;; put new val in BDA (diskette controller information)
8803 ;; -----------------------------------------------------------------
8804
8805 mov al, #0x00
8806 mov 0x0490, al ;; diskette 0 media state
8807 mov 0x0491, al ;; diskette 1 media state
8808
8809 ;; diskette 0,1 operational starting state
8810 ;; drive type has not been determined,
8811 ;; has no changed detection line
8812 mov 0x0492, al
8813 mov 0x0493, al
8814
8815 mov 0x0494, al ;; diskette 0 current cylinder
8816 mov 0x0495, al ;; diskette 1 current cylinder
8817
8818 mov al, #0x02
8819 out #0x0a, al ;; clear DMA-1 channel 2 mask bit
8820
8821 SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
8822 SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
8823 SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
8824
8825 ret
8826
8827
8828;--------------------
8829;- POST: HARD DRIVE -
8830;--------------------
8831; relocated here because the primary POST area isnt big enough.
8832hard_drive_post:
8833 // IRQ 14 = INT 76h
8834 // INT 76h calls INT 15h function ax=9100
8835
8836 mov al, #0x0a ; 0000 1010 = reserved, disable IRQ 14
8837 mov dx, #0x03f6
8838 out dx, al
8839
8840 xor ax, ax
8841 mov ds, ax
8842 mov 0x0474, al /* hard disk status of last operation */
8843 mov 0x0477, al /* hard disk port offset (XT only ???) */
8844 mov 0x048c, al /* hard disk status register */
8845 mov 0x048d, al /* hard disk error register */
8846 mov 0x048e, al /* hard disk task complete flag */
8847 mov al, #0x01
8848 mov 0x0475, al /* hard disk number attached */
8849 mov al, #0xc0
8850 mov 0x0476, al /* hard disk control byte */
8851 SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
8852 SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
8853 ;; INT 41h: hard disk 0 configuration pointer
8854 ;; INT 46h: hard disk 1 configuration pointer
8855 SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D)
8856 SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D)
8857
8858 ;; move disk geometry data from CMOS to EBDA disk parameter table(s)
8859 mov al, #0x12
8860 out #0x70, al
8861 in al, #0x71
8862 and al, #0xf0
8863 cmp al, #0xf0
8864 je post_d0_extended
8865 jmp check_for_hd1
8866post_d0_extended:
8867 mov al, #0x19
8868 out #0x70, al
8869 in al, #0x71
8870 cmp al, #47 ;; decimal 47 - user definable
8871 je post_d0_type47
8872 HALT(__LINE__)
8873post_d0_type47:
8874 ;; CMOS purpose param table offset
8875 ;; 1b cylinders low 0
8876 ;; 1c cylinders high 1
8877 ;; 1d heads 2
8878 ;; 1e write pre-comp low 5
8879 ;; 1f write pre-comp high 6
8880 ;; 20 retries/bad map/heads>8 8
8881 ;; 21 landing zone low C
8882 ;; 22 landing zone high D
8883 ;; 23 sectors/track E
8884
8885 mov ax, #EBDA_SEG
8886 mov ds, ax
8887
8888 ;;; Filling EBDA table for hard disk 0.
8889 mov al, #0x1f
8890 out #0x70, al
8891 in al, #0x71
8892 mov ah, al
8893 mov al, #0x1e
8894 out #0x70, al
8895 in al, #0x71
8896 mov (0x003d + 0x05), ax ;; write precomp word
8897
8898 mov al, #0x20
8899 out #0x70, al
8900 in al, #0x71
8901 mov (0x003d + 0x08), al ;; drive control byte
8902
8903 mov al, #0x22
8904 out #0x70, al
8905 in al, #0x71
8906 mov ah, al
8907 mov al, #0x21
8908 out #0x70, al
8909 in al, #0x71
8910 mov (0x003d + 0x0C), ax ;; landing zone word
8911
8912 mov al, #0x1c ;; get cylinders word in AX
8913 out #0x70, al
8914 in al, #0x71 ;; high byte
8915 mov ah, al
8916 mov al, #0x1b
8917 out #0x70, al
8918 in al, #0x71 ;; low byte
8919 mov bx, ax ;; BX = cylinders
8920
8921 mov al, #0x1d
8922 out #0x70, al
8923 in al, #0x71
8924 mov cl, al ;; CL = heads
8925
8926 mov al, #0x23
8927 out #0x70, al
8928 in al, #0x71
8929 mov dl, al ;; DL = sectors
8930
8931 cmp bx, #1024
8932 jnbe hd0_post_logical_chs ;; if cylinders > 1024, use translated style CHS
8933
8934hd0_post_physical_chs:
8935 ;; no logical CHS mapping used, just physical CHS
8936 ;; use Standard Fixed Disk Parameter Table (FDPT)
8937 mov (0x003d + 0x00), bx ;; number of physical cylinders
8938 mov (0x003d + 0x02), cl ;; number of physical heads
8939 mov (0x003d + 0x0E), dl ;; number of physical sectors
8940 jmp check_for_hd1
8941
8942hd0_post_logical_chs:
8943 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
8944 mov (0x003d + 0x09), bx ;; number of physical cylinders
8945 mov (0x003d + 0x0b), cl ;; number of physical heads
8946 mov (0x003d + 0x04), dl ;; number of physical sectors
8947 mov (0x003d + 0x0e), dl ;; number of logical sectors (same)
8948 mov al, #0xa0
8949 mov (0x003d + 0x03), al ;; A0h signature, indicates translated table
8950
8951 cmp bx, #2048
8952 jnbe hd0_post_above_2048
8953 ;; 1024 < c <= 2048 cylinders
8954 shr bx, #0x01
8955 shl cl, #0x01
8956 jmp hd0_post_store_logical
8957
8958hd0_post_above_2048:
8959 cmp bx, #4096
8960 jnbe hd0_post_above_4096
8961 ;; 2048 < c <= 4096 cylinders
8962 shr bx, #0x02
8963 shl cl, #0x02
8964 jmp hd0_post_store_logical
8965
8966hd0_post_above_4096:
8967 cmp bx, #8192
8968 jnbe hd0_post_above_8192
8969 ;; 4096 < c <= 8192 cylinders
8970 shr bx, #0x03
8971 shl cl, #0x03
8972 jmp hd0_post_store_logical
8973
8974hd0_post_above_8192:
8975 ;; 8192 < c <= 16384 cylinders
8976 shr bx, #0x04
8977 shl cl, #0x04
8978
8979hd0_post_store_logical:
8980 mov (0x003d + 0x00), bx ;; number of physical cylinders
8981 mov (0x003d + 0x02), cl ;; number of physical heads
8982 ;; checksum
8983 mov cl, #0x0f ;; repeat count
8984 mov si, #0x003d ;; offset to disk0 FDPT
8985 mov al, #0x00 ;; sum
8986hd0_post_checksum_loop:
8987 add al, [si]
8988 inc si
8989 dec cl
8990 jnz hd0_post_checksum_loop
8991 not al ;; now take 2s complement
8992 inc al
8993 mov [si], al
8994;;; Done filling EBDA table for hard disk 0.
8995
8996
8997check_for_hd1:
8998 ;; is there really a second hard disk? if not, return now
8999 mov al, #0x12
9000 out #0x70, al
9001 in al, #0x71
9002 and al, #0x0f
9003 jnz post_d1_exists
9004 ret
9005post_d1_exists:
9006 ;; check that the hd type is really 0x0f.
9007 cmp al, #0x0f
9008 jz post_d1_extended
9009 HALT(__LINE__)
9010post_d1_extended:
9011 ;; check that the extended type is 47 - user definable
9012 mov al, #0x1a
9013 out #0x70, al
9014 in al, #0x71
9015 cmp al, #47 ;; decimal 47 - user definable
9016 je post_d1_type47
9017 HALT(__LINE__)
9018post_d1_type47:
9019 ;; Table for disk1.
9020 ;; CMOS purpose param table offset
9021 ;; 0x24 cylinders low 0
9022 ;; 0x25 cylinders high 1
9023 ;; 0x26 heads 2
9024 ;; 0x27 write pre-comp low 5
9025 ;; 0x28 write pre-comp high 6
9026 ;; 0x29 heads>8 8
9027 ;; 0x2a landing zone low C
9028 ;; 0x2b landing zone high D
9029 ;; 0x2c sectors/track E
9030;;; Fill EBDA table for hard disk 1.
9031 mov ax, #EBDA_SEG
9032 mov ds, ax
9033 mov al, #0x28
9034 out #0x70, al
9035 in al, #0x71
9036 mov ah, al
9037 mov al, #0x27
9038 out #0x70, al
9039 in al, #0x71
9040 mov (0x004d + 0x05), ax ;; write precomp word
9041
9042 mov al, #0x29
9043 out #0x70, al
9044 in al, #0x71
9045 mov (0x004d + 0x08), al ;; drive control byte
9046
9047 mov al, #0x2b
9048 out #0x70, al
9049 in al, #0x71
9050 mov ah, al
9051 mov al, #0x2a
9052 out #0x70, al
9053 in al, #0x71
9054 mov (0x004d + 0x0C), ax ;; landing zone word
9055
9056 mov al, #0x25 ;; get cylinders word in AX
9057 out #0x70, al
9058 in al, #0x71 ;; high byte
9059 mov ah, al
9060 mov al, #0x24
9061 out #0x70, al
9062 in al, #0x71 ;; low byte
9063 mov bx, ax ;; BX = cylinders
9064
9065 mov al, #0x26
9066 out #0x70, al
9067 in al, #0x71
9068 mov cl, al ;; CL = heads
9069
9070 mov al, #0x2c
9071 out #0x70, al
9072 in al, #0x71
9073 mov dl, al ;; DL = sectors
9074
9075 cmp bx, #1024
9076 jnbe hd1_post_logical_chs ;; if cylinders > 1024, use translated style CHS
9077
9078hd1_post_physical_chs:
9079 ;; no logical CHS mapping used, just physical CHS
9080 ;; use Standard Fixed Disk Parameter Table (FDPT)
9081 mov (0x004d + 0x00), bx ;; number of physical cylinders
9082 mov (0x004d + 0x02), cl ;; number of physical heads
9083 mov (0x004d + 0x0E), dl ;; number of physical sectors
9084 ret
9085
9086hd1_post_logical_chs:
9087 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
9088 mov (0x004d + 0x09), bx ;; number of physical cylinders
9089 mov (0x004d + 0x0b), cl ;; number of physical heads
9090 mov (0x004d + 0x04), dl ;; number of physical sectors
9091 mov (0x004d + 0x0e), dl ;; number of logical sectors (same)
9092 mov al, #0xa0
9093 mov (0x004d + 0x03), al ;; A0h signature, indicates translated table
9094
9095 cmp bx, #2048
9096 jnbe hd1_post_above_2048
9097 ;; 1024 < c <= 2048 cylinders
9098 shr bx, #0x01
9099 shl cl, #0x01
9100 jmp hd1_post_store_logical
9101
9102hd1_post_above_2048:
9103 cmp bx, #4096
9104 jnbe hd1_post_above_4096
9105 ;; 2048 < c <= 4096 cylinders
9106 shr bx, #0x02
9107 shl cl, #0x02
9108 jmp hd1_post_store_logical
9109
9110hd1_post_above_4096:
9111 cmp bx, #8192
9112 jnbe hd1_post_above_8192
9113 ;; 4096 < c <= 8192 cylinders
9114 shr bx, #0x03
9115 shl cl, #0x03
9116 jmp hd1_post_store_logical
9117
9118hd1_post_above_8192:
9119 ;; 8192 < c <= 16384 cylinders
9120 shr bx, #0x04
9121 shl cl, #0x04
9122
9123hd1_post_store_logical:
9124 mov (0x004d + 0x00), bx ;; number of physical cylinders
9125 mov (0x004d + 0x02), cl ;; number of physical heads
9126 ;; checksum
9127 mov cl, #0x0f ;; repeat count
9128 mov si, #0x004d ;; offset to disk0 FDPT
9129 mov al, #0x00 ;; sum
9130hd1_post_checksum_loop:
9131 add al, [si]
9132 inc si
9133 dec cl
9134 jnz hd1_post_checksum_loop
9135 not al ;; now take 2s complement
9136 inc al
9137 mov [si], al
9138;;; Done filling EBDA table for hard disk 1.
9139
9140 ret
9141
9142;--------------------
9143;- POST: EBDA segment
9144;--------------------
9145; relocated here because the primary POST area isnt big enough.
9146ebda_post:
9147#if BX_USE_EBDA
9148 mov ax, #EBDA_SEG
9149 mov ds, ax
9150 mov byte ptr [0x0], #EBDA_SIZE
9151#endif
9152 xor ax, ax ; mov EBDA seg into 40E
9153 mov ds, ax
9154 mov word ptr [0x40E], #EBDA_SEG
9155 ret;;
9156
9157;--------------------
9158;- POST: EOI + jmp via [0x40:67)
9159;--------------------
9160; relocated here because the primary POST area isnt big enough.
9161eoi_jmp_post:
9162 call eoi_both_pics
9163
9164 xor ax, ax
9165 mov ds, ax
9166
9167 jmp far ptr [0x467]
9168
9169
9170;--------------------
9171eoi_both_pics:
9172 mov al, #0x20
9173 out #0xA0, al ;; slave PIC EOI
9174eoi_master_pic:
9175 mov al, #0x20
9176 out #0x20, al ;; master PIC EOI
9177 ret
9178
9179;--------------------
9180BcdToBin:
9181 ;; in: AL in BCD format
9182 ;; out: AL in binary format, AH will always be 0
9183 ;; trashes BX
9184 mov bl, al
9185 and bl, #0x0f ;; bl has low digit
9186 shr al, #4 ;; al has high digit
9187 mov bh, #10
9188 mul al, bh ;; multiply high digit by 10 (result in AX)
9189 add al, bl ;; then add low digit
9190 ret
9191
9192;--------------------
9193timer_tick_post:
9194 ;; Setup the Timer Ticks Count (0x46C:dword) and
9195 ;; Timer Ticks Roller Flag (0x470:byte)
9196 ;; The Timer Ticks Count needs to be set according to
9197 ;; the current CMOS time, as if ticks have been occurring
9198 ;; at 18.2hz since midnight up to this point. Calculating
9199 ;; this is a little complicated. Here are the factors I gather
9200 ;; regarding this. 14,318,180 hz was the original clock speed,
9201 ;; chosen so it could be divided by either 3 to drive the 5Mhz CPU
9202 ;; at the time, or 4 to drive the CGA video adapter. The div3
9203 ;; source was divided again by 4 to feed a 1.193Mhz signal to
9204 ;; the timer. With a maximum 16bit timer count, this is again
9205 ;; divided down by 65536 to 18.2hz.
9206 ;;
9207 ;; 14,318,180 Hz clock
9208 ;; /3 = 4,772,726 Hz fed to orginal 5Mhz CPU
9209 ;; /4 = 1,193,181 Hz fed to timer
9210 ;; /65536 (maximum timer count) = 18.20650736 ticks/second
9211 ;; 1 second = 18.20650736 ticks
9212 ;; 1 minute = 1092.390442 ticks
9213 ;; 1 hour = 65543.42651 ticks
9214 ;;
9215 ;; Given the values in the CMOS clock, one could calculate
9216 ;; the number of ticks by the following:
9217 ;; ticks = (BcdToBin(seconds) * 18.206507) +
9218 ;; (BcdToBin(minutes) * 1092.3904)
9219 ;; (BcdToBin(hours) * 65543.427)
9220 ;; To get a little more accuracy, since Im using integer
9221 ;; arithmatic, I use:
9222 ;; ticks = (BcdToBin(seconds) * 18206507) / 1000000 +
9223 ;; (BcdToBin(minutes) * 10923904) / 10000 +
9224 ;; (BcdToBin(hours) * 65543427) / 1000
9225
9226 ;; assuming DS=0000
9227
9228 ;; get CMOS seconds
9229 xor eax, eax ;; clear EAX
9230 mov al, #0x00
9231 out #0x70, al
9232 in al, #0x71 ;; AL has CMOS seconds in BCD
9233 call BcdToBin ;; EAX now has seconds in binary
9234 mov edx, #18206507
9235 mul eax, edx
9236 mov ebx, #1000000
9237 xor edx, edx
9238 div eax, ebx
9239 mov ecx, eax ;; ECX will accumulate total ticks
9240
9241 ;; get CMOS minutes
9242 xor eax, eax ;; clear EAX
9243 mov al, #0x02
9244 out #0x70, al
9245 in al, #0x71 ;; AL has CMOS minutes in BCD
9246 call BcdToBin ;; EAX now has minutes in binary
9247 mov edx, #10923904
9248 mul eax, edx
9249 mov ebx, #10000
9250 xor edx, edx
9251 div eax, ebx
9252 add ecx, eax ;; add to total ticks
9253
9254 ;; get CMOS hours
9255 xor eax, eax ;; clear EAX
9256 mov al, #0x04
9257 out #0x70, al
9258 in al, #0x71 ;; AL has CMOS hours in BCD
9259 call BcdToBin ;; EAX now has hours in binary
9260 mov edx, #65543427
9261 mul eax, edx
9262 mov ebx, #1000
9263 xor edx, edx
9264 div eax, ebx
9265 add ecx, eax ;; add to total ticks
9266
9267 mov 0x46C, ecx ;; Timer Ticks Count
9268 xor al, al
9269 mov 0x470, al ;; Timer Ticks Rollover Flag
9270 ret
9271
9272;--------------------
9273int76_handler:
9274 ;; record completion in BIOS task complete flag
9275 push ax
9276 push ds
9277 mov ax, #0x0040
9278 mov ds, ax
9279 mov 0x008E, #0xff
9280 call eoi_both_pics
9281 pop ds
9282 pop ax
9283 iret
9284
9285
9286;--------------------
9287#if BX_APM
9288
9289use32 386
9290#define APM_PROT32
9291#include "apmbios.S"
9292
9293use16 386
9294#define APM_PROT16
9295#include "apmbios.S"
9296
9297#define APM_REAL
9298#include "apmbios.S"
9299
9300#endif
9301
9302;--------------------
9303#if BX_PCIBIOS
9304use32 386
9305.align 16
9306bios32_structure:
9307 db 0x5f, 0x33, 0x32, 0x5f ;; "_32_" signature
9308 dw bios32_entry_point, 0xf ;; 32 bit physical address
9309 db 0 ;; revision level
9310 ;; length in paragraphs and checksum stored in a word to prevent errors
9311 dw (~(((bios32_entry_point >> 8) + (bios32_entry_point & 0xff) + 0x32) \
9312 & 0xff) << 8) + 0x01
9313 db 0,0,0,0,0 ;; reserved
9314
9315.align 16
9316bios32_entry_point:
9317 pushfd
9318 cmp eax, #0x49435024 ;; "$PCI"
9319 jne unknown_service
9320 mov eax, #0x80000000
9321 mov dx, #0x0cf8
9322 out dx, eax
9323 mov dx, #0x0cfc
9324 in eax, dx
9325#ifdef PCI_FIXED_HOST_BRIDGE
9326 cmp eax, #PCI_FIXED_HOST_BRIDGE
9327 jne unknown_service
9328#else
9329 ;; say ok if a device is present
9330 cmp eax, #0xffffffff
9331 je unknown_service
9332#endif
9333 mov ebx, #0x000f0000
9334 mov ecx, #0
9335 mov edx, #pcibios_protected
9336 xor al, al
9337 jmp bios32_end
9338unknown_service:
9339 mov al, #0x80
9340bios32_end:
9341#ifdef BX_QEMU
9342 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
9343#endif
9344 popfd
9345 retf
9346
9347.align 16
9348pcibios_protected:
9349 pushfd
9350 cli
9351 push esi
9352 push edi
9353 cmp al, #0x01 ;; installation check
9354 jne pci_pro_f02
9355 mov bx, #0x0210
9356 mov cx, #0
9357 mov edx, #0x20494350 ;; "PCI "
9358 mov al, #0x01
9359 jmp pci_pro_ok
9360pci_pro_f02: ;; find pci device
9361 cmp al, #0x02
9362 jne pci_pro_f03
9363 shl ecx, #16
9364 mov cx, dx
9365 xor bx, bx
9366 mov di, #0x00
9367pci_pro_devloop:
9368 call pci_pro_select_reg
9369 mov dx, #0x0cfc
9370 in eax, dx
9371 cmp eax, ecx
9372 jne pci_pro_nextdev
9373 cmp si, #0
9374 je pci_pro_ok
9375 dec si
9376pci_pro_nextdev:
9377 inc bx
9378 cmp bx, #0x0100
9379 jne pci_pro_devloop
9380 mov ah, #0x86
9381 jmp pci_pro_fail
9382pci_pro_f03: ;; find class code
9383 cmp al, #0x03
9384 jne pci_pro_f08
9385 xor bx, bx
9386 mov di, #0x08
9387pci_pro_devloop2:
9388 call pci_pro_select_reg
9389 mov dx, #0x0cfc
9390 in eax, dx
9391 shr eax, #8
9392 cmp eax, ecx
9393 jne pci_pro_nextdev2
9394 cmp si, #0
9395 je pci_pro_ok
9396 dec si
9397pci_pro_nextdev2:
9398 inc bx
9399 cmp bx, #0x0100
9400 jne pci_pro_devloop2
9401 mov ah, #0x86
9402 jmp pci_pro_fail
9403pci_pro_f08: ;; read configuration byte
9404 cmp al, #0x08
9405 jne pci_pro_f09
9406 call pci_pro_select_reg
9407 push edx
9408 mov dx, di
9409 and dx, #0x03
9410 add dx, #0x0cfc
9411 in al, dx
9412 pop edx
9413 mov cl, al
9414 jmp pci_pro_ok
9415pci_pro_f09: ;; read configuration word
9416 cmp al, #0x09
9417 jne pci_pro_f0a
9418 call pci_pro_select_reg
9419 push edx
9420 mov dx, di
9421 and dx, #0x02
9422 add dx, #0x0cfc
9423 in ax, dx
9424 pop edx
9425 mov cx, ax
9426 jmp pci_pro_ok
9427pci_pro_f0a: ;; read configuration dword
9428 cmp al, #0x0a
9429 jne pci_pro_f0b
9430 call pci_pro_select_reg
9431 push edx
9432 mov dx, #0x0cfc
9433 in eax, dx
9434 pop edx
9435 mov ecx, eax
9436 jmp pci_pro_ok
9437pci_pro_f0b: ;; write configuration byte
9438 cmp al, #0x0b
9439 jne pci_pro_f0c
9440 call pci_pro_select_reg
9441 push edx
9442 mov dx, di
9443 and dx, #0x03
9444 add dx, #0x0cfc
9445 mov al, cl
9446 out dx, al
9447 pop edx
9448 jmp pci_pro_ok
9449pci_pro_f0c: ;; write configuration word
9450 cmp al, #0x0c
9451 jne pci_pro_f0d
9452 call pci_pro_select_reg
9453 push edx
9454 mov dx, di
9455 and dx, #0x02
9456 add dx, #0x0cfc
9457 mov ax, cx
9458 out dx, ax
9459 pop edx
9460 jmp pci_pro_ok
9461pci_pro_f0d: ;; write configuration dword
9462 cmp al, #0x0d
9463 jne pci_pro_unknown
9464 call pci_pro_select_reg
9465 push edx
9466 mov dx, #0x0cfc
9467 mov eax, ecx
9468 out dx, eax
9469 pop edx
9470 jmp pci_pro_ok
9471pci_pro_unknown:
9472 mov ah, #0x81
9473pci_pro_fail:
9474 pop edi
9475 pop esi
9476#ifdef BX_QEMU
9477 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
9478#endif
9479 popfd
9480 stc
9481 retf
9482pci_pro_ok:
9483 xor ah, ah
9484 pop edi
9485 pop esi
9486#ifdef BX_QEMU
9487 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
9488#endif
9489 popfd
9490 clc
9491 retf
9492
9493pci_pro_select_reg:
9494 push edx
9495 mov eax, #0x800000
9496 mov ax, bx
9497 shl eax, #8
9498 and di, #0xff
9499 or ax, di
9500 and al, #0xfc
9501 mov dx, #0x0cf8
9502 out dx, eax
9503 pop edx
9504 ret
9505
9506use16 386
9507
9508pcibios_real:
9509 push eax
9510 push dx
9511 mov eax, #0x80000000
9512 mov dx, #0x0cf8
9513 out dx, eax
9514 mov dx, #0x0cfc
9515 in eax, dx
9516#ifdef PCI_FIXED_HOST_BRIDGE
9517 cmp eax, #PCI_FIXED_HOST_BRIDGE
9518 je pci_present
9519#else
9520 ;; say ok if a device is present
9521 cmp eax, #0xffffffff
9522 jne pci_present
9523#endif
9524 pop dx
9525 pop eax
9526 mov ah, #0xff
9527 stc
9528 ret
9529pci_present:
9530 pop dx
9531 pop eax
9532 cmp al, #0x01 ;; installation check
9533 jne pci_real_f02
9534 mov ax, #0x0001
9535 mov bx, #0x0210
9536 mov cx, #0
9537 mov edx, #0x20494350 ;; "PCI "
9538 mov edi, #0xf0000
9539 mov di, #pcibios_protected
9540 clc
9541 ret
9542pci_real_f02: ;; find pci device
9543 push esi
9544 push edi
9545 cmp al, #0x02
9546 jne pci_real_f03
9547 shl ecx, #16
9548 mov cx, dx
9549 xor bx, bx
9550 mov di, #0x00
9551pci_real_devloop:
9552 call pci_real_select_reg
9553 mov dx, #0x0cfc
9554 in eax, dx
9555 cmp eax, ecx
9556 jne pci_real_nextdev
9557 cmp si, #0
9558 je pci_real_ok
9559 dec si
9560pci_real_nextdev:
9561 inc bx
9562 cmp bx, #0x0100
9563 jne pci_real_devloop
9564 mov dx, cx
9565 shr ecx, #16
9566 mov ax, #0x8602
9567 jmp pci_real_fail
9568pci_real_f03: ;; find class code
9569 cmp al, #0x03
9570 jne pci_real_f08
9571 xor bx, bx
9572 mov di, #0x08
9573pci_real_devloop2:
9574 call pci_real_select_reg
9575 mov dx, #0x0cfc
9576 in eax, dx
9577 shr eax, #8
9578 cmp eax, ecx
9579 jne pci_real_nextdev2
9580 cmp si, #0
9581 je pci_real_ok
9582 dec si
9583pci_real_nextdev2:
9584 inc bx
9585 cmp bx, #0x0100
9586 jne pci_real_devloop2
9587 mov dx, cx
9588 shr ecx, #16
9589 mov ax, #0x8603
9590 jmp pci_real_fail
9591pci_real_f08: ;; read configuration byte
9592 cmp al, #0x08
9593 jne pci_real_f09
9594 call pci_real_select_reg
9595 push dx
9596 mov dx, di
9597 and dx, #0x03
9598 add dx, #0x0cfc
9599 in al, dx
9600 pop dx
9601 mov cl, al
9602 jmp pci_real_ok
9603pci_real_f09: ;; read configuration word
9604 cmp al, #0x09
9605 jne pci_real_f0a
9606 call pci_real_select_reg
9607 push dx
9608 mov dx, di
9609 and dx, #0x02
9610 add dx, #0x0cfc
9611 in ax, dx
9612 pop dx
9613 mov cx, ax
9614 jmp pci_real_ok
9615pci_real_f0a: ;; read configuration dword
9616 cmp al, #0x0a
9617 jne pci_real_f0b
9618 call pci_real_select_reg
9619 push dx
9620 mov dx, #0x0cfc
9621 in eax, dx
9622 pop dx
9623 mov ecx, eax
9624 jmp pci_real_ok
9625pci_real_f0b: ;; write configuration byte
9626 cmp al, #0x0b
9627 jne pci_real_f0c
9628 call pci_real_select_reg
9629 push dx
9630 mov dx, di
9631 and dx, #0x03
9632 add dx, #0x0cfc
9633 mov al, cl
9634 out dx, al
9635 pop dx
9636 jmp pci_real_ok
9637pci_real_f0c: ;; write configuration word
9638 cmp al, #0x0c
9639 jne pci_real_f0d
9640 call pci_real_select_reg
9641 push dx
9642 mov dx, di
9643 and dx, #0x02
9644 add dx, #0x0cfc
9645 mov ax, cx
9646 out dx, ax
9647 pop dx
9648 jmp pci_real_ok
9649pci_real_f0d: ;; write configuration dword
9650 cmp al, #0x0d
9651 jne pci_real_f0e
9652 call pci_real_select_reg
9653 push dx
9654 mov dx, #0x0cfc
9655 mov eax, ecx
9656 out dx, eax
9657 pop dx
9658 jmp pci_real_ok
9659pci_real_f0e: ;; get irq routing options
9660 cmp al, #0x0e
9661 jne pci_real_unknown
9662 SEG ES
9663 cmp word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
9664 jb pci_real_too_small
9665 SEG ES
9666 mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
9667 pushf
9668 push ds
9669 push es
9670 push cx
9671 push si
9672 push di
9673 cld
9674 mov si, #pci_routing_table_structure_start
9675 push cs
9676 pop ds
9677 SEG ES
9678 mov cx, [di+2]
9679 SEG ES
9680 mov es, [di+4]
9681 mov di, cx
9682 mov cx, #pci_routing_table_structure_end - pci_routing_table_structure_start
9683 rep
9684 movsb
9685 pop di
9686 pop si
9687 pop cx
9688 pop es
9689 pop ds
9690 popf
9691 mov bx, #(1 << 9) | (1 << 11) ;; irq 9 and 11 are used
9692 jmp pci_real_ok
9693pci_real_too_small:
9694 SEG ES
9695 mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
9696 mov ah, #0x89
9697 jmp pci_real_fail
9698
9699pci_real_unknown:
9700 mov ah, #0x81
9701pci_real_fail:
9702 pop edi
9703 pop esi
9704 stc
9705 ret
9706pci_real_ok:
9707 xor ah, ah
9708 pop edi
9709 pop esi
9710 clc
9711 ret
9712
9713pci_real_select_reg:
9714 push dx
9715 mov eax, #0x800000
9716 mov ax, bx
9717 shl eax, #8
9718 and di, #0xff
9719 or ax, di
9720 and al, #0xfc
9721 mov dx, #0x0cf8
9722 out dx, eax
9723 pop dx
9724 ret
9725
9726.align 16
9727pci_routing_table_structure:
9728 db 0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature
9729 db 0, 1 ;; version
9730#ifdef VBOX
9731 dw 32 + (10 * 16) ;; table size
9732#else /* !VBOX */
9733 dw 32 + (6 * 16) ;; table size
9734#endif /* !VBOX */
9735 db 0 ;; PCI interrupt router bus
9736 db 0x08 ;; PCI interrupt router DevFunc
9737 dw 0x0000 ;; PCI exclusive IRQs
9738 dw 0x8086 ;; compatible PCI interrupt router vendor ID
9739 dw 0x7000 ;; compatible PCI interrupt router device ID
9740 dw 0,0 ;; Miniport data
9741 db 0,0,0,0,0,0,0,0,0,0,0 ;; reserved
9742#ifdef VBOX
9743 db 0x21 ;; checksum
9744#else /* !VBOX */
9745 db 0x07 ;; checksum
9746#endif /* !VBOX */
9747pci_routing_table_structure_start:
9748 ;; first slot entry PCI-to-ISA (embedded)
9749 db 0 ;; pci bus number
9750 db 0x08 ;; pci device number (bit 7-3)
9751 db 0x60 ;; link value INTA#: pointer into PCI2ISA config space
9752 dw 0xdef8 ;; IRQ bitmap INTA#
9753 db 0x61 ;; link value INTB#
9754 dw 0xdef8 ;; IRQ bitmap INTB#
9755 db 0x62 ;; link value INTC#
9756 dw 0xdef8 ;; IRQ bitmap INTC#
9757 db 0x63 ;; link value INTD#
9758 dw 0xdef8 ;; IRQ bitmap INTD#
9759 db 0 ;; physical slot (0 = embedded)
9760 db 0 ;; reserved
9761 ;; second slot entry: 1st PCI slot
9762 db 0 ;; pci bus number
9763 db 0x10 ;; pci device number (bit 7-3)
9764 db 0x61 ;; link value INTA#
9765 dw 0xdef8 ;; IRQ bitmap INTA#
9766 db 0x62 ;; link value INTB#
9767 dw 0xdef8 ;; IRQ bitmap INTB#
9768 db 0x63 ;; link value INTC#
9769 dw 0xdef8 ;; IRQ bitmap INTC#
9770 db 0x60 ;; link value INTD#
9771 dw 0xdef8 ;; IRQ bitmap INTD#
9772 db 1 ;; physical slot (0 = embedded)
9773 db 0 ;; reserved
9774 ;; third slot entry: 2nd PCI slot
9775 db 0 ;; pci bus number
9776 db 0x18 ;; pci device number (bit 7-3)
9777 db 0x62 ;; link value INTA#
9778 dw 0xdef8 ;; IRQ bitmap INTA#
9779 db 0x63 ;; link value INTB#
9780 dw 0xdef8 ;; IRQ bitmap INTB#
9781 db 0x60 ;; link value INTC#
9782 dw 0xdef8 ;; IRQ bitmap INTC#
9783 db 0x61 ;; link value INTD#
9784 dw 0xdef8 ;; IRQ bitmap INTD#
9785 db 2 ;; physical slot (0 = embedded)
9786 db 0 ;; reserved
9787 ;; 4th slot entry: 3rd PCI slot
9788 db 0 ;; pci bus number
9789 db 0x20 ;; pci device number (bit 7-3)
9790 db 0x63 ;; link value INTA#
9791 dw 0xdef8 ;; IRQ bitmap INTA#
9792 db 0x60 ;; link value INTB#
9793 dw 0xdef8 ;; IRQ bitmap INTB#
9794 db 0x61 ;; link value INTC#
9795 dw 0xdef8 ;; IRQ bitmap INTC#
9796 db 0x62 ;; link value INTD#
9797 dw 0xdef8 ;; IRQ bitmap INTD#
9798 db 3 ;; physical slot (0 = embedded)
9799 db 0 ;; reserved
9800 ;; 5th slot entry: 4rd PCI slot
9801 db 0 ;; pci bus number
9802 db 0x28 ;; pci device number (bit 7-3)
9803 db 0x60 ;; link value INTA#
9804 dw 0xdef8 ;; IRQ bitmap INTA#
9805 db 0x61 ;; link value INTB#
9806 dw 0xdef8 ;; IRQ bitmap INTB#
9807 db 0x62 ;; link value INTC#
9808 dw 0xdef8 ;; IRQ bitmap INTC#
9809 db 0x63 ;; link value INTD#
9810 dw 0xdef8 ;; IRQ bitmap INTD#
9811 db 4 ;; physical slot (0 = embedded)
9812 db 0 ;; reserved
9813 ;; 6th slot entry: 5rd PCI slot
9814 db 0 ;; pci bus number
9815 db 0x30 ;; pci device number (bit 7-3)
9816 db 0x61 ;; link value INTA#
9817 dw 0xdef8 ;; IRQ bitmap INTA#
9818 db 0x62 ;; link value INTB#
9819 dw 0xdef8 ;; IRQ bitmap INTB#
9820 db 0x63 ;; link value INTC#
9821 dw 0xdef8 ;; IRQ bitmap INTC#
9822 db 0x60 ;; link value INTD#
9823 dw 0xdef8 ;; IRQ bitmap INTD#
9824 db 5 ;; physical slot (0 = embedded)
9825 db 0 ;; reserved
9826#ifdef VBOX
9827 ;; 7th slot entry: 6th PCI slot
9828 db 0 ;; pci bus number
9829 db 0x38 ;; pci device number (bit 7-3)
9830 db 0x62 ;; link value INTA#
9831 dw 0xdef8 ;; IRQ bitmap INTA#
9832 db 0x63 ;; link value INTB#
9833 dw 0xdef8 ;; IRQ bitmap INTB#
9834 db 0x60 ;; link value INTC#
9835 dw 0xdef8 ;; IRQ bitmap INTC#
9836 db 0x61 ;; link value INTD#
9837 dw 0xdef8 ;; IRQ bitmap INTD#
9838 db 6 ;; physical slot (0 = embedded)
9839 db 0 ;; reserved
9840 ;; 8th slot entry: 7th PCI slot
9841 db 0 ;; pci bus number
9842 db 0x40 ;; pci device number (bit 7-3)
9843 db 0x63 ;; link value INTA#
9844 dw 0xdef8 ;; IRQ bitmap INTA#
9845 db 0x60 ;; link value INTB#
9846 dw 0xdef8 ;; IRQ bitmap INTB#
9847 db 0x61 ;; link value INTC#
9848 dw 0xdef8 ;; IRQ bitmap INTC#
9849 db 0x62 ;; link value INTD#
9850 dw 0xdef8 ;; IRQ bitmap INTD#
9851 db 7 ;; physical slot (0 = embedded)
9852 db 0 ;; reserved
9853 ;; 9th slot entry: 8th PCI slot
9854 db 0 ;; pci bus number
9855 db 0x48 ;; pci device number (bit 7-3)
9856 db 0x60 ;; link value INTA#
9857 dw 0xdef8 ;; IRQ bitmap INTA#
9858 db 0x61 ;; link value INTB#
9859 dw 0xdef8 ;; IRQ bitmap INTB#
9860 db 0x62 ;; link value INTC#
9861 dw 0xdef8 ;; IRQ bitmap INTC#
9862 db 0x63 ;; link value INTD#
9863 dw 0xdef8 ;; IRQ bitmap INTD#
9864 db 8 ;; physical slot (0 = embedded)
9865 db 0 ;; reserved
9866 ;; 10th slot entry: 9th PCI slot
9867 db 0 ;; pci bus number
9868 db 0x50 ;; pci device number (bit 7-3)
9869 db 0x61 ;; link value INTA#
9870 dw 0xdef8 ;; IRQ bitmap INTA#
9871 db 0x62 ;; link value INTB#
9872 dw 0xdef8 ;; IRQ bitmap INTB#
9873 db 0x63 ;; link value INTC#
9874 dw 0xdef8 ;; IRQ bitmap INTC#
9875 db 0x60 ;; link value INTD#
9876 dw 0xdef8 ;; IRQ bitmap INTD#
9877 db 9 ;; physical slot (0 = embedded)
9878 db 0 ;; reserved
9879#endif /* VBOX */
9880pci_routing_table_structure_end:
9881
9882#if !BX_ROMBIOS32
9883pci_irq_list:
9884 db 11, 10, 9, 5;
9885
9886pcibios_init_sel_reg:
9887 push eax
9888 mov eax, #0x800000
9889 mov ax, bx
9890 shl eax, #8
9891 and dl, #0xfc
9892 or al, dl
9893 mov dx, #0x0cf8
9894 out dx, eax
9895 pop eax
9896 ret
9897
9898pcibios_init_iomem_bases:
9899 push bp
9900 mov bp, sp
9901 mov eax, #0xe0000000 ;; base for memory init
9902 push eax
9903 mov ax, #0xc000 ;; base for i/o init
9904 push ax
9905 mov ax, #0x0010 ;; start at base address #0
9906 push ax
9907 mov bx, #0x0008
9908pci_init_io_loop1:
9909 mov dl, #0x00
9910 call pcibios_init_sel_reg
9911 mov dx, #0x0cfc
9912 in ax, dx
9913 cmp ax, #0xffff
9914 jz next_pci_dev
9915#ifndef VBOX /* This currently breaks restoring a previously saved state. */
9916 mov dl, #0x04 ;; disable i/o and memory space access
9917 call pcibios_init_sel_reg
9918 mov dx, #0x0cfc
9919 in al, dx
9920 and al, #0xfc
9921 out dx, al
9922pci_init_io_loop2:
9923 mov dl, [bp-8]
9924 call pcibios_init_sel_reg
9925 mov dx, #0x0cfc
9926 in eax, dx
9927 test al, #0x01
9928 jnz init_io_base
9929 mov ecx, eax
9930 mov eax, #0xffffffff
9931 out dx, eax
9932 in eax, dx
9933 cmp eax, ecx
9934 je next_pci_base
9935 xor eax, #0xffffffff
9936 mov ecx, eax
9937 mov eax, [bp-4]
9938 out dx, eax
9939 add eax, ecx ;; calculate next free mem base
9940 add eax, #0x01000000
9941 and eax, #0xff000000
9942 mov [bp-4], eax
9943 jmp next_pci_base
9944init_io_base:
9945 mov cx, ax
9946 mov ax, #0xffff
9947 out dx, ax
9948 in ax, dx
9949 cmp ax, cx
9950 je next_pci_base
9951 xor ax, #0xfffe
9952 mov cx, ax
9953 mov ax, [bp-6]
9954 out dx, ax
9955 add ax, cx ;; calculate next free i/o base
9956 add ax, #0x0100
9957 and ax, #0xff00
9958 mov [bp-6], ax
9959next_pci_base:
9960 mov al, [bp-8]
9961 add al, #0x04
9962 cmp al, #0x28
9963 je enable_iomem_space
9964 mov byte ptr[bp-8], al
9965 jmp pci_init_io_loop2
9966#endif /* !VBOX */
9967enable_iomem_space:
9968 mov dl, #0x04 ;; enable i/o and memory space access if available
9969 call pcibios_init_sel_reg
9970 mov dx, #0x0cfc
9971 in al, dx
9972 or al, #0x07
9973 out dx, al
9974#ifdef VBOX
9975 mov dl, #0x00 ;; check if PCI device is AMD PCNet
9976 call pcibios_init_sel_reg
9977 mov dx, #0x0cfc
9978 in eax, dx
9979 cmp eax, #0x20001022
9980 jne next_pci_dev
9981 mov dl, #0x10 ;; get I/O address
9982 call pcibios_init_sel_reg
9983 mov dx, #0x0cfc
9984 in ax, dx
9985 and ax, #0xfffc
9986 mov cx, ax
9987 mov dx, cx
9988 add dx, #0x14 ;; reset register if PCNet is in word I/O mode
9989 in ax, dx ;; reset is performed by reading the reset register
9990 mov dx, cx
9991 add dx, #0x18 ;; reset register if PCNet is in word I/O mode
9992 in eax, dx ;; reset is performed by reading the reset register
9993#endif /* VBOX */
9994next_pci_dev:
9995 mov byte ptr[bp-8], #0x10
9996 inc bx
9997 cmp bx, #0x0100
9998 jne pci_init_io_loop1
9999 mov sp, bp
10000 pop bp
10001 ret
10002
10003pcibios_init_set_elcr:
10004 push ax
10005 push cx
10006 mov dx, #0x04d0
10007 test al, #0x08
10008 jz is_master_pic
10009 inc dx
10010 and al, #0x07
10011is_master_pic:
10012 mov cl, al
10013 mov bl, #0x01
10014 shl bl, cl
10015 in al, dx
10016 or al, bl
10017 out dx, al
10018 pop cx
10019 pop ax
10020 ret
10021
10022pcibios_init_irqs:
10023 push ds
10024 push bp
10025 mov ax, #0xf000
10026 mov ds, ax
10027 mov dx, #0x04d0 ;; reset ELCR1 + ELCR2
10028 mov al, #0x00
10029 out dx, al
10030 inc dx
10031 out dx, al
10032 mov si, #pci_routing_table_structure
10033 mov bh, [si+8]
10034 mov bl, [si+9]
10035 mov dl, #0x00
10036 call pcibios_init_sel_reg
10037 mov dx, #0x0cfc
10038 in eax, dx
10039 cmp eax, [si+12] ;; check irq router
10040 jne pci_init_end
10041 mov dl, [si+34]
10042 call pcibios_init_sel_reg
10043 push bx ;; save irq router bus + devfunc
10044 mov dx, #0x0cfc
10045 mov ax, #0x8080
10046 out dx, ax ;; reset PIRQ route control
10047 inc dx
10048 inc dx
10049 out dx, ax
10050 mov ax, [si+6]
10051 sub ax, #0x20
10052 shr ax, #4
10053 mov cx, ax
10054 add si, #0x20 ;; set pointer to 1st entry
10055 mov bp, sp
10056 mov ax, #pci_irq_list
10057 push ax
10058 xor ax, ax
10059 push ax
10060pci_init_irq_loop1:
10061 mov bh, [si]
10062 mov bl, [si+1]
10063pci_init_irq_loop2:
10064 mov dl, #0x00
10065 call pcibios_init_sel_reg
10066 mov dx, #0x0cfc
10067 in ax, dx
10068 cmp ax, #0xffff
10069 jnz pci_test_int_pin
10070 test bl, #0x07
10071 jz next_pir_entry
10072 jmp next_pci_func
10073pci_test_int_pin:
10074 mov dl, #0x3c
10075 call pcibios_init_sel_reg
10076 mov dx, #0x0cfd
10077 in al, dx
10078 and al, #0x07
10079 jz next_pci_func
10080 dec al ;; determine pirq reg
10081 mov dl, #0x03
10082 mul al, dl
10083 add al, #0x02
10084 xor ah, ah
10085 mov bx, ax
10086 mov al, [si+bx]
10087 mov dl, al
10088 mov bx, [bp]
10089 call pcibios_init_sel_reg
10090 mov dx, #0x0cfc
10091 and al, #0x03
10092 add dl, al
10093 in al, dx
10094 cmp al, #0x80
10095 jb pirq_found
10096 mov bx, [bp-2] ;; pci irq list pointer
10097 mov al, [bx]
10098 out dx, al
10099 inc bx
10100 mov [bp-2], bx
10101 call pcibios_init_set_elcr
10102pirq_found:
10103 mov bh, [si]
10104 mov bl, [si+1]
10105 add bl, [bp-3] ;; pci function number
10106 mov dl, #0x3c
10107 call pcibios_init_sel_reg
10108 mov dx, #0x0cfc
10109 out dx, al
10110next_pci_func:
10111 inc byte ptr[bp-3]
10112 inc bl
10113 test bl, #0x07
10114 jnz pci_init_irq_loop2
10115next_pir_entry:
10116 add si, #0x10
10117 mov byte ptr[bp-3], #0x00
10118 loop pci_init_irq_loop1
10119 mov sp, bp
10120 pop bx
10121pci_init_end:
10122 pop bp
10123 pop ds
10124 ret
10125#endif // BX_ROMBIOS32
10126#endif // BX_PCIBIOS
10127
10128#if BX_ROMBIOS32
10129rombios32_init:
10130 ;; save a20 and enable it
10131 in al, 0x92
10132 push ax
10133 or al, #0x02
10134 out 0x92, al
10135
10136 ;; save SS:SP to the BDA
10137 xor ax, ax
10138 mov ds, ax
10139 mov 0x0469, ss
10140 mov 0x0467, sp
10141
10142 SEG CS
10143 lidt [pmode_IDT_info]
10144 SEG CS
10145 lgdt [rombios32_gdt_48]
10146 ;; set PE bit in CR0
10147 mov eax, cr0
10148 or al, #0x01
10149 mov cr0, eax
10150 ;; start protected mode code: ljmpl 0x10:rombios32_init1
10151 db 0x66, 0xea
10152 dw rombios32_05
10153 dw 0x000f ;; high 16 bit address
10154 dw 0x0010
10155
10156use32 386
10157rombios32_05:
10158 ;; init data segments
10159 mov eax, #0x18
10160 mov ds, ax
10161 mov es, ax
10162 mov ss, ax
10163 xor eax, eax
10164 mov fs, ax
10165 mov gs, ax
10166 cld
10167
10168 ;; copy rombios32 code to ram (ram offset = 1MB)
10169 mov esi, #0xfffe0000
10170 mov edi, #0x00040000
10171 mov ecx, #0x10000 / 4
10172 rep
10173 movsd
10174
10175 ;; init the stack pointer
10176 mov esp, #0x00080000
10177
10178 ;; call rombios32 code
10179 mov eax, #0x00040000
10180 call eax
10181
10182 ;; return to 16 bit protected mode first
10183 db 0xea
10184 dd rombios32_10
10185 dw 0x20
10186
10187use16 386
10188rombios32_10:
10189 ;; restore data segment limits to 0xffff
10190 mov ax, #0x28
10191 mov ds, ax
10192 mov es, ax
10193 mov ss, ax
10194 mov fs, ax
10195 mov gs, ax
10196
10197 ;; reset PE bit in CR0
10198 mov eax, cr0
10199 and al, #0xFE
10200 mov cr0, eax
10201
10202 ;; far jump to flush CPU queue after transition to real mode
10203 JMP_AP(0xf000, rombios32_real_mode)
10204
10205rombios32_real_mode:
10206 ;; restore IDT to normal real-mode defaults
10207 SEG CS
10208 lidt [rmode_IDT_info]
10209
10210 xor ax, ax
10211 mov ds, ax
10212 mov es, ax
10213 mov fs, ax
10214 mov gs, ax
10215
10216 ;; restore SS:SP from the BDA
10217 mov ss, 0x0469
10218 xor esp, esp
10219 mov sp, 0x0467
10220 ;; restore a20
10221 pop ax
10222 out 0x92, al
10223 ret
10224
10225rombios32_gdt_48:
10226 dw 0x30
10227 dw rombios32_gdt
10228 dw 0x000f
10229
10230rombios32_gdt:
10231 dw 0, 0, 0, 0
10232 dw 0, 0, 0, 0
10233 dw 0xffff, 0, 0x9b00, 0x00cf ; 32 bit flat code segment (0x10)
10234 dw 0xffff, 0, 0x9300, 0x00cf ; 32 bit flat data segment (0x18)
10235 dw 0xffff, 0, 0x9b0f, 0x0000 ; 16 bit code segment base=0xf0000 limit=0xffff
10236 dw 0xffff, 0, 0x9300, 0x0000 ; 16 bit data segment base=0x0 limit=0xffff
10237#endif
10238
10239
10240; parallel port detection: base address in DX, index in BX, timeout in CL
10241detect_parport:
10242 push dx
10243 add dx, #2
10244 in al, dx
10245 and al, #0xdf ; clear input mode
10246 out dx, al
10247 pop dx
10248 mov al, #0xaa
10249 out dx, al
10250 in al, dx
10251 cmp al, #0xaa
10252 jne no_parport
10253 push bx
10254 shl bx, #1
10255 mov [bx+0x408], dx ; Parallel I/O address
10256 pop bx
10257 mov [bx+0x478], cl ; Parallel printer timeout
10258 inc bx
10259no_parport:
10260 ret
10261
10262; serial port detection: base address in DX, index in BX, timeout in CL
10263detect_serial:
10264 push dx
10265 inc dx
10266 mov al, #0x02
10267 out dx, al
10268 in al, dx
10269 cmp al, #0x02
10270 jne no_serial
10271 inc dx
10272 in al, dx
10273 cmp al, #0x02
10274 jne no_serial
10275 dec dx
10276 xor al, al
10277 out dx, al
10278 pop dx
10279 push bx
10280 shl bx, #1
10281 mov [bx+0x400], dx ; Serial I/O address
10282 pop bx
10283 mov [bx+0x47c], cl ; Serial timeout
10284 inc bx
10285 ret
10286no_serial:
10287 pop dx
10288 ret
10289
10290rom_checksum:
10291 push ax
10292 push bx
10293 push cx
10294 xor ax, ax
10295 xor bx, bx
10296 xor cx, cx
10297 mov ch, [2]
10298 shl cx, #1
10299checksum_loop:
10300 add al, [bx]
10301 inc bx
10302 loop checksum_loop
10303 and al, #0xff
10304 pop cx
10305 pop bx
10306 pop ax
10307 ret
10308
10309rom_scan:
10310 ;; Scan for existence of valid expansion ROMS.
10311 ;; Video ROM: from 0xC0000..0xC7FFF in 2k increments
10312 ;; General ROM: from 0xC8000..0xDFFFF in 2k increments
10313 ;; System ROM: only 0xE0000
10314 ;;
10315 ;; Header:
10316 ;; Offset Value
10317 ;; 0 0x55
10318 ;; 1 0xAA
10319 ;; 2 ROM length in 512-byte blocks
10320 ;; 3 ROM initialization entry point (FAR CALL)
10321
10322 mov cx, #0xc000
10323rom_scan_loop:
10324 mov ds, cx
10325 mov ax, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
10326 cmp [0], #0xAA55 ;; look for signature
10327 jne rom_scan_increment
10328 call rom_checksum
10329 jnz rom_scan_increment
10330 mov al, [2] ;; change increment to ROM length in 512-byte blocks
10331
10332 ;; We want our increment in 512-byte quantities, rounded to
10333 ;; the nearest 2k quantity, since we only scan at 2k intervals.
10334 test al, #0x03
10335 jz block_count_rounded
10336 and al, #0xfc ;; needs rounding up
10337 add al, #0x04
10338block_count_rounded:
10339
10340 xor bx, bx ;; Restore DS back to 0000:
10341 mov ds, bx
10342 push ax ;; Save AX
10343 ;; Push addr of ROM entry point
10344 push cx ;; Push seg
10345 push #0x0003 ;; Push offset
10346 mov bp, sp ;; Call ROM init routine using seg:off on stack
10347 db 0xff ;; call_far ss:[bp+0]
10348 db 0x5e
10349 db 0
10350 cli ;; In case expansion ROM BIOS turns IF on
10351 add sp, #2 ;; Pop offset value
10352 pop cx ;; Pop seg value (restore CX)
10353 pop ax ;; Restore AX
10354rom_scan_increment:
10355 shl ax, #5 ;; convert 512-bytes blocks to 16-byte increments
10356 ;; because the segment selector is shifted left 4 bits.
10357 add cx, ax
10358 cmp cx, #0xe000
10359 jbe rom_scan_loop
10360
10361 xor ax, ax ;; Restore DS back to 0000:
10362 mov ds, ax
10363 ret
10364
10365;; for 'C' strings and other data, insert them here with
10366;; a the following hack:
10367;; DATA_SEG_DEFS_HERE
10368
10369
10370;; the following area can be used to write dynamically generated tables
10371 .align 16
10372bios_table_area_start:
10373 dd 0xaafb4442
10374 dd bios_table_area_end - bios_table_area_start - 8;
10375
10376;--------
10377;- POST -
10378;--------
10379.org 0xe05b ; POST Entry Point
10380bios_table_area_end:
10381post:
10382
10383 xor ax, ax
10384
10385 ;; first reset the DMA controllers
10386 out 0x0d,al
10387 out 0xda,al
10388
10389 ;; then initialize the DMA controllers
10390 mov al, #0xC0
10391 out 0xD6, al ; cascade mode of channel 4 enabled
10392 mov al, #0x00
10393 out 0xD4, al ; unmask channel 4
10394
10395 ;; Examine CMOS shutdown status.
10396 mov AL, #0x0f
10397 out 0x70, AL
10398 in AL, 0x71
10399
10400 ;; backup status
10401 mov bl, al
10402
10403 ;; Reset CMOS shutdown status.
10404 mov AL, #0x0f
10405 out 0x70, AL ; select CMOS register Fh
10406 mov AL, #0x00
10407 out 0x71, AL ; set shutdown action to normal
10408
10409 ;; Examine CMOS shutdown status.
10410 mov al, bl
10411
10412 ;; 0x00, 0x09, 0x0D+ = normal startup
10413 cmp AL, #0x00
10414 jz normal_post
10415 cmp AL, #0x0d
10416 jae normal_post
10417 cmp AL, #0x09
10418 je normal_post
10419
10420 ;; 0x05 = eoi + jmp via [0x40:0x67] jump
10421 cmp al, #0x05
10422 je eoi_jmp_post
10423
10424 ;; Examine CMOS shutdown status.
10425 ;; 0x01,0x02,0x03,0x04,0x06,0x07,0x08, 0x0a, 0x0b, 0x0c = Unimplemented shutdown status.
10426 push bx
10427 call _shutdown_status_panic
10428
10429#if 0
10430 HALT(__LINE__)
10431 ;
10432 ;#if 0
10433 ; 0xb0, 0x20, /* mov al, #0x20 */
10434 ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */
10435 ;#endif
10436 ;
10437 pop es
10438 pop ds
10439 popa
10440 iret
10441#endif
10442
10443normal_post:
10444 ; case 0: normal startup
10445
10446 cli
10447 mov ax, #0xfffe
10448 mov sp, ax
10449 xor ax, ax
10450 mov ds, ax
10451 mov ss, ax
10452
10453#ifndef VBOX
10454 ;; zero out BIOS data area (40:00..40:ff)
10455 mov es, ax
10456 mov cx, #0x0080 ;; 128 words
10457 mov di, #0x0400
10458 cld
10459 rep
10460 stosw
10461#else /* VBOX */
10462 ;; zero out segment 0 (includes BIOS data area) except word at 40:72
10463 mov es, ax
10464 xor di, di
10465 cld
10466 mov cx, #0x0239 ;; 569 words
10467 rep
10468 stosw
10469 inc di
10470 inc di
10471 mov cx, #0x7dc6 ;; 32198 words
10472 rep
10473 stosw
10474 ;; zero out remaining base memory
10475 xor eax, eax
10476 xor bx, bx
10477memory_zero_loop:
10478 add bx, #0x1000
10479 cmp bx, #0xa000
10480 jae memory_cleared
10481 mov es, bx
10482 xor di, di
10483 mov cx, #0x4000
10484 rep
10485 stosd
10486 jmp memory_zero_loop
10487memory_cleared:
10488 xor bx, bx
10489#endif
10490
10491 call _log_bios_start
10492
10493 ;; set all interrupts to default handler
10494 xor bx, bx ;; offset index
10495 mov cx, #0x0100 ;; counter (256 interrupts)
10496 mov ax, #dummy_iret_handler
10497 mov dx, #0xF000
10498
10499post_default_ints:
10500 mov [bx], ax
10501 inc bx
10502 inc bx
10503 mov [bx], dx
10504 inc bx
10505 inc bx
10506 loop post_default_ints
10507
10508 ;; set vector 0x79 to zero
10509 ;; this is used by 'gardian angel' protection system
10510 SET_INT_VECTOR(0x79, #0, #0)
10511
10512 ;; base memory in K 40:13 (word)
10513 mov ax, #BASE_MEM_IN_K
10514 mov 0x0413, ax
10515
10516
10517 ;; Manufacturing Test 40:12
10518 ;; zerod out above
10519
10520#ifndef VBOX
10521 ;; Warm Boot Flag 0040:0072
10522 ;; value of 1234h = skip memory checks
10523 ;; zerod out above
10524#endif /* !VBOX */
10525
10526
10527 ;; Printer Services vector
10528 SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
10529
10530 ;; Bootstrap failure vector
10531 SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
10532
10533 ;; Bootstrap Loader vector
10534 SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
10535
10536 ;; User Timer Tick vector
10537 SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
10538
10539 ;; Memory Size Check vector
10540 SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
10541
10542 ;; Equipment Configuration Check vector
10543 SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
10544
10545 ;; System Services
10546 SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
10547
10548 ;; EBDA setup
10549 call ebda_post
10550
10551 ;; PIT setup
10552 SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
10553 ;; int 1C already points at dummy_iret_handler (above)
10554 mov al, #0x34 ; timer0: binary count, 16bit count, mode 2
10555 out 0x43, al
10556 mov al, #0x00 ; maximum count of 0000H = 18.2Hz
10557 out 0x40, al
10558 out 0x40, al
10559
10560 ;; Keyboard
10561 SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
10562 SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
10563
10564 xor ax, ax
10565 mov ds, ax
10566 mov 0x0417, al /* keyboard shift flags, set 1 */
10567 mov 0x0418, al /* keyboard shift flags, set 2 */
10568 mov 0x0419, al /* keyboard alt-numpad work area */
10569 mov 0x0471, al /* keyboard ctrl-break flag */
10570 mov 0x0497, al /* keyboard status flags 4 */
10571 mov al, #0x10
10572 mov 0x0496, al /* keyboard status flags 3 */
10573
10574
10575 /* keyboard head of buffer pointer */
10576 mov bx, #0x001E
10577 mov 0x041A, bx
10578
10579 /* keyboard end of buffer pointer */
10580 mov 0x041C, bx
10581
10582 /* keyboard pointer to start of buffer */
10583 mov bx, #0x001E
10584 mov 0x0480, bx
10585
10586 /* keyboard pointer to end of buffer */
10587 mov bx, #0x003E
10588 mov 0x0482, bx
10589
10590 /* init the keyboard */
10591 call _keyboard_init
10592
10593 ;; mov CMOS Equipment Byte to BDA Equipment Word
10594 mov ax, 0x0410
10595 mov al, #0x14
10596 out 0x70, al
10597 in al, 0x71
10598 mov 0x0410, ax
10599
10600
10601 ;; Parallel setup
10602 SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
10603 xor ax, ax
10604 mov ds, ax
10605 xor bx, bx
10606 mov cl, #0x14 ; timeout value
10607 mov dx, #0x378 ; Parallel I/O address, port 1
10608 call detect_parport
10609 mov dx, #0x278 ; Parallel I/O address, port 2
10610 call detect_parport
10611 shl bx, #0x0e
10612 mov ax, 0x410 ; Equipment word bits 14..15 determing # parallel ports
10613 and ax, #0x3fff
10614 or ax, bx ; set number of parallel ports
10615 mov 0x410, ax
10616
10617 ;; Serial setup
10618 SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
10619 SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
10620 xor bx, bx
10621 mov cl, #0x0a ; timeout value
10622 mov dx, #0x03f8 ; Serial I/O address, port 1
10623 call detect_serial
10624 mov dx, #0x02f8 ; Serial I/O address, port 2
10625 call detect_serial
10626 mov dx, #0x03e8 ; Serial I/O address, port 3
10627 call detect_serial
10628 mov dx, #0x02e8 ; Serial I/O address, port 4
10629 call detect_serial
10630 shl bx, #0x09
10631 mov ax, 0x410 ; Equipment word bits 9..11 determing # serial ports
10632 and ax, #0xf1ff
10633 or ax, bx ; set number of serial port
10634 mov 0x410, ax
10635
10636 ;; CMOS RTC
10637 SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
10638 SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
10639 SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
10640 ;; BIOS DATA AREA 0x4CE ???
10641 call timer_tick_post
10642
10643 ;; PS/2 mouse setup
10644 SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
10645
10646 ;; IRQ13 (FPU exception) setup
10647 SET_INT_VECTOR(0x75, #0xF000, #int75_handler)
10648
10649 ;; Video setup
10650 SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
10651
10652 ;; PIC
10653 mov al, #0x11 ; send initialisation commands
10654 out 0x20, al
10655 out 0xa0, al
10656 mov al, #0x08
10657 out 0x21, al
10658 mov al, #0x70
10659 out 0xa1, al
10660 mov al, #0x04
10661 out 0x21, al
10662 mov al, #0x02
10663 out 0xa1, al
10664 mov al, #0x01
10665 out 0x21, al
10666 out 0xa1, al
10667 mov al, #0xb8
10668 out 0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6
10669#if BX_USE_PS2_MOUSE
10670 mov al, #0x8f
10671#else
10672 mov al, #0x9f
10673#endif
10674 out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14
10675
10676#if BX_ROMBIOS32
10677 call rombios32_init
10678#else
10679 call pcibios_init_iomem_bases
10680 call pcibios_init_irqs
10681#endif
10682 call rom_scan
10683
10684 call _print_bios_banner
10685
10686 ;;
10687 ;; Floppy setup
10688 ;;
10689 call floppy_drive_post
10690
10691#if BX_USE_ATADRV
10692
10693 ;;
10694 ;; Hard Drive setup
10695 ;;
10696 call hard_drive_post
10697
10698 ;;
10699 ;; ATA/ATAPI driver setup
10700 ;;
10701 call _ata_init
10702 call _ata_detect
10703 ;;
10704#else // BX_USE_ATADRV
10705
10706 ;;
10707 ;; Hard Drive setup
10708 ;;
10709 call hard_drive_post
10710
10711#endif // BX_USE_ATADRV
10712
10713#if BX_ELTORITO_BOOT
10714 ;;
10715 ;; eltorito floppy/harddisk emulation from cd
10716 ;;
10717 call _cdemu_init
10718 ;;
10719#endif // BX_ELTORITO_BOOT
10720
10721 sti ;; enable interrupts
10722 int #0x19
10723
10724
10725.org 0xe2c3 ; NMI Handler Entry Point
10726nmi:
10727 ;; FIXME the NMI handler should not panic
10728 ;; but iret when called from int75 (fpu exception)
10729 call _nmi_handler_msg
10730 iret
10731
10732int75_handler:
10733 out 0xf0, al // clear irq13
10734 call eoi_both_pics // clear interrupt
10735 int 2 // legacy nmi call
10736 iret
10737
10738;-------------------------------------------
10739;- INT 13h Fixed Disk Services Entry Point -
10740;-------------------------------------------
10741.org 0xe3fe ; INT 13h Fixed Disk Services Entry Point
10742int13_handler:
10743 //JMPL(int13_relocated)
10744 jmp int13_relocated
10745
10746.org 0xe401 ; Fixed Disk Parameter Table
10747
10748;----------
10749;- INT19h -
10750;----------
10751.org 0xe6f2 ; INT 19h Boot Load Service Entry Point
10752int19_handler:
10753
10754 jmp int19_relocated
10755;-------------------------------------------
10756;- System BIOS Configuration Data Table
10757;-------------------------------------------
10758.org BIOS_CONFIG_TABLE
10759db 0x08 ; Table size (bytes) -Lo
10760db 0x00 ; Table size (bytes) -Hi
10761db SYS_MODEL_ID
10762db SYS_SUBMODEL_ID
10763db BIOS_REVISION
10764; Feature byte 1
10765; b7: 1=DMA channel 3 used by hard disk
10766; b6: 1=2 interrupt controllers present
10767; b5: 1=RTC present
10768; b4: 1=BIOS calls int 15h/4Fh every key
10769; b3: 1=wait for extern event supported (Int 15h/41h)
10770; b2: 1=extended BIOS data area used
10771; b1: 0=AT or ESDI bus, 1=MicroChannel
10772; b0: 1=Dual bus (MicroChannel + ISA)
10773db (0 << 7) | \
10774 (1 << 6) | \
10775 (1 << 5) | \
10776 (BX_CALL_INT15_4F << 4) | \
10777 (0 << 3) | \
10778 (BX_USE_EBDA << 2) | \
10779 (0 << 1) | \
10780 (0 << 0)
10781; Feature byte 2
10782; b7: 1=32-bit DMA supported
10783; b6: 1=int16h, function 9 supported
10784; b5: 1=int15h/C6h (get POS data) supported
10785; b4: 1=int15h/C7h (get mem map info) supported
10786; b3: 1=int15h/C8h (en/dis CPU) supported
10787; b2: 1=non-8042 kb controller
10788; b1: 1=data streaming supported
10789; b0: reserved
10790db (0 << 7) | \
10791 (1 << 6) | \
10792 (0 << 5) | \
10793 (0 << 4) | \
10794 (0 << 3) | \
10795 (0 << 2) | \
10796 (0 << 1) | \
10797 (0 << 0)
10798; Feature byte 3
10799; b7: not used
10800; b6: reserved
10801; b5: reserved
10802; b4: POST supports ROM-to-RAM enable/disable
10803; b3: SCSI on system board
10804; b2: info panel installed
10805; b1: Initial Machine Load (IML) system - BIOS on disk
10806; b0: SCSI supported in IML
10807db 0x00
10808; Feature byte 4
10809; b7: IBM private
10810; b6: EEPROM present
10811; b5-3: ABIOS presence (011 = not supported)
10812; b2: private
10813; b1: memory split above 16Mb supported
10814; b0: POSTEXT directly supported by POST
10815db 0x00
10816; Feature byte 5 (IBM)
10817; b1: enhanced mouse
10818; b0: flash EPROM
10819db 0x00
10820
10821
10822
10823.org 0xe729 ; Baud Rate Generator Table
10824
10825;----------
10826;- INT14h -
10827;----------
10828.org 0xe739 ; INT 14h Serial Communications Service Entry Point
10829int14_handler:
10830 push ds
10831 pusha
10832 xor ax, ax
10833 mov ds, ax
10834 call _int14_function
10835 popa
10836 pop ds
10837 iret
10838
10839
10840;----------------------------------------
10841;- INT 16h Keyboard Service Entry Point -
10842;----------------------------------------
10843.org 0xe82e
10844int16_handler:
10845
10846 sti
10847 push ds
10848 pushf
10849 pusha
10850
10851 cmp ah, #0x00
10852 je int16_F00
10853 cmp ah, #0x10
10854 je int16_F00
10855
10856 mov bx, #0xf000
10857 mov ds, bx
10858 call _int16_function
10859 popa
10860 popf
10861 pop ds
10862 jz int16_zero_set
10863
10864int16_zero_clear:
10865 push bp
10866 mov bp, sp
10867 //SEG SS
10868 and BYTE [bp + 0x06], #0xbf
10869 pop bp
10870 iret
10871
10872int16_zero_set:
10873 push bp
10874 mov bp, sp
10875 //SEG SS
10876 or BYTE [bp + 0x06], #0x40
10877 pop bp
10878 iret
10879
10880int16_F00:
10881 mov bx, #0x0040
10882 mov ds, bx
10883
10884int16_wait_for_key:
10885 cli
10886 mov bx, 0x001a
10887 cmp bx, 0x001c
10888 jne int16_key_found
10889 sti
10890 nop
10891#if 0
10892 /* no key yet, call int 15h, function AX=9002 */
10893 0x50, /* push AX */
10894 0xb8, 0x02, 0x90, /* mov AX, #0x9002 */
10895 0xcd, 0x15, /* int 15h */
10896 0x58, /* pop AX */
10897 0xeb, 0xea, /* jmp WAIT_FOR_KEY */
10898#endif
10899 jmp int16_wait_for_key
10900
10901int16_key_found:
10902 mov bx, #0xf000
10903 mov ds, bx
10904 call _int16_function
10905 popa
10906 popf
10907 pop ds
10908#if 0
10909 /* notify int16 complete w/ int 15h, function AX=9102 */
10910 0x50, /* push AX */
10911 0xb8, 0x02, 0x91, /* mov AX, #0x9102 */
10912 0xcd, 0x15, /* int 15h */
10913 0x58, /* pop AX */
10914#endif
10915 iret
10916
10917
10918
10919;-------------------------------------------------
10920;- INT09h : Keyboard Hardware Service Entry Point -
10921;-------------------------------------------------
10922.org 0xe987
10923int09_handler:
10924 cli
10925 push ax
10926
10927 mov al, #0xAD ;;disable keyboard
10928 out #0x64, al
10929
10930 mov al, #0x0B
10931 out #0x20, al
10932 in al, #0x20
10933 and al, #0x02
10934 jz int09_finish
10935
10936 in al, #0x60 ;;read key from keyboard controller
10937 sti
10938 push ds
10939 pusha
10940#ifdef BX_CALL_INT15_4F
10941 mov ah, #0x4f ;; allow for keyboard intercept
10942 stc
10943 int #0x15
10944 jnc int09_done
10945#endif
10946
10947 ;; check for extended key
10948 cmp al, #0xe0
10949 jne int09_check_pause
10950 xor ax, ax
10951 mov ds, ax
10952 mov al, BYTE [0x496] ;; mf2_state |= 0x02
10953 or al, #0x02
10954 mov BYTE [0x496], al
10955 jmp int09_done
10956
10957int09_check_pause: ;; check for pause key
10958 cmp al, #0xe1
10959 jne int09_process_key
10960 xor ax, ax
10961 mov ds, ax
10962 mov al, BYTE [0x496] ;; mf2_state |= 0x01
10963 or al, #0x01
10964 mov BYTE [0x496], al
10965 jmp int09_done
10966
10967int09_process_key:
10968 mov bx, #0xf000
10969 mov ds, bx
10970 call _int09_function
10971
10972int09_done:
10973 popa
10974 pop ds
10975 cli
10976 call eoi_master_pic
10977
10978int09_finish:
10979 mov al, #0xAE ;;enable keyboard
10980 out #0x64, al
10981 pop ax
10982 iret
10983
10984
10985;----------------------------------------
10986;- INT 13h Diskette Service Entry Point -
10987;----------------------------------------
10988.org 0xec59
10989int13_diskette:
10990 jmp int13_noeltorito
10991
10992;---------------------------------------------
10993;- INT 0Eh Diskette Hardware ISR Entry Point -
10994;---------------------------------------------
10995.org 0xef57 ; INT 0Eh Diskette Hardware ISR Entry Point
10996int0e_handler:
10997 push ax
10998 push dx
10999 mov dx, #0x03f4
11000 in al, dx
11001 and al, #0xc0
11002 cmp al, #0xc0
11003 je int0e_normal
11004 mov dx, #0x03f5
11005 mov al, #0x08 ; sense interrupt status
11006 out dx, al
11007int0e_loop1:
11008 mov dx, #0x03f4
11009 in al, dx
11010 and al, #0xc0
11011 cmp al, #0xc0
11012 jne int0e_loop1
11013int0e_loop2:
11014 mov dx, #0x03f5
11015 in al, dx
11016 mov dx, #0x03f4
11017 in al, dx
11018 and al, #0xc0
11019 cmp al, #0xc0
11020 je int0e_loop2
11021int0e_normal:
11022 push ds
11023 xor ax, ax ;; segment 0000
11024 mov ds, ax
11025 call eoi_master_pic
11026 mov al, 0x043e
11027 or al, #0x80 ;; diskette interrupt has occurred
11028 mov 0x043e, al
11029 pop ds
11030 pop dx
11031 pop ax
11032 iret
11033
11034
11035.org 0xefc7 ; Diskette Controller Parameter Table
11036diskette_param_table:
11037;; Since no provisions are made for multiple drive types, most
11038;; values in this table are ignored. I set parameters for 1.44M
11039;; floppy here
11040db 0xAF
11041db 0x02 ;; head load time 0000001, DMA used
11042db 0x25
11043db 0x02
11044db 18
11045db 0x1B
11046db 0xFF
11047db 0x6C
11048db 0xF6
11049db 0x0F
11050db 0x08
11051
11052
11053;----------------------------------------
11054;- INT17h : Printer Service Entry Point -
11055;----------------------------------------
11056.org 0xefd2
11057int17_handler:
11058 push ds
11059 pusha
11060 xor ax, ax
11061 mov ds, ax
11062 call _int17_function
11063 popa
11064 pop ds
11065 iret
11066
11067diskette_param_table2:
11068;; New diskette parameter table adding 3 parameters from IBM
11069;; Since no provisions are made for multiple drive types, most
11070;; values in this table are ignored. I set parameters for 1.44M
11071;; floppy here
11072db 0xAF
11073db 0x02 ;; head load time 0000001, DMA used
11074db 0x25
11075db 0x02
11076db 18
11077db 0x1B
11078db 0xFF
11079db 0x6C
11080db 0xF6
11081db 0x0F
11082db 0x08
11083db 79 ;; maximum track
11084db 0 ;; data transfer rate
11085db 4 ;; drive type in cmos
11086
11087.org 0xf045 ; INT 10 Functions 0-Fh Entry Point
11088 HALT(__LINE__)
11089 iret
11090
11091;----------
11092;- INT10h -
11093;----------
11094.org 0xf065 ; INT 10h Video Support Service Entry Point
11095int10_handler:
11096 ;; dont do anything, since the VGA BIOS handles int10h requests
11097 iret
11098
11099.org 0xf0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
11100
11101;----------
11102;- INT12h -
11103;----------
11104.org 0xf841 ; INT 12h Memory Size Service Entry Point
11105; ??? different for Pentium (machine check)?
11106int12_handler:
11107 push ds
11108 mov ax, #0x0040
11109 mov ds, ax
11110 mov ax, 0x0013
11111 pop ds
11112 iret
11113
11114;----------
11115;- INT11h -
11116;----------
11117.org 0xf84d ; INT 11h Equipment List Service Entry Point
11118int11_handler:
11119 push ds
11120 mov ax, #0x0040
11121 mov ds, ax
11122 mov ax, 0x0010
11123 pop ds
11124 iret
11125
11126;----------
11127;- INT15h -
11128;----------
11129.org 0xf859 ; INT 15h System Services Entry Point
11130int15_handler:
11131 pushf
11132#if BX_APM
11133 cmp ah, #0x53
11134 je apm_call
11135#endif
11136 push ds
11137 push es
11138 cmp ah, #0x86
11139 je int15_handler32
11140 cmp ah, #0xE8
11141 je int15_handler32
11142 pusha
11143#if BX_USE_PS2_MOUSE
11144 cmp ah, #0xC2
11145 je int15_handler_mouse
11146#endif
11147 call _int15_function
11148int15_handler_mouse_ret:
11149 popa
11150int15_handler32_ret:
11151 pop es
11152 pop ds
11153 popf
11154 jmp iret_modify_cf
11155#if BX_APM
11156apm_call:
11157 jmp _apmreal_entry
11158#endif
11159
11160#if BX_USE_PS2_MOUSE
11161int15_handler_mouse:
11162 call _int15_function_mouse
11163 jmp int15_handler_mouse_ret
11164#endif
11165
11166int15_handler32:
11167 pushad
11168 call _int15_function32
11169 popad
11170 jmp int15_handler32_ret
11171
11172;; Protected mode IDT descriptor
11173;;
11174;; I just make the limit 0, so the machine will shutdown
11175;; if an exception occurs during protected mode memory
11176;; transfers.
11177;;
11178;; Set base to f0000 to correspond to beginning of BIOS,
11179;; in case I actually define an IDT later
11180;; Set limit to 0
11181
11182pmode_IDT_info:
11183dw 0x0000 ;; limit 15:00
11184dw 0x0000 ;; base 15:00
11185db 0x0f ;; base 23:16
11186
11187;; Real mode IDT descriptor
11188;;
11189;; Set to typical real-mode values.
11190;; base = 000000
11191;; limit = 03ff
11192
11193rmode_IDT_info:
11194dw 0x03ff ;; limit 15:00
11195dw 0x0000 ;; base 15:00
11196db 0x00 ;; base 23:16
11197
11198
11199;----------
11200;- INT1Ah -
11201;----------
11202.org 0xfe6e ; INT 1Ah Time-of-day Service Entry Point
11203int1a_handler:
11204#if BX_PCIBIOS
11205 cmp ah, #0xb1
11206 jne int1a_normal
11207 call pcibios_real
11208 jc pcibios_error
11209 retf 2
11210pcibios_error:
11211 mov bl, ah
11212 mov ah, #0xb1
11213 push ds
11214 pusha
11215 mov ax, ss ; set readable descriptor to ds, for calling pcibios
11216 mov ds, ax ; on 16bit protected mode.
11217 jmp int1a_callfunction
11218int1a_normal:
11219#endif
11220 push ds
11221 pusha
11222 xor ax, ax
11223 mov ds, ax
11224int1a_callfunction:
11225 call _int1a_function
11226 popa
11227 pop ds
11228 iret
11229
11230;;
11231;; int70h: IRQ8 - CMOS RTC
11232;;
11233int70_handler:
11234 push ds
11235 pushad
11236 xor ax, ax
11237 mov ds, ax
11238 call _int70_function
11239 popad
11240 pop ds
11241 iret
11242
11243;---------
11244;- INT08 -
11245;---------
11246.org 0xfea5 ; INT 08h System Timer ISR Entry Point
11247int08_handler:
11248 sti
11249 push eax
11250 push ds
11251 xor ax, ax
11252 mov ds, ax
11253
11254 ;; time to turn off drive(s)?
11255 mov al,0x0440
11256 or al,al
11257 jz int08_floppy_off
11258 dec al
11259 mov 0x0440,al
11260 jnz int08_floppy_off
11261 ;; turn motor(s) off
11262 push dx
11263 mov dx,#0x03f2
11264 in al,dx
11265 and al,#0xcf
11266 out dx,al
11267 pop dx
11268int08_floppy_off:
11269
11270 mov eax, 0x046c ;; get ticks dword
11271 inc eax
11272
11273 ;; compare eax to one days worth of timer ticks at 18.2 hz
11274 cmp eax, #0x001800B0
11275 jb int08_store_ticks
11276 ;; there has been a midnight rollover at this point
11277 xor eax, eax ;; zero out counter
11278 inc BYTE 0x0470 ;; increment rollover flag
11279
11280int08_store_ticks:
11281 mov 0x046c, eax ;; store new ticks dword
11282 ;; chain to user timer tick INT #0x1c
11283 //pushf
11284 //;; call_ep [ds:loc]
11285 //CALL_EP( 0x1c << 2 )
11286 int #0x1c
11287 cli
11288 call eoi_master_pic
11289 pop ds
11290 pop eax
11291 iret
11292
11293.org 0xfef3 ; Initial Interrupt Vector Offsets Loaded by POST
11294
11295
11296.org 0xff00
11297.ascii BIOS_COPYRIGHT_STRING
11298
11299#ifdef VBOX
11300// The DMI header
11301.org 0xff40
11302.align 16
11303 db 0x5f, 0x44, 0x4d, 0x49, 0x5f ; "_DMI_" signature
11304 ; calculate the DMI header checksum
11305 db ( - ( 0x5f + 0x44 + 0x4d + 0x49 + 0x5f \
11306 + ((VBOX_DMI_TABLE_BASE ) & 0xff) + ((VBOX_DMI_TABLE_BASE >> 8) & 0xff) \
11307 + ((VBOX_DMI_TABLE_BASE >> 16) & 0xff) + ((VBOX_DMI_TABLE_BASE >> 24) & 0xff) \
11308 + ((VBOX_DMI_TABLE_SIZE ) & 0xff) + ((VBOX_DMI_TABLE_SIZE >> 8) & 0xff) \
11309 + ((VBOX_DMI_TABLE_ENTR ) & 0xff) + ((VBOX_DMI_TABLE_ENTR >> 8) & 0xff) \
11310 + VBOX_DMI_TABLE_VER \
11311 )) & 0xff
11312 dw VBOX_DMI_TABLE_SIZE ; DMI tables length
11313 dd VBOX_DMI_TABLE_BASE ; DMI tables base
11314 dw VBOX_DMI_TABLE_ENTR ; DMI tables entries
11315 db VBOX_DMI_TABLE_VER ; DMI version
11316 db 0x00 ; Just for alignment
11317#endif
11318
11319;------------------------------------------------
11320;- IRET Instruction for Dummy Interrupt Handler -
11321;------------------------------------------------
11322.org 0xff53 ; IRET Instruction for Dummy Interrupt Handler
11323dummy_iret_handler:
11324 iret
11325
11326.org 0xff54 ; INT 05h Print Screen Service Entry Point
11327 HALT(__LINE__)
11328 iret
11329
11330.org 0xfff0 ; Power-up Entry Point
11331 jmp 0xf000:post
11332
11333.org 0xfff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
11334.ascii BIOS_BUILD_DATE
11335
11336.org 0xfffe ; System Model ID
11337db SYS_MODEL_ID
11338db 0x00 ; filler
11339
11340.org 0xfa6e ;; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
11341ASM_END
11342/*
11343 * This font comes from the fntcol16.zip package (c) by Joseph Gil
11344 * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
11345 * This font is public domain
11346 */
11347static Bit8u vgafont8[128*8]=
11348{
11349 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
11350 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
11351 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
11352 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
11353 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
11354 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
11355 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
11356 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
11357 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
11358 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
11359 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
11360 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
11361 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
11362 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
11363 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
11364 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
11365 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
11366 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
11367 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
11368 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
11369 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
11370 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
11371 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
11372 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
11373 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
11374 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
11375 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
11376 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
11377 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
11378 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
11379 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
11380 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
11381 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
11382 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
11383 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
11384 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
11385 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
11386 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
11387 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
11388 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
11389 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
11390 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
11391 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
11392 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
11393 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
11394 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
11395 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
11396 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
11397 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
11398 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
11399 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
11400 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
11401 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
11402 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
11403 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
11404 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
11405 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
11406 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
11407 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
11408 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
11409 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
11410 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
11411 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
11412 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
11413 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
11414 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
11415 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
11416 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
11417 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
11418 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
11419 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
11420 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
11421 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
11422 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
11423 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
11424 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
11425 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
11426 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
11427 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
11428 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
11429 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
11430 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
11431 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
11432 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
11433 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
11434 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
11435 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
11436 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
11437 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
11438 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
11439 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
11440 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
11441 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
11442 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
11443 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
11444 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
11445 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
11446 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
11447 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
11448 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
11449 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
11450 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
11451 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
11452 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
11453 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
11454 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
11455 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
11456 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
11457 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
11458 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
11459 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
11460 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
11461 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
11462 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
11463 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
11464 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
11465 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
11466 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
11467 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
11468 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
11469 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
11470 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
11471 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
11472 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
11473 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
11474 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
11475 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
11476 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
11477};
11478
11479ASM_START
11480.org 0xcc00
11481// bcc-generated data will be placed here
11482
11483#ifdef VBOX_SMP
11484// For documentation of this config structure, look on developer.intel.com and
11485// search for multiprocessor specification. Note that when you change anything
11486// you must update the checksum (a pain!). It would be better to construct this
11487// with C structures, or at least fill in the checksum automatically.
11488//
11489// Maybe this structs could be moved elsewhere than d000
11490
11491#if (BX_SMP_PROCESSORS==1)
11492 // no structure necessary.
11493#elif (BX_SMP_PROCESSORS==2)
11494// define the Intel MP Configuration Structure for 2 processors at
11495// APIC ID 0,1. I/O APIC at ID=2.
11496.align 16
11497mp_config_table:
11498 db 0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature
11499 dw (mp_config_end-mp_config_table) ;; table length
11500 db 4 ;; spec rev
11501 db 0x65 ;; checksum
11502 .ascii "BOCHSCPU" ;; OEM id = "BOCHSCPU"
11503 db 0x30, 0x2e, 0x31, 0x20 ;; vendor id = "0.1 "
11504 db 0x20, 0x20, 0x20, 0x20
11505 db 0x20, 0x20, 0x20, 0x20
11506 dw 0,0 ;; oem table ptr
11507 dw 0 ;; oem table size
11508 dw 20 ;; entry count
11509 dw 0x0000, 0xfee0 ;; memory mapped address of local APIC
11510 dw 0 ;; extended table length
11511 db 0 ;; extended table checksum
11512 db 0 ;; reserved
11513mp_config_proc0:
11514 db 0 ;; entry type=processor
11515 db 0 ;; local APIC id
11516 db 0x11 ;; local APIC version number
11517 db 3 ;; cpu flags: enabled, bootstrap processor
11518 db 0,6,0,0 ;; cpu signature
11519 dw 0x201,0 ;; feature flags
11520 dw 0,0 ;; reserved
11521 dw 0,0 ;; reserved
11522mp_config_proc1:
11523 db 0 ;; entry type=processor
11524 db 1 ;; local APIC id
11525 db 0x11 ;; local APIC version number
11526 db 1 ;; cpu flags: enabled
11527 db 0,6,0,0 ;; cpu signature
11528 dw 0x201,0 ;; feature flags
11529 dw 0,0 ;; reserved
11530 dw 0,0 ;; reserved
11531mp_config_isa_bus:
11532 db 1 ;; entry type=bus
11533 db 0 ;; bus ID
11534 db 0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type="ISA "
11535mp_config_ioapic:
11536 db 2 ;; entry type=I/O APIC
11537 db 2 ;; apic id=2. linux will set.
11538 db 0x11 ;; I/O APIC version number
11539 db 1 ;; flags=1=enabled
11540 dw 0x0000, 0xfec0 ;; memory mapped address of I/O APIC
11541mp_config_irqs:
11542 db 3 ;; entry type=I/O interrupt
11543 db 0 ;; interrupt type=vectored interrupt
11544 db 0,0 ;; flags po=0, el=0 (linux uses as default)
11545 db 0 ;; source bus ID is ISA
11546 db 0 ;; source bus IRQ
11547 db 2 ;; destination I/O APIC ID
11548 db 0 ;; destination I/O APIC interrrupt in
11549 ;; repeat pattern for interrupts 0-15
11550 db 3,0,0,0,0,1,2,1
11551 db 3,0,0,0,0,2,2,2
11552 db 3,0,0,0,0,3,2,3
11553 db 3,0,0,0,0,4,2,4
11554 db 3,0,0,0,0,5,2,5
11555 db 3,0,0,0,0,6,2,6
11556 db 3,0,0,0,0,7,2,7
11557 db 3,0,0,0,0,8,2,8
11558 db 3,0,0,0,0,9,2,9
11559 db 3,0,0,0,0,10,2,10
11560 db 3,0,0,0,0,11,2,11
11561 db 3,0,0,0,0,12,2,12
11562 db 3,0,0,0,0,13,2,13
11563 db 3,0,0,0,0,14,2,14
11564 db 3,0,0,0,0,15,2,15
11565#elif (BX_SMP_PROCESSORS==4)
11566// define the Intel MP Configuration Structure for 4 processors at
11567// APIC ID 0,1,2,3. I/O APIC at ID=4.
11568.align 16
11569mp_config_table:
11570 db 0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature
11571 dw (mp_config_end-mp_config_table) ;; table length
11572 db 4 ;; spec rev
11573 db 0xdd ;; checksum
11574 .ascii "BOCHSCPU" ;; OEM id = "BOCHSCPU"
11575 db 0x30, 0x2e, 0x31, 0x20 ;; vendor id = "0.1 "
11576 db 0x20, 0x20, 0x20, 0x20
11577 db 0x20, 0x20, 0x20, 0x20
11578 dw 0,0 ;; oem table ptr
11579 dw 0 ;; oem table size
11580 dw 22 ;; entry count
11581 dw 0x0000, 0xfee0 ;; memory mapped address of local APIC
11582 dw 0 ;; extended table length
11583 db 0 ;; extended table checksum
11584 db 0 ;; reserved
11585mp_config_proc0:
11586 db 0 ;; entry type=processor
11587 db 0 ;; local APIC id
11588 db 0x11 ;; local APIC version number
11589 db 3 ;; cpu flags: enabled, bootstrap processor
11590 db 0,6,0,0 ;; cpu signature
11591 dw 0x201,0 ;; feature flags
11592 dw 0,0 ;; reserved
11593 dw 0,0 ;; reserved
11594mp_config_proc1:
11595 db 0 ;; entry type=processor
11596 db 1 ;; local APIC id
11597 db 0x11 ;; local APIC version number
11598 db 1 ;; cpu flags: enabled
11599 db 0,6,0,0 ;; cpu signature
11600 dw 0x201,0 ;; feature flags
11601 dw 0,0 ;; reserved
11602 dw 0,0 ;; reserved
11603mp_config_proc2:
11604 db 0 ;; entry type=processor
11605 db 2 ;; local APIC id
11606 db 0x11 ;; local APIC version number
11607 db 1 ;; cpu flags: enabled
11608 db 0,6,0,0 ;; cpu signature
11609 dw 0x201,0 ;; feature flags
11610 dw 0,0 ;; reserved
11611 dw 0,0 ;; reserved
11612mp_config_proc3:
11613 db 0 ;; entry type=processor
11614 db 3 ;; local APIC id
11615 db 0x11 ;; local APIC version number
11616 db 1 ;; cpu flags: enabled
11617 db 0,6,0,0 ;; cpu signature
11618 dw 0x201,0 ;; feature flags
11619 dw 0,0 ;; reserved
11620 dw 0,0 ;; reserved
11621mp_config_isa_bus:
11622 db 1 ;; entry type=bus
11623 db 0 ;; bus ID
11624 db 0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type="ISA "
11625mp_config_ioapic:
11626 db 2 ;; entry type=I/O APIC
11627 db 4 ;; apic id=4. linux will set.
11628 db 0x11 ;; I/O APIC version number
11629 db 1 ;; flags=1=enabled
11630 dw 0x0000, 0xfec0 ;; memory mapped address of I/O APIC
11631mp_config_irqs:
11632 db 3 ;; entry type=I/O interrupt
11633 db 0 ;; interrupt type=vectored interrupt
11634 db 0,0 ;; flags po=0, el=0 (linux uses as default)
11635 db 0 ;; source bus ID is ISA
11636 db 0 ;; source bus IRQ
11637 db 4 ;; destination I/O APIC ID
11638 db 0 ;; destination I/O APIC interrrupt in
11639 ;; repeat pattern for interrupts 0-15
11640 db 3,0,0,0,0,1,4,1
11641 db 3,0,0,0,0,2,4,2
11642 db 3,0,0,0,0,3,4,3
11643 db 3,0,0,0,0,4,4,4
11644 db 3,0,0,0,0,5,4,5
11645 db 3,0,0,0,0,6,4,6
11646 db 3,0,0,0,0,7,4,7
11647 db 3,0,0,0,0,8,4,8
11648 db 3,0,0,0,0,9,4,9
11649 db 3,0,0,0,0,10,4,10
11650 db 3,0,0,0,0,11,4,11
11651 db 3,0,0,0,0,12,4,12
11652 db 3,0,0,0,0,13,4,13
11653 db 3,0,0,0,0,14,4,14
11654 db 3,0,0,0,0,15,4,15
11655#elif (BX_SMP_PROCESSORS==8)
11656// define the Intel MP Configuration Structure for 8 processors at
11657// APIC ID 0,1,2,3,4,5,6,7. I/O APIC at ID=8.
11658.align 16
11659mp_config_table:
11660 db 0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature
11661 dw (mp_config_end-mp_config_table) ;; table length
11662 db 4 ;; spec rev
11663 db 0xc3 ;; checksum
11664 .ascii "BOCHSCPU" ;; OEM id = "BOCHSCPU"
11665 db 0x30, 0x2e, 0x31, 0x20 ;; vendor id = "0.1 "
11666 db 0x20, 0x20, 0x20, 0x20
11667 db 0x20, 0x20, 0x20, 0x20
11668 dw 0,0 ;; oem table ptr
11669 dw 0 ;; oem table size
11670 dw 26 ;; entry count
11671 dw 0x0000, 0xfee0 ;; memory mapped address of local APIC
11672 dw 0 ;; extended table length
11673 db 0 ;; extended table checksum
11674 db 0 ;; reserved
11675mp_config_proc0:
11676 db 0 ;; entry type=processor
11677 db 0 ;; local APIC id
11678 db 0x11 ;; local APIC version number
11679 db 3 ;; cpu flags: enabled, bootstrap processor
11680 db 0,6,0,0 ;; cpu signature
11681 dw 0x201,0 ;; feature flags
11682 dw 0,0 ;; reserved
11683 dw 0,0 ;; reserved
11684mp_config_proc1:
11685 db 0 ;; entry type=processor
11686 db 1 ;; local APIC id
11687 db 0x11 ;; local APIC version number
11688 db 1 ;; cpu flags: enabled
11689 db 0,6,0,0 ;; cpu signature
11690 dw 0x201,0 ;; feature flags
11691 dw 0,0 ;; reserved
11692 dw 0,0 ;; reserved
11693mp_config_proc2:
11694 db 0 ;; entry type=processor
11695 db 2 ;; local APIC id
11696 db 0x11 ;; local APIC version number
11697 db 1 ;; cpu flags: enabled
11698 db 0,6,0,0 ;; cpu signature
11699 dw 0x201,0 ;; feature flags
11700 dw 0,0 ;; reserved
11701 dw 0,0 ;; reserved
11702mp_config_proc3:
11703 db 0 ;; entry type=processor
11704 db 3 ;; local APIC id
11705 db 0x11 ;; local APIC version number
11706 db 1 ;; cpu flags: enabled
11707 db 0,6,0,0 ;; cpu signature
11708 dw 0x201,0 ;; feature flags
11709 dw 0,0 ;; reserved
11710 dw 0,0 ;; reserved
11711mp_config_proc4:
11712 db 0 ;; entry type=processor
11713 db 4 ;; local APIC id
11714 db 0x11 ;; local APIC version number
11715 db 1 ;; cpu flags: enabled
11716 db 0,6,0,0 ;; cpu signature
11717 dw 0x201,0 ;; feature flags
11718 dw 0,0 ;; reserved
11719 dw 0,0 ;; reserved
11720mp_config_proc5:
11721 db 0 ;; entry type=processor
11722 db 5 ;; local APIC id
11723 db 0x11 ;; local APIC version number
11724 db 1 ;; cpu flags: enabled
11725 db 0,6,0,0 ;; cpu signature
11726 dw 0x201,0 ;; feature flags
11727 dw 0,0 ;; reserved
11728 dw 0,0 ;; reserved
11729mp_config_proc6:
11730 db 0 ;; entry type=processor
11731 db 6 ;; local APIC id
11732 db 0x11 ;; local APIC version number
11733 db 1 ;; cpu flags: enabled
11734 db 0,6,0,0 ;; cpu signature
11735 dw 0x201,0 ;; feature flags
11736 dw 0,0 ;; reserved
11737 dw 0,0 ;; reserved
11738mp_config_proc7:
11739 db 0 ;; entry type=processor
11740 db 7 ;; local APIC id
11741 db 0x11 ;; local APIC version number
11742 db 1 ;; cpu flags: enabled
11743 db 0,6,0,0 ;; cpu signature
11744 dw 0x201,0 ;; feature flags
11745 dw 0,0 ;; reserved
11746 dw 0,0 ;; reserved
11747mp_config_isa_bus:
11748 db 1 ;; entry type=bus
11749 db 0 ;; bus ID
11750 db 0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type="ISA "
11751mp_config_ioapic:
11752 db 2 ;; entry type=I/O APIC
11753 db 8 ;; apic id=8
11754 db 0x11 ;; I/O APIC version number
11755 db 1 ;; flags=1=enabled
11756 dw 0x0000, 0xfec0 ;; memory mapped address of I/O APIC
11757mp_config_irqs:
11758 db 3 ;; entry type=I/O interrupt
11759 db 0 ;; interrupt type=vectored interrupt
11760 db 0,0 ;; flags po=0, el=0 (linux uses as default)
11761 db 0 ;; source bus ID is ISA
11762 db 0 ;; source bus IRQ
11763 db 8 ;; destination I/O APIC ID
11764 db 0 ;; destination I/O APIC interrrupt in
11765 ;; repeat pattern for interrupts 0-15
11766 db 3,0,0,0,0,1,8,1
11767 db 3,0,0,0,0,2,8,2
11768 db 3,0,0,0,0,3,8,3
11769 db 3,0,0,0,0,4,8,4
11770 db 3,0,0,0,0,5,8,5
11771 db 3,0,0,0,0,6,8,6
11772 db 3,0,0,0,0,7,8,7
11773 db 3,0,0,0,0,8,8,8
11774 db 3,0,0,0,0,9,8,9
11775 db 3,0,0,0,0,10,8,10
11776 db 3,0,0,0,0,11,8,11
11777 db 3,0,0,0,0,12,8,12
11778 db 3,0,0,0,0,13,8,13
11779 db 3,0,0,0,0,14,8,14
11780 db 3,0,0,0,0,15,8,15
11781#else
11782# error Sorry, rombios only has configurations for 1, 2, 4 or 8 processors.
11783#endif // if (BX_SMP_PROCESSORS==...)
11784
11785mp_config_end: // this label used to find length of mp structure
11786 db 0
11787
11788#if (BX_SMP_PROCESSORS>1)
11789.align 16
11790mp_floating_pointer_structure:
11791db 0x5f, 0x4d, 0x50, 0x5f ; "_MP_" signature
11792dw mp_config_table, 0xf ;; pointer to MP configuration table
11793db 1 ;; length of this struct in 16-bit byte chunks
11794db 4 ;; MP spec revision
11795db 0xc1 ;; checksum
11796db 0 ;; MP feature byte 1. value 0 means look at the config table
11797db 0,0,0,0 ;; MP feature bytes 2-5.
11798#endif
11799#endif /* VBOX_SMP */
11800
11801ASM_END
Note: See TracBrowser for help on using the repository browser.

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