VirtualBox

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

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

Hack to allow configurable boot delay (up to 15 seconds).

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

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