VirtualBox

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

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

fixed BIOS guest log

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

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