VirtualBox

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

Last change on this file since 1 was 1, checked in by vboxsync, 55 years ago

import

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

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