VirtualBox

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

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

Don't log GRUB invoking the ROM get configuration BIOS function.

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