VirtualBox

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

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

Don't look for 0x55AA signature on floppy boot sectors. There is no
requirement for such signature and UNIX boot floppies rarely or never
have it.

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

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