VirtualBox

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

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

marked the change.

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

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