VirtualBox

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

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

Removed obsolete MPS tables from rombios. Extend DevPcBios.cpp instead when supporting guest-SMP.

  • 屬性 svn:eol-style 設為 native
檔案大小: 304.7 KB
 
1/////////////////////////////////////////////////////////////////////////
2// $Id: rombios.c,v 1.176 2006/12/30 17:13:17 vruppert Exp $
3/////////////////////////////////////////////////////////////////////////
4//
5// Copyright (C) 2002 MandrakeSoft S.A.
6//
7// MandrakeSoft S.A.
8// 43, rue d'Aboukir
9// 75002 Paris - France
10// http://www.linux-mandrake.com/
11// http://www.mandrakesoft.com/
12//
13// This library is free software; you can redistribute it and/or
14// modify it under the terms of the GNU Lesser General Public
15// License as published by the Free Software Foundation; either
16// version 2 of the License, or (at your option) any later version.
17//
18// This library is distributed in the hope that it will be useful,
19// but WITHOUT ANY WARRANTY; without even the implied warranty of
20// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21// Lesser General Public License for more details.
22//
23// You should have received a copy of the GNU Lesser General Public
24// License along with this library; if not, write to the Free Software
25// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
26
27// ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
28
29
30// ROM BIOS compatability entry points:
31// ===================================
32// $e05b ; POST Entry Point
33// $e2c3 ; NMI Handler Entry Point
34// $e3fe ; INT 13h Fixed Disk Services Entry Point
35// $e401 ; Fixed Disk Parameter Table
36// $e6f2 ; INT 19h Boot Load Service Entry Point
37// $e6f5 ; Configuration Data Table
38// $e729 ; Baud Rate Generator Table
39// $e739 ; INT 14h Serial Communications Service Entry Point
40// $e82e ; INT 16h Keyboard Service Entry Point
41// $e987 ; INT 09h Keyboard Service Entry Point
42// $ec59 ; INT 13h Diskette Service Entry Point
43// $ef57 ; INT 0Eh Diskette Hardware ISR Entry Point
44// $efc7 ; Diskette Controller Parameter Table
45// $efd2 ; INT 17h Printer Service Entry Point
46// $f045 ; INT 10 Functions 0-Fh Entry Point
47// $f065 ; INT 10h Video Support Service Entry Point
48// $f0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
49// $f841 ; INT 12h Memory Size Service Entry Point
50// $f84d ; INT 11h Equipment List Service Entry Point
51// $f859 ; INT 15h System Services Entry Point
52// $fa6e ; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
53// $fe6e ; INT 1Ah Time-of-day Service Entry Point
54// $fea5 ; INT 08h System Timer ISR Entry Point
55// $fef3 ; Initial Interrupt Vector Offsets Loaded by POST
56// $ff53 ; IRET Instruction for Dummy Interrupt Handler
57// $ff54 ; INT 05h Print Screen Service Entry Point
58// $fff0 ; Power-up Entry Point
59// $fff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
60// $fffe ; System Model ID
61
62// NOTES for ATA/ATAPI driver ([email protected])
63// Features
64// - supports up to 4 ATA interfaces
65// - device/geometry detection
66// - 16bits/32bits device access
67// - pchs/lba access
68// - datain/dataout/packet command support
69//
70// NOTES for El-Torito Boot ([email protected])
71// - CD-ROM booting is only available if ATA/ATAPI Driver is available
72// - Current code is only able to boot mono-session cds
73// - Current code can not boot and emulate a hard-disk
74// the bios will panic otherwise
75// - Current code also use memory in EBDA segement.
76// - I used cmos byte 0x3D to store extended information on boot-device
77// - Code has to be modified modified to handle multiple cdrom drives
78// - Here are the cdrom boot failure codes:
79// 1 : no atapi device found
80// 2 : no atapi cdrom found
81// 3 : can not read cd - BRVD
82// 4 : cd is not eltorito (BRVD)
83// 5 : cd is not eltorito (ISO TAG)
84// 6 : cd is not eltorito (ELTORITO TAG)
85// 7 : can not read cd - boot catalog
86// 8 : boot catalog : bad header
87// 9 : boot catalog : bad platform
88// 10 : boot catalog : bad signature
89// 11 : boot catalog : bootable flag not set
90// 12 : can not read cd - boot image
91//
92// ATA driver
93// - EBDA segment.
94// I used memory starting at 0x121 in the segment
95// - the translation policy is defined in cmos regs 0x39 & 0x3a
96//
97// TODO :
98//
99// int74
100// - needs to be reworked. Uses direct [bp] offsets. (?)
101//
102// int13:
103// - f04 (verify sectors) isn't complete (?)
104// - f02/03/04 should set current cyl,etc in BDA (?)
105// - rewrite int13_relocated & clean up int13 entry code
106//
107// NOTES:
108// - NMI access (bit7 of addr written to 70h)
109//
110// ATA driver
111// - should handle the "don't detect" bit (cmos regs 0x3b & 0x3c)
112// - could send the multiple-sector read/write commands
113//
114// El-Torito
115// - Emulate a Hard-disk (currently only diskette can be emulated) see "FIXME ElTorito Harddisk"
116// - Implement remaining int13_cdemu functions (as defined by El-Torito specs)
117// - cdrom drive is hardcoded to ide 0 device 1 in several places. see "FIXME ElTorito Hardcoded"
118// - int13 Fix DL when emulating a cd. In that case DL is decremented before calling real int13.
119// This is ok. But DL should be reincremented afterwards.
120// - Fix all "FIXME ElTorito Various"
121// - should be able to boot any cdrom instead of the first one
122//
123// BCC Bug: find a generic way to handle the bug of #asm after an "if" (fixed in 0.16.7)
124
125#ifdef VBOX
126#include "DevPcBios.h"
127#include <VBox/version.h>
128#endif
129
130#define BX_ROMBIOS32 0
131#define DEBUG_ROMBIOS 0
132
133#define DEBUG_ATA 0
134#define DEBUG_INT13_HD 0
135#define DEBUG_INT13_CD 0
136#define DEBUG_INT13_ET 0
137#define DEBUG_INT13_FL 0
138#define DEBUG_INT15 0
139#define DEBUG_INT16 0
140#define DEBUG_INT1A 0
141#define DEBUG_INT74 0
142#define DEBUG_APM 0
143
144#define BX_CPU 3
145#define BX_USE_PS2_MOUSE 1
146#define BX_CALL_INT15_4F 1
147#define BX_USE_EBDA 1
148#define BX_SUPPORT_FLOPPY 1
149#define BX_FLOPPY_ON_CNT 37 /* 2 seconds */
150#define BX_PCIBIOS 1
151#define BX_APM 1
152
153#define BX_USE_ATADRV 1
154#define BX_ELTORITO_BOOT 1
155
156#define BX_MAX_ATA_INTERFACES 4
157#define BX_MAX_ATA_DEVICES (BX_MAX_ATA_INTERFACES*2)
158
159#define BX_VIRTUAL_PORTS 1 /* normal output to Bochs ports */
160#define BX_DEBUG_SERIAL 0 /* output to COM1 */
161
162 /* model byte 0xFC = AT */
163#define SYS_MODEL_ID 0xFC
164#define SYS_SUBMODEL_ID 0x00
165#define BIOS_REVISION 1
166#define BIOS_CONFIG_TABLE 0xe6f5
167
168#ifndef BIOS_BUILD_DATE
169# define BIOS_BUILD_DATE "06/23/99"
170#endif
171
172 // 1K of base memory used for Extended Bios Data Area (EBDA)
173 // EBDA is used for PS/2 mouse support, and IDE BIOS, etc.
174#define EBDA_SEG 0x9FC0
175#define EBDA_SIZE 1 // In KiB
176#define BASE_MEM_IN_K (640 - EBDA_SIZE)
177
178#define ACPI_DATA_SIZE 0x00010000L
179
180 // Define the application NAME
181#if defined(BX_QEMU)
182# define BX_APPNAME "QEMU"
183#elif defined(PLEX86)
184# define BX_APPNAME "Plex86"
185#else
186# define BX_APPNAME "Bochs"
187#endif
188
189 // Sanity Checks
190#if BX_USE_ATADRV && BX_CPU<3
191# error The ATA/ATAPI Driver can only to be used with a 386+ cpu
192#endif
193#if BX_USE_ATADRV && !BX_USE_EBDA
194# error ATA/ATAPI Driver can only be used if EBDA is available
195#endif
196#if BX_ELTORITO_BOOT && !BX_USE_ATADRV
197# error El-Torito Boot can only be use if ATA/ATAPI Driver is available
198#endif
199#if BX_PCIBIOS && BX_CPU<3
200# error PCI BIOS can only be used with 386+ cpu
201#endif
202#if BX_APM && BX_CPU<3
203# error APM BIOS can only be used with 386+ cpu
204#endif
205
206#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 mov bx, sp
4413 SEG SS
4414 mov ax, _int15_function.CX [bx]
4415 shl eax, #16
4416 SEG SS
4417 mov ax, _int15_function.DX [bx]
4418
4419 ;; convert to numbers of 15usec ticks
4420 mov ebx, #15
4421 xor edx, edx
4422 div eax, ebx
4423 mov ecx, eax
4424
4425 ;; wait for ecx number of refresh requests
4426 in al, #0x61
4427 and al,#0x10
4428 mov ah, al
4429
4430 or ecx, ecx
4431 je int1586_tick_end
4432int1586_tick:
4433 in al, #0x61
4434 and al,#0x10
4435 cmp al, ah
4436 je int1586_tick
4437 mov ah, al
4438 dec ecx
4439 jnz int1586_tick
4440int1586_tick_end:
4441ASM_END
4442
4443 break;
4444
4445 case 0xe8:
4446 switch(regs.u.r8.al)
4447 {
4448 case 0x20: // coded by osmaker aka K.J.
4449 if(regs.u.r32.edx == 0x534D4150)
4450 {
4451 extended_memory_size = inb_cmos(0x35);
4452 extended_memory_size <<= 8;
4453 extended_memory_size |= inb_cmos(0x34);
4454 extended_memory_size *= 64;
4455 // greater than EFF00000???
4456 if(extended_memory_size > 0x3bc000) {
4457 extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4458 }
4459 extended_memory_size *= 1024;
4460 extended_memory_size += (16L * 1024 * 1024);
4461
4462 if(extended_memory_size <= (16L * 1024 * 1024)) {
4463 extended_memory_size = inb_cmos(0x31);
4464 extended_memory_size <<= 8;
4465 extended_memory_size |= inb_cmos(0x30);
4466 extended_memory_size *= 1024;
4467 }
4468
4469 switch(regs.u.r16.bx)
4470 {
4471 case 0:
4472 set_e820_range(ES, regs.u.r16.di,
4473 0x0000000L, 0x0009fc00L, 1);
4474 regs.u.r32.ebx = 1;
4475 regs.u.r32.eax = 0x534D4150;
4476 regs.u.r32.ecx = 0x14;
4477 CLEAR_CF();
4478 return;
4479 break;
4480 case 1:
4481 set_e820_range(ES, regs.u.r16.di,
4482 0x0009fc00L, 0x000a0000L, 2);
4483 regs.u.r32.ebx = 2;
4484 regs.u.r32.eax = 0x534D4150;
4485 regs.u.r32.ecx = 0x14;
4486 CLEAR_CF();
4487 return;
4488 break;
4489 case 2:
4490#ifdef VBOX
4491 /* Mark the BIOS as reserved. VBox doesn't currently
4492 * use the 0xe0000-0xeffff area. It does use the
4493 * 0xd0000-0xdffff area for the BIOS logo, but it's
4494 * not worth marking it as reserved. Note that various
4495 * Windows versions don't accept (read: in debug builds
4496 * they trigger the "Too many similar traps" assertion)
4497 * a single reserved range from 0xd0000 to 0xffffff.
4498 * A 128K area starting from 0xd0000 works. */
4499 set_e820_range(ES, regs.u.r16.di,
4500 0x000f0000L, 0x00100000L, 2);
4501#else /* !VBOX */
4502 set_e820_range(ES, regs.u.r16.di,
4503 0x000e8000L, 0x00100000L, 2);
4504#endif /* !VBOX */
4505 regs.u.r32.ebx = 3;
4506 regs.u.r32.eax = 0x534D4150;
4507 regs.u.r32.ecx = 0x14;
4508 CLEAR_CF();
4509 return;
4510 break;
4511 case 3:
4512 set_e820_range(ES, regs.u.r16.di,
4513 0x00100000L,
4514 extended_memory_size - ACPI_DATA_SIZE, 1);
4515 regs.u.r32.ebx = 4;
4516 regs.u.r32.eax = 0x534D4150;
4517 regs.u.r32.ecx = 0x14;
4518 CLEAR_CF();
4519 return;
4520 break;
4521 case 4:
4522 set_e820_range(ES, regs.u.r16.di,
4523 extended_memory_size - ACPI_DATA_SIZE,
4524 extended_memory_size, 3); // ACPI RAM
4525 regs.u.r32.ebx = 5;
4526 regs.u.r32.eax = 0x534D4150;
4527 regs.u.r32.ecx = 0x14;
4528 CLEAR_CF();
4529 return;
4530 break;
4531 case 5:
4532 /* 256KB BIOS area at the end of 4 GB */
4533 set_e820_range(ES, regs.u.r16.di,
4534 0xfffc0000L, 0x00000000L, 2);
4535 regs.u.r32.ebx = 0;
4536 regs.u.r32.eax = 0x534D4150;
4537 regs.u.r32.ecx = 0x14;
4538 CLEAR_CF();
4539 return;
4540 default: /* AX=E820, DX=534D4150, BX unrecognized */
4541 goto int15_unimplemented;
4542 break;
4543 }
4544 } else {
4545 // if DX != 0x534D4150)
4546 goto int15_unimplemented;
4547 }
4548 break;
4549
4550 case 0x01:
4551 // do we have any reason to fail here ?
4552 CLEAR_CF();
4553
4554 // my real system sets ax and bx to 0
4555 // this is confirmed by Ralph Brown list
4556 // but syslinux v1.48 is known to behave
4557 // strangely if ax is set to 0
4558 // regs.u.r16.ax = 0;
4559 // regs.u.r16.bx = 0;
4560
4561 // Get the amount of extended memory (above 1M)
4562 regs.u.r8.cl = inb_cmos(0x30);
4563 regs.u.r8.ch = inb_cmos(0x31);
4564
4565 // limit to 15M
4566 if(regs.u.r16.cx > 0x3c00)
4567 {
4568 regs.u.r16.cx = 0x3c00;
4569 }
4570
4571 // Get the amount of extended memory above 16M in 64k blocs
4572 regs.u.r8.dl = inb_cmos(0x34);
4573 regs.u.r8.dh = inb_cmos(0x35);
4574
4575 // Set configured memory equal to extended memory
4576 regs.u.r16.ax = regs.u.r16.cx;
4577 regs.u.r16.bx = regs.u.r16.dx;
4578 break;
4579 default: /* AH=0xE8?? but not implemented */
4580 goto int15_unimplemented;
4581 }
4582 break;
4583 int15_unimplemented:
4584 // fall into the default
4585 default:
4586 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4587 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4588 SET_CF();
4589 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4590 break;
4591 }
4592}
4593
4594 void
4595int16_function(DI, SI, BP, SP, BX, DX, CX, AX, FLAGS)
4596 Bit16u DI, SI, BP, SP, BX, DX, CX, AX, FLAGS;
4597{
4598 Bit8u scan_code, ascii_code, shift_flags, led_flags, count;
4599 Bit16u kbd_code, max;
4600
4601 BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX, BX, CX, DX);
4602
4603 shift_flags = read_byte(0x0040, 0x17);
4604 led_flags = read_byte(0x0040, 0x97);
4605 if ((((shift_flags >> 4) & 0x07) ^ (led_flags & 0x07)) != 0) {
4606ASM_START
4607 cli
4608ASM_END
4609 outb(0x60, 0xed);
4610 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
4611 if ((inb(0x60) == 0xfa)) {
4612 led_flags &= 0xf8;
4613 led_flags |= ((shift_flags >> 4) & 0x07);
4614 outb(0x60, led_flags & 0x07);
4615 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
4616 inb(0x60);
4617 write_byte(0x0040, 0x97, led_flags);
4618 }
4619ASM_START
4620 sti
4621ASM_END
4622 }
4623
4624 switch (GET_AH()) {
4625 case 0x00: /* read keyboard input */
4626
4627 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4628 BX_PANIC("KBD: int16h: out of keyboard input\n");
4629 }
4630 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4631 else if (ascii_code == 0xE0) ascii_code = 0;
4632 AX = (scan_code << 8) | ascii_code;
4633 break;
4634
4635 case 0x01: /* check keyboard status */
4636 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4637 SET_ZF();
4638 return;
4639 }
4640 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4641 else if (ascii_code == 0xE0) ascii_code = 0;
4642 AX = (scan_code << 8) | ascii_code;
4643 CLEAR_ZF();
4644 break;
4645
4646 case 0x02: /* get shift flag status */
4647 shift_flags = read_byte(0x0040, 0x17);
4648 SET_AL(shift_flags);
4649 break;
4650
4651 case 0x05: /* store key-stroke into buffer */
4652 if ( !enqueue_key(GET_CH(), GET_CL()) ) {
4653 SET_AL(1);
4654 }
4655 else {
4656 SET_AL(0);
4657 }
4658 break;
4659
4660 case 0x09: /* GET KEYBOARD FUNCTIONALITY */
4661 // bit Bochs Description
4662 // 7 0 reserved
4663 // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
4664 // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
4665 // 4 1 INT 16/AH=0Ah supported
4666 // 3 0 INT 16/AX=0306h supported
4667 // 2 0 INT 16/AX=0305h supported
4668 // 1 0 INT 16/AX=0304h supported
4669 // 0 0 INT 16/AX=0300h supported
4670 //
4671 SET_AL(0x30);
4672 break;
4673
4674 case 0x0A: /* GET KEYBOARD ID */
4675 count = 2;
4676 kbd_code = 0x0;
4677 outb(0x60, 0xf2);
4678 /* Wait for data */
4679 max=0xffff;
4680 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4681 if (max>0x0) {
4682 if ((inb(0x60) == 0xfa)) {
4683 do {
4684 max=0xffff;
4685 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4686 if (max>0x0) {
4687 kbd_code >>= 8;
4688 kbd_code |= (inb(0x60) << 8);
4689 }
4690 } while (--count>0);
4691 }
4692 }
4693 BX=kbd_code;
4694 break;
4695
4696 case 0x10: /* read MF-II keyboard input */
4697
4698 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4699 BX_PANIC("KBD: int16h: out of keyboard input\n");
4700 }
4701 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4702 AX = (scan_code << 8) | ascii_code;
4703 break;
4704
4705 case 0x11: /* check MF-II keyboard status */
4706 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4707 SET_ZF();
4708 return;
4709 }
4710 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4711 AX = (scan_code << 8) | ascii_code;
4712 CLEAR_ZF();
4713 break;
4714
4715 case 0x12: /* get extended keyboard status */
4716 shift_flags = read_byte(0x0040, 0x17);
4717 SET_AL(shift_flags);
4718 shift_flags = read_byte(0x0040, 0x18) & 0x73;
4719 shift_flags |= read_byte(0x0040, 0x96) & 0x0c;
4720 SET_AH(shift_flags);
4721 BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX);
4722 break;
4723
4724 case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
4725 SET_AH(0x80); // function int16 ah=0x10-0x12 supported
4726 break;
4727
4728 case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
4729 // don't change AH : function int16 ah=0x20-0x22 NOT supported
4730 break;
4731
4732 case 0x6F:
4733 if (GET_AL() == 0x08)
4734 SET_AH(0x02); // unsupported, aka normal keyboard
4735
4736 default:
4737 BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
4738 }
4739}
4740
4741 unsigned int
4742dequeue_key(scan_code, ascii_code, incr)
4743 Bit8u *scan_code;
4744 Bit8u *ascii_code;
4745 unsigned int incr;
4746{
4747 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail;
4748 Bit16u ss;
4749 Bit8u acode, scode;
4750
4751#if BX_CPU < 2
4752 buffer_start = 0x001E;
4753 buffer_end = 0x003E;
4754#else
4755 buffer_start = read_word(0x0040, 0x0080);
4756 buffer_end = read_word(0x0040, 0x0082);
4757#endif
4758
4759 buffer_head = read_word(0x0040, 0x001a);
4760 buffer_tail = read_word(0x0040, 0x001c);
4761
4762 if (buffer_head != buffer_tail) {
4763 ss = get_SS();
4764 acode = read_byte(0x0040, buffer_head);
4765 scode = read_byte(0x0040, buffer_head+1);
4766 write_byte(ss, ascii_code, acode);
4767 write_byte(ss, scan_code, scode);
4768
4769 if (incr) {
4770 buffer_head += 2;
4771 if (buffer_head >= buffer_end)
4772 buffer_head = buffer_start;
4773 write_word(0x0040, 0x001a, buffer_head);
4774 }
4775 return(1);
4776 }
4777 else {
4778 return(0);
4779 }
4780}
4781
4782static char panic_msg_keyb_buffer_full[] = "%s: keyboard input buffer full\n";
4783
4784 Bit8u
4785send_to_mouse_ctrl(sendbyte)
4786 Bit8u sendbyte;
4787{
4788 Bit8u response;
4789
4790 // wait for chance to write to ctrl
4791 if ( inb(0x64) & 0x02 )
4792 BX_PANIC(panic_msg_keyb_buffer_full,"sendmouse");
4793 outb(0x64, 0xD4);
4794 outb(0x60, sendbyte);
4795 return(0);
4796}
4797
4798
4799 Bit8u
4800get_mouse_data(data)
4801 Bit8u *data;
4802{
4803 Bit8u response;
4804 Bit16u ss;
4805
4806 while ( (inb(0x64) & 0x21) != 0x21 ) {
4807 }
4808
4809 response = inb(0x60);
4810
4811 ss = get_SS();
4812 write_byte(ss, data, response);
4813 return(0);
4814}
4815
4816 void
4817set_kbd_command_byte(command_byte)
4818 Bit8u command_byte;
4819{
4820 if ( inb(0x64) & 0x02 )
4821 BX_PANIC(panic_msg_keyb_buffer_full,"setkbdcomm");
4822
4823 outb(0x64, 0x60); // write command byte
4824 outb(0x60, command_byte);
4825}
4826
4827 void
4828int09_function(DI, SI, BP, SP, BX, DX, CX, AX)
4829 Bit16u DI, SI, BP, SP, BX, DX, CX, AX;
4830{
4831 Bit8u scancode, asciicode, shift_flags;
4832 Bit8u mf2_flags, mf2_state;
4833
4834 //
4835 // DS has been set to F000 before call
4836 //
4837
4838
4839 scancode = GET_AL();
4840
4841 if (scancode == 0) {
4842 BX_INFO("KBD: int09 handler: AL=0\n");
4843 return;
4844 }
4845
4846
4847 shift_flags = read_byte(0x0040, 0x17);
4848 mf2_flags = read_byte(0x0040, 0x18);
4849 mf2_state = read_byte(0x0040, 0x96);
4850 asciicode = 0;
4851
4852 switch (scancode) {
4853 case 0x3a: /* Caps Lock press */
4854 shift_flags ^= 0x40;
4855 write_byte(0x0040, 0x17, shift_flags);
4856 mf2_flags |= 0x40;
4857 write_byte(0x0040, 0x18, mf2_flags);
4858 break;
4859 case 0xba: /* Caps Lock release */
4860 mf2_flags &= ~0x40;
4861 write_byte(0x0040, 0x18, mf2_flags);
4862 break;
4863
4864 case 0x2a: /* L Shift press */
4865 shift_flags |= 0x02;
4866 write_byte(0x0040, 0x17, shift_flags);
4867 break;
4868 case 0xaa: /* L Shift release */
4869 shift_flags &= ~0x02;
4870 write_byte(0x0040, 0x17, shift_flags);
4871 break;
4872
4873 case 0x36: /* R Shift press */
4874 shift_flags |= 0x01;
4875 write_byte(0x0040, 0x17, shift_flags);
4876 break;
4877 case 0xb6: /* R Shift release */
4878 shift_flags &= ~0x01;
4879 write_byte(0x0040, 0x17, shift_flags);
4880 break;
4881
4882 case 0x1d: /* Ctrl press */
4883 if ((mf2_state & 0x01) == 0) {
4884 shift_flags |= 0x04;
4885 write_byte(0x0040, 0x17, shift_flags);
4886 if (mf2_state & 0x02) {
4887 mf2_state |= 0x04;
4888 write_byte(0x0040, 0x96, mf2_state);
4889 } else {
4890 mf2_flags |= 0x01;
4891 write_byte(0x0040, 0x18, mf2_flags);
4892 }
4893 }
4894 break;
4895 case 0x9d: /* Ctrl release */
4896 if ((mf2_state & 0x01) == 0) {
4897 shift_flags &= ~0x04;
4898 write_byte(0x0040, 0x17, shift_flags);
4899 if (mf2_state & 0x02) {
4900 mf2_state &= ~0x04;
4901 write_byte(0x0040, 0x96, mf2_state);
4902 } else {
4903 mf2_flags &= ~0x01;
4904 write_byte(0x0040, 0x18, mf2_flags);
4905 }
4906 }
4907 break;
4908
4909 case 0x38: /* Alt press */
4910 shift_flags |= 0x08;
4911 write_byte(0x0040, 0x17, shift_flags);
4912 if (mf2_state & 0x02) {
4913 mf2_state |= 0x08;
4914 write_byte(0x0040, 0x96, mf2_state);
4915 } else {
4916 mf2_flags |= 0x02;
4917 write_byte(0x0040, 0x18, mf2_flags);
4918 }
4919 break;
4920 case 0xb8: /* Alt release */
4921 shift_flags &= ~0x08;
4922 write_byte(0x0040, 0x17, shift_flags);
4923 if (mf2_state & 0x02) {
4924 mf2_state &= ~0x08;
4925 write_byte(0x0040, 0x96, mf2_state);
4926 } else {
4927 mf2_flags &= ~0x02;
4928 write_byte(0x0040, 0x18, mf2_flags);
4929 }
4930 break;
4931
4932 case 0x45: /* Num Lock press */
4933 if ((mf2_state & 0x03) == 0) {
4934 mf2_flags |= 0x20;
4935 write_byte(0x0040, 0x18, mf2_flags);
4936 shift_flags ^= 0x20;
4937 write_byte(0x0040, 0x17, shift_flags);
4938 }
4939 break;
4940 case 0xc5: /* Num Lock release */
4941 if ((mf2_state & 0x03) == 0) {
4942 mf2_flags &= ~0x20;
4943 write_byte(0x0040, 0x18, mf2_flags);
4944 }
4945 break;
4946
4947 case 0x46: /* Scroll Lock press */
4948 mf2_flags |= 0x10;
4949 write_byte(0x0040, 0x18, mf2_flags);
4950 shift_flags ^= 0x10;
4951 write_byte(0x0040, 0x17, shift_flags);
4952 break;
4953
4954 case 0xc6: /* Scroll Lock release */
4955 mf2_flags &= ~0x10;
4956 write_byte(0x0040, 0x18, mf2_flags);
4957 break;
4958
4959 default:
4960 if (scancode & 0x80) {
4961 break; /* toss key releases ... */
4962 }
4963 if (scancode > MAX_SCAN_CODE) {
4964 BX_INFO("KBD: int09h_handler(): unknown scancode read: 0x%02x!\n", scancode);
4965 return;
4966 }
4967 if (shift_flags & 0x08) { /* ALT */
4968 asciicode = scan_to_scanascii[scancode].alt;
4969 scancode = scan_to_scanascii[scancode].alt >> 8;
4970 } else if (shift_flags & 0x04) { /* CONTROL */
4971 asciicode = scan_to_scanascii[scancode].control;
4972 scancode = scan_to_scanascii[scancode].control >> 8;
4973 } else if (((mf2_state & 0x02) > 0) && ((scancode >= 0x47) && (scancode <= 0x53))) {
4974 /* extended keys handling */
4975 asciicode = 0xe0;
4976 scancode = scan_to_scanascii[scancode].normal >> 8;
4977 } else if (shift_flags & 0x03) { /* LSHIFT + RSHIFT */
4978 /* check if lock state should be ignored
4979 * because a SHIFT key are pressed */
4980
4981 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
4982 asciicode = scan_to_scanascii[scancode].normal;
4983 scancode = scan_to_scanascii[scancode].normal >> 8;
4984 } else {
4985 asciicode = scan_to_scanascii[scancode].shift;
4986 scancode = scan_to_scanascii[scancode].shift >> 8;
4987 }
4988 } else {
4989 /* check if lock is on */
4990 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
4991 asciicode = scan_to_scanascii[scancode].shift;
4992 scancode = scan_to_scanascii[scancode].shift >> 8;
4993 } else {
4994 asciicode = scan_to_scanascii[scancode].normal;
4995 scancode = scan_to_scanascii[scancode].normal >> 8;
4996 }
4997 }
4998 if (scancode==0 && asciicode==0) {
4999 BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
5000 }
5001 enqueue_key(scancode, asciicode);
5002 break;
5003 }
5004 if ((scancode & 0x7f) != 0x1d) {
5005 mf2_state &= ~0x01;
5006 }
5007 mf2_state &= ~0x02;
5008 write_byte(0x0040, 0x96, mf2_state);
5009}
5010
5011 unsigned int
5012enqueue_key(scan_code, ascii_code)
5013 Bit8u scan_code, ascii_code;
5014{
5015 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail, temp_tail;
5016
5017#if BX_CPU < 2
5018 buffer_start = 0x001E;
5019 buffer_end = 0x003E;
5020#else
5021 buffer_start = read_word(0x0040, 0x0080);
5022 buffer_end = read_word(0x0040, 0x0082);
5023#endif
5024
5025 buffer_head = read_word(0x0040, 0x001A);
5026 buffer_tail = read_word(0x0040, 0x001C);
5027
5028 temp_tail = buffer_tail;
5029 buffer_tail += 2;
5030 if (buffer_tail >= buffer_end)
5031 buffer_tail = buffer_start;
5032
5033 if (buffer_tail == buffer_head) {
5034 return(0);
5035 }
5036
5037 write_byte(0x0040, temp_tail, ascii_code);
5038 write_byte(0x0040, temp_tail+1, scan_code);
5039 write_word(0x0040, 0x001C, buffer_tail);
5040 return(1);
5041}
5042
5043
5044 void
5045int74_function(make_farcall, Z, Y, X, status)
5046 Bit16u make_farcall, Z, Y, X, status;
5047{
5048 Bit16u ebda_seg=read_word(0x0040,0x000E);
5049 Bit8u in_byte, index, package_count;
5050 Bit8u mouse_flags_1, mouse_flags_2;
5051
5052BX_DEBUG_INT74("entering int74_function\n");
5053 make_farcall = 0;
5054
5055 in_byte = inb(0x64);
5056 if ( (in_byte & 0x21) != 0x21 ) {
5057 return;
5058 }
5059 in_byte = inb(0x60);
5060BX_DEBUG_INT74("int74: read byte %02x\n", in_byte);
5061
5062 mouse_flags_1 = read_byte(ebda_seg, 0x0026);
5063 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
5064
5065 if ( (mouse_flags_2 & 0x80) != 0x80 ) {
5066 return;
5067 }
5068
5069 package_count = mouse_flags_2 & 0x07;
5070 index = mouse_flags_1 & 0x07;
5071 write_byte(ebda_seg, 0x28 + index, in_byte);
5072
5073 if ( index >= package_count ) {
5074BX_DEBUG_INT74("int74_function: make_farcall=1\n");
5075 status = read_byte(ebda_seg, 0x0028 + 0);
5076 X = read_byte(ebda_seg, 0x0028 + 1);
5077 Y = read_byte(ebda_seg, 0x0028 + 2);
5078 Z = 0;
5079 mouse_flags_1 = 0;
5080 // check if far call handler installed
5081 if (mouse_flags_2 & 0x80)
5082 make_farcall = 1;
5083 }
5084 else {
5085 mouse_flags_1++;
5086 }
5087 write_byte(ebda_seg, 0x0026, mouse_flags_1);
5088}
5089
5090#define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
5091
5092#if BX_USE_ATADRV
5093
5094 void
5095int13_harddisk(EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5096 Bit16u EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5097{
5098 Bit32u lba;
5099 Bit16u ebda_seg=read_word(0x0040,0x000E);
5100 Bit16u cylinder, head, sector;
5101 Bit16u segment, offset;
5102 Bit16u npc, nph, npspt, nlc, nlh, nlspt;
5103 Bit16u size, count;
5104 Bit8u device, status;
5105
5106 BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5107
5108 write_byte(0x0040, 0x008e, 0); // clear completion flag
5109
5110 // basic check : device has to be defined
5111 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES) ) {
5112 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5113 goto int13_fail;
5114 }
5115
5116 // Get the ata channel
5117 device=read_byte(ebda_seg,&EbdaData->ata.hdidmap[GET_ELDL()-0x80]);
5118
5119 // basic check : device has to be valid
5120 if (device >= BX_MAX_ATA_DEVICES) {
5121 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5122 goto int13_fail;
5123 }
5124
5125 switch (GET_AH()) {
5126
5127 case 0x00: /* disk controller reset */
5128 ata_reset (device);
5129 goto int13_success;
5130 break;
5131
5132 case 0x01: /* read disk status */
5133 status = read_byte(0x0040, 0x0074);
5134 SET_AH(status);
5135 SET_DISK_RET_STATUS(0);
5136 /* set CF if error status read */
5137 if (status) goto int13_fail_nostatus;
5138 else goto int13_success_noah;
5139 break;
5140
5141 case 0x02: // read disk sectors
5142 case 0x03: // write disk sectors
5143 case 0x04: // verify disk sectors
5144
5145 count = GET_AL();
5146 cylinder = GET_CH();
5147 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
5148 sector = (GET_CL() & 0x3f);
5149 head = GET_DH();
5150
5151 segment = ES;
5152 offset = BX;
5153
5154 if ( (count > 128) || (count == 0) ) {
5155 BX_INFO("int13_harddisk: function %02x, count out of range!\n",GET_AH());
5156 goto int13_fail;
5157 }
5158
5159 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
5160 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
5161 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
5162
5163 // sanity check on cyl heads, sec
5164 if( (cylinder >= nlc) || (head >= nlh) || (sector > nlspt )) {
5165 BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder, head, sector);
5166 goto int13_fail;
5167 }
5168
5169 // FIXME verify
5170 if ( GET_AH() == 0x04 ) goto int13_success;
5171
5172 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5173 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5174
5175 // if needed, translate lchs to lba, and execute command
5176 if ( (nph != nlh) || (npspt != nlspt)) {
5177 lba = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
5178 sector = 0; // this forces the command to be lba
5179 }
5180
5181 if ( GET_AH() == 0x02 )
5182 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, cylinder, head, sector, lba, segment, offset);
5183 else
5184 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, cylinder, head, sector, lba, segment, offset);
5185
5186 // Set nb of sector transferred
5187 SET_AL(read_word(ebda_seg, &EbdaData->ata.trsfsectors));
5188
5189 if (status != 0) {
5190 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5191 SET_AH(0x0c);
5192 goto int13_fail_noah;
5193 }
5194
5195 goto int13_success;
5196 break;
5197
5198 case 0x05: /* format disk track */
5199 BX_INFO("format disk track called\n");
5200 goto int13_success;
5201 return;
5202 break;
5203
5204 case 0x08: /* read disk drive parameters */
5205
5206 // Get logical geometry from table
5207 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
5208 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
5209 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
5210 count = read_byte(ebda_seg, &EbdaData->ata.hdcount);
5211
5212#ifndef VBOX
5213 nlc = nlc - 2; /* 0 based , last sector not used */
5214#else /* VBOX */
5215 /* Maximum cylinder number is just one less than the number of cylinders. */
5216 nlc = nlc - 1; /* 0 based , last sector not used */
5217#endif /* VBOX */
5218 SET_AL(0);
5219 SET_CH(nlc & 0xff);
5220 SET_CL(((nlc >> 2) & 0xc0) | (nlspt & 0x3f));
5221 SET_DH(nlh - 1);
5222 SET_DL(count); /* FIXME returns 0, 1, or n hard drives */
5223
5224 // FIXME should set ES & DI
5225
5226 goto int13_success;
5227 break;
5228
5229 case 0x10: /* check drive ready */
5230 // should look at 40:8E also???
5231
5232 // Read the status from controller
5233 status = inb(read_word(ebda_seg, &EbdaData->ata.channels[device/2].iobase1) + ATA_CB_STAT);
5234 if ( (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY ) {
5235 goto int13_success;
5236 }
5237 else {
5238 SET_AH(0xAA);
5239 goto int13_fail_noah;
5240 }
5241 break;
5242
5243 case 0x15: /* read disk drive size */
5244
5245 // Get physical geometry from table
5246 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5247 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5248 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5249
5250 // Compute sector count seen by int13
5251#ifndef VBOX
5252 lba = (Bit32u)(npc - 1) * (Bit32u)nph * (Bit32u)npspt;
5253#else /* VBOX */
5254 /* Is it so hard to multiply a couple of counts (without introducing
5255 * arbitrary off by one errors)? */
5256 lba = (Bit32u)npc * (Bit32u)nph * (Bit32u)npspt;
5257#endif /* VBOX */
5258 CX = lba >> 16;
5259 DX = lba & 0xffff;
5260
5261 SET_AH(3); // hard disk accessible
5262 goto int13_success_noah;
5263 break;
5264
5265 case 0x41: // IBM/MS installation check
5266 BX=0xaa55; // install check
5267 SET_AH(0x30); // EDD 3.0
5268 CX=0x0007; // ext disk access and edd, removable supported
5269 goto int13_success_noah;
5270 break;
5271
5272 case 0x42: // IBM/MS extended read
5273 case 0x43: // IBM/MS extended write
5274 case 0x44: // IBM/MS verify
5275 case 0x47: // IBM/MS extended seek
5276
5277 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5278 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5279 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5280
5281 // Can't use 64 bits lba
5282 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5283 if (lba != 0L) {
5284 BX_PANIC("int13_harddisk: function %02x. Can't use 64bits lba\n",GET_AH());
5285 goto int13_fail;
5286 }
5287
5288 // Get 32 bits lba and check
5289 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5290 if (lba >= read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors) ) {
5291 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5292 goto int13_fail;
5293 }
5294
5295 // If verify or seek
5296 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5297 goto int13_success;
5298
5299 // Execute the command
5300 if ( GET_AH() == 0x42 )
5301#ifdef VBOX
5302 {
5303 if (count >= 256 || lba + count >= 268435456)
5304 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS_EXT, count, 0, 0, 0, lba, segment, offset);
5305 else
5306 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba, segment, offset);
5307 }
5308#else /* !VBOX */
5309 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba, segment, offset);
5310#endif /* VBOX */
5311 else
5312#ifdef VBOX
5313 {
5314 if (count >= 256 || lba + count >= 268435456)
5315 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS_EXT, count, 0, 0, 0, lba, segment, offset);
5316 else
5317 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
5318 }
5319#else /* !VBOX */
5320 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
5321#endif /* VBOX */
5322
5323 count=read_word(ebda_seg, &EbdaData->ata.trsfsectors);
5324 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5325
5326 if (status != 0) {
5327 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5328 SET_AH(0x0c);
5329 goto int13_fail_noah;
5330 }
5331
5332 goto int13_success;
5333 break;
5334
5335 case 0x45: // IBM/MS lock/unlock drive
5336 case 0x49: // IBM/MS extended media change
5337 goto int13_success; // Always success for HD
5338 break;
5339
5340 case 0x46: // IBM/MS eject media
5341 SET_AH(0xb2); // Volume Not Removable
5342 goto int13_fail_noah; // Always fail for HD
5343 break;
5344
5345 case 0x48: // IBM/MS get drive parameters
5346 size=read_word(DS,SI+(Bit16u)&Int13DPT->size);
5347
5348 // Buffer is too small
5349 if(size < 0x1a)
5350 goto int13_fail;
5351
5352 // EDD 1.x
5353 if(size >= 0x1a) {
5354 Bit16u blksize;
5355
5356 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5357 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5358 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5359 lba = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors);
5360 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5361
5362 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5363 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x02); // geometry is valid
5364 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, (Bit32u)npc);
5365 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, (Bit32u)nph);
5366 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, (Bit32u)npspt);
5367 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, lba); // FIXME should be Bit64
5368 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0L);
5369 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5370 }
5371
5372 // EDD 2.x
5373 if(size >= 0x1e) {
5374 Bit8u channel, dev, irq, mode, checksum, i, translation;
5375 Bit16u iobase1, iobase2, options;
5376
5377 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5378
5379 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5380 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5381
5382 // Fill in dpte
5383 channel = device / 2;
5384 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5385 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5386 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5387 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5388 translation = read_byte(ebda_seg, &EbdaData->ata.devices[device].translation);
5389
5390 options = (translation==ATA_TRANSLATION_NONE?0:1<<3); // chs translation
5391 options |= (1<<4); // lba translation
5392 options |= (mode==ATA_MODE_PIO32?1:0<<7);
5393 options |= (translation==ATA_TRANSLATION_LBA?1:0<<9);
5394 options |= (translation==ATA_TRANSLATION_RECHS?3:0<<9);
5395
5396 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5397 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5398 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5399 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5400 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5401 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5402 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5403 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5404 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5405 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5406 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5407
5408 checksum=0;
5409 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5410 checksum = ~checksum;
5411 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5412 }
5413
5414 // EDD 3.x
5415 if(size >= 0x42) {
5416 Bit8u channel, iface, checksum, i;
5417 Bit16u iobase1;
5418
5419 channel = device / 2;
5420 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5421 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5422
5423 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5424 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5425 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5426 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5427 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5428
5429 if (iface==ATA_IFACE_ISA) {
5430 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5431 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5432 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5433 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5434 }
5435 else {
5436 // FIXME PCI
5437 }
5438 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5439 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5440 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5441 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5442
5443 if (iface==ATA_IFACE_ISA) {
5444 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5445 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5446 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5447 }
5448 else {
5449 // FIXME PCI
5450 }
5451 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5452 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5453 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5454 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5455
5456 checksum=0;
5457 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5458 checksum = ~checksum;
5459 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5460 }
5461
5462 goto int13_success;
5463 break;
5464
5465 case 0x4e: // // IBM/MS set hardware configuration
5466 // DMA, prefetch, PIO maximum not supported
5467 switch (GET_AL()) {
5468 case 0x01:
5469 case 0x03:
5470 case 0x04:
5471 case 0x06:
5472 goto int13_success;
5473 break;
5474 default :
5475 goto int13_fail;
5476 }
5477 break;
5478
5479 case 0x09: /* initialize drive parameters */
5480 case 0x0c: /* seek to specified cylinder */
5481 case 0x0d: /* alternate disk reset */
5482 case 0x11: /* recalibrate */
5483 case 0x14: /* controller internal diagnostic */
5484 BX_INFO("int13_harddisk: function %02xh unimplemented, returns success\n", GET_AH());
5485 goto int13_success;
5486 break;
5487
5488 case 0x0a: /* read disk sectors with ECC */
5489 case 0x0b: /* write disk sectors with ECC */
5490 case 0x18: // set media type for format
5491 case 0x50: // IBM/MS send packet command
5492 default:
5493 BX_INFO("int13_harddisk: function %02xh unsupported, returns fail\n", GET_AH());
5494 goto int13_fail;
5495 break;
5496 }
5497
5498int13_fail:
5499 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5500int13_fail_noah:
5501 SET_DISK_RET_STATUS(GET_AH());
5502int13_fail_nostatus:
5503 SET_CF(); // error occurred
5504 return;
5505
5506int13_success:
5507 SET_AH(0x00); // no error
5508int13_success_noah:
5509 SET_DISK_RET_STATUS(0x00);
5510 CLEAR_CF(); // no error
5511 return;
5512}
5513
5514// ---------------------------------------------------------------------------
5515// Start of int13 for cdrom
5516// ---------------------------------------------------------------------------
5517
5518 void
5519int13_cdrom(EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5520 Bit16u EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5521{
5522 Bit16u ebda_seg=read_word(0x0040,0x000E);
5523 Bit8u device, status, locks;
5524 Bit8u atacmd[12];
5525 Bit32u lba;
5526 Bit16u count, segment, offset, i, size;
5527
5528 BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5529
5530 SET_DISK_RET_STATUS(0x00);
5531
5532 /* basic check : device should be 0xE0+ */
5533 if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES) ) {
5534 BX_INFO("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5535 goto int13_fail;
5536 }
5537
5538 // Get the ata channel
5539 device=read_byte(ebda_seg,&EbdaData->ata.cdidmap[GET_ELDL()-0xE0]);
5540
5541 /* basic check : device has to be valid */
5542 if (device >= BX_MAX_ATA_DEVICES) {
5543 BX_INFO("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5544 goto int13_fail;
5545 }
5546
5547 switch (GET_AH()) {
5548
5549 // all those functions return SUCCESS
5550 case 0x00: /* disk controller reset */
5551 case 0x09: /* initialize drive parameters */
5552 case 0x0c: /* seek to specified cylinder */
5553 case 0x0d: /* alternate disk reset */
5554 case 0x10: /* check drive ready */
5555 case 0x11: /* recalibrate */
5556 case 0x14: /* controller internal diagnostic */
5557 case 0x16: /* detect disk change */
5558 goto int13_success;
5559 break;
5560
5561 // all those functions return disk write-protected
5562 case 0x03: /* write disk sectors */
5563 case 0x05: /* format disk track */
5564 case 0x43: // IBM/MS extended write
5565 SET_AH(0x03);
5566 goto int13_fail_noah;
5567 break;
5568
5569 case 0x01: /* read disk status */
5570 status = read_byte(0x0040, 0x0074);
5571 SET_AH(status);
5572 SET_DISK_RET_STATUS(0);
5573
5574 /* set CF if error status read */
5575 if (status) goto int13_fail_nostatus;
5576 else goto int13_success_noah;
5577 break;
5578
5579 case 0x15: /* read disk drive size */
5580 SET_AH(0x02);
5581 goto int13_fail_noah;
5582 break;
5583
5584 case 0x41: // IBM/MS installation check
5585 BX=0xaa55; // install check
5586 SET_AH(0x30); // EDD 2.1
5587 CX=0x0007; // ext disk access, removable and edd
5588 goto int13_success_noah;
5589 break;
5590
5591 case 0x42: // IBM/MS extended read
5592 case 0x44: // IBM/MS verify sectors
5593 case 0x47: // IBM/MS extended seek
5594
5595 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5596 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5597 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5598
5599 // Can't use 64 bits lba
5600 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5601 if (lba != 0L) {
5602 BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
5603 goto int13_fail;
5604 }
5605
5606 // Get 32 bits lba
5607 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5608
5609 // If verify or seek
5610 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5611 goto int13_success;
5612
5613 memsetb(get_SS(),atacmd,0,12);
5614 atacmd[0]=0x28; // READ command
5615 atacmd[7]=(count & 0xff00) >> 8; // Sectors
5616 atacmd[8]=(count & 0x00ff); // Sectors
5617 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
5618 atacmd[3]=(lba & 0x00ff0000) >> 16;
5619 atacmd[4]=(lba & 0x0000ff00) >> 8;
5620 atacmd[5]=(lba & 0x000000ff);
5621 status = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, count*2048L, ATA_DATA_IN, segment,offset);
5622
5623 count = (Bit16u)(read_dword(ebda_seg, &EbdaData->ata.trsfbytes) >> 11);
5624 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5625
5626 if (status != 0) {
5627 BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status);
5628 SET_AH(0x0c);
5629 goto int13_fail_noah;
5630 }
5631
5632 goto int13_success;
5633 break;
5634
5635 case 0x45: // IBM/MS lock/unlock drive
5636 if (GET_AL() > 2) goto int13_fail;
5637
5638 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
5639
5640 switch (GET_AL()) {
5641 case 0 : // lock
5642 if (locks == 0xff) {
5643 SET_AH(0xb4);
5644 SET_AL(1);
5645 goto int13_fail_noah;
5646 }
5647 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, ++locks);
5648 SET_AL(1);
5649 break;
5650 case 1 : // unlock
5651 if (locks == 0x00) {
5652 SET_AH(0xb0);
5653 SET_AL(0);
5654 goto int13_fail_noah;
5655 }
5656 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, --locks);
5657 SET_AL(locks==0?0:1);
5658 break;
5659 case 2 : // status
5660 SET_AL(locks==0?0:1);
5661 break;
5662 }
5663 goto int13_success;
5664 break;
5665
5666 case 0x46: // IBM/MS eject media
5667 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
5668
5669 if (locks != 0) {
5670 SET_AH(0xb1); // media locked
5671 goto int13_fail_noah;
5672 }
5673 // FIXME should handle 0x31 no media in device
5674 // FIXME should handle 0xb5 valid request failed
5675
5676 // Call removable media eject
5677 ASM_START
5678 push bp
5679 mov bp, sp
5680
5681 mov ah, #0x52
5682 int 15
5683 mov _int13_cdrom.status + 2[bp], ah
5684 jnc int13_cdrom_rme_end
5685 mov _int13_cdrom.status, #1
5686int13_cdrom_rme_end:
5687 pop bp
5688 ASM_END
5689
5690 if (status != 0) {
5691 SET_AH(0xb1); // media locked
5692 goto int13_fail_noah;
5693 }
5694
5695 goto int13_success;
5696 break;
5697
5698 case 0x48: // IBM/MS get drive parameters
5699 size = read_word(DS,SI+(Bit16u)&Int13Ext->size);
5700
5701 // Buffer is too small
5702 if(size < 0x1a)
5703 goto int13_fail;
5704
5705 // EDD 1.x
5706 if(size >= 0x1a) {
5707 Bit16u cylinders, heads, spt, blksize;
5708
5709 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5710
5711 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5712 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x74); // removable, media change, lockable, max values
5713 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, 0xffffffff);
5714 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, 0xffffffff);
5715 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, 0xffffffff);
5716 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, 0xffffffff); // FIXME should be Bit64
5717 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0xffffffff);
5718 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5719 }
5720
5721 // EDD 2.x
5722 if(size >= 0x1e) {
5723 Bit8u channel, dev, irq, mode, checksum, i;
5724 Bit16u iobase1, iobase2, options;
5725
5726 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5727
5728 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5729 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5730
5731 // Fill in dpte
5732 channel = device / 2;
5733 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5734 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5735 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5736 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5737
5738 // FIXME atapi device
5739 options = (1<<4); // lba translation
5740 options |= (1<<5); // removable device
5741 options |= (1<<6); // atapi device
5742 options |= (mode==ATA_MODE_PIO32?1:0<<7);
5743
5744 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5745 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5746 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5747 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5748 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5749 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5750 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5751 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5752 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5753 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5754 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5755
5756 checksum=0;
5757 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5758 checksum = ~checksum;
5759 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5760 }
5761
5762 // EDD 3.x
5763 if(size >= 0x42) {
5764 Bit8u channel, iface, checksum, i;
5765 Bit16u iobase1;
5766
5767 channel = device / 2;
5768 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5769 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5770
5771 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5772 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5773 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5774 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5775 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5776
5777 if (iface==ATA_IFACE_ISA) {
5778 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5779 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5780 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5781 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5782 }
5783 else {
5784 // FIXME PCI
5785 }
5786 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5787 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5788 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5789 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5790
5791 if (iface==ATA_IFACE_ISA) {
5792 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5793 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5794 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5795 }
5796 else {
5797 // FIXME PCI
5798 }
5799 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5800 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5801 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5802 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5803
5804 checksum=0;
5805 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5806 checksum = ~checksum;
5807 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5808 }
5809
5810 goto int13_success;
5811 break;
5812
5813 case 0x49: // IBM/MS extended media change
5814 // always send changed ??
5815 SET_AH(06);
5816 goto int13_fail_nostatus;
5817 break;
5818
5819 case 0x4e: // // IBM/MS set hardware configuration
5820 // DMA, prefetch, PIO maximum not supported
5821 switch (GET_AL()) {
5822 case 0x01:
5823 case 0x03:
5824 case 0x04:
5825 case 0x06:
5826 goto int13_success;
5827 break;
5828 default :
5829 goto int13_fail;
5830 }
5831 break;
5832
5833 // all those functions return unimplemented
5834 case 0x02: /* read sectors */
5835 case 0x04: /* verify sectors */
5836 case 0x08: /* read disk drive parameters */
5837 case 0x0a: /* read disk sectors with ECC */
5838 case 0x0b: /* write disk sectors with ECC */
5839 case 0x18: /* set media type for format */
5840 case 0x50: // ? - send packet command
5841 default:
5842 BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
5843 goto int13_fail;
5844 break;
5845 }
5846
5847int13_fail:
5848 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5849int13_fail_noah:
5850 SET_DISK_RET_STATUS(GET_AH());
5851int13_fail_nostatus:
5852 SET_CF(); // error occurred
5853 return;
5854
5855int13_success:
5856 SET_AH(0x00); // no error
5857int13_success_noah:
5858 SET_DISK_RET_STATUS(0x00);
5859 CLEAR_CF(); // no error
5860 return;
5861}
5862
5863// ---------------------------------------------------------------------------
5864// End of int13 for cdrom
5865// ---------------------------------------------------------------------------
5866
5867#if BX_ELTORITO_BOOT
5868// ---------------------------------------------------------------------------
5869// Start of int13 for eltorito functions
5870// ---------------------------------------------------------------------------
5871
5872 void
5873int13_eltorito(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
5874 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
5875{
5876 Bit16u ebda_seg=read_word(0x0040,0x000E);
5877
5878 BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5879 // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
5880
5881 switch (GET_AH()) {
5882
5883 // FIXME ElTorito Various. Should be implemented
5884 case 0x4a: // ElTorito - Initiate disk emu
5885 case 0x4c: // ElTorito - Initiate disk emu and boot
5886 case 0x4d: // ElTorito - Return Boot catalog
5887 BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX);
5888 goto int13_fail;
5889 break;
5890
5891 case 0x4b: // ElTorito - Terminate disk emu
5892 // FIXME ElTorito Hardcoded
5893 write_byte(DS,SI+0x00,0x13);
5894 write_byte(DS,SI+0x01,read_byte(ebda_seg,&EbdaData->cdemu.media));
5895 write_byte(DS,SI+0x02,read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
5896 write_byte(DS,SI+0x03,read_byte(ebda_seg,&EbdaData->cdemu.controller_index));
5897 write_dword(DS,SI+0x04,read_dword(ebda_seg,&EbdaData->cdemu.ilba));
5898 write_word(DS,SI+0x08,read_word(ebda_seg,&EbdaData->cdemu.device_spec));
5899 write_word(DS,SI+0x0a,read_word(ebda_seg,&EbdaData->cdemu.buffer_segment));
5900 write_word(DS,SI+0x0c,read_word(ebda_seg,&EbdaData->cdemu.load_segment));
5901 write_word(DS,SI+0x0e,read_word(ebda_seg,&EbdaData->cdemu.sector_count));
5902 write_byte(DS,SI+0x10,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.cylinders));
5903 write_byte(DS,SI+0x11,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.spt));
5904 write_byte(DS,SI+0x12,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.heads));
5905
5906 // If we have to terminate emulation
5907 if(GET_AL() == 0x00) {
5908 // FIXME ElTorito Various. Should be handled accordingly to spec
5909 write_byte(ebda_seg,&EbdaData->cdemu.active, 0x00); // bye bye
5910 }
5911
5912 goto int13_success;
5913 break;
5914
5915 default:
5916 BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
5917 goto int13_fail;
5918 break;
5919 }
5920
5921int13_fail:
5922 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5923 SET_DISK_RET_STATUS(GET_AH());
5924 SET_CF(); // error occurred
5925 return;
5926
5927int13_success:
5928 SET_AH(0x00); // no error
5929 SET_DISK_RET_STATUS(0x00);
5930 CLEAR_CF(); // no error
5931 return;
5932}
5933
5934// ---------------------------------------------------------------------------
5935// End of int13 for eltorito functions
5936// ---------------------------------------------------------------------------
5937
5938// ---------------------------------------------------------------------------
5939// Start of int13 when emulating a device from the cd
5940// ---------------------------------------------------------------------------
5941
5942 void
5943int13_cdemu(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
5944 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
5945{
5946 Bit16u ebda_seg=read_word(0x0040,0x000E);
5947 Bit8u device, status;
5948 Bit16u vheads, vspt, vcylinders;
5949 Bit16u head, sector, cylinder, nbsectors;
5950 Bit32u vlba, ilba, slba, elba;
5951 Bit16u before, segment, offset;
5952 Bit8u atacmd[12];
5953
5954 BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5955
5956 /* at this point, we are emulating a floppy/harddisk */
5957
5958 // Recompute the device number
5959 device = read_byte(ebda_seg,&EbdaData->cdemu.controller_index) * 2;
5960 device += read_byte(ebda_seg,&EbdaData->cdemu.device_spec);
5961
5962 SET_DISK_RET_STATUS(0x00);
5963
5964 /* basic checks : emulation should be active, dl should equal the emulated drive */
5965 if( (read_byte(ebda_seg,&EbdaData->cdemu.active) ==0 )
5966 || (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive ) != GET_DL())) {
5967 BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
5968 goto int13_fail;
5969 }
5970
5971 switch (GET_AH()) {
5972
5973 // all those functions return SUCCESS
5974 case 0x00: /* disk controller reset */
5975 case 0x09: /* initialize drive parameters */
5976 case 0x0c: /* seek to specified cylinder */
5977 case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
5978 case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
5979 case 0x11: /* recalibrate */
5980 case 0x14: /* controller internal diagnostic */
5981 case 0x16: /* detect disk change */
5982 goto int13_success;
5983 break;
5984
5985 // all those functions return disk write-protected
5986 case 0x03: /* write disk sectors */
5987 case 0x05: /* format disk track */
5988 SET_AH(0x03);
5989 goto int13_fail_noah;
5990 break;
5991
5992 case 0x01: /* read disk status */
5993 status=read_byte(0x0040, 0x0074);
5994 SET_AH(status);
5995 SET_DISK_RET_STATUS(0);
5996
5997 /* set CF if error status read */
5998 if (status) goto int13_fail_nostatus;
5999 else goto int13_success_noah;
6000 break;
6001
6002 case 0x02: // read disk sectors
6003 case 0x04: // verify disk sectors
6004 vspt = read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
6005 vcylinders = read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders);
6006 vheads = read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads);
6007
6008 ilba = read_dword(ebda_seg,&EbdaData->cdemu.ilba);
6009
6010 sector = GET_CL() & 0x003f;
6011 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
6012 head = GET_DH();
6013 nbsectors = GET_AL();
6014 segment = ES;
6015 offset = BX;
6016
6017 // no sector to read ?
6018 if(nbsectors==0) goto int13_success;
6019
6020 // sanity checks sco openserver needs this!
6021 if ((sector > vspt)
6022 || (cylinder >= vcylinders)
6023 || (head >= vheads)) {
6024 goto int13_fail;
6025 }
6026
6027 // After controls, verify do nothing
6028 if (GET_AH() == 0x04) goto int13_success;
6029
6030 segment = ES+(BX / 16);
6031 offset = BX % 16;
6032
6033 // calculate the virtual lba inside the image
6034 vlba=((((Bit32u)cylinder*(Bit32u)vheads)+(Bit32u)head)*(Bit32u)vspt)+((Bit32u)(sector-1));
6035
6036 // In advance so we don't loose the count
6037 SET_AL(nbsectors);
6038
6039 // start lba on cd
6040 slba = (Bit32u)vlba/4;
6041 before= (Bit16u)vlba%4;
6042
6043 // end lba on cd
6044 elba = (Bit32u)(vlba+nbsectors-1)/4;
6045
6046 memsetb(get_SS(),atacmd,0,12);
6047 atacmd[0]=0x28; // READ command
6048 atacmd[7]=((Bit16u)(elba-slba+1) & 0xff00) >> 8; // Sectors
6049 atacmd[8]=((Bit16u)(elba-slba+1) & 0x00ff); // Sectors
6050 atacmd[2]=(ilba+slba & 0xff000000) >> 24; // LBA
6051 atacmd[3]=(ilba+slba & 0x00ff0000) >> 16;
6052 atacmd[4]=(ilba+slba & 0x0000ff00) >> 8;
6053 atacmd[5]=(ilba+slba & 0x000000ff);
6054 if((status = ata_cmd_packet(device, 12, get_SS(), atacmd, before*512, nbsectors*512L, ATA_DATA_IN, segment,offset)) != 0) {
6055 BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status);
6056 SET_AH(0x02);
6057 SET_AL(0);
6058 goto int13_fail_noah;
6059 }
6060
6061 goto int13_success;
6062 break;
6063
6064 case 0x08: /* read disk drive parameters */
6065 vspt=read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
6066 vcylinders=read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders) - 1;
6067 vheads=read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads) - 1;
6068
6069 SET_AL( 0x00 );
6070 SET_BL( 0x00 );
6071 SET_CH( vcylinders & 0xff );
6072 SET_CL((( vcylinders >> 2) & 0xc0) | ( vspt & 0x3f ));
6073 SET_DH( vheads );
6074 SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2
6075 // FIXME ElTorito Harddisk. should send the HD count
6076
6077 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
6078 case 0x01: SET_BL( 0x02 ); break;
6079 case 0x02: SET_BL( 0x04 ); break;
6080 case 0x03: SET_BL( 0x06 ); break;
6081 }
6082
6083ASM_START
6084 push bp
6085 mov bp, sp
6086 mov ax, #diskette_param_table2
6087 mov _int13_cdemu.DI+2[bp], ax
6088 mov _int13_cdemu.ES+2[bp], cs
6089 pop bp
6090ASM_END
6091 goto int13_success;
6092 break;
6093
6094 case 0x15: /* read disk drive size */
6095 // FIXME ElTorito Harddisk. What geometry to send ?
6096 SET_AH(0x03);
6097 goto int13_success_noah;
6098 break;
6099
6100 // all those functions return unimplemented
6101 case 0x0a: /* read disk sectors with ECC */
6102 case 0x0b: /* write disk sectors with ECC */
6103 case 0x18: /* set media type for format */
6104 case 0x41: // IBM/MS installation check
6105 // FIXME ElTorito Harddisk. Darwin would like to use EDD
6106 case 0x42: // IBM/MS extended read
6107 case 0x43: // IBM/MS extended write
6108 case 0x44: // IBM/MS verify sectors
6109 case 0x45: // IBM/MS lock/unlock drive
6110 case 0x46: // IBM/MS eject media
6111 case 0x47: // IBM/MS extended seek
6112 case 0x48: // IBM/MS get drive parameters
6113 case 0x49: // IBM/MS extended media change
6114 case 0x4e: // ? - set hardware configuration
6115 case 0x50: // ? - send packet command
6116 default:
6117 BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
6118 goto int13_fail;
6119 break;
6120 }
6121
6122int13_fail:
6123 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6124int13_fail_noah:
6125 SET_DISK_RET_STATUS(GET_AH());
6126int13_fail_nostatus:
6127 SET_CF(); // error occurred
6128 return;
6129
6130int13_success:
6131 SET_AH(0x00); // no error
6132int13_success_noah:
6133 SET_DISK_RET_STATUS(0x00);
6134 CLEAR_CF(); // no error
6135 return;
6136}
6137
6138// ---------------------------------------------------------------------------
6139// End of int13 when emulating a device from the cd
6140// ---------------------------------------------------------------------------
6141
6142#endif // BX_ELTORITO_BOOT
6143
6144#else //BX_USE_ATADRV
6145
6146 void
6147outLBA(cylinder,hd_heads,head,hd_sectors,sector,dl)
6148 Bit16u cylinder;
6149 Bit16u hd_heads;
6150 Bit16u head;
6151 Bit16u hd_sectors;
6152 Bit16u sector;
6153 Bit16u dl;
6154{
6155ASM_START
6156 push bp
6157 mov bp, sp
6158 push eax
6159 push ebx
6160 push edx
6161 xor eax,eax
6162 mov ax,4[bp] // cylinder
6163 xor ebx,ebx
6164 mov bl,6[bp] // hd_heads
6165 imul ebx
6166
6167 mov bl,8[bp] // head
6168 add eax,ebx
6169 mov bl,10[bp] // hd_sectors
6170 imul ebx
6171 mov bl,12[bp] // sector
6172 add eax,ebx
6173
6174 dec eax
6175 mov dx,#0x1f3
6176 out dx,al
6177 mov dx,#0x1f4
6178 mov al,ah
6179 out dx,al
6180 shr eax,#16
6181 mov dx,#0x1f5
6182 out dx,al
6183 and ah,#0xf
6184 mov bl,14[bp] // dl
6185 and bl,#1
6186 shl bl,#4
6187 or ah,bl
6188 or ah,#0xe0
6189 mov al,ah
6190 mov dx,#0x01f6
6191 out dx,al
6192 pop edx
6193 pop ebx
6194 pop eax
6195 pop bp
6196ASM_END
6197}
6198
6199 void
6200int13_harddisk(EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
6201 Bit16u EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
6202{
6203 Bit8u drive, num_sectors, sector, head, status, mod;
6204 Bit8u drive_map;
6205 Bit8u n_drives;
6206 Bit16u cyl_mod, ax;
6207 Bit16u max_cylinder, cylinder, total_sectors;
6208 Bit16u hd_cylinders;
6209 Bit8u hd_heads, hd_sectors;
6210 Bit16u val16;
6211 Bit8u sector_count;
6212 unsigned int i;
6213 Bit16u tempbx;
6214 Bit16u dpsize;
6215
6216 Bit16u count, segment, offset;
6217 Bit32u lba;
6218 Bit16u error;
6219
6220 BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6221
6222 write_byte(0x0040, 0x008e, 0); // clear completion flag
6223
6224 /* at this point, DL is >= 0x80 to be passed from the floppy int13h
6225 handler code */
6226 /* check how many disks first (cmos reg 0x12), return an error if
6227 drive not present */
6228 drive_map = inb_cmos(0x12);
6229 drive_map = (((drive_map & 0xf0)==0) ? 0 : 1) |
6230 (((drive_map & 0x0f)==0) ? 0 : 2);
6231 n_drives = (drive_map==0) ? 0 :
6232 ((drive_map==3) ? 2 : 1);
6233
6234 if (!(drive_map & (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
6235 SET_AH(0x01);
6236 SET_DISK_RET_STATUS(0x01);
6237 SET_CF(); /* error occurred */
6238 return;
6239 }
6240
6241 switch (GET_AH()) {
6242
6243 case 0x00: /* disk controller reset */
6244BX_DEBUG_INT13_HD("int13_f00\n");
6245
6246 SET_AH(0);
6247 SET_DISK_RET_STATUS(0);
6248 set_diskette_ret_status(0);
6249 set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
6250 set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
6251 CLEAR_CF(); /* successful */
6252 return;
6253 break;
6254
6255 case 0x01: /* read disk status */
6256BX_DEBUG_INT13_HD("int13_f01\n");
6257 status = read_byte(0x0040, 0x0074);
6258 SET_AH(status);
6259 SET_DISK_RET_STATUS(0);
6260 /* set CF if error status read */
6261 if (status) SET_CF();
6262 else CLEAR_CF();
6263 return;
6264 break;
6265
6266 case 0x04: // verify disk sectors
6267 case 0x02: // read disk sectors
6268 drive = GET_ELDL();
6269 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6270
6271 num_sectors = GET_AL();
6272 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
6273 sector = (GET_CL() & 0x3f);
6274 head = GET_DH();
6275
6276
6277 if (hd_cylinders > 1024) {
6278 if (hd_cylinders <= 2048) {
6279 cylinder <<= 1;
6280 }
6281 else if (hd_cylinders <= 4096) {
6282 cylinder <<= 2;
6283 }
6284 else if (hd_cylinders <= 8192) {
6285 cylinder <<= 3;
6286 }
6287 else { // hd_cylinders <= 16384
6288 cylinder <<= 4;
6289 }
6290
6291 ax = head / hd_heads;
6292 cyl_mod = ax & 0xff;
6293 head = ax >> 8;
6294 cylinder |= cyl_mod;
6295 }
6296
6297 if ( (cylinder >= hd_cylinders) ||
6298 (sector > hd_sectors) ||
6299 (head >= hd_heads) ) {
6300 SET_AH(1);
6301 SET_DISK_RET_STATUS(1);
6302 SET_CF(); /* error occurred */
6303 return;
6304 }
6305
6306 if ( (num_sectors > 128) || (num_sectors == 0) )
6307 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6308
6309 if (head > 15)
6310 BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
6311
6312 if ( GET_AH() == 0x04 ) {
6313 SET_AH(0);
6314 SET_DISK_RET_STATUS(0);
6315 CLEAR_CF();
6316 return;
6317 }
6318
6319 status = inb(0x1f7);
6320 if (status & 0x80) {
6321 BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
6322 }
6323 outb(0x01f2, num_sectors);
6324 /* activate LBA? (tomv) */
6325 if (hd_heads > 16) {
6326BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder, head, sector);
6327 outLBA(cylinder,hd_heads,head,hd_sectors,sector,drive);
6328 }
6329 else {
6330 outb(0x01f3, sector);
6331 outb(0x01f4, cylinder & 0x00ff);
6332 outb(0x01f5, cylinder >> 8);
6333 outb(0x01f6, 0xa0 | ((drive & 0x01)<<4) | (head & 0x0f));
6334 }
6335 outb(0x01f7, 0x20);
6336
6337 while (1) {
6338 status = inb(0x1f7);
6339 if ( !(status & 0x80) ) break;
6340 }
6341
6342 if (status & 0x01) {
6343 BX_PANIC("hard drive BIOS:(read/verify) read error\n");
6344 } else if ( !(status & 0x08) ) {
6345 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6346 BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
6347 }
6348
6349 sector_count = 0;
6350 tempbx = BX;
6351
6352ASM_START
6353 sti ;; enable higher priority interrupts
6354ASM_END
6355
6356 while (1) {
6357ASM_START
6358 ;; store temp bx in real DI register
6359 push bp
6360 mov bp, sp
6361 mov di, _int13_harddisk.tempbx + 2 [bp]
6362 pop bp
6363
6364 ;; adjust if there will be an overrun
6365 cmp di, #0xfe00
6366 jbe i13_f02_no_adjust
6367i13_f02_adjust:
6368 sub di, #0x0200 ; sub 512 bytes from offset
6369 mov ax, es
6370 add ax, #0x0020 ; add 512 to segment
6371 mov es, ax
6372
6373i13_f02_no_adjust:
6374 mov cx, #0x0100 ;; counter (256 words = 512b)
6375 mov dx, #0x01f0 ;; AT data read port
6376
6377 rep
6378 insw ;; CX words transfered from port(DX) to ES:[DI]
6379
6380i13_f02_done:
6381 ;; store real DI register back to temp bx
6382 push bp
6383 mov bp, sp
6384 mov _int13_harddisk.tempbx + 2 [bp], di
6385 pop bp
6386ASM_END
6387
6388 sector_count++;
6389 num_sectors--;
6390 if (num_sectors == 0) {
6391 status = inb(0x1f7);
6392 if ( (status & 0xc9) != 0x40 )
6393 BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status);
6394 break;
6395 }
6396 else {
6397 status = inb(0x1f7);
6398 if ( (status & 0xc9) != 0x48 )
6399 BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status);
6400 continue;
6401 }
6402 }
6403
6404 SET_AH(0);
6405 SET_DISK_RET_STATUS(0);
6406 SET_AL(sector_count);
6407 CLEAR_CF(); /* successful */
6408 return;
6409 break;
6410
6411
6412 case 0x03: /* write disk sectors */
6413BX_DEBUG_INT13_HD("int13_f03\n");
6414 drive = GET_ELDL ();
6415 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6416
6417 num_sectors = GET_AL();
6418 cylinder = GET_CH();
6419 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
6420 sector = (GET_CL() & 0x3f);
6421 head = GET_DH();
6422
6423 if (hd_cylinders > 1024) {
6424 if (hd_cylinders <= 2048) {
6425 cylinder <<= 1;
6426 }
6427 else if (hd_cylinders <= 4096) {
6428 cylinder <<= 2;
6429 }
6430 else if (hd_cylinders <= 8192) {
6431 cylinder <<= 3;
6432 }
6433 else { // hd_cylinders <= 16384
6434 cylinder <<= 4;
6435 }
6436
6437 ax = head / hd_heads;
6438 cyl_mod = ax & 0xff;
6439 head = ax >> 8;
6440 cylinder |= cyl_mod;
6441 }
6442
6443 if ( (cylinder >= hd_cylinders) ||
6444 (sector > hd_sectors) ||
6445 (head >= hd_heads) ) {
6446 SET_AH( 1);
6447 SET_DISK_RET_STATUS(1);
6448 SET_CF(); /* error occurred */
6449 return;
6450 }
6451
6452 if ( (num_sectors > 128) || (num_sectors == 0) )
6453 BX_PANIC("int13_harddisk: num_sectors out of range!\n");
6454
6455 if (head > 15)
6456 BX_PANIC("hard drive BIOS:(read) head > 15\n");
6457
6458 status = inb(0x1f7);
6459 if (status & 0x80) {
6460 BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
6461 }
6462// should check for Drive Ready Bit also in status reg
6463 outb(0x01f2, num_sectors);
6464
6465 /* activate LBA? (tomv) */
6466 if (hd_heads > 16) {
6467BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder, head, sector);
6468 outLBA(cylinder,hd_heads,head,hd_sectors,sector,GET_ELDL());
6469 }
6470 else {
6471 outb(0x01f3, sector);
6472 outb(0x01f4, cylinder & 0x00ff);
6473 outb(0x01f5, cylinder >> 8);
6474 outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head & 0x0f));
6475 }
6476 outb(0x01f7, 0x30);
6477
6478 // wait for busy bit to turn off after seeking
6479 while (1) {
6480 status = inb(0x1f7);
6481 if ( !(status & 0x80) ) break;
6482 }
6483
6484 if ( !(status & 0x08) ) {
6485 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6486 BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
6487 }
6488
6489 sector_count = 0;
6490 tempbx = BX;
6491
6492ASM_START
6493 sti ;; enable higher priority interrupts
6494ASM_END
6495
6496 while (1) {
6497ASM_START
6498 ;; store temp bx in real SI register
6499 push bp
6500 mov bp, sp
6501 mov si, _int13_harddisk.tempbx + 2 [bp]
6502 pop bp
6503
6504 ;; adjust if there will be an overrun
6505 cmp si, #0xfe00
6506 jbe i13_f03_no_adjust
6507i13_f03_adjust:
6508 sub si, #0x0200 ; sub 512 bytes from offset
6509 mov ax, es
6510 add ax, #0x0020 ; add 512 to segment
6511 mov es, ax
6512
6513i13_f03_no_adjust:
6514 mov cx, #0x0100 ;; counter (256 words = 512b)
6515 mov dx, #0x01f0 ;; AT data read port
6516
6517 seg ES
6518 rep
6519 outsw ;; CX words tranfered from ES:[SI] to port(DX)
6520
6521 ;; store real SI register back to temp bx
6522 push bp
6523 mov bp, sp
6524 mov _int13_harddisk.tempbx + 2 [bp], si
6525 pop bp
6526ASM_END
6527
6528 sector_count++;
6529 num_sectors--;
6530 if (num_sectors == 0) {
6531 status = inb(0x1f7);
6532 if ( (status & 0xe9) != 0x40 )
6533 BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status);
6534 break;
6535 }
6536 else {
6537 status = inb(0x1f7);
6538 if ( (status & 0xc9) != 0x48 )
6539 BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status);
6540 continue;
6541 }
6542 }
6543
6544 SET_AH(0);
6545 SET_DISK_RET_STATUS(0);
6546 SET_AL(sector_count);
6547 CLEAR_CF(); /* successful */
6548 return;
6549 break;
6550
6551 case 0x05: /* format disk track */
6552BX_DEBUG_INT13_HD("int13_f05\n");
6553 BX_PANIC("format disk track called\n");
6554 /* nop */
6555 SET_AH(0);
6556 SET_DISK_RET_STATUS(0);
6557 CLEAR_CF(); /* successful */
6558 return;
6559 break;
6560
6561 case 0x08: /* read disk drive parameters */
6562BX_DEBUG_INT13_HD("int13_f08\n");
6563
6564 drive = GET_ELDL ();
6565 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6566
6567 // translate CHS
6568 //
6569 if (hd_cylinders <= 1024) {
6570 // hd_cylinders >>= 0;
6571 // hd_heads <<= 0;
6572 }
6573 else if (hd_cylinders <= 2048) {
6574 hd_cylinders >>= 1;
6575 hd_heads <<= 1;
6576 }
6577 else if (hd_cylinders <= 4096) {
6578 hd_cylinders >>= 2;
6579 hd_heads <<= 2;
6580 }
6581 else if (hd_cylinders <= 8192) {
6582 hd_cylinders >>= 3;
6583 hd_heads <<= 3;
6584 }
6585 else { // hd_cylinders <= 16384
6586 hd_cylinders >>= 4;
6587 hd_heads <<= 4;
6588 }
6589
6590 max_cylinder = hd_cylinders - 2; /* 0 based */
6591 SET_AL(0);
6592 SET_CH(max_cylinder & 0xff);
6593 SET_CL(((max_cylinder >> 2) & 0xc0) | (hd_sectors & 0x3f));
6594 SET_DH(hd_heads - 1);
6595 SET_DL(n_drives); /* returns 0, 1, or 2 hard drives */
6596 SET_AH(0);
6597 SET_DISK_RET_STATUS(0);
6598 CLEAR_CF(); /* successful */
6599
6600 return;
6601 break;
6602
6603 case 0x09: /* initialize drive parameters */
6604BX_DEBUG_INT13_HD("int13_f09\n");
6605 SET_AH(0);
6606 SET_DISK_RET_STATUS(0);
6607 CLEAR_CF(); /* successful */
6608 return;
6609 break;
6610
6611 case 0x0a: /* read disk sectors with ECC */
6612BX_DEBUG_INT13_HD("int13_f0a\n");
6613 case 0x0b: /* write disk sectors with ECC */
6614BX_DEBUG_INT13_HD("int13_f0b\n");
6615 BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
6616 return;
6617 break;
6618
6619 case 0x0c: /* seek to specified cylinder */
6620BX_DEBUG_INT13_HD("int13_f0c\n");
6621 BX_INFO("int13h function 0ch (seek) not implemented!\n");
6622 SET_AH(0);
6623 SET_DISK_RET_STATUS(0);
6624 CLEAR_CF(); /* successful */
6625 return;
6626 break;
6627
6628 case 0x0d: /* alternate disk reset */
6629BX_DEBUG_INT13_HD("int13_f0d\n");
6630 SET_AH(0);
6631 SET_DISK_RET_STATUS(0);
6632 CLEAR_CF(); /* successful */
6633 return;
6634 break;
6635
6636 case 0x10: /* check drive ready */
6637BX_DEBUG_INT13_HD("int13_f10\n");
6638 //SET_AH(0);
6639 //SET_DISK_RET_STATUS(0);
6640 //CLEAR_CF(); /* successful */
6641 //return;
6642 //break;
6643
6644 // should look at 40:8E also???
6645 status = inb(0x01f7);
6646 if ( (status & 0xc0) == 0x40 ) {
6647 SET_AH(0);
6648 SET_DISK_RET_STATUS(0);
6649 CLEAR_CF(); // drive ready
6650 return;
6651 }
6652 else {
6653 SET_AH(0xAA);
6654 SET_DISK_RET_STATUS(0xAA);
6655 SET_CF(); // not ready
6656 return;
6657 }
6658 break;
6659
6660 case 0x11: /* recalibrate */
6661BX_DEBUG_INT13_HD("int13_f11\n");
6662 SET_AH(0);
6663 SET_DISK_RET_STATUS(0);
6664 CLEAR_CF(); /* successful */
6665 return;
6666 break;
6667
6668 case 0x14: /* controller internal diagnostic */
6669BX_DEBUG_INT13_HD("int13_f14\n");
6670 SET_AH(0);
6671 SET_DISK_RET_STATUS(0);
6672 CLEAR_CF(); /* successful */
6673 SET_AL(0);
6674 return;
6675 break;
6676
6677 case 0x15: /* read disk drive size */
6678 drive = GET_ELDL();
6679 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6680ASM_START
6681 push bp
6682 mov bp, sp
6683 mov al, _int13_harddisk.hd_heads + 2 [bp]
6684 mov ah, _int13_harddisk.hd_sectors + 2 [bp]
6685 mul al, ah ;; ax = heads * sectors
6686 mov bx, _int13_harddisk.hd_cylinders + 2 [bp]
6687 dec bx ;; use (cylinders - 1) ???
6688 mul ax, bx ;; dx:ax = (cylinders -1) * (heads * sectors)
6689 ;; now we need to move the 32bit result dx:ax to what the
6690 ;; BIOS wants which is cx:dx.
6691 ;; and then into CX:DX on the stack
6692 mov _int13_harddisk.CX + 2 [bp], dx
6693 mov _int13_harddisk.DX + 2 [bp], ax
6694 pop bp
6695ASM_END
6696 SET_AH(3); // hard disk accessible
6697 SET_DISK_RET_STATUS(0); // ??? should this be 0
6698 CLEAR_CF(); // successful
6699 return;
6700 break;
6701
6702 case 0x18: // set media type for format
6703 case 0x41: // IBM/MS
6704 case 0x42: // IBM/MS
6705 case 0x43: // IBM/MS
6706 case 0x44: // IBM/MS
6707 case 0x45: // IBM/MS lock/unlock drive
6708 case 0x46: // IBM/MS eject media
6709 case 0x47: // IBM/MS extended seek
6710 case 0x49: // IBM/MS extended media change
6711 case 0x50: // IBM/MS send packet command
6712 default:
6713 BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
6714
6715 SET_AH(1); // code=invalid function in AH or invalid parameter
6716 SET_DISK_RET_STATUS(1);
6717 SET_CF(); /* unsuccessful */
6718 return;
6719 break;
6720 }
6721}
6722
6723static char panic_msg_reg12h[] = "HD%d cmos reg 12h not type F\n";
6724static char panic_msg_reg19h[] = "HD%d cmos reg %02xh not user definable type 47\n";
6725
6726 void
6727get_hd_geometry(drive, hd_cylinders, hd_heads, hd_sectors)
6728 Bit8u drive;
6729 Bit16u *hd_cylinders;
6730 Bit8u *hd_heads;
6731 Bit8u *hd_sectors;
6732{
6733 Bit8u hd_type;
6734 Bit16u ss;
6735 Bit16u cylinders;
6736 Bit8u iobase;
6737
6738 ss = get_SS();
6739 if (drive == 0x80) {
6740 hd_type = inb_cmos(0x12) & 0xf0;
6741 if (hd_type != 0xf0)
6742 BX_INFO(panic_msg_reg12h,0);
6743 hd_type = inb_cmos(0x19); // HD0: extended type
6744 if (hd_type != 47)
6745 BX_INFO(panic_msg_reg19h,0,0x19);
6746 iobase = 0x1b;
6747 } else {
6748 hd_type = inb_cmos(0x12) & 0x0f;
6749 if (hd_type != 0x0f)
6750 BX_INFO(panic_msg_reg12h,1);
6751 hd_type = inb_cmos(0x1a); // HD0: extended type
6752 if (hd_type != 47)
6753 BX_INFO(panic_msg_reg19h,0,0x1a);
6754 iobase = 0x24;
6755 }
6756
6757 // cylinders
6758 cylinders = inb_cmos(iobase) | (inb_cmos(iobase+1) << 8);
6759 write_word(ss, hd_cylinders, cylinders);
6760
6761 // heads
6762 write_byte(ss, hd_heads, inb_cmos(iobase+2));
6763
6764 // sectors per track
6765 write_byte(ss, hd_sectors, inb_cmos(iobase+8));
6766}
6767
6768#endif //else BX_USE_ATADRV
6769
6770
6771//////////////////////
6772// FLOPPY functions //
6773//////////////////////
6774
6775void floppy_reset_controller()
6776{
6777 Bit8u val8;
6778
6779 // Reset controller
6780 val8 = inb(0x03f2);
6781 outb(0x03f2, val8 & ~0x04);
6782 outb(0x03f2, val8 | 0x04);
6783
6784 // Wait for controller to come out of reset
6785 do {
6786 val8 = inb(0x3f4);
6787 } while ( (val8 & 0xc0) != 0x80 );
6788}
6789
6790void floppy_prepare_controller(drive)
6791 Bit16u drive;
6792{
6793 Bit8u val8, dor, prev_reset;
6794
6795 // set 40:3e bit 7 to 0
6796 val8 = read_byte(0x0040, 0x003e);
6797 val8 &= 0x7f;
6798 write_byte(0x0040, 0x003e, val8);
6799
6800 // turn on motor of selected drive, DMA & int enabled, normal operation
6801 prev_reset = inb(0x03f2) & 0x04;
6802 if (drive)
6803 dor = 0x20;
6804 else
6805 dor = 0x10;
6806 dor |= 0x0c;
6807 dor |= drive;
6808 outb(0x03f2, dor);
6809
6810 // reset the disk motor timeout value of INT 08
6811 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
6812
6813 // wait for drive readiness
6814 do {
6815 val8 = inb(0x3f4);
6816 } while ( (val8 & 0xc0) != 0x80 );
6817
6818 if (prev_reset == 0) {
6819 // turn on interrupts
6820ASM_START
6821 sti
6822ASM_END
6823 // wait on 40:3e bit 7 to become 1
6824 do {
6825 val8 = read_byte(0x0040, 0x003e);
6826 } while ( (val8 & 0x80) == 0 );
6827 val8 &= 0x7f;
6828ASM_START
6829 cli
6830ASM_END
6831 write_byte(0x0040, 0x003e, val8);
6832 }
6833}
6834
6835 bx_bool
6836floppy_media_known(drive)
6837 Bit16u drive;
6838{
6839 Bit8u val8;
6840 Bit16u media_state_offset;
6841
6842 val8 = read_byte(0x0040, 0x003e); // diskette recal status
6843 if (drive)
6844 val8 >>= 1;
6845 val8 &= 0x01;
6846 if (val8 == 0)
6847 return(0);
6848
6849 media_state_offset = 0x0090;
6850 if (drive)
6851 media_state_offset += 1;
6852
6853 val8 = read_byte(0x0040, media_state_offset);
6854 val8 = (val8 >> 4) & 0x01;
6855 if (val8 == 0)
6856 return(0);
6857
6858 // check pass, return KNOWN
6859 return(1);
6860}
6861
6862 bx_bool
6863floppy_media_sense(drive)
6864 Bit16u drive;
6865{
6866 bx_bool retval;
6867 Bit16u media_state_offset;
6868 Bit8u drive_type, config_data, media_state;
6869
6870 if (floppy_drive_recal(drive) == 0) {
6871 return(0);
6872 }
6873
6874 // for now cheat and get drive type from CMOS,
6875 // assume media is same as drive type
6876
6877 // ** config_data **
6878 // Bitfields for diskette media control:
6879 // Bit(s) Description (Table M0028)
6880 // 7-6 last data rate set by controller
6881 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6882 // 5-4 last diskette drive step rate selected
6883 // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
6884 // 3-2 {data rate at start of operation}
6885 // 1-0 reserved
6886
6887 // ** media_state **
6888 // Bitfields for diskette drive media state:
6889 // Bit(s) Description (Table M0030)
6890 // 7-6 data rate
6891 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6892 // 5 double stepping required (e.g. 360kB in 1.2MB)
6893 // 4 media type established
6894 // 3 drive capable of supporting 4MB media
6895 // 2-0 on exit from BIOS, contains
6896 // 000 trying 360kB in 360kB
6897 // 001 trying 360kB in 1.2MB
6898 // 010 trying 1.2MB in 1.2MB
6899 // 011 360kB in 360kB established
6900 // 100 360kB in 1.2MB established
6901 // 101 1.2MB in 1.2MB established
6902 // 110 reserved
6903 // 111 all other formats/drives
6904
6905 drive_type = inb_cmos(0x10);
6906 if (drive == 0)
6907 drive_type >>= 4;
6908 else
6909 drive_type &= 0x0f;
6910 if ( drive_type == 1 ) {
6911 // 360K 5.25" drive
6912 config_data = 0x00; // 0000 0000
6913 media_state = 0x25; // 0010 0101
6914 retval = 1;
6915 }
6916 else if ( drive_type == 2 ) {
6917 // 1.2 MB 5.25" drive
6918 config_data = 0x00; // 0000 0000
6919 media_state = 0x25; // 0010 0101 // need double stepping??? (bit 5)
6920 retval = 1;
6921 }
6922 else if ( drive_type == 3 ) {
6923 // 720K 3.5" drive
6924 config_data = 0x00; // 0000 0000 ???
6925 media_state = 0x17; // 0001 0111
6926 retval = 1;
6927 }
6928 else if ( drive_type == 4 ) {
6929 // 1.44 MB 3.5" drive
6930 config_data = 0x00; // 0000 0000
6931 media_state = 0x17; // 0001 0111
6932 retval = 1;
6933 }
6934 else if ( drive_type == 5 ) {
6935 // 2.88 MB 3.5" drive
6936 config_data = 0xCC; // 1100 1100
6937 media_state = 0xD7; // 1101 0111
6938 retval = 1;
6939 }
6940 //
6941 // Extended floppy size uses special cmos setting
6942 else if ( drive_type == 6 ) {
6943 // 160k 5.25" drive
6944 config_data = 0x00; // 0000 0000
6945 media_state = 0x27; // 0010 0111
6946 retval = 1;
6947 }
6948 else if ( drive_type == 7 ) {
6949 // 180k 5.25" drive
6950 config_data = 0x00; // 0000 0000
6951 media_state = 0x27; // 0010 0111
6952 retval = 1;
6953 }
6954 else if ( drive_type == 8 ) {
6955 // 320k 5.25" drive
6956 config_data = 0x00; // 0000 0000
6957 media_state = 0x27; // 0010 0111
6958 retval = 1;
6959 }
6960
6961 else {
6962 // not recognized
6963 config_data = 0x00; // 0000 0000
6964 media_state = 0x00; // 0000 0000
6965 retval = 0;
6966 }
6967
6968 if (drive == 0)
6969 media_state_offset = 0x90;
6970 else
6971 media_state_offset = 0x91;
6972 write_byte(0x0040, 0x008B, config_data);
6973 write_byte(0x0040, media_state_offset, media_state);
6974
6975 return(retval);
6976}
6977
6978 bx_bool
6979floppy_drive_recal(drive)
6980 Bit16u drive;
6981{
6982 Bit8u val8;
6983 Bit16u curr_cyl_offset;
6984
6985 floppy_prepare_controller(drive);
6986
6987 // send Recalibrate command (2 bytes) to controller
6988 outb(0x03f5, 0x07); // 07: Recalibrate
6989 outb(0x03f5, drive); // 0=drive0, 1=drive1
6990
6991 // turn on interrupts
6992ASM_START
6993 sti
6994ASM_END
6995
6996 // wait on 40:3e bit 7 to become 1
6997 do {
6998 val8 = (read_byte(0x0040, 0x003e) & 0x80);
6999 } while ( val8 == 0 );
7000
7001 val8 = 0; // separate asm from while() loop
7002 // turn off interrupts
7003ASM_START
7004 cli
7005ASM_END
7006
7007 // set 40:3e bit 7 to 0, and calibrated bit
7008 val8 = read_byte(0x0040, 0x003e);
7009 val8 &= 0x7f;
7010 if (drive) {
7011 val8 |= 0x02; // Drive 1 calibrated
7012 curr_cyl_offset = 0x0095;
7013 } else {
7014 val8 |= 0x01; // Drive 0 calibrated
7015 curr_cyl_offset = 0x0094;
7016 }
7017 write_byte(0x0040, 0x003e, val8);
7018 write_byte(0x0040, curr_cyl_offset, 0); // current cylinder is 0
7019
7020 return(1);
7021}
7022
7023
7024
7025 bx_bool
7026floppy_drive_exists(drive)
7027 Bit16u drive;
7028{
7029 Bit8u drive_type;
7030
7031 // check CMOS to see if drive exists
7032 drive_type = inb_cmos(0x10);
7033 if (drive == 0)
7034 drive_type >>= 4;
7035 else
7036 drive_type &= 0x0f;
7037 if ( drive_type == 0 )
7038 return(0);
7039 else
7040 return(1);
7041}
7042
7043#if BX_SUPPORT_FLOPPY
7044 void
7045int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
7046 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
7047{
7048 Bit8u drive, num_sectors, track, sector, head, status;
7049 Bit16u base_address, base_count, base_es;
7050 Bit8u page, mode_register, val8, dor;
7051 Bit8u return_status[7];
7052 Bit8u drive_type, num_floppies, ah;
7053 Bit16u es, last_addr;
7054
7055 BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
7056
7057 ah = GET_AH();
7058
7059 switch ( ah ) {
7060 case 0x00: // diskette controller reset
7061BX_DEBUG_INT13_FL("floppy f00\n");
7062 drive = GET_ELDL();
7063 if (drive > 1) {
7064 SET_AH(1); // invalid param
7065 set_diskette_ret_status(1);
7066 SET_CF();
7067 return;
7068 }
7069 drive_type = inb_cmos(0x10);
7070
7071 if (drive == 0)
7072 drive_type >>= 4;
7073 else
7074 drive_type &= 0x0f;
7075 if (drive_type == 0) {
7076 SET_AH(0x80); // drive not responding
7077 set_diskette_ret_status(0x80);
7078 SET_CF();
7079 return;
7080 }
7081 SET_AH(0);
7082 set_diskette_ret_status(0);
7083 CLEAR_CF(); // successful
7084 set_diskette_current_cyl(drive, 0); // current cylinder
7085 return;
7086
7087 case 0x01: // Read Diskette Status
7088 CLEAR_CF();
7089 val8 = read_byte(0x0000, 0x0441);
7090 SET_AH(val8);
7091 if (val8) {
7092 SET_CF();
7093 }
7094 return;
7095
7096 case 0x02: // Read Diskette Sectors
7097 case 0x03: // Write Diskette Sectors
7098 case 0x04: // Verify Diskette Sectors
7099 num_sectors = GET_AL();
7100 track = GET_CH();
7101 sector = GET_CL();
7102 head = GET_DH();
7103 drive = GET_ELDL();
7104
7105 if ( (drive > 1) || (head > 1) ||
7106 (num_sectors == 0) || (num_sectors > 72) ) {
7107BX_INFO("floppy: drive>1 || head>1 ...\n");
7108 SET_AH(1);
7109 set_diskette_ret_status(1);
7110 SET_AL(0); // no sectors read
7111 SET_CF(); // error occurred
7112 return;
7113 }
7114
7115 // see if drive exists
7116 if (floppy_drive_exists(drive) == 0) {
7117 SET_AH(0x80); // not responding
7118 set_diskette_ret_status(0x80);
7119 SET_AL(0); // no sectors read
7120 SET_CF(); // error occurred
7121 return;
7122 }
7123
7124 // see if media in drive, and type is known
7125 if (floppy_media_known(drive) == 0) {
7126 if (floppy_media_sense(drive) == 0) {
7127 SET_AH(0x0C); // Media type not found
7128 set_diskette_ret_status(0x0C);
7129 SET_AL(0); // no sectors read
7130 SET_CF(); // error occurred
7131 return;
7132 }
7133 }
7134
7135 if (ah == 0x02) {
7136 // Read Diskette Sectors
7137
7138 //-----------------------------------
7139 // set up DMA controller for transfer
7140 //-----------------------------------
7141
7142 // es:bx = pointer to where to place information from diskette
7143 // port 04: DMA-1 base and current address, channel 2
7144 // port 05: DMA-1 base and current count, channel 2
7145 page = (ES >> 12); // upper 4 bits
7146 base_es = (ES << 4); // lower 16bits contributed by ES
7147 base_address = base_es + BX; // lower 16 bits of address
7148 // contributed by ES:BX
7149 if ( base_address < base_es ) {
7150 // in case of carry, adjust page by 1
7151 page++;
7152 }
7153 base_count = (num_sectors * 512) - 1;
7154
7155 // check for 64K boundary overrun
7156 last_addr = base_address + base_count;
7157 if (last_addr < base_address) {
7158 SET_AH(0x09);
7159 set_diskette_ret_status(0x09);
7160 SET_AL(0); // no sectors read
7161 SET_CF(); // error occurred
7162 return;
7163 }
7164
7165 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7166 outb(0x000a, 0x06);
7167
7168 BX_DEBUG_INT13_FL("clear flip-flop\n");
7169 outb(0x000c, 0x00); // clear flip-flop
7170 outb(0x0004, base_address);
7171 outb(0x0004, base_address>>8);
7172 BX_DEBUG_INT13_FL("clear flip-flop\n");
7173 outb(0x000c, 0x00); // clear flip-flop
7174 outb(0x0005, base_count);
7175 outb(0x0005, base_count>>8);
7176
7177 // port 0b: DMA-1 Mode Register
7178 mode_register = 0x46; // single mode, increment, autoinit disable,
7179 // transfer type=write, channel 2
7180 BX_DEBUG_INT13_FL("setting mode register\n");
7181 outb(0x000b, mode_register);
7182
7183 BX_DEBUG_INT13_FL("setting page register\n");
7184 // port 81: DMA-1 Page Register, channel 2
7185 outb(0x0081, page);
7186
7187 BX_DEBUG_INT13_FL("unmask chan 2\n");
7188 outb(0x000a, 0x02); // unmask channel 2
7189
7190 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7191 outb(0x000a, 0x02);
7192
7193 //--------------------------------------
7194 // set up floppy controller for transfer
7195 //--------------------------------------
7196 floppy_prepare_controller(drive);
7197
7198 // send read-normal-data command (9 bytes) to controller
7199 outb(0x03f5, 0xe6); // e6: read normal data
7200 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7201 outb(0x03f5, track);
7202 outb(0x03f5, head);
7203 outb(0x03f5, sector);
7204 outb(0x03f5, 2); // 512 byte sector size
7205 outb(0x03f5, sector + num_sectors - 1); // last sector to read on track
7206 outb(0x03f5, 0); // Gap length
7207 outb(0x03f5, 0xff); // Gap length
7208
7209 // turn on interrupts
7210 ASM_START
7211 sti
7212 ASM_END
7213
7214 // wait on 40:3e bit 7 to become 1
7215 do {
7216 val8 = read_byte(0x0040, 0x0040);
7217 if (val8 == 0) {
7218 floppy_reset_controller();
7219 SET_AH(0x80); // drive not ready (timeout)
7220 set_diskette_ret_status(0x80);
7221 SET_AL(0); // no sectors read
7222 SET_CF(); // error occurred
7223 return;
7224 }
7225 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7226 } while ( val8 == 0 );
7227
7228 val8 = 0; // separate asm from while() loop
7229 // turn off interrupts
7230 ASM_START
7231 cli
7232 ASM_END
7233
7234 // set 40:3e bit 7 to 0
7235 val8 = read_byte(0x0040, 0x003e);
7236 val8 &= 0x7f;
7237 write_byte(0x0040, 0x003e, val8);
7238
7239 // check port 3f4 for accessibility to status bytes
7240 val8 = inb(0x3f4);
7241 if ( (val8 & 0xc0) != 0xc0 )
7242 BX_PANIC("int13_diskette: ctrl not ready\n");
7243
7244 // read 7 return status bytes from controller
7245 // using loop index broken, have to unroll...
7246 return_status[0] = inb(0x3f5);
7247 return_status[1] = inb(0x3f5);
7248 return_status[2] = inb(0x3f5);
7249 return_status[3] = inb(0x3f5);
7250 return_status[4] = inb(0x3f5);
7251 return_status[5] = inb(0x3f5);
7252 return_status[6] = inb(0x3f5);
7253 // record in BIOS Data Area
7254 write_byte(0x0040, 0x0042, return_status[0]);
7255 write_byte(0x0040, 0x0043, return_status[1]);
7256 write_byte(0x0040, 0x0044, return_status[2]);
7257 write_byte(0x0040, 0x0045, return_status[3]);
7258 write_byte(0x0040, 0x0046, return_status[4]);
7259 write_byte(0x0040, 0x0047, return_status[5]);
7260 write_byte(0x0040, 0x0048, return_status[6]);
7261
7262 if ( (return_status[0] & 0xc0) != 0 ) {
7263 SET_AH(0x20);
7264 set_diskette_ret_status(0x20);
7265 SET_AL(0); // no sectors read
7266 SET_CF(); // error occurred
7267 return;
7268 }
7269
7270 // ??? should track be new val from return_status[3] ?
7271 set_diskette_current_cyl(drive, track);
7272 // AL = number of sectors read (same value as passed)
7273 SET_AH(0x00); // success
7274 CLEAR_CF(); // success
7275 return;
7276 } else if (ah == 0x03) {
7277 // Write Diskette Sectors
7278
7279 //-----------------------------------
7280 // set up DMA controller for transfer
7281 //-----------------------------------
7282
7283 // es:bx = pointer to where to place information from diskette
7284 // port 04: DMA-1 base and current address, channel 2
7285 // port 05: DMA-1 base and current count, channel 2
7286 page = (ES >> 12); // upper 4 bits
7287 base_es = (ES << 4); // lower 16bits contributed by ES
7288 base_address = base_es + BX; // lower 16 bits of address
7289 // contributed by ES:BX
7290 if ( base_address < base_es ) {
7291 // in case of carry, adjust page by 1
7292 page++;
7293 }
7294 base_count = (num_sectors * 512) - 1;
7295
7296 // check for 64K boundary overrun
7297 last_addr = base_address + base_count;
7298 if (last_addr < base_address) {
7299 SET_AH(0x09);
7300 set_diskette_ret_status(0x09);
7301 SET_AL(0); // no sectors read
7302 SET_CF(); // error occurred
7303 return;
7304 }
7305
7306 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7307 outb(0x000a, 0x06);
7308
7309 outb(0x000c, 0x00); // clear flip-flop
7310 outb(0x0004, base_address);
7311 outb(0x0004, base_address>>8);
7312 outb(0x000c, 0x00); // clear flip-flop
7313 outb(0x0005, base_count);
7314 outb(0x0005, base_count>>8);
7315
7316 // port 0b: DMA-1 Mode Register
7317 mode_register = 0x4a; // single mode, increment, autoinit disable,
7318 // transfer type=read, channel 2
7319 outb(0x000b, mode_register);
7320
7321 // port 81: DMA-1 Page Register, channel 2
7322 outb(0x0081, page);
7323
7324 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7325 outb(0x000a, 0x02);
7326
7327 //--------------------------------------
7328 // set up floppy controller for transfer
7329 //--------------------------------------
7330 floppy_prepare_controller(drive);
7331
7332 // send write-normal-data command (9 bytes) to controller
7333 outb(0x03f5, 0xc5); // c5: write normal data
7334 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7335 outb(0x03f5, track);
7336 outb(0x03f5, head);
7337 outb(0x03f5, sector);
7338 outb(0x03f5, 2); // 512 byte sector size
7339 outb(0x03f5, sector + num_sectors - 1); // last sector to write on track
7340 outb(0x03f5, 0); // Gap length
7341 outb(0x03f5, 0xff); // Gap length
7342
7343 // turn on interrupts
7344 ASM_START
7345 sti
7346 ASM_END
7347
7348 // wait on 40:3e bit 7 to become 1
7349 do {
7350 val8 = read_byte(0x0040, 0x0040);
7351 if (val8 == 0) {
7352 floppy_reset_controller();
7353 SET_AH(0x80); // drive not ready (timeout)
7354 set_diskette_ret_status(0x80);
7355 SET_AL(0); // no sectors written
7356 SET_CF(); // error occurred
7357 return;
7358 }
7359 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7360 } while ( val8 == 0 );
7361
7362 val8 = 0; // separate asm from while() loop
7363 // turn off interrupts
7364 ASM_START
7365 cli
7366 ASM_END
7367
7368 // set 40:3e bit 7 to 0
7369 val8 = read_byte(0x0040, 0x003e);
7370 val8 &= 0x7f;
7371 write_byte(0x0040, 0x003e, val8);
7372
7373 // check port 3f4 for accessibility to status bytes
7374 val8 = inb(0x3f4);
7375 if ( (val8 & 0xc0) != 0xc0 )
7376 BX_PANIC("int13_diskette: ctrl not ready\n");
7377
7378 // read 7 return status bytes from controller
7379 // using loop index broken, have to unroll...
7380 return_status[0] = inb(0x3f5);
7381 return_status[1] = inb(0x3f5);
7382 return_status[2] = inb(0x3f5);
7383 return_status[3] = inb(0x3f5);
7384 return_status[4] = inb(0x3f5);
7385 return_status[5] = inb(0x3f5);
7386 return_status[6] = inb(0x3f5);
7387 // record in BIOS Data Area
7388 write_byte(0x0040, 0x0042, return_status[0]);
7389 write_byte(0x0040, 0x0043, return_status[1]);
7390 write_byte(0x0040, 0x0044, return_status[2]);
7391 write_byte(0x0040, 0x0045, return_status[3]);
7392 write_byte(0x0040, 0x0046, return_status[4]);
7393 write_byte(0x0040, 0x0047, return_status[5]);
7394 write_byte(0x0040, 0x0048, return_status[6]);
7395
7396 if ( (return_status[0] & 0xc0) != 0 ) {
7397 if ( (return_status[1] & 0x02) != 0 ) {
7398 // diskette not writable.
7399 // AH=status code=0x03 (tried to write on write-protected disk)
7400 // AL=number of sectors written=0
7401 AX = 0x0300;
7402 SET_CF();
7403 return;
7404 } else {
7405 BX_PANIC("int13_diskette_function: read error\n");
7406 }
7407 }
7408
7409 // ??? should track be new val from return_status[3] ?
7410 set_diskette_current_cyl(drive, track);
7411 // AL = number of sectors read (same value as passed)
7412 SET_AH(0x00); // success
7413 CLEAR_CF(); // success
7414 return;
7415 } else { // if (ah == 0x04)
7416 // Verify Diskette Sectors
7417
7418 // ??? should track be new val from return_status[3] ?
7419 set_diskette_current_cyl(drive, track);
7420 // AL = number of sectors verified (same value as passed)
7421 CLEAR_CF(); // success
7422 SET_AH(0x00); // success
7423 return;
7424 }
7425 break;
7426
7427 case 0x05: // format diskette track
7428BX_DEBUG_INT13_FL("floppy f05\n");
7429
7430 num_sectors = GET_AL();
7431 track = GET_CH();
7432 head = GET_DH();
7433 drive = GET_ELDL();
7434
7435 if ((drive > 1) || (head > 1) || (track > 79) ||
7436 (num_sectors == 0) || (num_sectors > 18)) {
7437 SET_AH(1);
7438 set_diskette_ret_status(1);
7439 SET_CF(); // error occurred
7440 }
7441
7442 // see if drive exists
7443 if (floppy_drive_exists(drive) == 0) {
7444 SET_AH(0x80); // drive not responding
7445 set_diskette_ret_status(0x80);
7446 SET_CF(); // error occurred
7447 return;
7448 }
7449
7450 // see if media in drive, and type is known
7451 if (floppy_media_known(drive) == 0) {
7452 if (floppy_media_sense(drive) == 0) {
7453 SET_AH(0x0C); // Media type not found
7454 set_diskette_ret_status(0x0C);
7455 SET_AL(0); // no sectors read
7456 SET_CF(); // error occurred
7457 return;
7458 }
7459 }
7460
7461 // set up DMA controller for transfer
7462 page = (ES >> 12); // upper 4 bits
7463 base_es = (ES << 4); // lower 16bits contributed by ES
7464 base_address = base_es + BX; // lower 16 bits of address
7465 // contributed by ES:BX
7466 if ( base_address < base_es ) {
7467 // in case of carry, adjust page by 1
7468 page++;
7469 }
7470 base_count = (num_sectors * 4) - 1;
7471
7472 // check for 64K boundary overrun
7473 last_addr = base_address + base_count;
7474 if (last_addr < base_address) {
7475 SET_AH(0x09);
7476 set_diskette_ret_status(0x09);
7477 SET_AL(0); // no sectors read
7478 SET_CF(); // error occurred
7479 return;
7480 }
7481
7482 outb(0x000a, 0x06);
7483 outb(0x000c, 0x00); // clear flip-flop
7484 outb(0x0004, base_address);
7485 outb(0x0004, base_address>>8);
7486 outb(0x000c, 0x00); // clear flip-flop
7487 outb(0x0005, base_count);
7488 outb(0x0005, base_count>>8);
7489 mode_register = 0x4a; // single mode, increment, autoinit disable,
7490 // transfer type=read, channel 2
7491 outb(0x000b, mode_register);
7492 // port 81: DMA-1 Page Register, channel 2
7493 outb(0x0081, page);
7494 outb(0x000a, 0x02);
7495
7496 // set up floppy controller for transfer
7497 floppy_prepare_controller(drive);
7498
7499 // send format-track command (6 bytes) to controller
7500 outb(0x03f5, 0x4d); // 4d: format track
7501 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7502 outb(0x03f5, 2); // 512 byte sector size
7503 outb(0x03f5, num_sectors); // number of sectors per track
7504 outb(0x03f5, 0); // Gap length
7505 outb(0x03f5, 0xf6); // Fill byte
7506 // turn on interrupts
7507 ASM_START
7508 sti
7509 ASM_END
7510
7511 // wait on 40:3e bit 7 to become 1
7512 do {
7513 val8 = read_byte(0x0040, 0x0040);
7514 if (val8 == 0) {
7515 floppy_reset_controller();
7516 SET_AH(0x80); // drive not ready (timeout)
7517 set_diskette_ret_status(0x80);
7518 SET_CF(); // error occurred
7519 return;
7520 }
7521 val8 = (read_byte(0x0040, 0x003e) & 0x80);
7522 } while ( val8 == 0 );
7523
7524 val8 = 0; // separate asm from while() loop
7525 // turn off interrupts
7526 ASM_START
7527 cli
7528 ASM_END
7529 // set 40:3e bit 7 to 0
7530 val8 = read_byte(0x0040, 0x003e);
7531 val8 &= 0x7f;
7532 write_byte(0x0040, 0x003e, val8);
7533 // check port 3f4 for accessibility to status bytes
7534 val8 = inb(0x3f4);
7535 if ( (val8 & 0xc0) != 0xc0 )
7536 BX_PANIC("int13_diskette: ctrl not ready\n");
7537
7538 // read 7 return status bytes from controller
7539 // using loop index broken, have to unroll...
7540 return_status[0] = inb(0x3f5);
7541 return_status[1] = inb(0x3f5);
7542 return_status[2] = inb(0x3f5);
7543 return_status[3] = inb(0x3f5);
7544 return_status[4] = inb(0x3f5);
7545 return_status[5] = inb(0x3f5);
7546 return_status[6] = inb(0x3f5);
7547 // record in BIOS Data Area
7548 write_byte(0x0040, 0x0042, return_status[0]);
7549 write_byte(0x0040, 0x0043, return_status[1]);
7550 write_byte(0x0040, 0x0044, return_status[2]);
7551 write_byte(0x0040, 0x0045, return_status[3]);
7552 write_byte(0x0040, 0x0046, return_status[4]);
7553 write_byte(0x0040, 0x0047, return_status[5]);
7554 write_byte(0x0040, 0x0048, return_status[6]);
7555
7556 if ( (return_status[0] & 0xc0) != 0 ) {
7557 if ( (return_status[1] & 0x02) != 0 ) {
7558 // diskette not writable.
7559 // AH=status code=0x03 (tried to write on write-protected disk)
7560 // AL=number of sectors written=0
7561 AX = 0x0300;
7562 SET_CF();
7563 return;
7564 } else {
7565 BX_PANIC("int13_diskette_function: write error\n");
7566 }
7567 }
7568
7569 SET_AH(0);
7570 set_diskette_ret_status(0);
7571 set_diskette_current_cyl(drive, 0);
7572 CLEAR_CF(); // successful
7573 return;
7574
7575
7576 case 0x08: // read diskette drive parameters
7577BX_DEBUG_INT13_FL("floppy f08\n");
7578 drive = GET_ELDL();
7579
7580 if (drive > 1) {
7581 AX = 0;
7582 BX = 0;
7583 CX = 0;
7584 DX = 0;
7585 ES = 0;
7586 DI = 0;
7587 SET_DL(num_floppies);
7588 SET_CF();
7589 return;
7590 }
7591
7592 drive_type = inb_cmos(0x10);
7593 num_floppies = 0;
7594 if (drive_type & 0xf0)
7595 num_floppies++;
7596 if (drive_type & 0x0f)
7597 num_floppies++;
7598
7599 if (drive == 0)
7600 drive_type >>= 4;
7601 else
7602 drive_type &= 0x0f;
7603
7604 SET_BH(0);
7605 SET_BL(drive_type);
7606 SET_AH(0);
7607 SET_AL(0);
7608 SET_DL(num_floppies);
7609
7610 switch (drive_type) {
7611 case 0: // none
7612 CX = 0;
7613 SET_DH(0); // max head #
7614 break;
7615
7616 case 1: // 360KB, 5.25"
7617 CX = 0x2709; // 40 tracks, 9 sectors
7618 SET_DH(1); // max head #
7619 break;
7620
7621 case 2: // 1.2MB, 5.25"
7622 CX = 0x4f0f; // 80 tracks, 15 sectors
7623 SET_DH(1); // max head #
7624 break;
7625
7626 case 3: // 720KB, 3.5"
7627 CX = 0x4f09; // 80 tracks, 9 sectors
7628 SET_DH(1); // max head #
7629 break;
7630
7631 case 4: // 1.44MB, 3.5"
7632 CX = 0x4f12; // 80 tracks, 18 sectors
7633 SET_DH(1); // max head #
7634 break;
7635
7636 case 5: // 2.88MB, 3.5"
7637 CX = 0x4f24; // 80 tracks, 36 sectors
7638 SET_DH(1); // max head #
7639 break;
7640
7641 case 6: // 160k, 5.25"
7642 CX = 0x2708; // 40 tracks, 8 sectors
7643 SET_DH(0); // max head #
7644 break;
7645
7646 case 7: // 180k, 5.25"
7647 CX = 0x2709; // 40 tracks, 9 sectors
7648 SET_DH(0); // max head #
7649 break;
7650
7651 case 8: // 320k, 5.25"
7652 CX = 0x2708; // 40 tracks, 8 sectors
7653 SET_DH(1); // max head #
7654 break;
7655
7656 default: // ?
7657 BX_PANIC("floppy: int13: bad floppy type\n");
7658 }
7659
7660 /* set es & di to point to 11 byte diskette param table in ROM */
7661ASM_START
7662 push bp
7663 mov bp, sp
7664 mov ax, #diskette_param_table2
7665 mov _int13_diskette_function.DI+2[bp], ax
7666 mov _int13_diskette_function.ES+2[bp], cs
7667 pop bp
7668ASM_END
7669 CLEAR_CF(); // success
7670 /* disk status not changed upon success */
7671 return;
7672
7673
7674 case 0x15: // read diskette drive type
7675BX_DEBUG_INT13_FL("floppy f15\n");
7676 drive = GET_ELDL();
7677 if (drive > 1) {
7678 SET_AH(0); // only 2 drives supported
7679 // set_diskette_ret_status here ???
7680 SET_CF();
7681 return;
7682 }
7683 drive_type = inb_cmos(0x10);
7684
7685 if (drive == 0)
7686 drive_type >>= 4;
7687 else
7688 drive_type &= 0x0f;
7689 CLEAR_CF(); // successful, not present
7690 if (drive_type==0) {
7691 SET_AH(0); // drive not present
7692 }
7693 else {
7694 SET_AH(1); // drive present, does not support change line
7695 }
7696
7697 return;
7698
7699 case 0x16: // get diskette change line status
7700BX_DEBUG_INT13_FL("floppy f16\n");
7701 drive = GET_ELDL();
7702 if (drive > 1) {
7703 SET_AH(0x01); // invalid drive
7704 set_diskette_ret_status(0x01);
7705 SET_CF();
7706 return;
7707 }
7708
7709 SET_AH(0x06); // change line not supported
7710 set_diskette_ret_status(0x06);
7711 SET_CF();
7712 return;
7713
7714 case 0x17: // set diskette type for format(old)
7715BX_DEBUG_INT13_FL("floppy f17\n");
7716 /* not used for 1.44M floppies */
7717 SET_AH(0x01); // not supported
7718 set_diskette_ret_status(1); /* not supported */
7719 SET_CF();
7720 return;
7721
7722 case 0x18: // set diskette type for format(new)
7723BX_DEBUG_INT13_FL("floppy f18\n");
7724 SET_AH(0x01); // do later
7725 set_diskette_ret_status(1);
7726 SET_CF();
7727 return;
7728
7729 default:
7730 BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
7731
7732 // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
7733 SET_AH(0x01); // ???
7734 set_diskette_ret_status(1);
7735 SET_CF();
7736 return;
7737 // }
7738 }
7739}
7740#else // #if BX_SUPPORT_FLOPPY
7741 void
7742int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
7743 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
7744{
7745 Bit8u val8;
7746
7747 switch ( GET_AH() ) {
7748
7749 case 0x01: // Read Diskette Status
7750 CLEAR_CF();
7751 val8 = read_byte(0x0000, 0x0441);
7752 SET_AH(val8);
7753 if (val8) {
7754 SET_CF();
7755 }
7756 return;
7757
7758 default:
7759 SET_CF();
7760 write_byte(0x0000, 0x0441, 0x01);
7761 SET_AH(0x01);
7762 }
7763}
7764#endif // #if BX_SUPPORT_FLOPPY
7765
7766 void
7767set_diskette_ret_status(value)
7768 Bit8u value;
7769{
7770 write_byte(0x0040, 0x0041, value);
7771}
7772
7773 void
7774set_diskette_current_cyl(drive, cyl)
7775 Bit8u drive;
7776 Bit8u cyl;
7777{
7778 if (drive > 1)
7779 BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
7780 write_byte(0x0040, 0x0094+drive, cyl);
7781}
7782
7783 void
7784determine_floppy_media(drive)
7785 Bit16u drive;
7786{
7787#if 0
7788 Bit8u val8, DOR, ctrl_info;
7789
7790 ctrl_info = read_byte(0x0040, 0x008F);
7791 if (drive==1)
7792 ctrl_info >>= 4;
7793 else
7794 ctrl_info &= 0x0f;
7795
7796#if 0
7797 if (drive == 0) {
7798 DOR = 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
7799 }
7800 else {
7801 DOR = 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
7802 }
7803#endif
7804
7805 if ( (ctrl_info & 0x04) != 0x04 ) {
7806 // Drive not determined means no drive exists, done.
7807 return;
7808 }
7809
7810#if 0
7811 // check Main Status Register for readiness
7812 val8 = inb(0x03f4) & 0x80; // Main Status Register
7813 if (val8 != 0x80)
7814 BX_PANIC("d_f_m: MRQ bit not set\n");
7815
7816 // change line
7817
7818 // existing BDA values
7819
7820 // turn on drive motor
7821 outb(0x03f2, DOR); // Digital Output Register
7822 //
7823#endif
7824 BX_PANIC("d_f_m: OK so far\n");
7825#endif
7826}
7827
7828 void
7829int17_function(regs, ds, iret_addr)
7830 pusha_regs_t regs; // regs pushed from PUSHA instruction
7831 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
7832 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
7833{
7834 Bit16u addr,timeout;
7835 Bit8u val8;
7836
7837 ASM_START
7838 sti
7839 ASM_END
7840
7841 addr = read_word(0x0040, (regs.u.r16.dx << 1) + 8);
7842 if ((regs.u.r8.ah < 3) && (regs.u.r16.dx < 3) && (addr > 0)) {
7843 timeout = read_byte(0x0040, 0x0078 + regs.u.r16.dx) << 8;
7844 if (regs.u.r8.ah == 0) {
7845 outb(addr, regs.u.r8.al);
7846 val8 = inb(addr+2);
7847 outb(addr+2, val8 | 0x01); // send strobe
7848 ASM_START
7849 nop
7850 ASM_END
7851 outb(addr+2, val8 & ~0x01);
7852 while (((inb(addr+1) & 0x40) == 0x40) && (timeout)) {
7853 timeout--;
7854 }
7855 }
7856 if (regs.u.r8.ah == 1) {
7857 val8 = inb(addr+2);
7858 outb(addr+2, val8 & ~0x04); // send init
7859 ASM_START
7860 nop
7861 ASM_END
7862 outb(addr+2, val8 | 0x04);
7863 }
7864 val8 = inb(addr+1);
7865 regs.u.r8.ah = (val8 ^ 0x48);
7866 if (!timeout) regs.u.r8.ah |= 0x01;
7867 ClearCF(iret_addr.flags);
7868 } else {
7869 SetCF(iret_addr.flags); // Unsupported
7870 }
7871}
7872
7873// returns bootsegment in ax, drive in bl
7874 Bit32u
7875int19_function(bseqnr)
7876Bit8u bseqnr;
7877{
7878 Bit16u ebda_seg=read_word(0x0040,0x000E);
7879 Bit16u bootseq;
7880 Bit8u bootdrv;
7881 Bit8u bootcd;
7882#ifdef VBOX
7883 Bit8u bootlan;
7884#endif /* VBOX */
7885 Bit8u bootchk;
7886 Bit16u bootseg;
7887 Bit16u status;
7888 Bit8u lastdrive=0;
7889
7890 // if BX_ELTORITO_BOOT is not defined, old behavior
7891 // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
7892 // in preparation for the intial INT 13h (0=floppy A:, 0x80=C:)
7893 // 0: system boot sequence, first drive C: then A:
7894 // 1: system boot sequence, first drive A: then C:
7895 // else BX_ELTORITO_BOOT is defined
7896 // CMOS regs 0x3D and 0x38 contain the boot sequence:
7897 // CMOS reg 0x3D & 0x0f : 1st boot device
7898 // CMOS reg 0x3D & 0xf0 : 2nd boot device
7899 // CMOS reg 0x38 & 0xf0 : 3rd boot device
7900#ifdef VBOX
7901 // CMOS reg 0x3C & 0x0f : 4th boot device
7902#endif /* VBOX */
7903 // boot device codes:
7904 // 0x00 : not defined
7905 // 0x01 : first floppy
7906 // 0x02 : first harddrive
7907 // 0x03 : first cdrom
7908#ifdef VBOX
7909 // 0x04 : local area network
7910#endif /* VBOX */
7911 // else : boot failure
7912
7913 // Get the boot sequence
7914#if BX_ELTORITO_BOOT
7915 bootseq=inb_cmos(0x3d);
7916 bootseq|=((inb_cmos(0x38) & 0xf0) << 4);
7917#ifdef VBOX
7918 bootseq|=((inb_cmos(0x3c) & 0x0f) << 12);
7919 if (read_byte(ebda_seg, &EbdaData->uForceBootDrive))
7920 bootseq = read_byte(ebda_seg, &EbdaData->uForceBootDrive);
7921 /* Boot delay hack. */
7922 if (bseqnr == 1)
7923 delay_boot((inb_cmos(0x3c) & 0xf0) >> 4); /* Implemented in logo.c */
7924#endif /* VBOX */
7925
7926 if (bseqnr==2) bootseq >>= 4;
7927 if (bseqnr==3) bootseq >>= 8;
7928#ifdef VBOX
7929 if (bseqnr==4) bootseq >>= 12;
7930#endif /* VBOX */
7931 if (bootseq<0x10) lastdrive = 1;
7932 bootdrv=0x00; bootcd=0;
7933#ifdef VBOX
7934 bootlan=0;
7935#endif /* VBOX */
7936 switch(bootseq & 0x0f) {
7937 case 0x01: bootdrv=0x00; bootcd=0; break;
7938 case 0x02: bootdrv=0x80; bootcd=0; break;
7939 case 0x03: bootdrv=0x00; bootcd=1; break;
7940#ifdef VBOX
7941 case 0x04: bootlan=1; break;
7942#endif /* VBOX */
7943 default: return 0x00000000;
7944 }
7945#else
7946 bootseq=inb_cmos(0x2d);
7947
7948 if (bseqnr==2) {
7949 bootseq ^= 0x20;
7950 lastdrive = 1;
7951 }
7952 bootdrv=0x00; bootcd=0;
7953 if((bootseq&0x20)==0) bootdrv=0x80;
7954#endif // BX_ELTORITO_BOOT
7955
7956#if BX_ELTORITO_BOOT
7957 // We have to boot from cd
7958 if (bootcd != 0) {
7959 status = cdrom_boot();
7960
7961 // If failure
7962 if ( (status & 0x00ff) !=0 ) {
7963 print_cdromboot_failure(status);
7964#ifdef VBOX
7965 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
7966#else /* !VBOX */
7967 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
7968#endif /* !VBOX */
7969 return 0x00000000;
7970 }
7971
7972 bootseg = read_word(ebda_seg,&EbdaData->cdemu.load_segment);
7973 bootdrv = (Bit8u)(status>>8);
7974 }
7975
7976#endif // BX_ELTORITO_BOOT
7977
7978#ifdef VBOX
7979 // Check for boot from LAN first
7980 if (bootlan == 1) {
7981 if (read_word(VBOX_LANBOOT_SEG,0) == 0xaa55) {
7982 Bit16u pnpoff;
7983 // This is NOT a generic PnP implementation, but an Etherboot-specific hack.
7984 pnpoff = read_word(VBOX_LANBOOT_SEG,0x1a);
7985 if (read_dword(VBOX_LANBOOT_SEG,pnpoff) == 0x506e5024 &&
7986 read_dword(VBOX_LANBOOT_SEG,read_word(VBOX_LANBOOT_SEG,pnpoff+0xe)) == 0x65687445) {
7987 // Found PnP signature and Etherboot manufacturer string.
7988 print_boot_device(bootcd, bootlan, bootdrv);
7989ASM_START
7990 push ds
7991 push es
7992 pusha
7993 calli 0x0006,VBOX_LANBOOT_SEG
7994 popa
7995 pop es
7996 pop ds
7997ASM_END
7998 }
7999 }
8000
8001 // boot from LAN will not return if successful.
8002 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
8003 return 0x00000000;
8004 }
8005#endif /* VBOX */
8006 // We have to boot from harddisk or floppy
8007#ifdef VBOX
8008 if (bootcd == 0 && bootlan == 0) {
8009#else /* !VBOX */
8010 if (bootcd == 0) {
8011#endif /* !VBOX */
8012 bootseg=0x07c0;
8013
8014ASM_START
8015 push bp
8016 mov bp, sp
8017
8018 xor ax, ax
8019 mov _int19_function.status + 2[bp], ax
8020 mov dl, _int19_function.bootdrv + 2[bp]
8021 mov ax, _int19_function.bootseg + 2[bp]
8022 mov es, ax ;; segment
8023 xor bx, bx ;; offset
8024 mov ah, #0x02 ;; function 2, read diskette sector
8025 mov al, #0x01 ;; read 1 sector
8026 mov ch, #0x00 ;; track 0
8027 mov cl, #0x01 ;; sector 1
8028 mov dh, #0x00 ;; head 0
8029 int #0x13 ;; read sector
8030 jnc int19_load_done
8031 mov ax, #0x0001
8032 mov _int19_function.status + 2[bp], ax
8033
8034int19_load_done:
8035 pop bp
8036ASM_END
8037
8038 if (status != 0) {
8039#ifdef VBOX
8040 print_boot_failure(bootcd, bootlan, bootdrv, 1, lastdrive);
8041#else /* !VBOX */
8042 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
8043#endif /* !VBOX */
8044 return 0x00000000;
8045 }
8046 }
8047
8048 // check signature if instructed by cmos reg 0x38, only for floppy
8049 // bootchk = 1 : signature check disabled
8050 // bootchk = 0 : signature check enabled
8051 if (bootdrv != 0) bootchk = 0;
8052 else bootchk = inb_cmos(0x38) & 0x01;
8053
8054#if BX_ELTORITO_BOOT
8055 // if boot from cd, no signature check
8056 if (bootcd != 0)
8057 bootchk = 1;
8058#endif // BX_ELTORITO_BOOT
8059
8060 if (bootchk == 0) {
8061 if (read_word(bootseg,0x1fe) != 0xaa55) {
8062#ifdef VBOX
8063 print_boot_failure(bootcd, bootlan, bootdrv, 0, lastdrive);
8064#else /* !VBOX */
8065 print_boot_failure(bootcd, bootdrv, 0, lastdrive);
8066#endif /* VBOX */
8067 return 0x00000000;
8068 }
8069 }
8070
8071#if BX_ELTORITO_BOOT
8072 // Print out the boot string
8073#ifdef VBOX
8074 print_boot_device(bootcd, bootlan, bootdrv);
8075#else /* !VBOX */
8076 print_boot_device(bootcd, bootdrv);
8077#endif /* !VBOX */
8078#else // BX_ELTORITO_BOOT
8079#ifdef VBOX
8080 print_boot_device(0, bootlan, bootdrv);
8081#else /* !VBOX */
8082 print_boot_device(0, bootdrv);
8083#endif /* !VBOX */
8084#endif // BX_ELTORITO_BOOT
8085
8086 // return the boot segment
8087 return (((Bit32u)bootdrv) << 16) + bootseg;
8088}
8089
8090 void
8091int1a_function(regs, ds, iret_addr)
8092 pusha_regs_t regs; // regs pushed from PUSHA instruction
8093 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8094 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8095{
8096 Bit8u val8;
8097
8098 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);
8099
8100 ASM_START
8101 sti
8102 ASM_END
8103
8104 switch (regs.u.r8.ah) {
8105 case 0: // get current clock count
8106 ASM_START
8107 cli
8108 ASM_END
8109 regs.u.r16.cx = BiosData->ticks_high;
8110 regs.u.r16.dx = BiosData->ticks_low;
8111 regs.u.r8.al = BiosData->midnight_flag;
8112 BiosData->midnight_flag = 0; // reset flag
8113 ASM_START
8114 sti
8115 ASM_END
8116 // AH already 0
8117 ClearCF(iret_addr.flags); // OK
8118 break;
8119
8120 case 1: // Set Current Clock Count
8121 ASM_START
8122 cli
8123 ASM_END
8124 BiosData->ticks_high = regs.u.r16.cx;
8125 BiosData->ticks_low = regs.u.r16.dx;
8126 BiosData->midnight_flag = 0; // reset flag
8127 ASM_START
8128 sti
8129 ASM_END
8130 regs.u.r8.ah = 0;
8131 ClearCF(iret_addr.flags); // OK
8132 break;
8133
8134
8135 case 2: // Read CMOS Time
8136 if (rtc_updating()) {
8137 SetCF(iret_addr.flags);
8138 break;
8139 }
8140
8141 regs.u.r8.dh = inb_cmos(0x00); // Seconds
8142 regs.u.r8.cl = inb_cmos(0x02); // Minutes
8143 regs.u.r8.ch = inb_cmos(0x04); // Hours
8144 regs.u.r8.dl = inb_cmos(0x0b) & 0x01; // Stat Reg B
8145 regs.u.r8.ah = 0;
8146 regs.u.r8.al = regs.u.r8.ch;
8147 ClearCF(iret_addr.flags); // OK
8148 break;
8149
8150 case 3: // Set CMOS Time
8151 // Using a debugger, I notice the following masking/setting
8152 // of bits in Status Register B, by setting Reg B to
8153 // a few values and getting its value after INT 1A was called.
8154 //
8155 // try#1 try#2 try#3
8156 // before 1111 1101 0111 1101 0000 0000
8157 // after 0110 0010 0110 0010 0000 0010
8158 //
8159 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8160 // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
8161 if (rtc_updating()) {
8162 init_rtc();
8163 // fall through as if an update were not in progress
8164 }
8165 outb_cmos(0x00, regs.u.r8.dh); // Seconds
8166 outb_cmos(0x02, regs.u.r8.cl); // Minutes
8167 outb_cmos(0x04, regs.u.r8.ch); // Hours
8168 // Set Daylight Savings time enabled bit to requested value
8169 val8 = (inb_cmos(0x0b) & 0x60) | 0x02 | (regs.u.r8.dl & 0x01);
8170 // (reg B already selected)
8171 outb_cmos(0x0b, val8);
8172 regs.u.r8.ah = 0;
8173 regs.u.r8.al = val8; // val last written to Reg B
8174 ClearCF(iret_addr.flags); // OK
8175 break;
8176
8177 case 4: // Read CMOS Date
8178 regs.u.r8.ah = 0;
8179 if (rtc_updating()) {
8180 SetCF(iret_addr.flags);
8181 break;
8182 }
8183 regs.u.r8.cl = inb_cmos(0x09); // Year
8184 regs.u.r8.dh = inb_cmos(0x08); // Month
8185 regs.u.r8.dl = inb_cmos(0x07); // Day of Month
8186 regs.u.r8.ch = inb_cmos(0x32); // Century
8187 regs.u.r8.al = regs.u.r8.ch;
8188 ClearCF(iret_addr.flags); // OK
8189 break;
8190
8191 case 5: // Set CMOS Date
8192 // Using a debugger, I notice the following masking/setting
8193 // of bits in Status Register B, by setting Reg B to
8194 // a few values and getting its value after INT 1A was called.
8195 //
8196 // try#1 try#2 try#3 try#4
8197 // before 1111 1101 0111 1101 0000 0010 0000 0000
8198 // after 0110 1101 0111 1101 0000 0010 0000 0000
8199 //
8200 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8201 // My assumption: RegB = (RegB & 01111111b)
8202 if (rtc_updating()) {
8203 init_rtc();
8204 SetCF(iret_addr.flags);
8205 break;
8206 }
8207 outb_cmos(0x09, regs.u.r8.cl); // Year
8208 outb_cmos(0x08, regs.u.r8.dh); // Month
8209 outb_cmos(0x07, regs.u.r8.dl); // Day of Month
8210 outb_cmos(0x32, regs.u.r8.ch); // Century
8211 val8 = inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
8212 outb_cmos(0x0b, val8);
8213 regs.u.r8.ah = 0;
8214 regs.u.r8.al = val8; // AL = val last written to Reg B
8215 ClearCF(iret_addr.flags); // OK
8216 break;
8217
8218 case 6: // Set Alarm Time in CMOS
8219 // Using a debugger, I notice the following masking/setting
8220 // of bits in Status Register B, by setting Reg B to
8221 // a few values and getting its value after INT 1A was called.
8222 //
8223 // try#1 try#2 try#3
8224 // before 1101 1111 0101 1111 0000 0000
8225 // after 0110 1111 0111 1111 0010 0000
8226 //
8227 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8228 // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
8229 val8 = inb_cmos(0x0b); // Get Status Reg B
8230 regs.u.r16.ax = 0;
8231 if (val8 & 0x20) {
8232 // Alarm interrupt enabled already
8233 SetCF(iret_addr.flags); // Error: alarm in use
8234 break;
8235 }
8236 if (rtc_updating()) {
8237 init_rtc();
8238 // fall through as if an update were not in progress
8239 }
8240 outb_cmos(0x01, regs.u.r8.dh); // Seconds alarm
8241 outb_cmos(0x03, regs.u.r8.cl); // Minutes alarm
8242 outb_cmos(0x05, regs.u.r8.ch); // Hours alarm
8243 outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
8244 // enable Status Reg B alarm bit, clear halt clock bit
8245 outb_cmos(0x0b, (val8 & 0x7f) | 0x20);
8246 ClearCF(iret_addr.flags); // OK
8247 break;
8248
8249 case 7: // Turn off Alarm
8250 // Using a debugger, I notice the following masking/setting
8251 // of bits in Status Register B, by setting Reg B to
8252 // a few values and getting its value after INT 1A was called.
8253 //
8254 // try#1 try#2 try#3 try#4
8255 // before 1111 1101 0111 1101 0010 0000 0010 0010
8256 // after 0100 0101 0101 0101 0000 0000 0000 0010
8257 //
8258 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8259 // My assumption: RegB = (RegB & 01010111b)
8260 val8 = inb_cmos(0x0b); // Get Status Reg B
8261 // clear clock-halt bit, disable alarm bit
8262 outb_cmos(0x0b, val8 & 0x57); // disable alarm bit
8263 regs.u.r8.ah = 0;
8264 regs.u.r8.al = val8; // val last written to Reg B
8265 ClearCF(iret_addr.flags); // OK
8266 break;
8267#if BX_PCIBIOS
8268 case 0xb1:
8269 // real mode PCI BIOS functions now handled in assembler code
8270 // this C code handles the error code for information only
8271 if (regs.u.r8.bl == 0xff) {
8272 BX_INFO("PCI BIOS: PCI not present\n");
8273 } else if (regs.u.r8.bl == 0x81) {
8274 BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs.u.r8.al);
8275 } else if (regs.u.r8.bl == 0x83) {
8276 BX_INFO("bad PCI vendor ID %04x\n", regs.u.r16.dx);
8277 } else if (regs.u.r8.bl == 0x86) {
8278 if (regs.u.r8.al == 0x02) {
8279 BX_INFO("PCI device %04x:%04x not found at index %d\n", regs.u.r16.dx, regs.u.r16.cx, regs.u.r16.si);
8280 } else {
8281 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);
8282 }
8283 }
8284 regs.u.r8.ah = regs.u.r8.bl;
8285 SetCF(iret_addr.flags);
8286 break;
8287#endif
8288
8289 default:
8290 SetCF(iret_addr.flags); // Unsupported
8291 }
8292}
8293
8294 void
8295int70_function(regs, ds, iret_addr)
8296 pusha_regs_t regs; // regs pushed from PUSHA instruction
8297 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8298 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8299{
8300 // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
8301 Bit8u registerB = 0, registerC = 0;
8302
8303 // Check which modes are enabled and have occurred.
8304 registerB = inb_cmos( 0xB );
8305 registerC = inb_cmos( 0xC );
8306
8307 if( ( registerB & 0x60 ) != 0 ) {
8308 if( ( registerC & 0x20 ) != 0 ) {
8309 // Handle Alarm Interrupt.
8310ASM_START
8311 sti
8312 int #0x4a
8313 cli
8314ASM_END
8315 }
8316 if( ( registerC & 0x40 ) != 0 ) {
8317 // Handle Periodic Interrupt.
8318
8319 if( read_byte( 0x40, 0xA0 ) != 0 ) {
8320 // Wait Interval (Int 15, AH=83) active.
8321 Bit32u time, toggle;
8322
8323 time = read_dword( 0x40, 0x9C ); // Time left in microseconds.
8324 if( time < 0x3D1 ) {
8325 // Done waiting.
8326 Bit16u segment, offset;
8327
8328 segment = read_word( 0x40, 0x98 );
8329 offset = read_word( 0x40, 0x9A );
8330 write_byte( 0x40, 0xA0, 0 ); // Turn of status byte.
8331 outb_cmos( 0xB, registerB & 0x37 ); // Clear the Periodic Interrupt.
8332 write_byte(segment, offset, read_byte(segment, offset) | 0x80 ); // Write to specified flag byte.
8333 } else {
8334 // Continue waiting.
8335 time -= 0x3D1;
8336 write_dword( 0x40, 0x9C, time );
8337 }
8338 }
8339 }
8340 }
8341
8342ASM_START
8343 call eoi_both_pics
8344ASM_END
8345}
8346
8347
8348ASM_START
8349;------------------------------------------
8350;- INT74h : PS/2 mouse hardware interrupt -
8351;------------------------------------------
8352int74_handler:
8353 sti
8354 pusha
8355 push ds ;; save DS
8356 push #0x00 ;; placeholder for status
8357 push #0x00 ;; placeholder for X
8358 push #0x00 ;; placeholder for Y
8359 push #0x00 ;; placeholder for Z
8360 push #0x00 ;; placeholder for make_far_call boolean
8361 call _int74_function
8362 pop cx ;; remove make_far_call from stack
8363 jcxz int74_done
8364
8365 ;; make far call to EBDA:0022
8366 push #0x00
8367 pop ds
8368 push 0x040E ;; push 0000:040E (opcodes 0xff, 0x36, 0x0E, 0x04)
8369 pop ds
8370 //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
8371 call far ptr[0x22]
8372int74_done:
8373 cli
8374 call eoi_both_pics
8375 add sp, #8 ;; pop status, x, y, z
8376
8377 pop ds ;; restore DS
8378 popa
8379 iret
8380
8381
8382;; This will perform an IRET, but will retain value of current CF
8383;; by altering flags on stack. Better than RETF #02.
8384iret_modify_cf:
8385 jc carry_set
8386 push bp
8387 mov bp, sp
8388 and BYTE [bp + 0x06], #0xfe
8389 pop bp
8390 iret
8391carry_set:
8392 push bp
8393 mov bp, sp
8394 or BYTE [bp + 0x06], #0x01
8395 pop bp
8396 iret
8397
8398
8399;----------------------
8400;- INT13h (relocated) -
8401;----------------------
8402;
8403; int13_relocated is a little bit messed up since I played with it
8404; I have to rewrite it:
8405; - call a function that detect which function to call
8406; - make all called C function get the same parameters list
8407;
8408int13_relocated:
8409
8410#if BX_ELTORITO_BOOT
8411 ;; check for an eltorito function
8412 cmp ah,#0x4a
8413 jb int13_not_eltorito
8414 cmp ah,#0x4d
8415 ja int13_not_eltorito
8416
8417 pusha
8418 push es
8419 push ds
8420 push ss
8421 pop ds
8422
8423 push #int13_out
8424 jmp _int13_eltorito ;; ELDX not used
8425
8426int13_not_eltorito:
8427 push ax
8428 push bx
8429 push cx
8430 push dx
8431
8432 ;; check if emulation active
8433 call _cdemu_isactive
8434 cmp al,#0x00
8435 je int13_cdemu_inactive
8436
8437 ;; check if access to the emulated drive
8438 call _cdemu_emulated_drive
8439 pop dx
8440 push dx
8441 cmp al,dl ;; int13 on emulated drive
8442 jne int13_nocdemu
8443
8444 pop dx
8445 pop cx
8446 pop bx
8447 pop ax
8448
8449 pusha
8450 push es
8451 push ds
8452 push ss
8453 pop ds
8454
8455 push #int13_out
8456 jmp _int13_cdemu ;; ELDX not used
8457
8458int13_nocdemu:
8459 and dl,#0xE0 ;; mask to get device class, including cdroms
8460 cmp al,dl ;; al is 0x00 or 0x80
8461 jne int13_cdemu_inactive ;; inactive for device class
8462
8463 pop dx
8464 pop cx
8465 pop bx
8466 pop ax
8467
8468 push ax
8469 push cx
8470 push dx
8471 push bx
8472
8473 dec dl ;; real drive is dl - 1
8474 jmp int13_legacy
8475
8476int13_cdemu_inactive:
8477 pop dx
8478 pop cx
8479 pop bx
8480 pop ax
8481
8482#endif // BX_ELTORITO_BOOT
8483
8484int13_noeltorito:
8485
8486 push ax
8487 push cx
8488 push dx
8489 push bx
8490
8491int13_legacy:
8492
8493 push dx ;; push eltorito value of dx instead of sp
8494
8495 push bp
8496 push si
8497 push di
8498
8499 push es
8500 push ds
8501 push ss
8502 pop ds
8503
8504 ;; now the 16-bit registers can be restored with:
8505 ;; pop ds; pop es; popa; iret
8506 ;; arguments passed to functions should be
8507 ;; DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS
8508
8509 test dl, #0x80
8510 jnz int13_notfloppy
8511
8512 push #int13_out
8513 jmp _int13_diskette_function
8514
8515int13_notfloppy:
8516
8517#if BX_USE_ATADRV
8518
8519 cmp dl, #0xE0
8520 jb int13_notcdrom
8521
8522 // ebx is modified: BSD 5.2.1 boot loader problem
8523 // someone should figure out which 32 bit register that actually are used
8524
8525 shr ebx, #16
8526 push bx
8527
8528 call _int13_cdrom
8529
8530 pop bx
8531 shl ebx, #16
8532
8533 jmp int13_out
8534
8535int13_notcdrom:
8536
8537#endif
8538
8539int13_disk:
8540 ;; int13_harddisk modifies high word of EAX
8541 shr eax, #16
8542 push ax
8543 call _int13_harddisk
8544 pop ax
8545 shl eax, #16
8546
8547int13_out:
8548 pop ds
8549 pop es
8550 popa
8551 iret
8552
8553
8554;----------
8555;- INT18h -
8556;----------
8557int18_handler: ;; Boot Failure routing
8558 call _int18_panic_msg
8559 hlt
8560 iret
8561
8562;----------
8563;- INT19h -
8564;----------
8565int19_relocated: ;; Boot function, relocated
8566
8567#ifdef VBOX
8568 // If an already booted OS calls int 0x19 to reboot, it is not sufficient
8569 // just to try booting from the configured drives. All BIOS variables and
8570 // interrupt vectors need to be reset, otherwise strange things may happen.
8571 // The approach used is faking a warm reboot (which just skips showing the
8572 // logo), which is a bit more than what we need, but hey, it's fast.
8573 mov bp, sp
8574 mov ax, 2[bp]
8575 cmp ax, #0xf000
8576 jz bios_initiated_boot
8577 xor ax, ax
8578 mov ds, ax
8579 mov ax, #0x1234
8580 mov 0x472, ax
8581 jmp post
8582bios_initiated_boot:
8583#endif /* VBOX */
8584
8585 ;; int19 was beginning to be really complex, so now it
8586 ;; just calls an C function, that does the work
8587 ;; it returns in BL the boot drive, and in AX the boot segment
8588 ;; the boot segment will be 0x0000 if something has failed
8589
8590 push bp
8591 mov bp, sp
8592
8593 ;; drop ds
8594 xor ax, ax
8595 mov ds, ax
8596
8597 ;; 1st boot device
8598 mov ax, #0x0001
8599 push ax
8600 call _int19_function
8601 inc sp
8602 inc sp
8603 ;; bl contains the boot drive
8604 ;; ax contains the boot segment or 0 if failure
8605
8606 test ax, ax ;; if ax is 0 try next boot device
8607 jnz boot_setup
8608
8609 ;; 2nd boot device
8610 mov ax, #0x0002
8611 push ax
8612 call _int19_function
8613 inc sp
8614 inc sp
8615 test ax, ax ;; if ax is 0 try next boot device
8616 jnz boot_setup
8617
8618 ;; 3rd boot device
8619 mov ax, #0x0003
8620 push ax
8621 call _int19_function
8622 inc sp
8623 inc sp
8624#ifdef VBOX
8625 test ax, ax ;; if ax is 0 try next boot device
8626 jnz boot_setup
8627
8628 ;; 4th boot device
8629 mov ax, #0x0004
8630 push ax
8631 call _int19_function
8632 inc sp
8633 inc sp
8634#endif /* VBOX */
8635 test ax, ax ;; if ax is 0 call int18
8636 jz int18_handler
8637
8638boot_setup:
8639 mov dl, bl ;; set drive so guest os find it
8640 shl eax, #0x04 ;; convert seg to ip
8641 mov 2[bp], ax ;; set ip
8642
8643 shr eax, #0x04 ;; get cs back
8644 and ax, #0xF000 ;; remove what went in ip
8645 mov 4[bp], ax ;; set cs
8646 xor ax, ax
8647 mov es, ax ;; set es to zero fixes [ 549815 ]
8648 mov [bp], ax ;; set bp to zero
8649 mov ax, #0xaa55 ;; set ok flag
8650
8651 pop bp
8652 iret ;; Beam me up Scotty
8653
8654;----------
8655;- INT1Ch -
8656;----------
8657int1c_handler: ;; User Timer Tick
8658 iret
8659
8660
8661;----------------------
8662;- POST: Floppy Drive -
8663;----------------------
8664floppy_drive_post:
8665 xor ax, ax
8666 mov ds, ax
8667
8668 mov al, #0x00
8669 mov 0x043e, al ;; drive 0 & 1 uncalibrated, no interrupt has occurred
8670
8671 mov 0x043f, al ;; diskette motor status: read op, drive0, motors off
8672
8673 mov 0x0440, al ;; diskette motor timeout counter: not active
8674 mov 0x0441, al ;; diskette controller status return code
8675
8676 mov 0x0442, al ;; disk & diskette controller status register 0
8677 mov 0x0443, al ;; diskette controller status register 1
8678 mov 0x0444, al ;; diskette controller status register 2
8679 mov 0x0445, al ;; diskette controller cylinder number
8680 mov 0x0446, al ;; diskette controller head number
8681 mov 0x0447, al ;; diskette controller sector number
8682 mov 0x0448, al ;; diskette controller bytes written
8683
8684 mov 0x048b, al ;; diskette configuration data
8685
8686 ;; -----------------------------------------------------------------
8687 ;; (048F) diskette controller information
8688 ;;
8689 mov al, #0x10 ;; get CMOS diskette drive type
8690 out 0x70, AL
8691 in AL, 0x71
8692 mov ah, al ;; save byte to AH
8693
8694look_drive0:
8695 shr al, #4 ;; look at top 4 bits for drive 0
8696 jz f0_missing ;; jump if no drive0
8697 mov bl, #0x07 ;; drive0 determined, multi-rate, has changed line
8698 jmp look_drive1
8699f0_missing:
8700 mov bl, #0x00 ;; no drive0
8701
8702look_drive1:
8703 mov al, ah ;; restore from AH
8704 and al, #0x0f ;; look at bottom 4 bits for drive 1
8705 jz f1_missing ;; jump if no drive1
8706 or bl, #0x70 ;; drive1 determined, multi-rate, has changed line
8707f1_missing:
8708 ;; leave high bits in BL zerod
8709 mov 0x048f, bl ;; put new val in BDA (diskette controller information)
8710 ;; -----------------------------------------------------------------
8711
8712 mov al, #0x00
8713 mov 0x0490, al ;; diskette 0 media state
8714 mov 0x0491, al ;; diskette 1 media state
8715
8716 ;; diskette 0,1 operational starting state
8717 ;; drive type has not been determined,
8718 ;; has no changed detection line
8719 mov 0x0492, al
8720 mov 0x0493, al
8721
8722 mov 0x0494, al ;; diskette 0 current cylinder
8723 mov 0x0495, al ;; diskette 1 current cylinder
8724
8725 mov al, #0x02
8726 out #0x0a, al ;; clear DMA-1 channel 2 mask bit
8727
8728 SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
8729 SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
8730 SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
8731
8732 ret
8733
8734
8735;--------------------
8736;- POST: HARD DRIVE -
8737;--------------------
8738; relocated here because the primary POST area isnt big enough.
8739hard_drive_post:
8740 // IRQ 14 = INT 76h
8741 // INT 76h calls INT 15h function ax=9100
8742
8743 mov al, #0x0a ; 0000 1010 = reserved, disable IRQ 14
8744 mov dx, #0x03f6
8745 out dx, al
8746
8747 xor ax, ax
8748 mov ds, ax
8749 mov 0x0474, al /* hard disk status of last operation */
8750 mov 0x0477, al /* hard disk port offset (XT only ???) */
8751 mov 0x048c, al /* hard disk status register */
8752 mov 0x048d, al /* hard disk error register */
8753 mov 0x048e, al /* hard disk task complete flag */
8754 mov al, #0x01
8755 mov 0x0475, al /* hard disk number attached */
8756 mov al, #0xc0
8757 mov 0x0476, al /* hard disk control byte */
8758 SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
8759 SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
8760 ;; INT 41h: hard disk 0 configuration pointer
8761 ;; INT 46h: hard disk 1 configuration pointer
8762 SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D)
8763 SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D)
8764
8765 ;; move disk geometry data from CMOS to EBDA disk parameter table(s)
8766 mov al, #0x12
8767 out #0x70, al
8768 in al, #0x71
8769 and al, #0xf0
8770 cmp al, #0xf0
8771 je post_d0_extended
8772 jmp check_for_hd1
8773post_d0_extended:
8774 mov al, #0x19
8775 out #0x70, al
8776 in al, #0x71
8777 cmp al, #47 ;; decimal 47 - user definable
8778 je post_d0_type47
8779 HALT(__LINE__)
8780post_d0_type47:
8781 ;; CMOS purpose param table offset
8782 ;; 1b cylinders low 0
8783 ;; 1c cylinders high 1
8784 ;; 1d heads 2
8785 ;; 1e write pre-comp low 5
8786 ;; 1f write pre-comp high 6
8787 ;; 20 retries/bad map/heads>8 8
8788 ;; 21 landing zone low C
8789 ;; 22 landing zone high D
8790 ;; 23 sectors/track E
8791
8792 mov ax, #EBDA_SEG
8793 mov ds, ax
8794
8795 ;;; Filling EBDA table for hard disk 0.
8796 mov al, #0x1f
8797 out #0x70, al
8798 in al, #0x71
8799 mov ah, al
8800 mov al, #0x1e
8801 out #0x70, al
8802 in al, #0x71
8803 mov (0x003d + 0x05), ax ;; write precomp word
8804
8805 mov al, #0x20
8806 out #0x70, al
8807 in al, #0x71
8808 mov (0x003d + 0x08), al ;; drive control byte
8809
8810 mov al, #0x22
8811 out #0x70, al
8812 in al, #0x71
8813 mov ah, al
8814 mov al, #0x21
8815 out #0x70, al
8816 in al, #0x71
8817 mov (0x003d + 0x0C), ax ;; landing zone word
8818
8819 mov al, #0x1c ;; get cylinders word in AX
8820 out #0x70, al
8821 in al, #0x71 ;; high byte
8822 mov ah, al
8823 mov al, #0x1b
8824 out #0x70, al
8825 in al, #0x71 ;; low byte
8826 mov bx, ax ;; BX = cylinders
8827
8828 mov al, #0x1d
8829 out #0x70, al
8830 in al, #0x71
8831 mov cl, al ;; CL = heads
8832
8833 mov al, #0x23
8834 out #0x70, al
8835 in al, #0x71
8836 mov dl, al ;; DL = sectors
8837
8838 cmp bx, #1024
8839 jnbe hd0_post_logical_chs ;; if cylinders > 1024, use translated style CHS
8840
8841hd0_post_physical_chs:
8842 ;; no logical CHS mapping used, just physical CHS
8843 ;; use Standard Fixed Disk Parameter Table (FDPT)
8844 mov (0x003d + 0x00), bx ;; number of physical cylinders
8845 mov (0x003d + 0x02), cl ;; number of physical heads
8846 mov (0x003d + 0x0E), dl ;; number of physical sectors
8847 jmp check_for_hd1
8848
8849hd0_post_logical_chs:
8850 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
8851 mov (0x003d + 0x09), bx ;; number of physical cylinders
8852 mov (0x003d + 0x0b), cl ;; number of physical heads
8853 mov (0x003d + 0x04), dl ;; number of physical sectors
8854 mov (0x003d + 0x0e), dl ;; number of logical sectors (same)
8855 mov al, #0xa0
8856 mov (0x003d + 0x03), al ;; A0h signature, indicates translated table
8857
8858 cmp bx, #2048
8859 jnbe hd0_post_above_2048
8860 ;; 1024 < c <= 2048 cylinders
8861 shr bx, #0x01
8862 shl cl, #0x01
8863 jmp hd0_post_store_logical
8864
8865hd0_post_above_2048:
8866 cmp bx, #4096
8867 jnbe hd0_post_above_4096
8868 ;; 2048 < c <= 4096 cylinders
8869 shr bx, #0x02
8870 shl cl, #0x02
8871 jmp hd0_post_store_logical
8872
8873hd0_post_above_4096:
8874 cmp bx, #8192
8875 jnbe hd0_post_above_8192
8876 ;; 4096 < c <= 8192 cylinders
8877 shr bx, #0x03
8878 shl cl, #0x03
8879 jmp hd0_post_store_logical
8880
8881hd0_post_above_8192:
8882 ;; 8192 < c <= 16384 cylinders
8883 shr bx, #0x04
8884 shl cl, #0x04
8885
8886hd0_post_store_logical:
8887 mov (0x003d + 0x00), bx ;; number of physical cylinders
8888 mov (0x003d + 0x02), cl ;; number of physical heads
8889 ;; checksum
8890 mov cl, #0x0f ;; repeat count
8891 mov si, #0x003d ;; offset to disk0 FDPT
8892 mov al, #0x00 ;; sum
8893hd0_post_checksum_loop:
8894 add al, [si]
8895 inc si
8896 dec cl
8897 jnz hd0_post_checksum_loop
8898 not al ;; now take 2s complement
8899 inc al
8900 mov [si], al
8901;;; Done filling EBDA table for hard disk 0.
8902
8903
8904check_for_hd1:
8905 ;; is there really a second hard disk? if not, return now
8906 mov al, #0x12
8907 out #0x70, al
8908 in al, #0x71
8909 and al, #0x0f
8910 jnz post_d1_exists
8911 ret
8912post_d1_exists:
8913 ;; check that the hd type is really 0x0f.
8914 cmp al, #0x0f
8915 jz post_d1_extended
8916 HALT(__LINE__)
8917post_d1_extended:
8918 ;; check that the extended type is 47 - user definable
8919 mov al, #0x1a
8920 out #0x70, al
8921 in al, #0x71
8922 cmp al, #47 ;; decimal 47 - user definable
8923 je post_d1_type47
8924 HALT(__LINE__)
8925post_d1_type47:
8926 ;; Table for disk1.
8927 ;; CMOS purpose param table offset
8928 ;; 0x24 cylinders low 0
8929 ;; 0x25 cylinders high 1
8930 ;; 0x26 heads 2
8931 ;; 0x27 write pre-comp low 5
8932 ;; 0x28 write pre-comp high 6
8933 ;; 0x29 heads>8 8
8934 ;; 0x2a landing zone low C
8935 ;; 0x2b landing zone high D
8936 ;; 0x2c sectors/track E
8937;;; Fill EBDA table for hard disk 1.
8938 mov ax, #EBDA_SEG
8939 mov ds, ax
8940 mov al, #0x28
8941 out #0x70, al
8942 in al, #0x71
8943 mov ah, al
8944 mov al, #0x27
8945 out #0x70, al
8946 in al, #0x71
8947 mov (0x004d + 0x05), ax ;; write precomp word
8948
8949 mov al, #0x29
8950 out #0x70, al
8951 in al, #0x71
8952 mov (0x004d + 0x08), al ;; drive control byte
8953
8954 mov al, #0x2b
8955 out #0x70, al
8956 in al, #0x71
8957 mov ah, al
8958 mov al, #0x2a
8959 out #0x70, al
8960 in al, #0x71
8961 mov (0x004d + 0x0C), ax ;; landing zone word
8962
8963 mov al, #0x25 ;; get cylinders word in AX
8964 out #0x70, al
8965 in al, #0x71 ;; high byte
8966 mov ah, al
8967 mov al, #0x24
8968 out #0x70, al
8969 in al, #0x71 ;; low byte
8970 mov bx, ax ;; BX = cylinders
8971
8972 mov al, #0x26
8973 out #0x70, al
8974 in al, #0x71
8975 mov cl, al ;; CL = heads
8976
8977 mov al, #0x2c
8978 out #0x70, al
8979 in al, #0x71
8980 mov dl, al ;; DL = sectors
8981
8982 cmp bx, #1024
8983 jnbe hd1_post_logical_chs ;; if cylinders > 1024, use translated style CHS
8984
8985hd1_post_physical_chs:
8986 ;; no logical CHS mapping used, just physical CHS
8987 ;; use Standard Fixed Disk Parameter Table (FDPT)
8988 mov (0x004d + 0x00), bx ;; number of physical cylinders
8989 mov (0x004d + 0x02), cl ;; number of physical heads
8990 mov (0x004d + 0x0E), dl ;; number of physical sectors
8991 ret
8992
8993hd1_post_logical_chs:
8994 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
8995 mov (0x004d + 0x09), bx ;; number of physical cylinders
8996 mov (0x004d + 0x0b), cl ;; number of physical heads
8997 mov (0x004d + 0x04), dl ;; number of physical sectors
8998 mov (0x004d + 0x0e), dl ;; number of logical sectors (same)
8999 mov al, #0xa0
9000 mov (0x004d + 0x03), al ;; A0h signature, indicates translated table
9001
9002 cmp bx, #2048
9003 jnbe hd1_post_above_2048
9004 ;; 1024 < c <= 2048 cylinders
9005 shr bx, #0x01
9006 shl cl, #0x01
9007 jmp hd1_post_store_logical
9008
9009hd1_post_above_2048:
9010 cmp bx, #4096
9011 jnbe hd1_post_above_4096
9012 ;; 2048 < c <= 4096 cylinders
9013 shr bx, #0x02
9014 shl cl, #0x02
9015 jmp hd1_post_store_logical
9016
9017hd1_post_above_4096:
9018 cmp bx, #8192
9019 jnbe hd1_post_above_8192
9020 ;; 4096 < c <= 8192 cylinders
9021 shr bx, #0x03
9022 shl cl, #0x03
9023 jmp hd1_post_store_logical
9024
9025hd1_post_above_8192:
9026 ;; 8192 < c <= 16384 cylinders
9027 shr bx, #0x04
9028 shl cl, #0x04
9029
9030hd1_post_store_logical:
9031 mov (0x004d + 0x00), bx ;; number of physical cylinders
9032 mov (0x004d + 0x02), cl ;; number of physical heads
9033 ;; checksum
9034 mov cl, #0x0f ;; repeat count
9035 mov si, #0x004d ;; offset to disk0 FDPT
9036 mov al, #0x00 ;; sum
9037hd1_post_checksum_loop:
9038 add al, [si]
9039 inc si
9040 dec cl
9041 jnz hd1_post_checksum_loop
9042 not al ;; now take 2s complement
9043 inc al
9044 mov [si], al
9045;;; Done filling EBDA table for hard disk 1.
9046
9047 ret
9048
9049;--------------------
9050;- POST: EBDA segment
9051;--------------------
9052; relocated here because the primary POST area isnt big enough.
9053ebda_post:
9054#if BX_USE_EBDA
9055 mov ax, #EBDA_SEG
9056 mov ds, ax
9057 mov byte ptr [0x0], #EBDA_SIZE
9058#endif
9059 xor ax, ax ; mov EBDA seg into 40E
9060 mov ds, ax
9061 mov word ptr [0x40E], #EBDA_SEG
9062 ret;;
9063
9064;--------------------
9065;- POST: EOI + jmp via [0x40:67)
9066;--------------------
9067; relocated here because the primary POST area isnt big enough.
9068eoi_jmp_post:
9069 call eoi_both_pics
9070
9071 xor ax, ax
9072 mov ds, ax
9073
9074 jmp far ptr [0x467]
9075
9076
9077;--------------------
9078eoi_both_pics:
9079 mov al, #0x20
9080 out #0xA0, al ;; slave PIC EOI
9081eoi_master_pic:
9082 mov al, #0x20
9083 out #0x20, al ;; master PIC EOI
9084 ret
9085
9086;--------------------
9087BcdToBin:
9088 ;; in: AL in BCD format
9089 ;; out: AL in binary format, AH will always be 0
9090 ;; trashes BX
9091 mov bl, al
9092 and bl, #0x0f ;; bl has low digit
9093 shr al, #4 ;; al has high digit
9094 mov bh, #10
9095 mul al, bh ;; multiply high digit by 10 (result in AX)
9096 add al, bl ;; then add low digit
9097 ret
9098
9099;--------------------
9100timer_tick_post:
9101 ;; Setup the Timer Ticks Count (0x46C:dword) and
9102 ;; Timer Ticks Roller Flag (0x470:byte)
9103 ;; The Timer Ticks Count needs to be set according to
9104 ;; the current CMOS time, as if ticks have been occurring
9105 ;; at 18.2hz since midnight up to this point. Calculating
9106 ;; this is a little complicated. Here are the factors I gather
9107 ;; regarding this. 14,318,180 hz was the original clock speed,
9108 ;; chosen so it could be divided by either 3 to drive the 5Mhz CPU
9109 ;; at the time, or 4 to drive the CGA video adapter. The div3
9110 ;; source was divided again by 4 to feed a 1.193Mhz signal to
9111 ;; the timer. With a maximum 16bit timer count, this is again
9112 ;; divided down by 65536 to 18.2hz.
9113 ;;
9114 ;; 14,318,180 Hz clock
9115 ;; /3 = 4,772,726 Hz fed to orginal 5Mhz CPU
9116 ;; /4 = 1,193,181 Hz fed to timer
9117 ;; /65536 (maximum timer count) = 18.20650736 ticks/second
9118 ;; 1 second = 18.20650736 ticks
9119 ;; 1 minute = 1092.390442 ticks
9120 ;; 1 hour = 65543.42651 ticks
9121 ;;
9122 ;; Given the values in the CMOS clock, one could calculate
9123 ;; the number of ticks by the following:
9124 ;; ticks = (BcdToBin(seconds) * 18.206507) +
9125 ;; (BcdToBin(minutes) * 1092.3904)
9126 ;; (BcdToBin(hours) * 65543.427)
9127 ;; To get a little more accuracy, since Im using integer
9128 ;; arithmatic, I use:
9129 ;; ticks = (BcdToBin(seconds) * 18206507) / 1000000 +
9130 ;; (BcdToBin(minutes) * 10923904) / 10000 +
9131 ;; (BcdToBin(hours) * 65543427) / 1000
9132
9133 ;; assuming DS=0000
9134
9135 ;; get CMOS seconds
9136 xor eax, eax ;; clear EAX
9137 mov al, #0x00
9138 out #0x70, al
9139 in al, #0x71 ;; AL has CMOS seconds in BCD
9140 call BcdToBin ;; EAX now has seconds in binary
9141 mov edx, #18206507
9142 mul eax, edx
9143 mov ebx, #1000000
9144 xor edx, edx
9145 div eax, ebx
9146 mov ecx, eax ;; ECX will accumulate total ticks
9147
9148 ;; get CMOS minutes
9149 xor eax, eax ;; clear EAX
9150 mov al, #0x02
9151 out #0x70, al
9152 in al, #0x71 ;; AL has CMOS minutes in BCD
9153 call BcdToBin ;; EAX now has minutes in binary
9154 mov edx, #10923904
9155 mul eax, edx
9156 mov ebx, #10000
9157 xor edx, edx
9158 div eax, ebx
9159 add ecx, eax ;; add to total ticks
9160
9161 ;; get CMOS hours
9162 xor eax, eax ;; clear EAX
9163 mov al, #0x04
9164 out #0x70, al
9165 in al, #0x71 ;; AL has CMOS hours in BCD
9166 call BcdToBin ;; EAX now has hours in binary
9167 mov edx, #65543427
9168 mul eax, edx
9169 mov ebx, #1000
9170 xor edx, edx
9171 div eax, ebx
9172 add ecx, eax ;; add to total ticks
9173
9174 mov 0x46C, ecx ;; Timer Ticks Count
9175 xor al, al
9176 mov 0x470, al ;; Timer Ticks Rollover Flag
9177 ret
9178
9179;--------------------
9180int76_handler:
9181 ;; record completion in BIOS task complete flag
9182 push ax
9183 push ds
9184 mov ax, #0x0040
9185 mov ds, ax
9186 mov 0x008E, #0xff
9187 call eoi_both_pics
9188 pop ds
9189 pop ax
9190 iret
9191
9192
9193;--------------------
9194#if BX_APM
9195
9196use32 386
9197#define APM_PROT32
9198#include "apmbios.S"
9199
9200use16 386
9201#define APM_PROT16
9202#include "apmbios.S"
9203
9204#define APM_REAL
9205#include "apmbios.S"
9206
9207#endif
9208
9209;--------------------
9210#if BX_PCIBIOS
9211use32 386
9212.align 16
9213bios32_structure:
9214 db 0x5f, 0x33, 0x32, 0x5f ;; "_32_" signature
9215 dw bios32_entry_point, 0xf ;; 32 bit physical address
9216 db 0 ;; revision level
9217 ;; length in paragraphs and checksum stored in a word to prevent errors
9218 dw (~(((bios32_entry_point >> 8) + (bios32_entry_point & 0xff) + 0x32) \
9219 & 0xff) << 8) + 0x01
9220 db 0,0,0,0,0 ;; reserved
9221
9222.align 16
9223bios32_entry_point:
9224 pushfd
9225 cmp eax, #0x49435024 ;; "$PCI"
9226 jne unknown_service
9227 mov eax, #0x80000000
9228 mov dx, #0x0cf8
9229 out dx, eax
9230 mov dx, #0x0cfc
9231 in eax, dx
9232#ifdef PCI_FIXED_HOST_BRIDGE
9233 cmp eax, #PCI_FIXED_HOST_BRIDGE
9234 jne unknown_service
9235#else
9236 ;; say ok if a device is present
9237 cmp eax, #0xffffffff
9238 je unknown_service
9239#endif
9240 mov ebx, #0x000f0000
9241 mov ecx, #0
9242 mov edx, #pcibios_protected
9243 xor al, al
9244 jmp bios32_end
9245unknown_service:
9246 mov al, #0x80
9247bios32_end:
9248#ifdef BX_QEMU
9249 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
9250#endif
9251 popfd
9252 retf
9253
9254.align 16
9255pcibios_protected:
9256 pushfd
9257 cli
9258 push esi
9259 push edi
9260 cmp al, #0x01 ;; installation check
9261 jne pci_pro_f02
9262 mov bx, #0x0210
9263 mov cx, #0
9264 mov edx, #0x20494350 ;; "PCI "
9265 mov al, #0x01
9266 jmp pci_pro_ok
9267pci_pro_f02: ;; find pci device
9268 cmp al, #0x02
9269 jne pci_pro_f03
9270 shl ecx, #16
9271 mov cx, dx
9272 xor bx, bx
9273 mov di, #0x00
9274pci_pro_devloop:
9275 call pci_pro_select_reg
9276 mov dx, #0x0cfc
9277 in eax, dx
9278 cmp eax, ecx
9279 jne pci_pro_nextdev
9280 cmp si, #0
9281 je pci_pro_ok
9282 dec si
9283pci_pro_nextdev:
9284 inc bx
9285 cmp bx, #0x0100
9286 jne pci_pro_devloop
9287 mov ah, #0x86
9288 jmp pci_pro_fail
9289pci_pro_f03: ;; find class code
9290 cmp al, #0x03
9291 jne pci_pro_f08
9292 xor bx, bx
9293 mov di, #0x08
9294pci_pro_devloop2:
9295 call pci_pro_select_reg
9296 mov dx, #0x0cfc
9297 in eax, dx
9298 shr eax, #8
9299 cmp eax, ecx
9300 jne pci_pro_nextdev2
9301 cmp si, #0
9302 je pci_pro_ok
9303 dec si
9304pci_pro_nextdev2:
9305 inc bx
9306 cmp bx, #0x0100
9307 jne pci_pro_devloop2
9308 mov ah, #0x86
9309 jmp pci_pro_fail
9310pci_pro_f08: ;; read configuration byte
9311 cmp al, #0x08
9312 jne pci_pro_f09
9313 call pci_pro_select_reg
9314 push edx
9315 mov dx, di
9316 and dx, #0x03
9317 add dx, #0x0cfc
9318 in al, dx
9319 pop edx
9320 mov cl, al
9321 jmp pci_pro_ok
9322pci_pro_f09: ;; read configuration word
9323 cmp al, #0x09
9324 jne pci_pro_f0a
9325 call pci_pro_select_reg
9326 push edx
9327 mov dx, di
9328 and dx, #0x02
9329 add dx, #0x0cfc
9330 in ax, dx
9331 pop edx
9332 mov cx, ax
9333 jmp pci_pro_ok
9334pci_pro_f0a: ;; read configuration dword
9335 cmp al, #0x0a
9336 jne pci_pro_f0b
9337 call pci_pro_select_reg
9338 push edx
9339 mov dx, #0x0cfc
9340 in eax, dx
9341 pop edx
9342 mov ecx, eax
9343 jmp pci_pro_ok
9344pci_pro_f0b: ;; write configuration byte
9345 cmp al, #0x0b
9346 jne pci_pro_f0c
9347 call pci_pro_select_reg
9348 push edx
9349 mov dx, di
9350 and dx, #0x03
9351 add dx, #0x0cfc
9352 mov al, cl
9353 out dx, al
9354 pop edx
9355 jmp pci_pro_ok
9356pci_pro_f0c: ;; write configuration word
9357 cmp al, #0x0c
9358 jne pci_pro_f0d
9359 call pci_pro_select_reg
9360 push edx
9361 mov dx, di
9362 and dx, #0x02
9363 add dx, #0x0cfc
9364 mov ax, cx
9365 out dx, ax
9366 pop edx
9367 jmp pci_pro_ok
9368pci_pro_f0d: ;; write configuration dword
9369 cmp al, #0x0d
9370 jne pci_pro_unknown
9371 call pci_pro_select_reg
9372 push edx
9373 mov dx, #0x0cfc
9374 mov eax, ecx
9375 out dx, eax
9376 pop edx
9377 jmp pci_pro_ok
9378pci_pro_unknown:
9379 mov ah, #0x81
9380pci_pro_fail:
9381 pop edi
9382 pop esi
9383#ifdef BX_QEMU
9384 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
9385#endif
9386 popfd
9387 stc
9388 retf
9389pci_pro_ok:
9390 xor ah, ah
9391 pop edi
9392 pop esi
9393#ifdef BX_QEMU
9394 and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
9395#endif
9396 popfd
9397 clc
9398 retf
9399
9400pci_pro_select_reg:
9401 push edx
9402 mov eax, #0x800000
9403 mov ax, bx
9404 shl eax, #8
9405 and di, #0xff
9406 or ax, di
9407 and al, #0xfc
9408 mov dx, #0x0cf8
9409 out dx, eax
9410 pop edx
9411 ret
9412
9413use16 386
9414
9415pcibios_real:
9416 push eax
9417 push dx
9418 mov eax, #0x80000000
9419 mov dx, #0x0cf8
9420 out dx, eax
9421 mov dx, #0x0cfc
9422 in eax, dx
9423#ifdef PCI_FIXED_HOST_BRIDGE
9424 cmp eax, #PCI_FIXED_HOST_BRIDGE
9425 je pci_present
9426#else
9427 ;; say ok if a device is present
9428 cmp eax, #0xffffffff
9429 jne pci_present
9430#endif
9431 pop dx
9432 pop eax
9433 mov ah, #0xff
9434 stc
9435 ret
9436pci_present:
9437 pop dx
9438 pop eax
9439 cmp al, #0x01 ;; installation check
9440 jne pci_real_f02
9441 mov ax, #0x0001
9442 mov bx, #0x0210
9443 mov cx, #0
9444 mov edx, #0x20494350 ;; "PCI "
9445 mov edi, #0xf0000
9446 mov di, #pcibios_protected
9447 clc
9448 ret
9449pci_real_f02: ;; find pci device
9450 push esi
9451 push edi
9452 cmp al, #0x02
9453 jne pci_real_f03
9454 shl ecx, #16
9455 mov cx, dx
9456 xor bx, bx
9457 mov di, #0x00
9458pci_real_devloop:
9459 call pci_real_select_reg
9460 mov dx, #0x0cfc
9461 in eax, dx
9462 cmp eax, ecx
9463 jne pci_real_nextdev
9464 cmp si, #0
9465 je pci_real_ok
9466 dec si
9467pci_real_nextdev:
9468 inc bx
9469 cmp bx, #0x0100
9470 jne pci_real_devloop
9471 mov dx, cx
9472 shr ecx, #16
9473 mov ax, #0x8602
9474 jmp pci_real_fail
9475pci_real_f03: ;; find class code
9476 cmp al, #0x03
9477 jne pci_real_f08
9478 xor bx, bx
9479 mov di, #0x08
9480pci_real_devloop2:
9481 call pci_real_select_reg
9482 mov dx, #0x0cfc
9483 in eax, dx
9484 shr eax, #8
9485 cmp eax, ecx
9486 jne pci_real_nextdev2
9487 cmp si, #0
9488 je pci_real_ok
9489 dec si
9490pci_real_nextdev2:
9491 inc bx
9492 cmp bx, #0x0100
9493 jne pci_real_devloop2
9494 mov dx, cx
9495 shr ecx, #16
9496 mov ax, #0x8603
9497 jmp pci_real_fail
9498pci_real_f08: ;; read configuration byte
9499 cmp al, #0x08
9500 jne pci_real_f09
9501 call pci_real_select_reg
9502 push dx
9503 mov dx, di
9504 and dx, #0x03
9505 add dx, #0x0cfc
9506 in al, dx
9507 pop dx
9508 mov cl, al
9509 jmp pci_real_ok
9510pci_real_f09: ;; read configuration word
9511 cmp al, #0x09
9512 jne pci_real_f0a
9513 call pci_real_select_reg
9514 push dx
9515 mov dx, di
9516 and dx, #0x02
9517 add dx, #0x0cfc
9518 in ax, dx
9519 pop dx
9520 mov cx, ax
9521 jmp pci_real_ok
9522pci_real_f0a: ;; read configuration dword
9523 cmp al, #0x0a
9524 jne pci_real_f0b
9525 call pci_real_select_reg
9526 push dx
9527 mov dx, #0x0cfc
9528 in eax, dx
9529 pop dx
9530 mov ecx, eax
9531 jmp pci_real_ok
9532pci_real_f0b: ;; write configuration byte
9533 cmp al, #0x0b
9534 jne pci_real_f0c
9535 call pci_real_select_reg
9536 push dx
9537 mov dx, di
9538 and dx, #0x03
9539 add dx, #0x0cfc
9540 mov al, cl
9541 out dx, al
9542 pop dx
9543 jmp pci_real_ok
9544pci_real_f0c: ;; write configuration word
9545 cmp al, #0x0c
9546 jne pci_real_f0d
9547 call pci_real_select_reg
9548 push dx
9549 mov dx, di
9550 and dx, #0x02
9551 add dx, #0x0cfc
9552 mov ax, cx
9553 out dx, ax
9554 pop dx
9555 jmp pci_real_ok
9556pci_real_f0d: ;; write configuration dword
9557 cmp al, #0x0d
9558 jne pci_real_f0e
9559 call pci_real_select_reg
9560 push dx
9561 mov dx, #0x0cfc
9562 mov eax, ecx
9563 out dx, eax
9564 pop dx
9565 jmp pci_real_ok
9566pci_real_f0e: ;; get irq routing options
9567 cmp al, #0x0e
9568 jne pci_real_unknown
9569 SEG ES
9570 cmp word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
9571 jb pci_real_too_small
9572 SEG ES
9573 mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
9574 pushf
9575 push ds
9576 push es
9577 push cx
9578 push si
9579 push di
9580 cld
9581 mov si, #pci_routing_table_structure_start
9582 push cs
9583 pop ds
9584 SEG ES
9585 mov cx, [di+2]
9586 SEG ES
9587 mov es, [di+4]
9588 mov di, cx
9589 mov cx, #pci_routing_table_structure_end - pci_routing_table_structure_start
9590 rep
9591 movsb
9592 pop di
9593 pop si
9594 pop cx
9595 pop es
9596 pop ds
9597 popf
9598 mov bx, #(1 << 9) | (1 << 11) ;; irq 9 and 11 are used
9599 jmp pci_real_ok
9600pci_real_too_small:
9601 SEG ES
9602 mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
9603 mov ah, #0x89
9604 jmp pci_real_fail
9605
9606pci_real_unknown:
9607 mov ah, #0x81
9608pci_real_fail:
9609 pop edi
9610 pop esi
9611 stc
9612 ret
9613pci_real_ok:
9614 xor ah, ah
9615 pop edi
9616 pop esi
9617 clc
9618 ret
9619
9620pci_real_select_reg:
9621 push dx
9622 mov eax, #0x800000
9623 mov ax, bx
9624 shl eax, #8
9625 and di, #0xff
9626 or ax, di
9627 and al, #0xfc
9628 mov dx, #0x0cf8
9629 out dx, eax
9630 pop dx
9631 ret
9632
9633.align 16
9634pci_routing_table_structure:
9635 db 0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature
9636 db 0, 1 ;; version
9637#ifdef VBOX
9638 dw 32 + (10 * 16) ;; table size
9639#else /* !VBOX */
9640 dw 32 + (6 * 16) ;; table size
9641#endif /* !VBOX */
9642 db 0 ;; PCI interrupt router bus
9643 db 0x08 ;; PCI interrupt router DevFunc
9644 dw 0x0000 ;; PCI exclusive IRQs
9645 dw 0x8086 ;; compatible PCI interrupt router vendor ID
9646 dw 0x7000 ;; compatible PCI interrupt router device ID
9647 dw 0,0 ;; Miniport data
9648 db 0,0,0,0,0,0,0,0,0,0,0 ;; reserved
9649#ifdef VBOX
9650 db 0x21 ;; checksum
9651#else /* !VBOX */
9652 db 0x07 ;; checksum
9653#endif /* !VBOX */
9654pci_routing_table_structure_start:
9655 ;; first slot entry PCI-to-ISA (embedded)
9656 db 0 ;; pci bus number
9657 db 0x08 ;; pci device number (bit 7-3)
9658 db 0x60 ;; link value INTA#: pointer into PCI2ISA config space
9659 dw 0xdef8 ;; IRQ bitmap INTA#
9660 db 0x61 ;; link value INTB#
9661 dw 0xdef8 ;; IRQ bitmap INTB#
9662 db 0x62 ;; link value INTC#
9663 dw 0xdef8 ;; IRQ bitmap INTC#
9664 db 0x63 ;; link value INTD#
9665 dw 0xdef8 ;; IRQ bitmap INTD#
9666 db 0 ;; physical slot (0 = embedded)
9667 db 0 ;; reserved
9668 ;; second slot entry: 1st PCI slot
9669 db 0 ;; pci bus number
9670 db 0x10 ;; pci device number (bit 7-3)
9671 db 0x61 ;; link value INTA#
9672 dw 0xdef8 ;; IRQ bitmap INTA#
9673 db 0x62 ;; link value INTB#
9674 dw 0xdef8 ;; IRQ bitmap INTB#
9675 db 0x63 ;; link value INTC#
9676 dw 0xdef8 ;; IRQ bitmap INTC#
9677 db 0x60 ;; link value INTD#
9678 dw 0xdef8 ;; IRQ bitmap INTD#
9679 db 1 ;; physical slot (0 = embedded)
9680 db 0 ;; reserved
9681 ;; third slot entry: 2nd PCI slot
9682 db 0 ;; pci bus number
9683 db 0x18 ;; pci device number (bit 7-3)
9684 db 0x62 ;; link value INTA#
9685 dw 0xdef8 ;; IRQ bitmap INTA#
9686 db 0x63 ;; link value INTB#
9687 dw 0xdef8 ;; IRQ bitmap INTB#
9688 db 0x60 ;; link value INTC#
9689 dw 0xdef8 ;; IRQ bitmap INTC#
9690 db 0x61 ;; link value INTD#
9691 dw 0xdef8 ;; IRQ bitmap INTD#
9692 db 2 ;; physical slot (0 = embedded)
9693 db 0 ;; reserved
9694 ;; 4th slot entry: 3rd PCI slot
9695 db 0 ;; pci bus number
9696 db 0x20 ;; pci device number (bit 7-3)
9697 db 0x63 ;; link value INTA#
9698 dw 0xdef8 ;; IRQ bitmap INTA#
9699 db 0x60 ;; link value INTB#
9700 dw 0xdef8 ;; IRQ bitmap INTB#
9701 db 0x61 ;; link value INTC#
9702 dw 0xdef8 ;; IRQ bitmap INTC#
9703 db 0x62 ;; link value INTD#
9704 dw 0xdef8 ;; IRQ bitmap INTD#
9705 db 3 ;; physical slot (0 = embedded)
9706 db 0 ;; reserved
9707 ;; 5th slot entry: 4rd PCI slot
9708 db 0 ;; pci bus number
9709 db 0x28 ;; pci device number (bit 7-3)
9710 db 0x60 ;; link value INTA#
9711 dw 0xdef8 ;; IRQ bitmap INTA#
9712 db 0x61 ;; link value INTB#
9713 dw 0xdef8 ;; IRQ bitmap INTB#
9714 db 0x62 ;; link value INTC#
9715 dw 0xdef8 ;; IRQ bitmap INTC#
9716 db 0x63 ;; link value INTD#
9717 dw 0xdef8 ;; IRQ bitmap INTD#
9718 db 4 ;; physical slot (0 = embedded)
9719 db 0 ;; reserved
9720 ;; 6th slot entry: 5rd PCI slot
9721 db 0 ;; pci bus number
9722 db 0x30 ;; pci device number (bit 7-3)
9723 db 0x61 ;; link value INTA#
9724 dw 0xdef8 ;; IRQ bitmap INTA#
9725 db 0x62 ;; link value INTB#
9726 dw 0xdef8 ;; IRQ bitmap INTB#
9727 db 0x63 ;; link value INTC#
9728 dw 0xdef8 ;; IRQ bitmap INTC#
9729 db 0x60 ;; link value INTD#
9730 dw 0xdef8 ;; IRQ bitmap INTD#
9731 db 5 ;; physical slot (0 = embedded)
9732 db 0 ;; reserved
9733#ifdef VBOX
9734 ;; 7th slot entry: 6th PCI slot
9735 db 0 ;; pci bus number
9736 db 0x38 ;; pci device number (bit 7-3)
9737 db 0x62 ;; link value INTA#
9738 dw 0xdef8 ;; IRQ bitmap INTA#
9739 db 0x63 ;; link value INTB#
9740 dw 0xdef8 ;; IRQ bitmap INTB#
9741 db 0x60 ;; link value INTC#
9742 dw 0xdef8 ;; IRQ bitmap INTC#
9743 db 0x61 ;; link value INTD#
9744 dw 0xdef8 ;; IRQ bitmap INTD#
9745 db 6 ;; physical slot (0 = embedded)
9746 db 0 ;; reserved
9747 ;; 8th slot entry: 7th PCI slot
9748 db 0 ;; pci bus number
9749 db 0x40 ;; pci device number (bit 7-3)
9750 db 0x63 ;; link value INTA#
9751 dw 0xdef8 ;; IRQ bitmap INTA#
9752 db 0x60 ;; link value INTB#
9753 dw 0xdef8 ;; IRQ bitmap INTB#
9754 db 0x61 ;; link value INTC#
9755 dw 0xdef8 ;; IRQ bitmap INTC#
9756 db 0x62 ;; link value INTD#
9757 dw 0xdef8 ;; IRQ bitmap INTD#
9758 db 7 ;; physical slot (0 = embedded)
9759 db 0 ;; reserved
9760 ;; 9th slot entry: 8th PCI slot
9761 db 0 ;; pci bus number
9762 db 0x48 ;; pci device number (bit 7-3)
9763 db 0x60 ;; link value INTA#
9764 dw 0xdef8 ;; IRQ bitmap INTA#
9765 db 0x61 ;; link value INTB#
9766 dw 0xdef8 ;; IRQ bitmap INTB#
9767 db 0x62 ;; link value INTC#
9768 dw 0xdef8 ;; IRQ bitmap INTC#
9769 db 0x63 ;; link value INTD#
9770 dw 0xdef8 ;; IRQ bitmap INTD#
9771 db 8 ;; physical slot (0 = embedded)
9772 db 0 ;; reserved
9773 ;; 10th slot entry: 9th PCI slot
9774 db 0 ;; pci bus number
9775 db 0x50 ;; pci device number (bit 7-3)
9776 db 0x61 ;; link value INTA#
9777 dw 0xdef8 ;; IRQ bitmap INTA#
9778 db 0x62 ;; link value INTB#
9779 dw 0xdef8 ;; IRQ bitmap INTB#
9780 db 0x63 ;; link value INTC#
9781 dw 0xdef8 ;; IRQ bitmap INTC#
9782 db 0x60 ;; link value INTD#
9783 dw 0xdef8 ;; IRQ bitmap INTD#
9784 db 9 ;; physical slot (0 = embedded)
9785 db 0 ;; reserved
9786#endif /* VBOX */
9787pci_routing_table_structure_end:
9788
9789#if !BX_ROMBIOS32
9790pci_irq_list:
9791 db 11, 10, 9, 5;
9792
9793pcibios_init_sel_reg:
9794 push eax
9795 mov eax, #0x800000
9796 mov ax, bx
9797 shl eax, #8
9798 and dl, #0xfc
9799 or al, dl
9800 mov dx, #0x0cf8
9801 out dx, eax
9802 pop eax
9803 ret
9804
9805pcibios_init_iomem_bases:
9806 push bp
9807 mov bp, sp
9808 mov eax, #0xe0000000 ;; base for memory init
9809 push eax
9810 mov ax, #0xc000 ;; base for i/o init
9811 push ax
9812 mov ax, #0x0010 ;; start at base address #0
9813 push ax
9814 mov bx, #0x0008
9815pci_init_io_loop1:
9816 mov dl, #0x00
9817 call pcibios_init_sel_reg
9818 mov dx, #0x0cfc
9819 in ax, dx
9820 cmp ax, #0xffff
9821 jz next_pci_dev
9822#ifndef VBOX /* This currently breaks restoring a previously saved state. */
9823 mov dl, #0x04 ;; disable i/o and memory space access
9824 call pcibios_init_sel_reg
9825 mov dx, #0x0cfc
9826 in al, dx
9827 and al, #0xfc
9828 out dx, al
9829pci_init_io_loop2:
9830 mov dl, [bp-8]
9831 call pcibios_init_sel_reg
9832 mov dx, #0x0cfc
9833 in eax, dx
9834 test al, #0x01
9835 jnz init_io_base
9836 mov ecx, eax
9837 mov eax, #0xffffffff
9838 out dx, eax
9839 in eax, dx
9840 cmp eax, ecx
9841 je next_pci_base
9842 xor eax, #0xffffffff
9843 mov ecx, eax
9844 mov eax, [bp-4]
9845 out dx, eax
9846 add eax, ecx ;; calculate next free mem base
9847 add eax, #0x01000000
9848 and eax, #0xff000000
9849 mov [bp-4], eax
9850 jmp next_pci_base
9851init_io_base:
9852 mov cx, ax
9853 mov ax, #0xffff
9854 out dx, ax
9855 in ax, dx
9856 cmp ax, cx
9857 je next_pci_base
9858 xor ax, #0xfffe
9859 mov cx, ax
9860 mov ax, [bp-6]
9861 out dx, ax
9862 add ax, cx ;; calculate next free i/o base
9863 add ax, #0x0100
9864 and ax, #0xff00
9865 mov [bp-6], ax
9866next_pci_base:
9867 mov al, [bp-8]
9868 add al, #0x04
9869 cmp al, #0x28
9870 je enable_iomem_space
9871 mov byte ptr[bp-8], al
9872 jmp pci_init_io_loop2
9873#endif /* !VBOX */
9874enable_iomem_space:
9875 mov dl, #0x04 ;; enable i/o and memory space access if available
9876 call pcibios_init_sel_reg
9877 mov dx, #0x0cfc
9878 in al, dx
9879 or al, #0x07
9880 out dx, al
9881#ifdef VBOX
9882 mov dl, #0x00 ;; check if PCI device is AMD PCNet
9883 call pcibios_init_sel_reg
9884 mov dx, #0x0cfc
9885 in eax, dx
9886 cmp eax, #0x20001022
9887 jne next_pci_dev
9888 mov dl, #0x10 ;; get I/O address
9889 call pcibios_init_sel_reg
9890 mov dx, #0x0cfc
9891 in ax, dx
9892 and ax, #0xfffc
9893 mov cx, ax
9894 mov dx, cx
9895 add dx, #0x14 ;; reset register if PCNet is in word I/O mode
9896 in ax, dx ;; reset is performed by reading the reset register
9897 mov dx, cx
9898 add dx, #0x18 ;; reset register if PCNet is in word I/O mode
9899 in eax, dx ;; reset is performed by reading the reset register
9900#endif /* VBOX */
9901next_pci_dev:
9902 mov byte ptr[bp-8], #0x10
9903 inc bx
9904 cmp bx, #0x0100
9905 jne pci_init_io_loop1
9906 mov sp, bp
9907 pop bp
9908 ret
9909
9910pcibios_init_set_elcr:
9911 push ax
9912 push cx
9913 mov dx, #0x04d0
9914 test al, #0x08
9915 jz is_master_pic
9916 inc dx
9917 and al, #0x07
9918is_master_pic:
9919 mov cl, al
9920 mov bl, #0x01
9921 shl bl, cl
9922 in al, dx
9923 or al, bl
9924 out dx, al
9925 pop cx
9926 pop ax
9927 ret
9928
9929pcibios_init_irqs:
9930 push ds
9931 push bp
9932 mov ax, #0xf000
9933 mov ds, ax
9934 mov dx, #0x04d0 ;; reset ELCR1 + ELCR2
9935 mov al, #0x00
9936 out dx, al
9937 inc dx
9938 out dx, al
9939 mov si, #pci_routing_table_structure
9940 mov bh, [si+8]
9941 mov bl, [si+9]
9942 mov dl, #0x00
9943 call pcibios_init_sel_reg
9944 mov dx, #0x0cfc
9945 in eax, dx
9946 cmp eax, [si+12] ;; check irq router
9947 jne pci_init_end
9948 mov dl, [si+34]
9949 call pcibios_init_sel_reg
9950 push bx ;; save irq router bus + devfunc
9951 mov dx, #0x0cfc
9952 mov ax, #0x8080
9953 out dx, ax ;; reset PIRQ route control
9954 inc dx
9955 inc dx
9956 out dx, ax
9957 mov ax, [si+6]
9958 sub ax, #0x20
9959 shr ax, #4
9960 mov cx, ax
9961 add si, #0x20 ;; set pointer to 1st entry
9962 mov bp, sp
9963 mov ax, #pci_irq_list
9964 push ax
9965 xor ax, ax
9966 push ax
9967pci_init_irq_loop1:
9968 mov bh, [si]
9969 mov bl, [si+1]
9970pci_init_irq_loop2:
9971 mov dl, #0x00
9972 call pcibios_init_sel_reg
9973 mov dx, #0x0cfc
9974 in ax, dx
9975 cmp ax, #0xffff
9976 jnz pci_test_int_pin
9977 test bl, #0x07
9978 jz next_pir_entry
9979 jmp next_pci_func
9980pci_test_int_pin:
9981 mov dl, #0x3c
9982 call pcibios_init_sel_reg
9983 mov dx, #0x0cfd
9984 in al, dx
9985 and al, #0x07
9986 jz next_pci_func
9987 dec al ;; determine pirq reg
9988 mov dl, #0x03
9989 mul al, dl
9990 add al, #0x02
9991 xor ah, ah
9992 mov bx, ax
9993 mov al, [si+bx]
9994 mov dl, al
9995 mov bx, [bp]
9996 call pcibios_init_sel_reg
9997 mov dx, #0x0cfc
9998 and al, #0x03
9999 add dl, al
10000 in al, dx
10001 cmp al, #0x80
10002 jb pirq_found
10003 mov bx, [bp-2] ;; pci irq list pointer
10004 mov al, [bx]
10005 out dx, al
10006 inc bx
10007 mov [bp-2], bx
10008 call pcibios_init_set_elcr
10009pirq_found:
10010 mov bh, [si]
10011 mov bl, [si+1]
10012 add bl, [bp-3] ;; pci function number
10013 mov dl, #0x3c
10014 call pcibios_init_sel_reg
10015 mov dx, #0x0cfc
10016 out dx, al
10017next_pci_func:
10018 inc byte ptr[bp-3]
10019 inc bl
10020 test bl, #0x07
10021 jnz pci_init_irq_loop2
10022next_pir_entry:
10023 add si, #0x10
10024 mov byte ptr[bp-3], #0x00
10025 loop pci_init_irq_loop1
10026 mov sp, bp
10027 pop bx
10028pci_init_end:
10029 pop bp
10030 pop ds
10031 ret
10032#endif // BX_ROMBIOS32
10033#endif // BX_PCIBIOS
10034
10035#if BX_ROMBIOS32
10036rombios32_init:
10037 ;; save a20 and enable it
10038 in al, 0x92
10039 push ax
10040 or al, #0x02
10041 out 0x92, al
10042
10043 ;; save SS:SP to the BDA
10044 xor ax, ax
10045 mov ds, ax
10046 mov 0x0469, ss
10047 mov 0x0467, sp
10048
10049 SEG CS
10050 lidt [pmode_IDT_info]
10051 SEG CS
10052 lgdt [rombios32_gdt_48]
10053 ;; set PE bit in CR0
10054 mov eax, cr0
10055 or al, #0x01
10056 mov cr0, eax
10057 ;; start protected mode code: ljmpl 0x10:rombios32_init1
10058 db 0x66, 0xea
10059 dw rombios32_05
10060 dw 0x000f ;; high 16 bit address
10061 dw 0x0010
10062
10063use32 386
10064rombios32_05:
10065 ;; init data segments
10066 mov eax, #0x18
10067 mov ds, ax
10068 mov es, ax
10069 mov ss, ax
10070 xor eax, eax
10071 mov fs, ax
10072 mov gs, ax
10073 cld
10074
10075 ;; copy rombios32 code to ram (ram offset = 1MB)
10076 mov esi, #0xfffe0000
10077 mov edi, #0x00040000
10078 mov ecx, #0x10000 / 4
10079 rep
10080 movsd
10081
10082 ;; init the stack pointer
10083 mov esp, #0x00080000
10084
10085 ;; call rombios32 code
10086 mov eax, #0x00040000
10087 call eax
10088
10089 ;; return to 16 bit protected mode first
10090 db 0xea
10091 dd rombios32_10
10092 dw 0x20
10093
10094use16 386
10095rombios32_10:
10096 ;; restore data segment limits to 0xffff
10097 mov ax, #0x28
10098 mov ds, ax
10099 mov es, ax
10100 mov ss, ax
10101 mov fs, ax
10102 mov gs, ax
10103
10104 ;; reset PE bit in CR0
10105 mov eax, cr0
10106 and al, #0xFE
10107 mov cr0, eax
10108
10109 ;; far jump to flush CPU queue after transition to real mode
10110 JMP_AP(0xf000, rombios32_real_mode)
10111
10112rombios32_real_mode:
10113 ;; restore IDT to normal real-mode defaults
10114 SEG CS
10115 lidt [rmode_IDT_info]
10116
10117 xor ax, ax
10118 mov ds, ax
10119 mov es, ax
10120 mov fs, ax
10121 mov gs, ax
10122
10123 ;; restore SS:SP from the BDA
10124 mov ss, 0x0469
10125 xor esp, esp
10126 mov sp, 0x0467
10127 ;; restore a20
10128 pop ax
10129 out 0x92, al
10130 ret
10131
10132rombios32_gdt_48:
10133 dw 0x30
10134 dw rombios32_gdt
10135 dw 0x000f
10136
10137rombios32_gdt:
10138 dw 0, 0, 0, 0
10139 dw 0, 0, 0, 0
10140 dw 0xffff, 0, 0x9b00, 0x00cf ; 32 bit flat code segment (0x10)
10141 dw 0xffff, 0, 0x9300, 0x00cf ; 32 bit flat data segment (0x18)
10142 dw 0xffff, 0, 0x9b0f, 0x0000 ; 16 bit code segment base=0xf0000 limit=0xffff
10143 dw 0xffff, 0, 0x9300, 0x0000 ; 16 bit data segment base=0x0 limit=0xffff
10144#endif
10145
10146
10147; parallel port detection: base address in DX, index in BX, timeout in CL
10148detect_parport:
10149 push dx
10150 add dx, #2
10151 in al, dx
10152 and al, #0xdf ; clear input mode
10153 out dx, al
10154 pop dx
10155 mov al, #0xaa
10156 out dx, al
10157 in al, dx
10158 cmp al, #0xaa
10159 jne no_parport
10160 push bx
10161 shl bx, #1
10162 mov [bx+0x408], dx ; Parallel I/O address
10163 pop bx
10164 mov [bx+0x478], cl ; Parallel printer timeout
10165 inc bx
10166no_parport:
10167 ret
10168
10169; serial port detection: base address in DX, index in BX, timeout in CL
10170detect_serial:
10171 push dx
10172 inc dx
10173 mov al, #0x02
10174 out dx, al
10175 in al, dx
10176 cmp al, #0x02
10177 jne no_serial
10178 inc dx
10179 in al, dx
10180 cmp al, #0x02
10181 jne no_serial
10182 dec dx
10183 xor al, al
10184 out dx, al
10185 pop dx
10186 push bx
10187 shl bx, #1
10188 mov [bx+0x400], dx ; Serial I/O address
10189 pop bx
10190 mov [bx+0x47c], cl ; Serial timeout
10191 inc bx
10192 ret
10193no_serial:
10194 pop dx
10195 ret
10196
10197rom_checksum:
10198 push ax
10199 push bx
10200 push cx
10201 xor ax, ax
10202 xor bx, bx
10203 xor cx, cx
10204 mov ch, [2]
10205 shl cx, #1
10206checksum_loop:
10207 add al, [bx]
10208 inc bx
10209 loop checksum_loop
10210 and al, #0xff
10211 pop cx
10212 pop bx
10213 pop ax
10214 ret
10215
10216rom_scan:
10217 ;; Scan for existence of valid expansion ROMS.
10218 ;; Video ROM: from 0xC0000..0xC7FFF in 2k increments
10219 ;; General ROM: from 0xC8000..0xDFFFF in 2k increments
10220 ;; System ROM: only 0xE0000
10221 ;;
10222 ;; Header:
10223 ;; Offset Value
10224 ;; 0 0x55
10225 ;; 1 0xAA
10226 ;; 2 ROM length in 512-byte blocks
10227 ;; 3 ROM initialization entry point (FAR CALL)
10228
10229 mov cx, #0xc000
10230rom_scan_loop:
10231 mov ds, cx
10232 mov ax, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
10233 cmp [0], #0xAA55 ;; look for signature
10234 jne rom_scan_increment
10235 call rom_checksum
10236 jnz rom_scan_increment
10237 mov al, [2] ;; change increment to ROM length in 512-byte blocks
10238
10239 ;; We want our increment in 512-byte quantities, rounded to
10240 ;; the nearest 2k quantity, since we only scan at 2k intervals.
10241 test al, #0x03
10242 jz block_count_rounded
10243 and al, #0xfc ;; needs rounding up
10244 add al, #0x04
10245block_count_rounded:
10246
10247 xor bx, bx ;; Restore DS back to 0000:
10248 mov ds, bx
10249 push ax ;; Save AX
10250 ;; Push addr of ROM entry point
10251 push cx ;; Push seg
10252 push #0x0003 ;; Push offset
10253 mov bp, sp ;; Call ROM init routine using seg:off on stack
10254 db 0xff ;; call_far ss:[bp+0]
10255 db 0x5e
10256 db 0
10257 cli ;; In case expansion ROM BIOS turns IF on
10258 add sp, #2 ;; Pop offset value
10259 pop cx ;; Pop seg value (restore CX)
10260 pop ax ;; Restore AX
10261rom_scan_increment:
10262 shl ax, #5 ;; convert 512-bytes blocks to 16-byte increments
10263 ;; because the segment selector is shifted left 4 bits.
10264 add cx, ax
10265 cmp cx, #0xe000
10266 jbe rom_scan_loop
10267
10268 xor ax, ax ;; Restore DS back to 0000:
10269 mov ds, ax
10270 ret
10271
10272;; for 'C' strings and other data, insert them here with
10273;; a the following hack:
10274;; DATA_SEG_DEFS_HERE
10275
10276
10277;; the following area can be used to write dynamically generated tables
10278 .align 16
10279bios_table_area_start:
10280 dd 0xaafb4442
10281 dd bios_table_area_end - bios_table_area_start - 8;
10282
10283;--------
10284;- POST -
10285;--------
10286.org 0xe05b ; POST Entry Point
10287bios_table_area_end:
10288post:
10289
10290 xor ax, ax
10291
10292 ;; first reset the DMA controllers
10293 out 0x0d,al
10294 out 0xda,al
10295
10296 ;; then initialize the DMA controllers
10297 mov al, #0xC0
10298 out 0xD6, al ; cascade mode of channel 4 enabled
10299 mov al, #0x00
10300 out 0xD4, al ; unmask channel 4
10301
10302 ;; Examine CMOS shutdown status.
10303 mov AL, #0x0f
10304 out 0x70, AL
10305 in AL, 0x71
10306
10307 ;; backup status
10308 mov bl, al
10309
10310 ;; Reset CMOS shutdown status.
10311 mov AL, #0x0f
10312 out 0x70, AL ; select CMOS register Fh
10313 mov AL, #0x00
10314 out 0x71, AL ; set shutdown action to normal
10315
10316 ;; Examine CMOS shutdown status.
10317 mov al, bl
10318
10319 ;; 0x00, 0x09, 0x0D+ = normal startup
10320 cmp AL, #0x00
10321 jz normal_post
10322 cmp AL, #0x0d
10323 jae normal_post
10324 cmp AL, #0x09
10325 je normal_post
10326
10327 ;; 0x05 = eoi + jmp via [0x40:0x67] jump
10328 cmp al, #0x05
10329 je eoi_jmp_post
10330
10331 ;; Examine CMOS shutdown status.
10332 ;; 0x01,0x02,0x03,0x04,0x06,0x07,0x08, 0x0a, 0x0b, 0x0c = Unimplemented shutdown status.
10333 push bx
10334 call _shutdown_status_panic
10335
10336#if 0
10337 HALT(__LINE__)
10338 ;
10339 ;#if 0
10340 ; 0xb0, 0x20, /* mov al, #0x20 */
10341 ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */
10342 ;#endif
10343 ;
10344 pop es
10345 pop ds
10346 popa
10347 iret
10348#endif
10349
10350normal_post:
10351 ; case 0: normal startup
10352
10353 cli
10354 mov ax, #0xfffe
10355 mov sp, ax
10356 xor ax, ax
10357 mov ds, ax
10358 mov ss, ax
10359
10360#ifndef VBOX
10361 ;; zero out BIOS data area (40:00..40:ff)
10362 mov es, ax
10363 mov cx, #0x0080 ;; 128 words
10364 mov di, #0x0400
10365 cld
10366 rep
10367 stosw
10368#else /* VBOX */
10369 ;; zero out segment 0 (includes BIOS data area) except word at 40:72
10370 mov es, ax
10371 xor di, di
10372 cld
10373 mov cx, #0x0239 ;; 569 words
10374 rep
10375 stosw
10376 inc di
10377 inc di
10378 mov cx, #0x7dc6 ;; 32198 words
10379 rep
10380 stosw
10381 ;; zero out remaining base memory except the last 16 bytes of the EBDA
10382 ;; because we store the MP table there
10383 xor eax, eax
10384 xor bx, bx
10385memory_zero_loop:
10386 add bx, #0x1000
10387 cmp bx, #0x9000
10388 jae memory_cleared
10389 mov es, bx
10390 xor di, di
10391 mov cx, #0x4000
10392 rep
10393 stosd
10394 jmp memory_zero_loop
10395memory_cleared:
10396 mov es, bx
10397 xor di, di
10398 mov cx, #0x3f00
10399 rep
10400 stosd
10401 xor bx, bx
10402#endif
10403
10404 call _log_bios_start
10405
10406 ;; set all interrupts to default handler
10407 xor bx, bx ;; offset index
10408 mov cx, #0x0100 ;; counter (256 interrupts)
10409 mov ax, #dummy_iret_handler
10410 mov dx, #0xF000
10411
10412post_default_ints:
10413 mov [bx], ax
10414 inc bx
10415 inc bx
10416 mov [bx], dx
10417 inc bx
10418 inc bx
10419 loop post_default_ints
10420
10421 ;; set vector 0x79 to zero
10422 ;; this is used by 'gardian angel' protection system
10423 SET_INT_VECTOR(0x79, #0, #0)
10424
10425 ;; base memory in K 40:13 (word)
10426 mov ax, #BASE_MEM_IN_K
10427 mov 0x0413, ax
10428
10429
10430 ;; Manufacturing Test 40:12
10431 ;; zerod out above
10432
10433#ifndef VBOX
10434 ;; Warm Boot Flag 0040:0072
10435 ;; value of 1234h = skip memory checks
10436 ;; zerod out above
10437#endif /* !VBOX */
10438
10439
10440 ;; Printer Services vector
10441 SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
10442
10443 ;; Bootstrap failure vector
10444 SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
10445
10446 ;; Bootstrap Loader vector
10447 SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
10448
10449 ;; User Timer Tick vector
10450 SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
10451
10452 ;; Memory Size Check vector
10453 SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
10454
10455 ;; Equipment Configuration Check vector
10456 SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
10457
10458 ;; System Services
10459 SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
10460
10461 ;; EBDA setup
10462 call ebda_post
10463
10464 ;; PIT setup
10465 SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
10466 ;; int 1C already points at dummy_iret_handler (above)
10467 mov al, #0x34 ; timer0: binary count, 16bit count, mode 2
10468 out 0x43, al
10469 mov al, #0x00 ; maximum count of 0000H = 18.2Hz
10470 out 0x40, al
10471 out 0x40, al
10472
10473 ;; Keyboard
10474 SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
10475 SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
10476
10477 xor ax, ax
10478 mov ds, ax
10479 mov 0x0417, al /* keyboard shift flags, set 1 */
10480 mov 0x0418, al /* keyboard shift flags, set 2 */
10481 mov 0x0419, al /* keyboard alt-numpad work area */
10482 mov 0x0471, al /* keyboard ctrl-break flag */
10483 mov 0x0497, al /* keyboard status flags 4 */
10484 mov al, #0x10
10485 mov 0x0496, al /* keyboard status flags 3 */
10486
10487
10488 /* keyboard head of buffer pointer */
10489 mov bx, #0x001E
10490 mov 0x041A, bx
10491
10492 /* keyboard end of buffer pointer */
10493 mov 0x041C, bx
10494
10495 /* keyboard pointer to start of buffer */
10496 mov bx, #0x001E
10497 mov 0x0480, bx
10498
10499 /* keyboard pointer to end of buffer */
10500 mov bx, #0x003E
10501 mov 0x0482, bx
10502
10503 /* init the keyboard */
10504 call _keyboard_init
10505
10506 ;; mov CMOS Equipment Byte to BDA Equipment Word
10507 mov ax, 0x0410
10508 mov al, #0x14
10509 out 0x70, al
10510 in al, 0x71
10511 mov 0x0410, ax
10512
10513
10514 ;; Parallel setup
10515 SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
10516 xor ax, ax
10517 mov ds, ax
10518 xor bx, bx
10519 mov cl, #0x14 ; timeout value
10520 mov dx, #0x378 ; Parallel I/O address, port 1
10521 call detect_parport
10522 mov dx, #0x278 ; Parallel I/O address, port 2
10523 call detect_parport
10524 shl bx, #0x0e
10525 mov ax, 0x410 ; Equipment word bits 14..15 determing # parallel ports
10526 and ax, #0x3fff
10527 or ax, bx ; set number of parallel ports
10528 mov 0x410, ax
10529
10530 ;; Serial setup
10531 SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
10532 SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
10533 xor bx, bx
10534 mov cl, #0x0a ; timeout value
10535 mov dx, #0x03f8 ; Serial I/O address, port 1
10536 call detect_serial
10537 mov dx, #0x02f8 ; Serial I/O address, port 2
10538 call detect_serial
10539 mov dx, #0x03e8 ; Serial I/O address, port 3
10540 call detect_serial
10541 mov dx, #0x02e8 ; Serial I/O address, port 4
10542 call detect_serial
10543 shl bx, #0x09
10544 mov ax, 0x410 ; Equipment word bits 9..11 determing # serial ports
10545 and ax, #0xf1ff
10546 or ax, bx ; set number of serial port
10547 mov 0x410, ax
10548
10549 ;; CMOS RTC
10550 SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
10551 SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
10552 SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
10553 ;; BIOS DATA AREA 0x4CE ???
10554 call timer_tick_post
10555
10556 ;; PS/2 mouse setup
10557 SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
10558
10559 ;; IRQ13 (FPU exception) setup
10560 SET_INT_VECTOR(0x75, #0xF000, #int75_handler)
10561
10562 ;; Video setup
10563 SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
10564
10565 ;; PIC
10566 mov al, #0x11 ; send initialisation commands
10567 out 0x20, al
10568 out 0xa0, al
10569 mov al, #0x08
10570 out 0x21, al
10571 mov al, #0x70
10572 out 0xa1, al
10573 mov al, #0x04
10574 out 0x21, al
10575 mov al, #0x02
10576 out 0xa1, al
10577 mov al, #0x01
10578 out 0x21, al
10579 out 0xa1, al
10580 mov al, #0xb8
10581 out 0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6
10582#if BX_USE_PS2_MOUSE
10583 mov al, #0x8f
10584#else
10585 mov al, #0x9f
10586#endif
10587 out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14
10588
10589#if BX_ROMBIOS32
10590 call rombios32_init
10591#else
10592 call pcibios_init_iomem_bases
10593 call pcibios_init_irqs
10594#endif
10595 call rom_scan
10596
10597 call _print_bios_banner
10598
10599 ;;
10600 ;; Floppy setup
10601 ;;
10602 call floppy_drive_post
10603
10604#if BX_USE_ATADRV
10605
10606 ;;
10607 ;; Hard Drive setup
10608 ;;
10609 call hard_drive_post
10610
10611 ;;
10612 ;; ATA/ATAPI driver setup
10613 ;;
10614 call _ata_init
10615 call _ata_detect
10616 ;;
10617#else // BX_USE_ATADRV
10618
10619 ;;
10620 ;; Hard Drive setup
10621 ;;
10622 call hard_drive_post
10623
10624#endif // BX_USE_ATADRV
10625
10626#if BX_ELTORITO_BOOT
10627 ;;
10628 ;; eltorito floppy/harddisk emulation from cd
10629 ;;
10630 call _cdemu_init
10631 ;;
10632#endif // BX_ELTORITO_BOOT
10633
10634 sti ;; enable interrupts
10635 int #0x19
10636
10637
10638.org 0xe2c3 ; NMI Handler Entry Point
10639nmi:
10640 ;; FIXME the NMI handler should not panic
10641 ;; but iret when called from int75 (fpu exception)
10642 call _nmi_handler_msg
10643 iret
10644
10645int75_handler:
10646 out 0xf0, al // clear irq13
10647 call eoi_both_pics // clear interrupt
10648 int 2 // legacy nmi call
10649 iret
10650
10651;-------------------------------------------
10652;- INT 13h Fixed Disk Services Entry Point -
10653;-------------------------------------------
10654.org 0xe3fe ; INT 13h Fixed Disk Services Entry Point
10655int13_handler:
10656 //JMPL(int13_relocated)
10657 jmp int13_relocated
10658
10659.org 0xe401 ; Fixed Disk Parameter Table
10660
10661;----------
10662;- INT19h -
10663;----------
10664.org 0xe6f2 ; INT 19h Boot Load Service Entry Point
10665int19_handler:
10666
10667 jmp int19_relocated
10668;-------------------------------------------
10669;- System BIOS Configuration Data Table
10670;-------------------------------------------
10671.org BIOS_CONFIG_TABLE
10672db 0x08 ; Table size (bytes) -Lo
10673db 0x00 ; Table size (bytes) -Hi
10674db SYS_MODEL_ID
10675db SYS_SUBMODEL_ID
10676db BIOS_REVISION
10677; Feature byte 1
10678; b7: 1=DMA channel 3 used by hard disk
10679; b6: 1=2 interrupt controllers present
10680; b5: 1=RTC present
10681; b4: 1=BIOS calls int 15h/4Fh every key
10682; b3: 1=wait for extern event supported (Int 15h/41h)
10683; b2: 1=extended BIOS data area used
10684; b1: 0=AT or ESDI bus, 1=MicroChannel
10685; b0: 1=Dual bus (MicroChannel + ISA)
10686db (0 << 7) | \
10687 (1 << 6) | \
10688 (1 << 5) | \
10689 (BX_CALL_INT15_4F << 4) | \
10690 (0 << 3) | \
10691 (BX_USE_EBDA << 2) | \
10692 (0 << 1) | \
10693 (0 << 0)
10694; Feature byte 2
10695; b7: 1=32-bit DMA supported
10696; b6: 1=int16h, function 9 supported
10697; b5: 1=int15h/C6h (get POS data) supported
10698; b4: 1=int15h/C7h (get mem map info) supported
10699; b3: 1=int15h/C8h (en/dis CPU) supported
10700; b2: 1=non-8042 kb controller
10701; b1: 1=data streaming supported
10702; b0: reserved
10703db (0 << 7) | \
10704 (1 << 6) | \
10705 (0 << 5) | \
10706 (0 << 4) | \
10707 (0 << 3) | \
10708 (0 << 2) | \
10709 (0 << 1) | \
10710 (0 << 0)
10711; Feature byte 3
10712; b7: not used
10713; b6: reserved
10714; b5: reserved
10715; b4: POST supports ROM-to-RAM enable/disable
10716; b3: SCSI on system board
10717; b2: info panel installed
10718; b1: Initial Machine Load (IML) system - BIOS on disk
10719; b0: SCSI supported in IML
10720db 0x00
10721; Feature byte 4
10722; b7: IBM private
10723; b6: EEPROM present
10724; b5-3: ABIOS presence (011 = not supported)
10725; b2: private
10726; b1: memory split above 16Mb supported
10727; b0: POSTEXT directly supported by POST
10728db 0x00
10729; Feature byte 5 (IBM)
10730; b1: enhanced mouse
10731; b0: flash EPROM
10732db 0x00
10733
10734
10735
10736.org 0xe729 ; Baud Rate Generator Table
10737
10738;----------
10739;- INT14h -
10740;----------
10741.org 0xe739 ; INT 14h Serial Communications Service Entry Point
10742int14_handler:
10743 push ds
10744 pusha
10745 xor ax, ax
10746 mov ds, ax
10747 call _int14_function
10748 popa
10749 pop ds
10750 iret
10751
10752
10753;----------------------------------------
10754;- INT 16h Keyboard Service Entry Point -
10755;----------------------------------------
10756.org 0xe82e
10757int16_handler:
10758
10759 sti
10760 push ds
10761 pushf
10762 pusha
10763
10764 cmp ah, #0x00
10765 je int16_F00
10766 cmp ah, #0x10
10767 je int16_F00
10768
10769 mov bx, #0xf000
10770 mov ds, bx
10771 call _int16_function
10772 popa
10773 popf
10774 pop ds
10775 jz int16_zero_set
10776
10777int16_zero_clear:
10778 push bp
10779 mov bp, sp
10780 //SEG SS
10781 and BYTE [bp + 0x06], #0xbf
10782 pop bp
10783 iret
10784
10785int16_zero_set:
10786 push bp
10787 mov bp, sp
10788 //SEG SS
10789 or BYTE [bp + 0x06], #0x40
10790 pop bp
10791 iret
10792
10793int16_F00:
10794 mov bx, #0x0040
10795 mov ds, bx
10796
10797int16_wait_for_key:
10798 cli
10799 mov bx, 0x001a
10800 cmp bx, 0x001c
10801 jne int16_key_found
10802 sti
10803 nop
10804#if 0
10805 /* no key yet, call int 15h, function AX=9002 */
10806 0x50, /* push AX */
10807 0xb8, 0x02, 0x90, /* mov AX, #0x9002 */
10808 0xcd, 0x15, /* int 15h */
10809 0x58, /* pop AX */
10810 0xeb, 0xea, /* jmp WAIT_FOR_KEY */
10811#endif
10812 jmp int16_wait_for_key
10813
10814int16_key_found:
10815 mov bx, #0xf000
10816 mov ds, bx
10817 call _int16_function
10818 popa
10819 popf
10820 pop ds
10821#if 0
10822 /* notify int16 complete w/ int 15h, function AX=9102 */
10823 0x50, /* push AX */
10824 0xb8, 0x02, 0x91, /* mov AX, #0x9102 */
10825 0xcd, 0x15, /* int 15h */
10826 0x58, /* pop AX */
10827#endif
10828 iret
10829
10830
10831
10832;-------------------------------------------------
10833;- INT09h : Keyboard Hardware Service Entry Point -
10834;-------------------------------------------------
10835.org 0xe987
10836int09_handler:
10837 cli
10838 push ax
10839
10840 mov al, #0xAD ;;disable keyboard
10841 out #0x64, al
10842
10843 mov al, #0x0B
10844 out #0x20, al
10845 in al, #0x20
10846 and al, #0x02
10847 jz int09_finish
10848
10849 in al, #0x60 ;;read key from keyboard controller
10850 sti
10851 push ds
10852 pusha
10853#ifdef BX_CALL_INT15_4F
10854 mov ah, #0x4f ;; allow for keyboard intercept
10855 stc
10856 int #0x15
10857 jnc int09_done
10858#endif
10859
10860 ;; check for extended key
10861 cmp al, #0xe0
10862 jne int09_check_pause
10863 xor ax, ax
10864 mov ds, ax
10865 mov al, BYTE [0x496] ;; mf2_state |= 0x02
10866 or al, #0x02
10867 mov BYTE [0x496], al
10868 jmp int09_done
10869
10870int09_check_pause: ;; check for pause key
10871 cmp al, #0xe1
10872 jne int09_process_key
10873 xor ax, ax
10874 mov ds, ax
10875 mov al, BYTE [0x496] ;; mf2_state |= 0x01
10876 or al, #0x01
10877 mov BYTE [0x496], al
10878 jmp int09_done
10879
10880int09_process_key:
10881 mov bx, #0xf000
10882 mov ds, bx
10883 call _int09_function
10884
10885int09_done:
10886 popa
10887 pop ds
10888 cli
10889 call eoi_master_pic
10890
10891int09_finish:
10892 mov al, #0xAE ;;enable keyboard
10893 out #0x64, al
10894 pop ax
10895 iret
10896
10897
10898;----------------------------------------
10899;- INT 13h Diskette Service Entry Point -
10900;----------------------------------------
10901.org 0xec59
10902int13_diskette:
10903 jmp int13_noeltorito
10904
10905;---------------------------------------------
10906;- INT 0Eh Diskette Hardware ISR Entry Point -
10907;---------------------------------------------
10908.org 0xef57 ; INT 0Eh Diskette Hardware ISR Entry Point
10909int0e_handler:
10910 push ax
10911 push dx
10912 mov dx, #0x03f4
10913 in al, dx
10914 and al, #0xc0
10915 cmp al, #0xc0
10916 je int0e_normal
10917 mov dx, #0x03f5
10918 mov al, #0x08 ; sense interrupt status
10919 out dx, al
10920int0e_loop1:
10921 mov dx, #0x03f4
10922 in al, dx
10923 and al, #0xc0
10924 cmp al, #0xc0
10925 jne int0e_loop1
10926int0e_loop2:
10927 mov dx, #0x03f5
10928 in al, dx
10929 mov dx, #0x03f4
10930 in al, dx
10931 and al, #0xc0
10932 cmp al, #0xc0
10933 je int0e_loop2
10934int0e_normal:
10935 push ds
10936 xor ax, ax ;; segment 0000
10937 mov ds, ax
10938 call eoi_master_pic
10939 mov al, 0x043e
10940 or al, #0x80 ;; diskette interrupt has occurred
10941 mov 0x043e, al
10942 pop ds
10943 pop dx
10944 pop ax
10945 iret
10946
10947
10948.org 0xefc7 ; Diskette Controller Parameter Table
10949diskette_param_table:
10950;; Since no provisions are made for multiple drive types, most
10951;; values in this table are ignored. I set parameters for 1.44M
10952;; floppy here
10953db 0xAF
10954db 0x02 ;; head load time 0000001, DMA used
10955db 0x25
10956db 0x02
10957db 18
10958db 0x1B
10959db 0xFF
10960db 0x6C
10961db 0xF6
10962db 0x0F
10963db 0x08
10964
10965
10966;----------------------------------------
10967;- INT17h : Printer Service Entry Point -
10968;----------------------------------------
10969.org 0xefd2
10970int17_handler:
10971 push ds
10972 pusha
10973 xor ax, ax
10974 mov ds, ax
10975 call _int17_function
10976 popa
10977 pop ds
10978 iret
10979
10980diskette_param_table2:
10981;; New diskette parameter table adding 3 parameters from IBM
10982;; Since no provisions are made for multiple drive types, most
10983;; values in this table are ignored. I set parameters for 1.44M
10984;; floppy here
10985db 0xAF
10986db 0x02 ;; head load time 0000001, DMA used
10987db 0x25
10988db 0x02
10989db 18
10990db 0x1B
10991db 0xFF
10992db 0x6C
10993db 0xF6
10994db 0x0F
10995db 0x08
10996db 79 ;; maximum track
10997db 0 ;; data transfer rate
10998db 4 ;; drive type in cmos
10999
11000.org 0xf045 ; INT 10 Functions 0-Fh Entry Point
11001 HALT(__LINE__)
11002 iret
11003
11004;----------
11005;- INT10h -
11006;----------
11007.org 0xf065 ; INT 10h Video Support Service Entry Point
11008int10_handler:
11009 ;; dont do anything, since the VGA BIOS handles int10h requests
11010 iret
11011
11012.org 0xf0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
11013
11014;----------
11015;- INT12h -
11016;----------
11017.org 0xf841 ; INT 12h Memory Size Service Entry Point
11018; ??? different for Pentium (machine check)?
11019int12_handler:
11020 push ds
11021 mov ax, #0x0040
11022 mov ds, ax
11023 mov ax, 0x0013
11024 pop ds
11025 iret
11026
11027;----------
11028;- INT11h -
11029;----------
11030.org 0xf84d ; INT 11h Equipment List Service Entry Point
11031int11_handler:
11032 push ds
11033 mov ax, #0x0040
11034 mov ds, ax
11035 mov ax, 0x0010
11036 pop ds
11037 iret
11038
11039;----------
11040;- INT15h -
11041;----------
11042.org 0xf859 ; INT 15h System Services Entry Point
11043int15_handler:
11044 pushf
11045#if BX_APM
11046 cmp ah, #0x53
11047 je apm_call
11048#endif
11049 push ds
11050 push es
11051 cmp ah, #0x86
11052 je int15_handler32
11053 cmp ah, #0xE8
11054 je int15_handler32
11055 pusha
11056#if BX_USE_PS2_MOUSE
11057 cmp ah, #0xC2
11058 je int15_handler_mouse
11059#endif
11060 call _int15_function
11061int15_handler_mouse_ret:
11062 popa
11063int15_handler32_ret:
11064 pop es
11065 pop ds
11066 popf
11067 jmp iret_modify_cf
11068#if BX_APM
11069apm_call:
11070 jmp _apmreal_entry
11071#endif
11072
11073#if BX_USE_PS2_MOUSE
11074int15_handler_mouse:
11075 call _int15_function_mouse
11076 jmp int15_handler_mouse_ret
11077#endif
11078
11079int15_handler32:
11080 pushad
11081 call _int15_function32
11082 popad
11083 jmp int15_handler32_ret
11084
11085;; Protected mode IDT descriptor
11086;;
11087;; I just make the limit 0, so the machine will shutdown
11088;; if an exception occurs during protected mode memory
11089;; transfers.
11090;;
11091;; Set base to f0000 to correspond to beginning of BIOS,
11092;; in case I actually define an IDT later
11093;; Set limit to 0
11094
11095pmode_IDT_info:
11096dw 0x0000 ;; limit 15:00
11097dw 0x0000 ;; base 15:00
11098db 0x0f ;; base 23:16
11099
11100;; Real mode IDT descriptor
11101;;
11102;; Set to typical real-mode values.
11103;; base = 000000
11104;; limit = 03ff
11105
11106rmode_IDT_info:
11107dw 0x03ff ;; limit 15:00
11108dw 0x0000 ;; base 15:00
11109db 0x00 ;; base 23:16
11110
11111
11112;----------
11113;- INT1Ah -
11114;----------
11115.org 0xfe6e ; INT 1Ah Time-of-day Service Entry Point
11116int1a_handler:
11117#if BX_PCIBIOS
11118 cmp ah, #0xb1
11119 jne int1a_normal
11120 call pcibios_real
11121 jc pcibios_error
11122 retf 2
11123pcibios_error:
11124 mov bl, ah
11125 mov ah, #0xb1
11126 push ds
11127 pusha
11128 mov ax, ss ; set readable descriptor to ds, for calling pcibios
11129 mov ds, ax ; on 16bit protected mode.
11130 jmp int1a_callfunction
11131int1a_normal:
11132#endif
11133 push ds
11134 pusha
11135 xor ax, ax
11136 mov ds, ax
11137int1a_callfunction:
11138 call _int1a_function
11139 popa
11140 pop ds
11141 iret
11142
11143;;
11144;; int70h: IRQ8 - CMOS RTC
11145;;
11146int70_handler:
11147 push ds
11148 pushad
11149 xor ax, ax
11150 mov ds, ax
11151 call _int70_function
11152 popad
11153 pop ds
11154 iret
11155
11156;---------
11157;- INT08 -
11158;---------
11159.org 0xfea5 ; INT 08h System Timer ISR Entry Point
11160int08_handler:
11161 sti
11162 push eax
11163 push ds
11164 xor ax, ax
11165 mov ds, ax
11166
11167 ;; time to turn off drive(s)?
11168 mov al,0x0440
11169 or al,al
11170 jz int08_floppy_off
11171 dec al
11172 mov 0x0440,al
11173 jnz int08_floppy_off
11174 ;; turn motor(s) off
11175 push dx
11176 mov dx,#0x03f2
11177 in al,dx
11178 and al,#0xcf
11179 out dx,al
11180 pop dx
11181int08_floppy_off:
11182
11183 mov eax, 0x046c ;; get ticks dword
11184 inc eax
11185
11186 ;; compare eax to one days worth of timer ticks at 18.2 hz
11187 cmp eax, #0x001800B0
11188 jb int08_store_ticks
11189 ;; there has been a midnight rollover at this point
11190 xor eax, eax ;; zero out counter
11191 inc BYTE 0x0470 ;; increment rollover flag
11192
11193int08_store_ticks:
11194 mov 0x046c, eax ;; store new ticks dword
11195 ;; chain to user timer tick INT #0x1c
11196 //pushf
11197 //;; call_ep [ds:loc]
11198 //CALL_EP( 0x1c << 2 )
11199 int #0x1c
11200 cli
11201 call eoi_master_pic
11202 pop ds
11203 pop eax
11204 iret
11205
11206.org 0xfef3 ; Initial Interrupt Vector Offsets Loaded by POST
11207
11208
11209.org 0xff00
11210.ascii BIOS_COPYRIGHT_STRING
11211
11212#ifdef VBOX
11213// The DMI header
11214.org 0xff40
11215.align 16
11216 db 0x5f, 0x44, 0x4d, 0x49, 0x5f ; "_DMI_" signature
11217 ; calculate the DMI header checksum
11218 db ( - ( 0x5f + 0x44 + 0x4d + 0x49 + 0x5f \
11219 + ((VBOX_DMI_TABLE_BASE ) & 0xff) + ((VBOX_DMI_TABLE_BASE >> 8) & 0xff) \
11220 + ((VBOX_DMI_TABLE_BASE >> 16) & 0xff) + ((VBOX_DMI_TABLE_BASE >> 24) & 0xff) \
11221 + ((VBOX_DMI_TABLE_SIZE ) & 0xff) + ((VBOX_DMI_TABLE_SIZE >> 8) & 0xff) \
11222 + ((VBOX_DMI_TABLE_ENTR ) & 0xff) + ((VBOX_DMI_TABLE_ENTR >> 8) & 0xff) \
11223 + VBOX_DMI_TABLE_VER \
11224 )) & 0xff
11225 dw VBOX_DMI_TABLE_SIZE ; DMI tables length
11226 dd VBOX_DMI_TABLE_BASE ; DMI tables base
11227 dw VBOX_DMI_TABLE_ENTR ; DMI tables entries
11228 db VBOX_DMI_TABLE_VER ; DMI version
11229 db 0x00 ; Just for alignment
11230#endif
11231
11232;------------------------------------------------
11233;- IRET Instruction for Dummy Interrupt Handler -
11234;------------------------------------------------
11235.org 0xff53 ; IRET Instruction for Dummy Interrupt Handler
11236dummy_iret_handler:
11237 iret
11238
11239.org 0xff54 ; INT 05h Print Screen Service Entry Point
11240 HALT(__LINE__)
11241 iret
11242
11243.org 0xfff0 ; Power-up Entry Point
11244 jmp 0xf000:post
11245
11246.org 0xfff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
11247.ascii BIOS_BUILD_DATE
11248
11249.org 0xfffe ; System Model ID
11250db SYS_MODEL_ID
11251db 0x00 ; filler
11252
11253.org 0xfa6e ;; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
11254ASM_END
11255/*
11256 * This font comes from the fntcol16.zip package (c) by Joseph Gil
11257 * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
11258 * This font is public domain
11259 */
11260static Bit8u vgafont8[128*8]=
11261{
11262 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
11263 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
11264 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
11265 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
11266 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
11267 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
11268 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
11269 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
11270 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
11271 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
11272 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
11273 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
11274 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
11275 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
11276 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
11277 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
11278 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
11279 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
11280 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
11281 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
11282 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
11283 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
11284 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
11285 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
11286 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
11287 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
11288 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
11289 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
11290 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
11291 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
11292 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
11293 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
11294 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
11295 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
11296 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
11297 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
11298 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
11299 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
11300 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
11301 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
11302 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
11303 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
11304 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
11305 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
11306 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
11307 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
11308 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
11309 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
11310 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
11311 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
11312 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
11313 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
11314 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
11315 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
11316 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
11317 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
11318 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
11319 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
11320 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
11321 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
11322 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
11323 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
11324 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
11325 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
11326 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
11327 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
11328 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
11329 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
11330 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
11331 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
11332 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
11333 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
11334 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
11335 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
11336 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
11337 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
11338 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
11339 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
11340 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
11341 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
11342 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
11343 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
11344 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
11345 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
11346 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
11347 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
11348 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
11349 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
11350 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
11351 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
11352 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
11353 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
11354 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
11355 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
11356 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
11357 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
11358 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
11359 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
11360 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
11361 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
11362 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
11363 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
11364 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
11365 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
11366 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
11367 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
11368 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
11369 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
11370 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
11371 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
11372 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
11373 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
11374 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
11375 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
11376 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
11377 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
11378 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
11379 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
11380 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
11381 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
11382 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
11383 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
11384 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
11385 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
11386 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
11387 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
11388 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
11389 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
11390};
11391
11392ASM_START
11393.org 0xcc00
11394// bcc-generated data will be placed here
11395ASM_END
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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