VirtualBox

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

Last change on this file since 6291 was 6291, checked in by vboxsync, 17 years ago

Big virtual disk changeset containing several modifications

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