VirtualBox

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

最後變更 在這個檔案從2651是 2651,由 vboxsync 提交於 18 年 前

provide MPS table if IOAPIC is present, use the last 16 bytes of the EBDA for MPS floating pointer structure

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

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