ia64/xen-unstable

view tools/firmware/rombios/rombios.c @ 17217:9f6117e9d7d9

hvm bios: Fix EDD pointer in int 13h, fn 48h BIOS call return buffer

I ran into this when I was reviewing what was outstanding to get
NetWare to run fully virtualized.

The BIOS emulator code has the segment and offset backward in the
returned buffer for the int 13h, fn 48h BIOS call.

Signed-off-by: Bruce Rogers <brogers@novell.com>
author Keir Fraser <keir.fraser@citrix.com>
date Mon Mar 17 11:16:08 2008 +0000 (2008-03-17)
parents e6e165f72e57
children 7c752689b0ea
line source
1 /////////////////////////////////////////////////////////////////////////
2 // $Id: rombios.c,v 1.138 2005/05/07 15:55:26 vruppert Exp $
3 /////////////////////////////////////////////////////////////////////////
4 //
5 // Copyright (C) 2002 MandrakeSoft S.A.
6 //
7 // MandrakeSoft S.A.
8 // 43, rue d'Aboukir
9 // 75002 Paris - France
10 // http://www.linux-mandrake.com/
11 // http://www.mandrakesoft.com/
12 //
13 // This library is free software; you can redistribute it and/or
14 // modify it under the terms of the GNU Lesser General Public
15 // License as published by the Free Software Foundation; either
16 // version 2 of the License, or (at your option) any later version.
17 //
18 // This library is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 // Lesser General Public License for more details.
22 //
23 // You should have received a copy of the GNU Lesser General Public
24 // License along with this library; if not, write to the Free Software
25 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 // ROM BIOS for use with Bochs/Plex x86 emulation environment
29 #include "../hvmloader/config.h"
31 #define HVMASSIST
32 #undef HVMTEST
34 // Xen full virtualization does not handle unaligned IO with page crossing.
35 // Disable 32-bit PIO as a workaround.
36 #undef NO_PIO32
39 // ROM BIOS compatability entry points:
40 // ===================================
41 // $e05b ; POST Entry Point
42 // $e2c3 ; NMI Handler Entry Point
43 // $e3fe ; INT 13h Fixed Disk Services Entry Point
44 // $e401 ; Fixed Disk Parameter Table
45 // $e6f2 ; INT 19h Boot Load Service Entry Point
46 // $e6f5 ; Configuration Data Table
47 // $e729 ; Baud Rate Generator Table
48 // $e739 ; INT 14h Serial Communications Service Entry Point
49 // $e82e ; INT 16h Keyboard Service Entry Point
50 // $e987 ; INT 09h Keyboard Service Entry Point
51 // $ec59 ; INT 13h Diskette Service Entry Point
52 // $ef57 ; INT 0Eh Diskette Hardware ISR Entry Point
53 // $efc7 ; Diskette Controller Parameter Table
54 // $efd2 ; INT 17h Printer Service Entry Point
55 // $f045 ; INT 10 Functions 0-Fh Entry Point
56 // $f065 ; INT 10h Video Support Service Entry Point
57 // $f0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
58 // $f841 ; INT 12h Memory Size Service Entry Point
59 // $f84d ; INT 11h Equipment List Service Entry Point
60 // $f859 ; INT 15h System Services Entry Point
61 // $fa6e ; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
62 // $fe6e ; INT 1Ah Time-of-day Service Entry Point
63 // $fea5 ; INT 08h System Timer ISR Entry Point
64 // $fef3 ; Initial Interrupt Vector Offsets Loaded by POST
65 // $ff53 ; IRET Instruction for Dummy Interrupt Handler
66 // $ff54 ; INT 05h Print Screen Service Entry Point
67 // $fff0 ; Power-up Entry Point
68 // $fff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
69 // $fffe ; System Model ID
71 // NOTES for ATA/ATAPI driver (cbbochs@free.fr)
72 // Features
73 // - supports up to 4 ATA interfaces
74 // - device/geometry detection
75 // - 16bits/32bits device access
76 // - pchs/lba access
77 // - datain/dataout/packet command support
78 //
79 // NOTES for El-Torito Boot (cbbochs@free.fr)
80 // - CD-ROM booting is only available if ATA/ATAPI Driver is available
81 // - Current code is only able to boot mono-session cds
82 // - Current code can not boot and emulate a hard-disk
83 // the bios will panic otherwise
84 // - Current code also use memory in EBDA segement.
85 // - I used cmos byte 0x3D to store extended information on boot-device
86 // - Code has to be modified modified to handle multiple cdrom drives
87 // - Here are the cdrom boot failure codes:
88 // 1 : no atapi device found
89 // 2 : no atapi cdrom found
90 // 3 : can not read cd - BRVD
91 // 4 : cd is not eltorito (BRVD)
92 // 5 : cd is not eltorito (ISO TAG)
93 // 6 : cd is not eltorito (ELTORITO TAG)
94 // 7 : can not read cd - boot catalog
95 // 8 : boot catalog : bad header
96 // 9 : boot catalog : bad platform
97 // 10 : boot catalog : bad signature
98 // 11 : boot catalog : bootable flag not set
99 // 12 : can not read cd - boot image
100 //
101 // ATA driver
102 // - EBDA segment.
103 // I used memory starting at 0x121 in the segment
104 // - the translation policy is defined in cmos regs 0x39 & 0x3a
105 //
106 // TODO :
107 //
108 // int74
109 // - needs to be reworked. Uses direct [bp] offsets. (?)
110 //
111 // int13:
112 // - f04 (verify sectors) isn't complete (?)
113 // - f02/03/04 should set current cyl,etc in BDA (?)
114 // - rewrite int13_relocated & clean up int13 entry code
115 //
116 // NOTES:
117 // - NMI access (bit7 of addr written to 70h)
118 //
119 // ATA driver
120 // - should handle the "don't detect" bit (cmos regs 0x3b & 0x3c)
121 // - could send the multiple-sector read/write commands
122 //
123 // El-Torito
124 // - Emulate a Hard-disk (currently only diskette can be emulated) see "FIXME ElTorito Harddisk"
125 // - Implement remaining int13_cdemu functions (as defined by El-Torito specs)
126 // - cdrom drive is hardcoded to ide 0 device 1 in several places. see "FIXME ElTorito Hardcoded"
127 // - int13 Fix DL when emulating a cd. In that case DL is decremented before calling real int13.
128 // This is ok. But DL should be reincremented afterwards.
129 // - Fix all "FIXME ElTorito Various"
130 // - should be able to boot any cdrom instead of the first one
131 //
132 // BCC Bug: find a generic way to handle the bug of #asm after an "if" (fixed in 0.16.7)
134 #define DEBUG_ROMBIOS 0
136 #define DEBUG_ATA 0
137 #define DEBUG_INT13_HD 0
138 #define DEBUG_INT13_CD 0
139 #define DEBUG_INT13_ET 0
140 #define DEBUG_INT13_FL 0
141 #define DEBUG_INT15 0
142 #define DEBUG_INT16 0
143 #define DEBUG_INT1A 0
144 #define DEBUG_INT74 0
145 #define DEBUG_APM 0
147 #define BX_CPU 3
148 #define BX_USE_PS2_MOUSE 1
149 #define BX_CALL_INT15_4F 1
150 #define BX_USE_EBDA 1
151 #define BX_SUPPORT_FLOPPY 1
152 #define BX_FLOPPY_ON_CNT 37 /* 2 seconds */
153 #define BX_PCIBIOS 1
154 #define BX_APM 1
156 #define BX_USE_ATADRV 1
157 #define BX_ELTORITO_BOOT 1
159 #define BX_TCGBIOS 0 /* main switch for TCG BIOS ext. */
161 #define BX_MAX_ATA_INTERFACES 4
162 #define BX_MAX_ATA_DEVICES (BX_MAX_ATA_INTERFACES*2)
164 #define BX_VIRTUAL_PORTS 1 /* normal output to Bochs ports */
165 #define BX_DEBUG_SERIAL 0 /* output to COM1 */
167 /* model byte 0xFC = AT */
168 #define SYS_MODEL_ID 0xFC
169 #define SYS_SUBMODEL_ID 0x00
170 #define BIOS_REVISION 1
171 #define BIOS_CONFIG_TABLE 0xe6f5
173 #ifndef BIOS_BUILD_DATE
174 # define BIOS_BUILD_DATE "06/23/99"
175 #endif
177 // 1K of base memory used for Extended Bios Data Area (EBDA)
178 // EBDA is used for PS/2 mouse support, and IDE BIOS, etc.
179 #define EBDA_SEG 0x9FC0
180 #define EBDA_SIZE 1 // In KiB
181 #define BASE_MEM_IN_K (640 - EBDA_SIZE)
183 // Define the application NAME
184 #ifdef HVMASSIST
185 # define BX_APPNAME "HVMAssist"
186 #elif PLEX86
187 # define BX_APPNAME "Plex86"
188 #else
189 # define BX_APPNAME "Bochs"
190 #endif
192 // Sanity Checks
193 #if BX_USE_ATADRV && BX_CPU<3
194 # error The ATA/ATAPI Driver can only to be used with a 386+ cpu
195 #endif
196 #if BX_USE_ATADRV && !BX_USE_EBDA
197 # error ATA/ATAPI Driver can only be used if EBDA is available
198 #endif
199 #if BX_ELTORITO_BOOT && !BX_USE_ATADRV
200 # error El-Torito Boot can only be use if ATA/ATAPI Driver is available
201 #endif
202 #if BX_PCIBIOS && BX_CPU<3
203 # error PCI BIOS can only be used with 386+ cpu
204 #endif
205 #if BX_APM && BX_CPU<3
206 # error APM BIOS can only be used with 386+ cpu
207 #endif
209 #ifndef BX_SMP_PROCESSORS
210 #define BX_SMP_PROCESSORS 1
211 # warning BX_SMP_PROCESSORS not defined, defaulting to 1
212 #endif
214 #define PANIC_PORT 0x400
215 #define PANIC_PORT2 0x401
216 #define INFO_PORT 0x402
217 #define DEBUG_PORT 0x403
219 // #20 is dec 20
220 // #$20 is hex 20 = 32
221 // #0x20 is hex 20 = 32
222 // LDA #$20
223 // JSR $E820
224 // LDD .i,S
225 // JSR $C682
226 // mov al, #$20
228 // all hex literals should be prefixed with '0x'
229 // grep "#[0-9a-fA-F][0-9a-fA-F]" rombios.c
230 // no mov SEG-REG, #value, must mov register into seg-reg
231 // grep -i "mov[ ]*.s" rombios.c
233 // This is for compiling with gcc2 and gcc3
234 #define ASM_START #asm
235 #define ASM_END #endasm
237 ASM_START
238 .rom
240 .org 0x0000
242 #if BX_CPU >= 3
243 use16 386
244 #else
245 use16 286
246 #endif
248 MACRO HALT
249 ;; the HALT macro is called with the line number of the HALT call.
250 ;; The line number is then sent to the PANIC_PORT, causing Bochs/Plex
251 ;; to print a BX_PANIC message. This will normally halt the simulation
252 ;; with a message such as "BIOS panic at rombios.c, line 4091".
253 ;; However, users can choose to make panics non-fatal and continue.
254 #if BX_VIRTUAL_PORTS
255 mov dx,#PANIC_PORT
256 mov ax,#?1
257 out dx,ax
258 #else
259 mov dx,#0x80
260 mov ax,#?1
261 out dx,al
262 #endif
263 MEND
265 MACRO JMP_AP
266 db 0xea
267 dw ?2
268 dw ?1
269 MEND
271 MACRO SET_INT_VECTOR
272 mov ax, ?3
273 mov ?1*4, ax
274 mov ax, ?2
275 mov ?1*4+2, ax
276 MEND
278 ASM_END
280 typedef unsigned char Bit8u;
281 typedef unsigned short Bit16u;
282 typedef unsigned short bx_bool;
283 typedef unsigned long Bit32u;
286 void memsetb(seg,offset,value,count);
287 void memcpyb(dseg,doffset,sseg,soffset,count);
288 void memcpyd(dseg,doffset,sseg,soffset,count);
290 // memset of count bytes
291 void
292 memsetb(seg,offset,value,count)
293 Bit16u seg;
294 Bit16u offset;
295 Bit16u value;
296 Bit16u count;
297 {
298 ASM_START
299 push bp
300 mov bp, sp
302 push ax
303 push cx
304 push es
305 push di
307 mov cx, 10[bp] ; count
308 cmp cx, #0x00
309 je memsetb_end
310 mov ax, 4[bp] ; segment
311 mov es, ax
312 mov ax, 6[bp] ; offset
313 mov di, ax
314 mov al, 8[bp] ; value
315 cld
316 rep
317 stosb
319 memsetb_end:
320 pop di
321 pop es
322 pop cx
323 pop ax
325 pop bp
326 ASM_END
327 }
329 // memcpy of count bytes
330 void
331 memcpyb(dseg,doffset,sseg,soffset,count)
332 Bit16u dseg;
333 Bit16u doffset;
334 Bit16u sseg;
335 Bit16u soffset;
336 Bit16u count;
337 {
338 ASM_START
339 push bp
340 mov bp, sp
342 push ax
343 push cx
344 push es
345 push di
346 push ds
347 push si
349 mov cx, 12[bp] ; count
350 cmp cx, #0x0000
351 je memcpyb_end
352 mov ax, 4[bp] ; dsegment
353 mov es, ax
354 mov ax, 6[bp] ; doffset
355 mov di, ax
356 mov ax, 8[bp] ; ssegment
357 mov ds, ax
358 mov ax, 10[bp] ; soffset
359 mov si, ax
360 cld
361 rep
362 movsb
364 memcpyb_end:
365 pop si
366 pop ds
367 pop di
368 pop es
369 pop cx
370 pop ax
372 pop bp
373 ASM_END
374 }
376 #if 0
377 // memcpy of count dword
378 void
379 memcpyd(dseg,doffset,sseg,soffset,count)
380 Bit16u dseg;
381 Bit16u doffset;
382 Bit16u sseg;
383 Bit16u soffset;
384 Bit16u count;
385 {
386 ASM_START
387 push bp
388 mov bp, sp
390 push ax
391 push cx
392 push es
393 push di
394 push ds
395 push si
397 mov cx, 12[bp] ; count
398 cmp cx, #0x0000
399 je memcpyd_end
400 mov ax, 4[bp] ; dsegment
401 mov es, ax
402 mov ax, 6[bp] ; doffset
403 mov di, ax
404 mov ax, 8[bp] ; ssegment
405 mov ds, ax
406 mov ax, 10[bp] ; soffset
407 mov si, ax
408 cld
409 rep
410 movsd
412 memcpyd_end:
413 pop si
414 pop ds
415 pop di
416 pop es
417 pop cx
418 pop ax
420 pop bp
421 ASM_END
422 }
423 #endif
425 // read_dword and write_dword functions
426 static Bit32u read_dword();
427 static void write_dword();
429 Bit32u
430 read_dword(seg, offset)
431 Bit16u seg;
432 Bit16u offset;
433 {
434 ASM_START
435 push bp
436 mov bp, sp
438 push bx
439 push ds
440 mov ax, 4[bp] ; segment
441 mov ds, ax
442 mov bx, 6[bp] ; offset
443 mov ax, [bx]
444 inc bx
445 inc bx
446 mov dx, [bx]
447 ;; ax = return value (word)
448 ;; dx = return value (word)
449 pop ds
450 pop bx
452 pop bp
453 ASM_END
454 }
456 void
457 write_dword(seg, offset, data)
458 Bit16u seg;
459 Bit16u offset;
460 Bit32u data;
461 {
462 ASM_START
463 push bp
464 mov bp, sp
466 push ax
467 push bx
468 push ds
469 mov ax, 4[bp] ; segment
470 mov ds, ax
471 mov bx, 6[bp] ; offset
472 mov ax, 8[bp] ; data word
473 mov [bx], ax ; write data word
474 inc bx
475 inc bx
476 mov ax, 10[bp] ; data word
477 mov [bx], ax ; write data word
478 pop ds
479 pop bx
480 pop ax
482 pop bp
483 ASM_END
484 }
486 // Bit32u (unsigned long) and long helper functions
487 ASM_START
489 ;; and function
490 landl:
491 landul:
492 SEG SS
493 and ax,[di]
494 SEG SS
495 and bx,2[di]
496 ret
498 ;; add function
499 laddl:
500 laddul:
501 SEG SS
502 add ax,[di]
503 SEG SS
504 adc bx,2[di]
505 ret
507 ;; cmp function
508 lcmpl:
509 lcmpul:
510 and eax, #0x0000FFFF
511 shl ebx, #16
512 add eax, ebx
513 shr ebx, #16
514 SEG SS
515 cmp eax, dword ptr [di]
516 ret
518 ;; sub function
519 lsubl:
520 lsubul:
521 SEG SS
522 sub ax,[di]
523 SEG SS
524 sbb bx,2[di]
525 ret
527 ;; mul function
528 lmull:
529 lmulul:
530 and eax, #0x0000FFFF
531 shl ebx, #16
532 add eax, ebx
533 SEG SS
534 mul eax, dword ptr [di]
535 mov ebx, eax
536 shr ebx, #16
537 ret
539 ;; dec function
540 ldecl:
541 ldecul:
542 SEG SS
543 dec dword ptr [bx]
544 ret
546 ;; or function
547 lorl:
548 lorul:
549 SEG SS
550 or ax,[di]
551 SEG SS
552 or bx,2[di]
553 ret
555 ;; inc function
556 lincl:
557 lincul:
558 SEG SS
559 inc dword ptr [bx]
560 ret
562 ;; tst function
563 ltstl:
564 ltstul:
565 and eax, #0x0000FFFF
566 shl ebx, #16
567 add eax, ebx
568 shr ebx, #16
569 test eax, eax
570 ret
572 ;; sr function
573 lsrul:
574 mov cx,di
575 jcxz lsr_exit
576 and eax, #0x0000FFFF
577 shl ebx, #16
578 add eax, ebx
579 lsr_loop:
580 shr eax, #1
581 loop lsr_loop
582 mov ebx, eax
583 shr ebx, #16
584 lsr_exit:
585 ret
587 ;; sl function
588 lsll:
589 lslul:
590 mov cx,di
591 jcxz lsl_exit
592 and eax, #0x0000FFFF
593 shl ebx, #16
594 add eax, ebx
595 lsl_loop:
596 shl eax, #1
597 loop lsl_loop
598 mov ebx, eax
599 shr ebx, #16
600 lsl_exit:
601 ret
603 idiv_:
604 cwd
605 idiv bx
606 ret
608 idiv_u:
609 xor dx,dx
610 div bx
611 ret
613 ldivul:
614 and eax, #0x0000FFFF
615 shl ebx, #16
616 add eax, ebx
617 xor edx, edx
618 SEG SS
619 mov bx, 2[di]
620 shl ebx, #16
621 SEG SS
622 mov bx, [di]
623 div ebx
624 mov ebx, eax
625 shr ebx, #16
626 ret
628 ASM_END
630 // for access to RAM area which is used by interrupt vectors
631 // and BIOS Data Area
633 typedef struct {
634 unsigned char filler1[0x400];
635 unsigned char filler2[0x6c];
636 Bit16u ticks_low;
637 Bit16u ticks_high;
638 Bit8u midnight_flag;
639 } bios_data_t;
641 #define BiosData ((bios_data_t *) 0)
643 #if BX_USE_ATADRV
644 typedef struct {
645 Bit16u heads; // # heads
646 Bit16u cylinders; // # cylinders
647 Bit16u spt; // # sectors / track
648 } chs_t;
650 // DPTE definition
651 typedef struct {
652 Bit16u iobase1;
653 Bit16u iobase2;
654 Bit8u prefix;
655 Bit8u unused;
656 Bit8u irq;
657 Bit8u blkcount;
658 Bit8u dma;
659 Bit8u pio;
660 Bit16u options;
661 Bit16u reserved;
662 Bit8u revision;
663 Bit8u checksum;
664 } dpte_t;
666 typedef struct {
667 Bit8u iface; // ISA or PCI
668 Bit16u iobase1; // IO Base 1
669 Bit16u iobase2; // IO Base 2
670 Bit8u irq; // IRQ
671 } ata_channel_t;
673 typedef struct {
674 Bit8u type; // Detected type of ata (ata/atapi/none/unknown)
675 Bit8u device; // Detected type of attached devices (hd/cd/none)
676 Bit8u removable; // Removable device flag
677 Bit8u lock; // Locks for removable devices
678 // Bit8u lba_capable; // LBA capable flag - always yes for bochs devices
679 Bit8u mode; // transfert mode : PIO 16/32 bits - IRQ - ISADMA - PCIDMA
680 Bit16u blksize; // block size
682 Bit8u translation; // type of translation
683 chs_t lchs; // Logical CHS
684 chs_t pchs; // Physical CHS
686 Bit32u sectors; // Total sectors count
687 } ata_device_t;
689 typedef struct {
690 // ATA channels info
691 ata_channel_t channels[BX_MAX_ATA_INTERFACES];
693 // ATA devices info
694 ata_device_t devices[BX_MAX_ATA_DEVICES];
695 //
696 // map between (bios hd id - 0x80) and ata channels
697 Bit8u hdcount, hdidmap[BX_MAX_ATA_DEVICES];
699 // map between (bios cd id - 0xE0) and ata channels
700 Bit8u cdcount, cdidmap[BX_MAX_ATA_DEVICES];
702 // Buffer for DPTE table
703 dpte_t dpte;
705 // Count of transferred sectors and bytes
706 Bit16u trsfsectors;
707 Bit32u trsfbytes;
709 } ata_t;
711 #if BX_ELTORITO_BOOT
712 // ElTorito Device Emulation data
713 typedef struct {
714 Bit8u active;
715 Bit8u media;
716 Bit8u emulated_drive;
717 Bit8u controller_index;
718 Bit16u device_spec;
719 Bit32u ilba;
720 Bit16u buffer_segment;
721 Bit16u load_segment;
722 Bit16u sector_count;
724 // Virtual device
725 chs_t vdevice;
726 } cdemu_t;
727 #endif // BX_ELTORITO_BOOT
729 #include "32bitgateway.h"
731 // for access to EBDA area
732 // The EBDA structure should conform to
733 // http://www.cybertrails.com/~fys/rombios.htm document
734 // I made the ata and cdemu structs begin at 0x121 in the EBDA seg
735 // EBDA must be at most 768 bytes; it lives at 0x9fc00, and the boot
736 // device tables are at 0x9ff00 -- 0x9ffff
737 typedef struct {
738 unsigned char filler1[0x3D];
740 // FDPT - Can be splitted in data members if needed
741 unsigned char fdpt0[0x10];
742 unsigned char fdpt1[0x10];
744 unsigned char filler2[0xC4];
746 // ATA Driver data
747 ata_t ata;
749 #if BX_ELTORITO_BOOT
750 // El Torito Emulation data
751 cdemu_t cdemu;
752 #endif // BX_ELTORITO_BOOT
754 upcall_t upcall;
755 } ebda_data_t;
757 #define EbdaData ((ebda_data_t *) 0)
759 // for access to the int13ext structure
760 typedef struct {
761 Bit8u size;
762 Bit8u reserved;
763 Bit16u count;
764 Bit16u offset;
765 Bit16u segment;
766 Bit32u lba1;
767 Bit32u lba2;
768 } int13ext_t;
770 #define Int13Ext ((int13ext_t *) 0)
772 // Disk Physical Table definition
773 typedef struct {
774 Bit16u size;
775 Bit16u infos;
776 Bit32u cylinders;
777 Bit32u heads;
778 Bit32u spt;
779 Bit32u sector_count1;
780 Bit32u sector_count2;
781 Bit16u blksize;
782 Bit16u dpte_offset;
783 Bit16u dpte_segment;
784 Bit16u key;
785 Bit8u dpi_length;
786 Bit8u reserved1;
787 Bit16u reserved2;
788 Bit8u host_bus[4];
789 Bit8u iface_type[8];
790 Bit8u iface_path[8];
791 Bit8u device_path[8];
792 Bit8u reserved3;
793 Bit8u checksum;
794 } dpt_t;
796 #define Int13DPT ((dpt_t *) 0)
798 #endif // BX_USE_ATADRV
800 typedef struct {
801 union {
802 struct {
803 Bit16u di, si, bp, sp;
804 Bit16u bx, dx, cx, ax;
805 } r16;
806 struct {
807 Bit16u filler[4];
808 Bit8u bl, bh, dl, dh, cl, ch, al, ah;
809 } r8;
810 } u;
811 } pusha_regs_t;
813 typedef struct {
814 union {
815 struct {
816 Bit32u edi, esi, ebp, esp;
817 Bit32u ebx, edx, ecx, eax;
818 } r32;
819 struct {
820 Bit16u di, filler1, si, filler2, bp, filler3, sp, filler4;
821 Bit16u bx, filler5, dx, filler6, cx, filler7, ax, filler8;
822 } r16;
823 struct {
824 Bit32u filler[4];
825 Bit8u bl, bh;
826 Bit16u filler1;
827 Bit8u dl, dh;
828 Bit16u filler2;
829 Bit8u cl, ch;
830 Bit16u filler3;
831 Bit8u al, ah;
832 Bit16u filler4;
833 } r8;
834 } u;
835 } pushad_regs_t;
837 typedef struct {
838 union {
839 struct {
840 Bit16u flags;
841 } r16;
842 struct {
843 Bit8u flagsl;
844 Bit8u flagsh;
845 } r8;
846 } u;
847 } flags_t;
849 #define SetCF(x) x.u.r8.flagsl |= 0x01
850 #define SetZF(x) x.u.r8.flagsl |= 0x40
851 #define ClearCF(x) x.u.r8.flagsl &= 0xfe
852 #define ClearZF(x) x.u.r8.flagsl &= 0xbf
853 #define GetCF(x) (x.u.r8.flagsl & 0x01)
855 typedef struct {
856 Bit16u ip;
857 Bit16u cs;
858 flags_t flags;
859 } iret_addr_t;
863 static Bit8u inb();
864 static Bit8u inb_cmos();
865 static void outb();
866 static void outb_cmos();
867 static Bit16u inw();
868 static void outw();
869 static void init_rtc();
870 static bx_bool rtc_updating();
872 static Bit8u read_byte();
873 static Bit16u read_word();
874 static void write_byte();
875 static void write_word();
876 static void bios_printf();
877 static void copy_e820_table();
879 static Bit8u inhibit_mouse_int_and_events();
880 static void enable_mouse_int_and_events();
881 static Bit8u send_to_mouse_ctrl();
882 static Bit8u get_mouse_data();
883 static void set_kbd_command_byte();
885 static void int09_function();
886 static void int13_harddisk();
887 static void int13_cdrom();
888 static void int13_cdemu();
889 static void int13_eltorito();
890 static void int13_diskette_function();
891 static void int14_function();
892 static void int15_function();
893 static void int16_function();
894 static void int17_function();
895 static void int18_function();
896 static void int1a_function();
897 static void int70_function();
898 static void int74_function();
899 static Bit16u get_CS();
900 //static Bit16u get_DS();
901 //static void set_DS();
902 static Bit16u get_SS();
903 static unsigned int enqueue_key();
904 static unsigned int dequeue_key();
905 static void get_hd_geometry();
906 static void set_diskette_ret_status();
907 static void set_diskette_current_cyl();
908 static void determine_floppy_media();
909 static bx_bool floppy_drive_exists();
910 static bx_bool floppy_drive_recal();
911 static bx_bool floppy_media_known();
912 static bx_bool floppy_media_sense();
913 static bx_bool set_enable_a20();
914 static void debugger_on();
915 static void debugger_off();
916 static void keyboard_init();
917 static void keyboard_panic();
918 static void shutdown_status_panic();
919 static void nmi_handler_msg();
921 static void print_bios_banner();
922 static void print_boot_device();
923 static void print_boot_failure();
924 static void print_cdromboot_failure();
926 # if BX_USE_ATADRV
928 // ATA / ATAPI driver
929 void ata_init();
930 void ata_detect();
931 void ata_reset();
933 Bit16u ata_cmd_non_data();
934 Bit16u ata_cmd_data_in();
935 Bit16u ata_cmd_data_out();
936 Bit16u ata_cmd_packet();
938 Bit16u atapi_get_sense();
939 Bit16u atapi_is_ready();
940 Bit16u atapi_is_cdrom();
942 #endif // BX_USE_ATADRV
944 #if BX_ELTORITO_BOOT
946 void cdemu_init();
947 Bit8u cdemu_isactive();
948 Bit8u cdemu_emulated_drive();
950 Bit16u cdrom_boot();
952 #endif // BX_ELTORITO_BOOT
954 static char bios_cvs_version_string[] = "$Revision: 1.138 $";
955 static char bios_date_string[] = "$Date: 2005/05/07 15:55:26 $";
957 static char CVSID[] = "$Id: rombios.c,v 1.138 2005/05/07 15:55:26 vruppert Exp $";
959 /* Offset to skip the CVS $Id: prefix */
960 #define bios_version_string (CVSID + 4)
962 #define BIOS_PRINTF_HALT 1
963 #define BIOS_PRINTF_SCREEN 2
964 #define BIOS_PRINTF_INFO 4
965 #define BIOS_PRINTF_DEBUG 8
966 #define BIOS_PRINTF_ALL (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO)
967 #define BIOS_PRINTF_DEBHALT (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO | BIOS_PRINTF_HALT)
969 #define printf(format, p...) bios_printf(BIOS_PRINTF_SCREEN, format, ##p)
971 // Defines the output macros.
972 // BX_DEBUG goes to INFO port until we can easily choose debug info on a
973 // per-device basis. Debug info are sent only in debug mode
974 #if DEBUG_ROMBIOS
975 # define BX_DEBUG(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
976 #else
977 # define BX_DEBUG(format, p...)
978 #endif
979 #define BX_INFO(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
980 #define BX_PANIC(format, p...) bios_printf(BIOS_PRINTF_DEBHALT, format, ##p)
982 #if DEBUG_ATA
983 # define BX_DEBUG_ATA(a...) BX_DEBUG(a)
984 #else
985 # define BX_DEBUG_ATA(a...)
986 #endif
987 #if DEBUG_INT13_HD
988 # define BX_DEBUG_INT13_HD(a...) BX_DEBUG(a)
989 #else
990 # define BX_DEBUG_INT13_HD(a...)
991 #endif
992 #if DEBUG_INT13_CD
993 # define BX_DEBUG_INT13_CD(a...) BX_DEBUG(a)
994 #else
995 # define BX_DEBUG_INT13_CD(a...)
996 #endif
997 #if DEBUG_INT13_ET
998 # define BX_DEBUG_INT13_ET(a...) BX_DEBUG(a)
999 #else
1000 # define BX_DEBUG_INT13_ET(a...)
1001 #endif
1002 #if DEBUG_INT13_FL
1003 # define BX_DEBUG_INT13_FL(a...) BX_DEBUG(a)
1004 #else
1005 # define BX_DEBUG_INT13_FL(a...)
1006 #endif
1007 #if DEBUG_INT15
1008 # define BX_DEBUG_INT15(a...) BX_DEBUG(a)
1009 #else
1010 # define BX_DEBUG_INT15(a...)
1011 #endif
1012 #if DEBUG_INT16
1013 # define BX_DEBUG_INT16(a...) BX_DEBUG(a)
1014 #else
1015 # define BX_DEBUG_INT16(a...)
1016 #endif
1017 #if DEBUG_INT1A
1018 # define BX_DEBUG_INT1A(a...) BX_DEBUG(a)
1019 #else
1020 # define BX_DEBUG_INT1A(a...)
1021 #endif
1022 #if DEBUG_INT74
1023 # define BX_DEBUG_INT74(a...) BX_DEBUG(a)
1024 #else
1025 # define BX_DEBUG_INT74(a...)
1026 #endif
1028 #define SET_AL(val8) AX = ((AX & 0xff00) | (val8))
1029 #define SET_BL(val8) BX = ((BX & 0xff00) | (val8))
1030 #define SET_CL(val8) CX = ((CX & 0xff00) | (val8))
1031 #define SET_DL(val8) DX = ((DX & 0xff00) | (val8))
1032 #define SET_AH(val8) AX = ((AX & 0x00ff) | ((val8) << 8))
1033 #define SET_BH(val8) BX = ((BX & 0x00ff) | ((val8) << 8))
1034 #define SET_CH(val8) CX = ((CX & 0x00ff) | ((val8) << 8))
1035 #define SET_DH(val8) DX = ((DX & 0x00ff) | ((val8) << 8))
1037 #define GET_AL() ( AX & 0x00ff )
1038 #define GET_BL() ( BX & 0x00ff )
1039 #define GET_CL() ( CX & 0x00ff )
1040 #define GET_DL() ( DX & 0x00ff )
1041 #define GET_AH() ( AX >> 8 )
1042 #define GET_BH() ( BX >> 8 )
1043 #define GET_CH() ( CX >> 8 )
1044 #define GET_DH() ( DX >> 8 )
1046 #define GET_ELDL() ( ELDX & 0x00ff )
1047 #define GET_ELDH() ( ELDX >> 8 )
1049 #define SET_CF() FLAGS |= 0x0001
1050 #define CLEAR_CF() FLAGS &= 0xfffe
1051 #define GET_CF() (FLAGS & 0x0001)
1053 #define SET_ZF() FLAGS |= 0x0040
1054 #define CLEAR_ZF() FLAGS &= 0xffbf
1055 #define GET_ZF() (FLAGS & 0x0040)
1057 #define UNSUPPORTED_FUNCTION 0x86
1059 #define none 0
1060 #define MAX_SCAN_CODE 0x58
1062 static struct {
1063 Bit16u normal;
1064 Bit16u shift;
1065 Bit16u control;
1066 Bit16u alt;
1067 Bit8u lock_flags;
1068 } scan_to_scanascii[MAX_SCAN_CODE + 1] = {
1069 { none, none, none, none, none },
1070 { 0x011b, 0x011b, 0x011b, 0x0100, none }, /* escape */
1071 { 0x0231, 0x0221, none, 0x7800, none }, /* 1! */
1072 { 0x0332, 0x0340, 0x0300, 0x7900, none }, /* 2@ */
1073 { 0x0433, 0x0423, none, 0x7a00, none }, /* 3# */
1074 { 0x0534, 0x0524, none, 0x7b00, none }, /* 4$ */
1075 { 0x0635, 0x0625, none, 0x7c00, none }, /* 5% */
1076 { 0x0736, 0x075e, 0x071e, 0x7d00, none }, /* 6^ */
1077 { 0x0837, 0x0826, none, 0x7e00, none }, /* 7& */
1078 { 0x0938, 0x092a, none, 0x7f00, none }, /* 8* */
1079 { 0x0a39, 0x0a28, none, 0x8000, none }, /* 9( */
1080 { 0x0b30, 0x0b29, none, 0x8100, none }, /* 0) */
1081 { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200, none }, /* -_ */
1082 { 0x0d3d, 0x0d2b, none, 0x8300, none }, /* =+ */
1083 { 0x0e08, 0x0e08, 0x0e7f, none, none }, /* backspace */
1084 { 0x0f09, 0x0f00, none, none, none }, /* tab */
1085 { 0x1071, 0x1051, 0x1011, 0x1000, 0x40 }, /* Q */
1086 { 0x1177, 0x1157, 0x1117, 0x1100, 0x40 }, /* W */
1087 { 0x1265, 0x1245, 0x1205, 0x1200, 0x40 }, /* E */
1088 { 0x1372, 0x1352, 0x1312, 0x1300, 0x40 }, /* R */
1089 { 0x1474, 0x1454, 0x1414, 0x1400, 0x40 }, /* T */
1090 { 0x1579, 0x1559, 0x1519, 0x1500, 0x40 }, /* Y */
1091 { 0x1675, 0x1655, 0x1615, 0x1600, 0x40 }, /* U */
1092 { 0x1769, 0x1749, 0x1709, 0x1700, 0x40 }, /* I */
1093 { 0x186f, 0x184f, 0x180f, 0x1800, 0x40 }, /* O */
1094 { 0x1970, 0x1950, 0x1910, 0x1900, 0x40 }, /* P */
1095 { 0x1a5b, 0x1a7b, 0x1a1b, none, none }, /* [{ */
1096 { 0x1b5d, 0x1b7d, 0x1b1d, none, none }, /* ]} */
1097 { 0x1c0d, 0x1c0d, 0x1c0a, none, none }, /* Enter */
1098 { none, none, none, none, none }, /* L Ctrl */
1099 { 0x1e61, 0x1e41, 0x1e01, 0x1e00, 0x40 }, /* A */
1100 { 0x1f73, 0x1f53, 0x1f13, 0x1f00, 0x40 }, /* S */
1101 { 0x2064, 0x2044, 0x2004, 0x2000, 0x40 }, /* D */
1102 { 0x2166, 0x2146, 0x2106, 0x2100, 0x40 }, /* F */
1103 { 0x2267, 0x2247, 0x2207, 0x2200, 0x40 }, /* G */
1104 { 0x2368, 0x2348, 0x2308, 0x2300, 0x40 }, /* H */
1105 { 0x246a, 0x244a, 0x240a, 0x2400, 0x40 }, /* J */
1106 { 0x256b, 0x254b, 0x250b, 0x2500, 0x40 }, /* K */
1107 { 0x266c, 0x264c, 0x260c, 0x2600, 0x40 }, /* L */
1108 { 0x273b, 0x273a, none, none, none }, /* ;: */
1109 { 0x2827, 0x2822, none, none, none }, /* '" */
1110 { 0x2960, 0x297e, none, none, none }, /* `~ */
1111 { none, none, none, none, none }, /* L shift */
1112 { 0x2b5c, 0x2b7c, 0x2b1c, none, none }, /* |\ */
1113 { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, 0x40 }, /* Z */
1114 { 0x2d78, 0x2d58, 0x2d18, 0x2d00, 0x40 }, /* X */
1115 { 0x2e63, 0x2e43, 0x2e03, 0x2e00, 0x40 }, /* C */
1116 { 0x2f76, 0x2f56, 0x2f16, 0x2f00, 0x40 }, /* V */
1117 { 0x3062, 0x3042, 0x3002, 0x3000, 0x40 }, /* B */
1118 { 0x316e, 0x314e, 0x310e, 0x3100, 0x40 }, /* N */
1119 { 0x326d, 0x324d, 0x320d, 0x3200, 0x40 }, /* M */
1120 { 0x332c, 0x333c, none, none, none }, /* ,< */
1121 { 0x342e, 0x343e, none, none, none }, /* .> */
1122 { 0x352f, 0x353f, none, none, none }, /* /? */
1123 { none, none, none, none, none }, /* R Shift */
1124 { 0x372a, 0x372a, none, none, none }, /* * */
1125 { none, none, none, none, none }, /* L Alt */
1126 { 0x3920, 0x3920, 0x3920, 0x3920, none }, /* space */
1127 { none, none, none, none, none }, /* caps lock */
1128 { 0x3b00, 0x5400, 0x5e00, 0x6800, none }, /* F1 */
1129 { 0x3c00, 0x5500, 0x5f00, 0x6900, none }, /* F2 */
1130 { 0x3d00, 0x5600, 0x6000, 0x6a00, none }, /* F3 */
1131 { 0x3e00, 0x5700, 0x6100, 0x6b00, none }, /* F4 */
1132 { 0x3f00, 0x5800, 0x6200, 0x6c00, none }, /* F5 */
1133 { 0x4000, 0x5900, 0x6300, 0x6d00, none }, /* F6 */
1134 { 0x4100, 0x5a00, 0x6400, 0x6e00, none }, /* F7 */
1135 { 0x4200, 0x5b00, 0x6500, 0x6f00, none }, /* F8 */
1136 { 0x4300, 0x5c00, 0x6600, 0x7000, none }, /* F9 */
1137 { 0x4400, 0x5d00, 0x6700, 0x7100, none }, /* F10 */
1138 { none, none, none, none, none }, /* Num Lock */
1139 { none, none, none, none, none }, /* Scroll Lock */
1140 { 0x4700, 0x4737, 0x7700, none, 0x20 }, /* 7 Home */
1141 { 0x4800, 0x4838, none, none, 0x20 }, /* 8 UP */
1142 { 0x4900, 0x4939, 0x8400, none, 0x20 }, /* 9 PgUp */
1143 { 0x4a2d, 0x4a2d, none, none, none }, /* - */
1144 { 0x4b00, 0x4b34, 0x7300, none, 0x20 }, /* 4 Left */
1145 { 0x4c00, 0x4c35, none, none, 0x20 }, /* 5 */
1146 { 0x4d00, 0x4d36, 0x7400, none, 0x20 }, /* 6 Right */
1147 { 0x4e2b, 0x4e2b, none, none, none }, /* + */
1148 { 0x4f00, 0x4f31, 0x7500, none, 0x20 }, /* 1 End */
1149 { 0x5000, 0x5032, none, none, 0x20 }, /* 2 Down */
1150 { 0x5100, 0x5133, 0x7600, none, 0x20 }, /* 3 PgDn */
1151 { 0x5200, 0x5230, none, none, 0x20 }, /* 0 Ins */
1152 { 0x5300, 0x532e, none, none, 0x20 }, /* Del */
1153 { none, none, none, none, none }, /* ??? */
1154 { none, none, none, none, none }, /* ??? */
1155 { none, none, none, none, none }, /* ??? */
1156 { 0x8500, 0x8700, 0x8900, 0x8b00, none }, /* F11 */
1157 { 0x8600, 0x8800, 0x8a00, 0x8c00, none }, /* F12 */
1158 };
1160 Bit8u
1161 inb(port)
1162 Bit16u port;
1164 ASM_START
1165 push bp
1166 mov bp, sp
1168 push dx
1169 mov dx, 4[bp]
1170 in al, dx
1171 pop dx
1173 pop bp
1174 ASM_END
1177 #if BX_USE_ATADRV
1178 Bit16u
1179 inw(port)
1180 Bit16u port;
1182 ASM_START
1183 push bp
1184 mov bp, sp
1186 push dx
1187 mov dx, 4[bp]
1188 in ax, dx
1189 pop dx
1191 pop bp
1192 ASM_END
1194 #endif
1196 void
1197 outb(port, val)
1198 Bit16u port;
1199 Bit8u val;
1201 ASM_START
1202 push bp
1203 mov bp, sp
1205 push ax
1206 push dx
1207 mov dx, 4[bp]
1208 mov al, 6[bp]
1209 out dx, al
1210 pop dx
1211 pop ax
1213 pop bp
1214 ASM_END
1217 #if BX_USE_ATADRV
1218 void
1219 outw(port, val)
1220 Bit16u port;
1221 Bit16u val;
1223 ASM_START
1224 push bp
1225 mov bp, sp
1227 push ax
1228 push dx
1229 mov dx, 4[bp]
1230 mov ax, 6[bp]
1231 out dx, ax
1232 pop dx
1233 pop ax
1235 pop bp
1236 ASM_END
1238 #endif
1240 void
1241 outb_cmos(cmos_reg, val)
1242 Bit8u cmos_reg;
1243 Bit8u val;
1245 ASM_START
1246 push bp
1247 mov bp, sp
1249 mov al, 4[bp] ;; cmos_reg
1250 out 0x70, al
1251 mov al, 6[bp] ;; val
1252 out 0x71, al
1254 pop bp
1255 ASM_END
1258 Bit8u
1259 inb_cmos(cmos_reg)
1260 Bit8u cmos_reg;
1262 ASM_START
1263 push bp
1264 mov bp, sp
1266 mov al, 4[bp] ;; cmos_reg
1267 out 0x70, al
1268 in al, 0x71
1270 pop bp
1271 ASM_END
1274 void
1275 init_rtc()
1277 outb_cmos(0x0a, 0x26);
1278 outb_cmos(0x0b, 0x02);
1279 inb_cmos(0x0c);
1280 inb_cmos(0x0d);
1283 bx_bool
1284 rtc_updating()
1286 // This function checks to see if the update-in-progress bit
1287 // is set in CMOS Status Register A. If not, it returns 0.
1288 // If it is set, it tries to wait until there is a transition
1289 // to 0, and will return 0 if such a transition occurs. A 1
1290 // is returned only after timing out. The maximum period
1291 // that this bit should be set is constrained to 244useconds.
1292 // The count I use below guarantees coverage or more than
1293 // this time, with any reasonable IPS setting.
1295 Bit16u count;
1297 count = 25000;
1298 while (--count != 0) {
1299 if ( (inb_cmos(0x0a) & 0x80) == 0 )
1300 return(0);
1302 return(1); // update-in-progress never transitioned to 0
1306 Bit8u
1307 read_byte(seg, offset)
1308 Bit16u seg;
1309 Bit16u offset;
1311 ASM_START
1312 push bp
1313 mov bp, sp
1315 push bx
1316 push ds
1317 mov ax, 4[bp] ; segment
1318 mov ds, ax
1319 mov bx, 6[bp] ; offset
1320 mov al, [bx]
1321 ;; al = return value (byte)
1322 pop ds
1323 pop bx
1325 pop bp
1326 ASM_END
1329 Bit16u
1330 read_word(seg, offset)
1331 Bit16u seg;
1332 Bit16u offset;
1334 ASM_START
1335 push bp
1336 mov bp, sp
1338 push bx
1339 push ds
1340 mov ax, 4[bp] ; segment
1341 mov ds, ax
1342 mov bx, 6[bp] ; offset
1343 mov ax, [bx]
1344 ;; ax = return value (word)
1345 pop ds
1346 pop bx
1348 pop bp
1349 ASM_END
1352 void
1353 write_byte(seg, offset, data)
1354 Bit16u seg;
1355 Bit16u offset;
1356 Bit8u data;
1358 ASM_START
1359 push bp
1360 mov bp, sp
1362 push ax
1363 push bx
1364 push ds
1365 mov ax, 4[bp] ; segment
1366 mov ds, ax
1367 mov bx, 6[bp] ; offset
1368 mov al, 8[bp] ; data byte
1369 mov [bx], al ; write data byte
1370 pop ds
1371 pop bx
1372 pop ax
1374 pop bp
1375 ASM_END
1378 void
1379 write_word(seg, offset, data)
1380 Bit16u seg;
1381 Bit16u offset;
1382 Bit16u data;
1384 ASM_START
1385 push bp
1386 mov bp, sp
1388 push ax
1389 push bx
1390 push ds
1391 mov ax, 4[bp] ; segment
1392 mov ds, ax
1393 mov bx, 6[bp] ; offset
1394 mov ax, 8[bp] ; data word
1395 mov [bx], ax ; write data word
1396 pop ds
1397 pop bx
1398 pop ax
1400 pop bp
1401 ASM_END
1404 Bit16u
1405 get_CS()
1407 ASM_START
1408 mov ax, cs
1409 ASM_END
1412 // Bit16u
1413 //get_DS()
1414 //{
1415 //ASM_START
1416 // mov ax, ds
1417 //ASM_END
1418 //}
1419 //
1420 // void
1421 //set_DS(ds_selector)
1422 // Bit16u ds_selector;
1423 //{
1424 //ASM_START
1425 // push bp
1426 // mov bp, sp
1427 //
1428 // push ax
1429 // mov ax, 4[bp] ; ds_selector
1430 // mov ds, ax
1431 // pop ax
1432 //
1433 // pop bp
1434 //ASM_END
1435 //}
1437 Bit16u
1438 get_SS()
1440 ASM_START
1441 mov ax, ss
1442 ASM_END
1445 #ifdef HVMASSIST
1446 void
1447 copy_e820_table()
1449 Bit8u nr_entries = read_byte(0x9000, 0x1e8);
1450 Bit32u base_mem;
1451 if (nr_entries > 32)
1452 nr_entries = 32;
1453 write_word(0xe000, 0x8, nr_entries);
1454 memcpyb(0xe000, 0x10, 0x9000, 0x2d0, nr_entries * 0x14);
1455 /* Report the proper base memory size at address 0x0413: otherwise
1456 * non-e820 code will clobber things if BASE_MEM_IN_K is bigger than
1457 * the first e820 entry. Get the size by reading the second 64bit
1458 * field of the first e820 slot. */
1459 base_mem = read_dword(0x9000, 0x2d0 + 8);
1460 write_word(0x40, 0x13, base_mem >> 10);
1462 #endif /* HVMASSIST */
1464 #if BX_DEBUG_SERIAL
1465 /* serial debug port*/
1466 #define BX_DEBUG_PORT 0x03f8
1468 /* data */
1469 #define UART_RBR 0x00
1470 #define UART_THR 0x00
1472 /* control */
1473 #define UART_IER 0x01
1474 #define UART_IIR 0x02
1475 #define UART_FCR 0x02
1476 #define UART_LCR 0x03
1477 #define UART_MCR 0x04
1478 #define UART_DLL 0x00
1479 #define UART_DLM 0x01
1481 /* status */
1482 #define UART_LSR 0x05
1483 #define UART_MSR 0x06
1484 #define UART_SCR 0x07
1486 int uart_can_tx_byte(base_port)
1487 Bit16u base_port;
1489 return inb(base_port + UART_LSR) & 0x20;
1492 void uart_wait_to_tx_byte(base_port)
1493 Bit16u base_port;
1495 while (!uart_can_tx_byte(base_port));
1498 void uart_wait_until_sent(base_port)
1499 Bit16u base_port;
1501 while (!(inb(base_port + UART_LSR) & 0x40));
1504 void uart_tx_byte(base_port, data)
1505 Bit16u base_port;
1506 Bit8u data;
1508 uart_wait_to_tx_byte(base_port);
1509 outb(base_port + UART_THR, data);
1510 uart_wait_until_sent(base_port);
1512 #endif
1514 void
1515 wrch(c)
1516 Bit8u c;
1518 ASM_START
1519 push bp
1520 mov bp, sp
1522 push bx
1523 mov ah, #0x0e
1524 mov al, 4[bp]
1525 xor bx,bx
1526 int #0x10
1527 pop bx
1529 pop bp
1530 ASM_END
1533 void
1534 send(action, c)
1535 Bit16u action;
1536 Bit8u c;
1538 #if BX_DEBUG_SERIAL
1539 if (c == '\n') uart_tx_byte(BX_DEBUG_PORT, '\r');
1540 uart_tx_byte(BX_DEBUG_PORT, c);
1541 #endif
1542 #ifdef HVMASSIST
1543 outb(0xE9, c);
1544 #endif
1545 #if BX_VIRTUAL_PORTS
1546 if (action & BIOS_PRINTF_DEBUG) outb(DEBUG_PORT, c);
1547 if (action & BIOS_PRINTF_INFO) outb(INFO_PORT, c);
1548 #endif
1549 if (action & BIOS_PRINTF_SCREEN) {
1550 if (c == '\n') wrch('\r');
1551 wrch(c);
1555 void
1556 put_int(action, val, width, neg)
1557 Bit16u action;
1558 short val, width;
1559 bx_bool neg;
1561 short nval = val / 10;
1562 if (nval)
1563 put_int(action, nval, width - 1, neg);
1564 else {
1565 while (--width > 0) send(action, ' ');
1566 if (neg) send(action, '-');
1568 send(action, val - (nval * 10) + '0');
1571 void
1572 put_uint(action, val, width, neg)
1573 Bit16u action;
1574 unsigned short val;
1575 short width;
1576 bx_bool neg;
1578 unsigned short nval = val / 10;
1579 if (nval)
1580 put_uint(action, nval, width - 1, neg);
1581 else {
1582 while (--width > 0) send(action, ' ');
1583 if (neg) send(action, '-');
1585 send(action, val - (nval * 10) + '0');
1588 //--------------------------------------------------------------------------
1589 // bios_printf()
1590 // A compact variable argument printf function which prints its output via
1591 // an I/O port so that it can be logged by Bochs/Plex.
1592 // Currently, only %x is supported (or %02x, %04x, etc).
1593 //
1594 // Supports %[format_width][format]
1595 // where format can be d,x,c,s
1596 //--------------------------------------------------------------------------
1597 void
1598 bios_printf(action, s)
1599 Bit16u action;
1600 Bit8u *s;
1602 Bit8u c, format_char;
1603 bx_bool in_format;
1604 short i;
1605 Bit16u *arg_ptr;
1606 Bit16u arg_seg, arg, nibble, shift_count, format_width;
1608 arg_ptr = &s;
1609 arg_seg = get_SS();
1611 in_format = 0;
1612 format_width = 0;
1614 if ((action & BIOS_PRINTF_DEBHALT) == BIOS_PRINTF_DEBHALT) {
1615 #if BX_VIRTUAL_PORTS
1616 outb(PANIC_PORT2, 0x00);
1617 #endif
1618 bios_printf (BIOS_PRINTF_SCREEN, "FATAL: ");
1621 while (c = read_byte(get_CS(), s)) {
1622 if ( c == '%' ) {
1623 in_format = 1;
1624 format_width = 0;
1626 else if (in_format) {
1627 if ( (c>='0') && (c<='9') ) {
1628 format_width = (format_width * 10) + (c - '0');
1630 else {
1631 arg_ptr++; // increment to next arg
1632 arg = read_word(arg_seg, arg_ptr);
1633 if (c == 'x') {
1634 if (format_width == 0)
1635 format_width = 4;
1636 for (i=format_width-1; i>=0; i--) {
1637 nibble = (arg >> (4 * i)) & 0x000f;
1638 send (action, (nibble<=9)? (nibble+'0') : (nibble-10+'A'));
1641 else if (c == 'u') {
1642 put_uint(action, arg, format_width, 0);
1644 else if (c == 'd') {
1645 if (arg & 0x8000)
1646 put_int(action, -arg, format_width - 1, 1);
1647 else
1648 put_int(action, arg, format_width, 0);
1650 else if (c == 's') {
1651 bios_printf(action & (~BIOS_PRINTF_HALT), arg);
1653 else if (c == 'c') {
1654 send(action, arg);
1656 else
1657 BX_PANIC("bios_printf: unknown format\n");
1658 in_format = 0;
1661 else {
1662 send(action, c);
1664 s ++;
1667 if (action & BIOS_PRINTF_HALT) {
1668 // freeze in a busy loop.
1669 ASM_START
1670 cli
1671 halt2_loop:
1672 hlt
1673 jmp halt2_loop
1674 ASM_END
1678 //--------------------------------------------------------------------------
1679 // keyboard_init
1680 //--------------------------------------------------------------------------
1681 // this file is based on LinuxBIOS implementation of keyboard.c
1682 // could convert to #asm to gain space
1683 void
1684 keyboard_init()
1686 Bit16u max;
1688 /* ------------------- Flush buffers ------------------------*/
1689 /* Wait until buffer is empty */
1690 max=0xffff;
1691 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
1693 /* flush incoming keys */
1694 max=0x2000;
1695 while (--max > 0) {
1696 outb(0x80, 0x00);
1697 if (inb(0x64) & 0x01) {
1698 inb(0x60);
1699 max = 0x2000;
1703 // Due to timer issues, and if the IPS setting is > 15000000,
1704 // the incoming keys might not be flushed here. That will
1705 // cause a panic a few lines below. See sourceforge bug report :
1706 // [ 642031 ] FATAL: Keyboard RESET error:993
1708 /* ------------------- controller side ----------------------*/
1709 /* send cmd = 0xAA, self test 8042 */
1710 outb(0x64, 0xaa);
1712 /* Wait until buffer is empty */
1713 max=0xffff;
1714 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
1715 if (max==0x0) keyboard_panic(00);
1717 /* Wait for data */
1718 max=0xffff;
1719 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x01);
1720 if (max==0x0) keyboard_panic(01);
1722 /* read self-test result, 0x55 should be returned from 0x60 */
1723 if ((inb(0x60) != 0x55)){
1724 keyboard_panic(991);
1727 /* send cmd = 0xAB, keyboard interface test */
1728 outb(0x64,0xab);
1730 /* Wait until buffer is empty */
1731 max=0xffff;
1732 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x10);
1733 if (max==0x0) keyboard_panic(10);
1735 /* Wait for data */
1736 max=0xffff;
1737 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x11);
1738 if (max==0x0) keyboard_panic(11);
1740 /* read keyboard interface test result, */
1741 /* 0x00 should be returned form 0x60 */
1742 if ((inb(0x60) != 0x00)) {
1743 keyboard_panic(992);
1746 /* Enable Keyboard clock */
1747 outb(0x64,0xae);
1748 outb(0x64,0xa8);
1750 /* ------------------- keyboard side ------------------------*/
1751 /* reset kerboard and self test (keyboard side) */
1752 outb(0x60, 0xff);
1754 /* Wait until buffer is empty */
1755 max=0xffff;
1756 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x20);
1757 if (max==0x0) keyboard_panic(20);
1759 /* Wait for data */
1760 max=0xffff;
1761 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x21);
1762 if (max==0x0) keyboard_panic(21);
1764 /* keyboard should return ACK */
1765 if ((inb(0x60) != 0xfa)) {
1766 keyboard_panic(993);
1769 /* Wait for data */
1770 max=0xffff;
1771 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x31);
1772 if (max==0x0) keyboard_panic(31);
1774 if ((inb(0x60) != 0xaa)) {
1775 keyboard_panic(994);
1778 /* Disable keyboard */
1779 outb(0x60, 0xf5);
1781 /* Wait until buffer is empty */
1782 max=0xffff;
1783 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x40);
1784 if (max==0x0) keyboard_panic(40);
1786 /* Wait for data */
1787 max=0xffff;
1788 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x41);
1789 if (max==0x0) keyboard_panic(41);
1791 /* keyboard should return ACK */
1792 if ((inb(0x60) != 0xfa)) {
1793 keyboard_panic(995);
1796 /* Write Keyboard Mode */
1797 outb(0x64, 0x60);
1799 /* Wait until buffer is empty */
1800 max=0xffff;
1801 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x50);
1802 if (max==0x0) keyboard_panic(50);
1804 /* send cmd: scan code convert, disable mouse, enable IRQ 1 */
1805 outb(0x60, 0x61);
1807 /* Wait until buffer is empty */
1808 max=0xffff;
1809 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x60);
1810 if (max==0x0) keyboard_panic(60);
1812 /* Enable keyboard */
1813 outb(0x60, 0xf4);
1815 /* Wait until buffer is empty */
1816 max=0xffff;
1817 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x70);
1818 if (max==0x0) keyboard_panic(70);
1820 /* Wait for data */
1821 max=0xffff;
1822 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x71);
1823 if (max==0x0) keyboard_panic(70);
1825 /* keyboard should return ACK */
1826 if ((inb(0x60) != 0xfa)) {
1827 keyboard_panic(996);
1830 outb(0x80, 0x77);
1833 //--------------------------------------------------------------------------
1834 // keyboard_panic
1835 //--------------------------------------------------------------------------
1836 void
1837 keyboard_panic(status)
1838 Bit16u status;
1840 // If you're getting a 993 keyboard panic here,
1841 // please see the comment in keyboard_init
1843 BX_PANIC("Keyboard error:%u\n",status);
1846 //--------------------------------------------------------------------------
1847 // machine_reset
1848 //--------------------------------------------------------------------------
1849 void
1850 machine_reset()
1852 /* Frob the keyboard reset line to reset the processor */
1853 outb(0x64, 0x60); /* Map the flags register at data port (0x60) */
1854 outb(0x60, 0x14); /* Set the flags to system|disable */
1855 outb(0x64, 0xfe); /* Pulse output 0 (system reset) low */
1856 BX_PANIC("Couldn't reset the machine\n");
1859 //--------------------------------------------------------------------------
1860 // clobber_entry_point
1861 // Because PV drivers in HVM guests detach some of the emulated devices,
1862 // it is not safe to do a soft reboot by just dropping to real mode and
1863 // jumping at ffff:0000. -- the boot drives might have disappeared!
1864 // This rather foul function overwrites(!) the BIOS entry point
1865 // to point at machine-reset, which will cause the Xen tools to
1866 // rebuild the whole machine from scratch.
1867 //--------------------------------------------------------------------------
1868 void
1869 clobber_entry_point()
1871 /* The instruction at the entry point is one byte (0xea) for the
1872 * jump opcode, then two bytes of address, then two of segment.
1873 * Overwrite the address bytes.*/
1874 write_word(0xffff, 0x0001, machine_reset);
1878 //--------------------------------------------------------------------------
1879 // shutdown_status_panic
1880 // called when the shutdown statsu is not implemented, displays the status
1881 //--------------------------------------------------------------------------
1882 void
1883 shutdown_status_panic(status)
1884 Bit16u status;
1886 BX_PANIC("Unimplemented shutdown status: %02x\n",(Bit8u)status);
1889 //--------------------------------------------------------------------------
1890 // print_bios_banner
1891 // displays a the bios version
1892 //--------------------------------------------------------------------------
1893 void
1894 print_bios_banner()
1896 printf(BX_APPNAME" BIOS, %d cpu%s, ", BX_SMP_PROCESSORS, BX_SMP_PROCESSORS>1?"s":"");
1897 printf("%s %s\n", bios_cvs_version_string, bios_date_string);
1898 #if BX_TCGBIOS
1899 printf("TCG-enabled BIOS.\n");
1900 #endif
1901 printf("\n");
1905 //--------------------------------------------------------------------------
1906 // BIOS Boot Specification 1.0.1 compatibility
1907 //
1908 // Very basic support for the BIOS Boot Specification, which allows expansion
1909 // ROMs to register themselves as boot devices, instead of just stealing the
1910 // INT 19h boot vector.
1911 //
1912 // This is a hack: to do it properly requires a proper PnP BIOS and we aren't
1913 // one; we just lie to the option ROMs to make them behave correctly.
1914 // We also don't support letting option ROMs register as bootable disk
1915 // drives (BCVs), only as bootable devices (BEVs).
1916 //
1917 // http://www.phoenix.com/en/Customer+Services/White+Papers-Specs/pc+industry+specifications.htm
1918 //--------------------------------------------------------------------------
1920 /* 256 bytes at 0x9ff00 -- 0x9ffff is used for the IPL boot table. */
1921 #define IPL_SEG 0x9ff0
1922 #define IPL_TABLE_OFFSET 0x0000
1923 #define IPL_TABLE_ENTRIES 8
1924 #define IPL_COUNT_OFFSET 0x0080 /* u16: number of valid table entries */
1925 #define IPL_SEQUENCE_OFFSET 0x0082 /* u16: next boot device */
1927 struct ipl_entry {
1928 Bit16u type;
1929 Bit16u flags;
1930 Bit32u vector;
1931 Bit32u description;
1932 Bit32u reserved;
1933 };
1935 static void
1936 init_boot_vectors()
1938 struct ipl_entry e;
1939 Bit16u count = 0;
1940 Bit16u ss = get_SS();
1942 /* Clear out the IPL table. */
1943 memsetb(IPL_SEG, IPL_TABLE_OFFSET, 0, 0xff);
1945 /* Floppy drive */
1946 e.type = 1; e.flags = 0; e.vector = 0; e.description = 0; e.reserved = 0;
1947 memcpyb(IPL_SEG, IPL_TABLE_OFFSET + count * sizeof (e), ss, &e, sizeof (e));
1948 count++;
1950 /* First HDD */
1951 e.type = 2; e.flags = 0; e.vector = 0; e.description = 0; e.reserved = 0;
1952 memcpyb(IPL_SEG, IPL_TABLE_OFFSET + count * sizeof (e), ss, &e, sizeof (e));
1953 count++;
1955 #if BX_ELTORITO_BOOT
1956 /* CDROM */
1957 e.type = 3; e.flags = 0; e.vector = 0; e.description = 0; e.reserved = 0;
1958 memcpyb(IPL_SEG, IPL_TABLE_OFFSET + count * sizeof (e), ss, &e, sizeof (e));
1959 count++;
1960 #endif
1962 /* Remember how many devices we have */
1963 write_word(IPL_SEG, IPL_COUNT_OFFSET, count);
1964 /* Not tried booting anything yet */
1965 write_word(IPL_SEG, IPL_SEQUENCE_OFFSET, 0xffff);
1968 static Bit8u
1969 get_boot_vector(i, e)
1970 Bit16u i; struct ipl_entry *e;
1972 Bit16u count;
1973 Bit16u ss = get_SS();
1974 /* Get the count of boot devices, and refuse to overrun the array */
1975 count = read_word(IPL_SEG, IPL_COUNT_OFFSET);
1976 if (i >= count) return 0;
1977 /* OK to read this device */
1978 memcpyb(ss, e, IPL_SEG, IPL_TABLE_OFFSET + i * sizeof (*e), sizeof (*e));
1979 return 1;
1983 //--------------------------------------------------------------------------
1984 // print_boot_device
1985 // displays the boot device
1986 //--------------------------------------------------------------------------
1988 static char drivetypes[][10]={"", "Floppy","Hard Disk","CD-Rom", "Network"};
1990 void
1991 print_boot_device(type)
1992 Bit16u type;
1994 /* NIC appears as type 0x80 */
1995 if (type == 0x80 ) type = 0x4;
1996 if (type == 0 || type > 0x4) BX_PANIC("Bad drive type\n");
1997 printf("Booting from %s...\n", drivetypes[type]);
2000 //--------------------------------------------------------------------------
2001 // print_boot_failure
2002 // displays the reason why boot failed
2003 //--------------------------------------------------------------------------
2004 void
2005 print_boot_failure(type, reason)
2006 Bit16u type; Bit8u reason;
2008 if (type == 0 || type > 0x3) BX_PANIC("Bad drive type\n");
2010 printf("Boot from %s failed", drivetypes[type]);
2011 if (type < 4) {
2012 /* Report the reason too */
2013 if (reason==0)
2014 printf(": not a bootable disk");
2015 else
2016 printf(": could not read the boot disk");
2018 printf("\n");
2021 //--------------------------------------------------------------------------
2022 // print_cdromboot_failure
2023 // displays the reason why boot failed
2024 //--------------------------------------------------------------------------
2025 void
2026 print_cdromboot_failure( code )
2027 Bit16u code;
2029 bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "CDROM boot failure code : %04x\n",code);
2031 return;
2034 #define WAIT_HZ 18
2035 /**
2036 * Check for keystroke.
2037 * @returns True if keystroke available, False if not.
2038 */
2039 Bit8u check_for_keystroke()
2041 ASM_START
2042 mov ax, #0x100
2043 int #0x16
2044 jz no_key
2045 mov al, #1
2046 jmp done
2047 no_key:
2048 xor al, al
2049 done:
2050 ASM_END
2053 /**
2054 * Get keystroke.
2055 * @returns BIOS scan code.
2056 */
2057 Bit8u get_keystroke()
2059 ASM_START
2060 mov ax, #0x0
2061 int #0x16
2062 xchg ah, al
2063 ASM_END
2066 /**
2067 * Waits (sleeps) for the given number of ticks.
2068 * Checks for keystroke.
2070 * @returns BIOS scan code if available, 0 if not.
2071 * @param ticks Number of ticks to sleep.
2072 * @param stop_on_key Whether to stop immediately upon keypress.
2073 */
2074 Bit8u wait(ticks, stop_on_key)
2075 Bit16u ticks;
2076 Bit8u stop_on_key;
2078 long ticks_to_wait, delta;
2079 Bit32u prev_ticks, t;
2080 Bit8u scan_code = 0;
2082 /*
2083 * The 0:046c wraps around at 'midnight' according to a 18.2Hz clock.
2084 * We also have to be careful about interrupt storms.
2085 */
2086 ticks_to_wait = ticks;
2087 prev_ticks = read_dword(0x0, 0x46c);
2088 do
2090 t = read_dword(0x0, 0x46c);
2091 if (t > prev_ticks)
2093 delta = t - prev_ticks; /* The temp var is required or bcc screws up. */
2094 ticks_to_wait -= delta;
2096 else if (t < prev_ticks)
2097 ticks_to_wait -= t; /* wrapped */
2098 prev_ticks = t;
2100 if (check_for_keystroke())
2102 scan_code = get_keystroke();
2103 bios_printf(BIOS_PRINTF_DEBUG, "Key pressed: %x\n", scan_code);
2104 if (stop_on_key)
2105 return scan_code;
2107 } while (ticks_to_wait > 0);
2108 return scan_code;
2111 static void clearscreen() {
2112 /* Hide cursor, clear screen and move cursor to starting position */
2113 ASM_START
2114 push bx
2115 push cx
2116 push dx
2118 mov ax, #0x100
2119 mov cx, #0x1000
2120 int #0x10
2122 mov ax, #0x700
2123 mov bh, #7
2124 xor cx, cx
2125 mov dx, #0x184f
2126 int #0x10
2128 mov ax, #0x200
2129 xor bx, bx
2130 xor dx, dx
2131 int #0x10
2133 pop dx
2134 pop cx
2135 pop bx
2136 ASM_END
2139 int bootmenu(selected)
2140 int selected;
2142 Bit8u scode;
2143 int max;
2145 /* get the number of boot devices */
2146 max = read_word(IPL_SEG, IPL_COUNT_OFFSET);
2148 for(;;) {
2149 if (selected > max || selected < 1) selected = 1;
2150 clearscreen();
2151 bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "\n\n\n\n\n\n\n");
2152 bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, " Select boot device\n\n");
2153 bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, " 1. Floppy\n");
2154 bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, " 2. Hard drive\n");
2155 bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, " 3. CD-ROM\n");
2156 if (max == 4)
2157 bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, " 4. Network\n");
2158 bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "\n\n Currently selected: %d\n", selected);
2160 do {
2161 scode = wait(WAIT_HZ, 1);
2162 } while (scode == 0);
2163 switch(scode) {
2164 case 0x02:
2165 case 0x03:
2166 case 0x04:
2167 selected = scode - 1;
2168 break;
2169 case 0x05:
2170 if (max == 4)
2171 selected = scode -1 ;
2172 else
2173 scode = 0;
2174 break;
2175 case 0x48:
2176 selected -= 1;
2177 if (selected < 1)
2178 selected = 1;
2179 scode = 0;
2180 break;
2181 case 0x50:
2182 selected += 1;
2183 if (selected > max)
2184 selected = max;
2185 scode = 0;
2186 break;
2187 case 0x1c:
2188 break;
2189 default:
2190 scode = 0;
2191 break;
2193 if (scode != 0)
2194 break;
2197 switch (selected) {
2198 case 1:
2199 return 0x3D;
2200 case 2:
2201 return 0x3E;
2202 case 3:
2203 return 0x3F;
2204 case 4:
2205 return 0x58;
2206 default:
2207 return 0;
2211 void interactive_bootkey()
2213 Bit16u i;
2214 Bit8u scan = 0;
2216 bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "\n\nPress F10 to select boot device.\n");
2217 for (i = 3; i > 0; i--)
2219 scan = wait(WAIT_HZ, 0);
2220 switch (scan) {
2221 case 0x3D:
2222 case 0x3E:
2223 case 0x3F:
2224 case 0x58:
2225 break;
2226 case 0x44:
2227 scan = bootmenu(inb_cmos(0x3d) & 0x0f);
2228 break;
2229 default:
2230 scan = 0;
2231 break;
2233 if (scan != 0)
2234 break;
2237 /* set the default based on the keypress or menu */
2238 switch(scan) {
2239 case 0x3D:
2240 outb_cmos(0x3d, 0x01);
2241 break;
2242 case 0x3E:
2243 outb_cmos(0x3d, 0x02);
2244 break;
2245 case 0x3F:
2246 outb_cmos(0x3d, 0x03);
2247 break;
2248 case 0x58:
2249 outb_cmos(0x3d, 0x04);
2250 break;
2251 default:
2252 break;
2257 void
2258 nmi_handler_msg()
2260 BX_PANIC("NMI Handler called\n");
2263 void
2264 int18_panic_msg()
2266 BX_PANIC("INT18: BOOT FAILURE\n");
2269 void
2270 log_bios_start()
2272 #if BX_DEBUG_SERIAL
2273 outb(BX_DEBUG_PORT+UART_LCR, 0x03); /* setup for serial logging: 8N1 */
2274 #endif
2275 BX_INFO("%s\n", bios_version_string);
2278 bx_bool
2279 set_enable_a20(val)
2280 bx_bool val;
2282 Bit8u oldval;
2284 // Use PS2 System Control port A to set A20 enable
2286 // get current setting first
2287 oldval = inb(0x92);
2289 // change A20 status
2290 if (val)
2291 outb(0x92, oldval | 0x02);
2292 else
2293 outb(0x92, oldval & 0xfd);
2295 return((oldval & 0x02) != 0);
2298 void
2299 debugger_on()
2301 outb(0xfedc, 0x01);
2304 void
2305 debugger_off()
2307 outb(0xfedc, 0x00);
2310 #if BX_USE_ATADRV
2312 // ---------------------------------------------------------------------------
2313 // Start of ATA/ATAPI Driver
2314 // ---------------------------------------------------------------------------
2316 // Global defines -- ATA register and register bits.
2317 // command block & control block regs
2318 #define ATA_CB_DATA 0 // data reg in/out pio_base_addr1+0
2319 #define ATA_CB_ERR 1 // error in pio_base_addr1+1
2320 #define ATA_CB_FR 1 // feature reg out pio_base_addr1+1
2321 #define ATA_CB_SC 2 // sector count in/out pio_base_addr1+2
2322 #define ATA_CB_SN 3 // sector number in/out pio_base_addr1+3
2323 #define ATA_CB_CL 4 // cylinder low in/out pio_base_addr1+4
2324 #define ATA_CB_CH 5 // cylinder high in/out pio_base_addr1+5
2325 #define ATA_CB_DH 6 // device head in/out pio_base_addr1+6
2326 #define ATA_CB_STAT 7 // primary status in pio_base_addr1+7
2327 #define ATA_CB_CMD 7 // command out pio_base_addr1+7
2328 #define ATA_CB_ASTAT 6 // alternate status in pio_base_addr2+6
2329 #define ATA_CB_DC 6 // device control out pio_base_addr2+6
2330 #define ATA_CB_DA 7 // device address in pio_base_addr2+7
2332 #define ATA_CB_ER_ICRC 0x80 // ATA Ultra DMA bad CRC
2333 #define ATA_CB_ER_BBK 0x80 // ATA bad block
2334 #define ATA_CB_ER_UNC 0x40 // ATA uncorrected error
2335 #define ATA_CB_ER_MC 0x20 // ATA media change
2336 #define ATA_CB_ER_IDNF 0x10 // ATA id not found
2337 #define ATA_CB_ER_MCR 0x08 // ATA media change request
2338 #define ATA_CB_ER_ABRT 0x04 // ATA command aborted
2339 #define ATA_CB_ER_NTK0 0x02 // ATA track 0 not found
2340 #define ATA_CB_ER_NDAM 0x01 // ATA address mark not found
2342 #define ATA_CB_ER_P_SNSKEY 0xf0 // ATAPI sense key (mask)
2343 #define ATA_CB_ER_P_MCR 0x08 // ATAPI Media Change Request
2344 #define ATA_CB_ER_P_ABRT 0x04 // ATAPI command abort
2345 #define ATA_CB_ER_P_EOM 0x02 // ATAPI End of Media
2346 #define ATA_CB_ER_P_ILI 0x01 // ATAPI Illegal Length Indication
2348 // ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC)
2349 #define ATA_CB_SC_P_TAG 0xf8 // ATAPI tag (mask)
2350 #define ATA_CB_SC_P_REL 0x04 // ATAPI release
2351 #define ATA_CB_SC_P_IO 0x02 // ATAPI I/O
2352 #define ATA_CB_SC_P_CD 0x01 // ATAPI C/D
2354 // bits 7-4 of the device/head (CB_DH) reg
2355 #define ATA_CB_DH_DEV0 0xa0 // select device 0
2356 #define ATA_CB_DH_DEV1 0xb0 // select device 1
2358 // status reg (CB_STAT and CB_ASTAT) bits
2359 #define ATA_CB_STAT_BSY 0x80 // busy
2360 #define ATA_CB_STAT_RDY 0x40 // ready
2361 #define ATA_CB_STAT_DF 0x20 // device fault
2362 #define ATA_CB_STAT_WFT 0x20 // write fault (old name)
2363 #define ATA_CB_STAT_SKC 0x10 // seek complete
2364 #define ATA_CB_STAT_SERV 0x10 // service
2365 #define ATA_CB_STAT_DRQ 0x08 // data request
2366 #define ATA_CB_STAT_CORR 0x04 // corrected
2367 #define ATA_CB_STAT_IDX 0x02 // index
2368 #define ATA_CB_STAT_ERR 0x01 // error (ATA)
2369 #define ATA_CB_STAT_CHK 0x01 // check (ATAPI)
2371 // device control reg (CB_DC) bits
2372 #define ATA_CB_DC_HD15 0x08 // bit should always be set to one
2373 #define ATA_CB_DC_SRST 0x04 // soft reset
2374 #define ATA_CB_DC_NIEN 0x02 // disable interrupts
2376 // Most mandtory and optional ATA commands (from ATA-3),
2377 #define ATA_CMD_CFA_ERASE_SECTORS 0xC0
2378 #define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03
2379 #define ATA_CMD_CFA_TRANSLATE_SECTOR 0x87
2380 #define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD
2381 #define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38
2382 #define ATA_CMD_CHECK_POWER_MODE1 0xE5
2383 #define ATA_CMD_CHECK_POWER_MODE2 0x98
2384 #define ATA_CMD_DEVICE_RESET 0x08
2385 #define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90
2386 #define ATA_CMD_FLUSH_CACHE 0xE7
2387 #define ATA_CMD_FORMAT_TRACK 0x50
2388 #define ATA_CMD_IDENTIFY_DEVICE 0xEC
2389 #define ATA_CMD_IDENTIFY_DEVICE_PACKET 0xA1
2390 #define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xA1
2391 #define ATA_CMD_IDLE1 0xE3
2392 #define ATA_CMD_IDLE2 0x97
2393 #define ATA_CMD_IDLE_IMMEDIATE1 0xE1
2394 #define ATA_CMD_IDLE_IMMEDIATE2 0x95
2395 #define ATA_CMD_INITIALIZE_DRIVE_PARAMETERS 0x91
2396 #define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
2397 #define ATA_CMD_NOP 0x00
2398 #define ATA_CMD_PACKET 0xA0
2399 #define ATA_CMD_READ_BUFFER 0xE4
2400 #define ATA_CMD_READ_DMA 0xC8
2401 #define ATA_CMD_READ_DMA_QUEUED 0xC7
2402 #define ATA_CMD_READ_MULTIPLE 0xC4
2403 #define ATA_CMD_READ_SECTORS 0x20
2404 #define ATA_CMD_READ_VERIFY_SECTORS 0x40
2405 #define ATA_CMD_RECALIBRATE 0x10
2406 #define ATA_CMD_SEEK 0x70
2407 #define ATA_CMD_SET_FEATURES 0xEF
2408 #define ATA_CMD_SET_MULTIPLE_MODE 0xC6
2409 #define ATA_CMD_SLEEP1 0xE6
2410 #define ATA_CMD_SLEEP2 0x99
2411 #define ATA_CMD_STANDBY1 0xE2
2412 #define ATA_CMD_STANDBY2 0x96
2413 #define ATA_CMD_STANDBY_IMMEDIATE1 0xE0
2414 #define ATA_CMD_STANDBY_IMMEDIATE2 0x94
2415 #define ATA_CMD_WRITE_BUFFER 0xE8
2416 #define ATA_CMD_WRITE_DMA 0xCA
2417 #define ATA_CMD_WRITE_DMA_QUEUED 0xCC
2418 #define ATA_CMD_WRITE_MULTIPLE 0xC5
2419 #define ATA_CMD_WRITE_SECTORS 0x30
2420 #define ATA_CMD_WRITE_VERIFY 0x3C
2422 #define ATA_IFACE_NONE 0x00
2423 #define ATA_IFACE_ISA 0x00
2424 #define ATA_IFACE_PCI 0x01
2426 #define ATA_TYPE_NONE 0x00
2427 #define ATA_TYPE_UNKNOWN 0x01
2428 #define ATA_TYPE_ATA 0x02
2429 #define ATA_TYPE_ATAPI 0x03
2431 #define ATA_DEVICE_NONE 0x00
2432 #define ATA_DEVICE_HD 0xFF
2433 #define ATA_DEVICE_CDROM 0x05
2435 #define ATA_MODE_NONE 0x00
2436 #define ATA_MODE_PIO16 0x00
2437 #define ATA_MODE_PIO32 0x01
2438 #define ATA_MODE_ISADMA 0x02
2439 #define ATA_MODE_PCIDMA 0x03
2440 #define ATA_MODE_USEIRQ 0x10
2442 #define ATA_TRANSLATION_NONE 0
2443 #define ATA_TRANSLATION_LBA 1
2444 #define ATA_TRANSLATION_LARGE 2
2445 #define ATA_TRANSLATION_RECHS 3
2447 #define ATA_DATA_NO 0x00
2448 #define ATA_DATA_IN 0x01
2449 #define ATA_DATA_OUT 0x02
2451 // ---------------------------------------------------------------------------
2452 // ATA/ATAPI driver : initialization
2453 // ---------------------------------------------------------------------------
2454 void ata_init( )
2456 Bit16u ebda_seg=read_word(0x0040,0x000E);
2457 Bit8u channel, device;
2459 // Channels info init.
2460 for (channel=0; channel<BX_MAX_ATA_INTERFACES; channel++) {
2461 write_byte(ebda_seg,&EbdaData->ata.channels[channel].iface,ATA_IFACE_NONE);
2462 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1,0x0);
2463 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2,0x0);
2464 write_byte(ebda_seg,&EbdaData->ata.channels[channel].irq,0);
2467 // Devices info init.
2468 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2469 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
2470 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_NONE);
2471 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable,0);
2472 write_byte(ebda_seg,&EbdaData->ata.devices[device].lock,0);
2473 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode,ATA_MODE_NONE);
2474 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,0);
2475 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation,ATA_TRANSLATION_NONE);
2476 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads,0);
2477 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders,0);
2478 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt,0);
2479 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads,0);
2480 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders,0);
2481 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt,0);
2483 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors,0L);
2486 // hdidmap and cdidmap init.
2487 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2488 write_byte(ebda_seg,&EbdaData->ata.hdidmap[device],BX_MAX_ATA_DEVICES);
2489 write_byte(ebda_seg,&EbdaData->ata.cdidmap[device],BX_MAX_ATA_DEVICES);
2492 write_byte(ebda_seg,&EbdaData->ata.hdcount,0);
2493 write_byte(ebda_seg,&EbdaData->ata.cdcount,0);
2496 // ---------------------------------------------------------------------------
2497 // ATA/ATAPI driver : device detection
2498 // ---------------------------------------------------------------------------
2500 void ata_detect( )
2502 Bit16u ebda_seg=read_word(0x0040,0x000E);
2503 Bit8u hdcount, cdcount, device, type;
2504 Bit8u buffer[0x0200];
2506 #if BX_MAX_ATA_INTERFACES > 0
2507 write_byte(ebda_seg,&EbdaData->ata.channels[0].iface,ATA_IFACE_ISA);
2508 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase1,0x1f0);
2509 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase2,0x3f0);
2510 write_byte(ebda_seg,&EbdaData->ata.channels[0].irq,14);
2511 #endif
2512 #if BX_MAX_ATA_INTERFACES > 1
2513 write_byte(ebda_seg,&EbdaData->ata.channels[1].iface,ATA_IFACE_ISA);
2514 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase1,0x170);
2515 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase2,0x370);
2516 write_byte(ebda_seg,&EbdaData->ata.channels[1].irq,15);
2517 #endif
2518 #if BX_MAX_ATA_INTERFACES > 2
2519 write_byte(ebda_seg,&EbdaData->ata.channels[2].iface,ATA_IFACE_ISA);
2520 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase1,0x1e8);
2521 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase2,0x3e0);
2522 write_byte(ebda_seg,&EbdaData->ata.channels[2].irq,12);
2523 #endif
2524 #if BX_MAX_ATA_INTERFACES > 3
2525 write_byte(ebda_seg,&EbdaData->ata.channels[3].iface,ATA_IFACE_ISA);
2526 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase1,0x168);
2527 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase2,0x360);
2528 write_byte(ebda_seg,&EbdaData->ata.channels[3].irq,11);
2529 #endif
2530 #if BX_MAX_ATA_INTERFACES > 4
2531 #error Please fill the ATA interface informations
2532 #endif
2534 // Device detection
2535 hdcount=cdcount=0;
2537 for(device=0; device<BX_MAX_ATA_DEVICES; device++) {
2538 Bit16u iobase1, iobase2;
2539 Bit8u channel, slave, shift;
2540 Bit8u sc, sn, cl, ch, st;
2542 channel = device / 2;
2543 slave = device % 2;
2545 iobase1 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1);
2546 iobase2 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2);
2548 // Disable interrupts
2549 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2551 // Look for device
2552 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2553 outb(iobase1+ATA_CB_SC, 0x55);
2554 outb(iobase1+ATA_CB_SN, 0xaa);
2555 outb(iobase1+ATA_CB_SC, 0xaa);
2556 outb(iobase1+ATA_CB_SN, 0x55);
2557 outb(iobase1+ATA_CB_SC, 0x55);
2558 outb(iobase1+ATA_CB_SN, 0xaa);
2560 // If we found something
2561 sc = inb(iobase1+ATA_CB_SC);
2562 sn = inb(iobase1+ATA_CB_SN);
2564 if ( (sc == 0x55) && (sn == 0xaa) ) {
2565 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_UNKNOWN);
2567 // reset the channel
2568 ata_reset (device);
2570 // check for ATA or ATAPI
2571 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2572 sc = inb(iobase1+ATA_CB_SC);
2573 sn = inb(iobase1+ATA_CB_SN);
2574 if ( (sc==0x01) && (sn==0x01) ) {
2575 cl = inb(iobase1+ATA_CB_CL);
2576 ch = inb(iobase1+ATA_CB_CH);
2577 st = inb(iobase1+ATA_CB_STAT);
2579 if ( (cl==0x14) && (ch==0xeb) ) {
2580 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATAPI);
2582 else if ( (cl==0x00) && (ch==0x00) && (st!=0x00) ) {
2583 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATA);
2588 type=read_byte(ebda_seg,&EbdaData->ata.devices[device].type);
2590 // Now we send a IDENTIFY command to ATA device
2591 if(type == ATA_TYPE_ATA) {
2592 Bit32u sectors;
2593 Bit16u cylinders, heads, spt, blksize;
2594 Bit8u translation, removable, mode;
2596 // default mode to PIO16
2597 mode = ATA_MODE_PIO16;
2599 //Temporary values to do the transfer
2600 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2601 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2603 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE, 1, 0, 0, 0, 0L, get_SS(),buffer) !=0 )
2604 BX_PANIC("ata-detect: Failed to detect ATA device\n");
2606 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2607 #ifndef NO_PIO32
2608 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2609 #endif
2611 blksize = read_word(get_SS(),buffer+10);
2613 cylinders = read_word(get_SS(),buffer+(1*2)); // word 1
2614 heads = read_word(get_SS(),buffer+(3*2)); // word 3
2615 spt = read_word(get_SS(),buffer+(6*2)); // word 6
2617 sectors = read_dword(get_SS(),buffer+(60*2)); // word 60 and word 61
2619 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2620 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2621 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2622 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2623 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads, heads);
2624 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders, cylinders);
2625 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt, spt);
2626 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors, sectors);
2627 BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel, slave,cylinders, heads, spt);
2629 translation = inb_cmos(0x39 + channel/2);
2630 for (shift=device%4; shift>0; shift--) translation >>= 2;
2631 translation &= 0x03;
2633 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation, translation);
2635 switch (translation) {
2636 case ATA_TRANSLATION_NONE:
2637 BX_INFO("none");
2638 break;
2639 case ATA_TRANSLATION_LBA:
2640 BX_INFO("lba");
2641 break;
2642 case ATA_TRANSLATION_LARGE:
2643 BX_INFO("large");
2644 break;
2645 case ATA_TRANSLATION_RECHS:
2646 BX_INFO("r-echs");
2647 break;
2649 switch (translation) {
2650 case ATA_TRANSLATION_NONE:
2651 break;
2652 case ATA_TRANSLATION_LBA:
2653 spt = 63;
2654 sectors /= 63;
2655 heads = sectors / 1024;
2656 if (heads>128) heads = 255;
2657 else if (heads>64) heads = 128;
2658 else if (heads>32) heads = 64;
2659 else if (heads>16) heads = 32;
2660 else heads=16;
2661 cylinders = sectors / heads;
2662 break;
2663 case ATA_TRANSLATION_RECHS:
2664 // Take care not to overflow
2665 if (heads==16) {
2666 if(cylinders>61439) cylinders=61439;
2667 heads=15;
2668 cylinders = (Bit16u)((Bit32u)(cylinders)*16/15);
2670 // then go through the large bitshift process
2671 case ATA_TRANSLATION_LARGE:
2672 while(cylinders > 1024) {
2673 cylinders >>= 1;
2674 heads <<= 1;
2676 // If we max out the head count
2677 if (heads > 127) break;
2679 break;
2681 // clip to 1024 cylinders in lchs
2682 if (cylinders > 1024) cylinders=1024;
2683 BX_INFO(" LCHS=%d/%d/%d\n", cylinders, heads, spt);
2685 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, heads);
2686 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, cylinders);
2687 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, spt);
2689 // fill hdidmap
2690 write_byte(ebda_seg,&EbdaData->ata.hdidmap[hdcount], device);
2691 hdcount++;
2694 // Now we send a IDENTIFY command to ATAPI device
2695 if(type == ATA_TYPE_ATAPI) {
2697 Bit8u type, removable, mode;
2698 Bit16u blksize;
2700 // default mode to PIO16
2701 mode = ATA_MODE_PIO16;
2703 //Temporary values to do the transfer
2704 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_CDROM);
2705 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2707 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE_PACKET, 1, 0, 0, 0, 0L, get_SS(),buffer) != 0)
2708 BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
2710 type = read_byte(get_SS(),buffer+1) & 0x1f;
2711 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2712 #ifndef NO_PIO32
2713 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2714 #endif
2715 blksize = 2048;
2717 write_byte(ebda_seg,&EbdaData->ata.devices[device].device, type);
2718 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2719 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2720 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2722 // fill cdidmap
2723 write_byte(ebda_seg,&EbdaData->ata.cdidmap[cdcount], device);
2724 cdcount++;
2728 Bit32u sizeinmb;
2729 Bit16u ataversion;
2730 Bit8u c, i, version, model[41];
2732 switch (type) {
2733 case ATA_TYPE_ATA:
2734 sizeinmb = read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors);
2735 sizeinmb >>= 11;
2736 case ATA_TYPE_ATAPI:
2737 // Read ATA/ATAPI version
2738 ataversion=((Bit16u)(read_byte(get_SS(),buffer+161))<<8)|read_byte(get_SS(),buffer+160);
2739 for(version=15;version>0;version--) {
2740 if((ataversion&(1<<version))!=0)
2741 break;
2744 // Read model name
2745 for(i=0;i<20;i++){
2746 write_byte(get_SS(),model+(i*2),read_byte(get_SS(),buffer+(i*2)+54+1));
2747 write_byte(get_SS(),model+(i*2)+1,read_byte(get_SS(),buffer+(i*2)+54));
2750 // Reformat
2751 write_byte(get_SS(),model+40,0x00);
2752 for(i=39;i>0;i--){
2753 if(read_byte(get_SS(),model+i)==0x20)
2754 write_byte(get_SS(),model+i,0x00);
2755 else break;
2757 break;
2760 switch (type) {
2761 case ATA_TYPE_ATA:
2762 printf("ata%d %s: ",channel,slave?" slave":"master");
2763 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2764 if (sizeinmb < 1UL<<16)
2765 printf(" ATA-%d Hard-Disk (%04u MBytes)\n",version,(Bit16u)sizeinmb);
2766 else
2767 printf(" ATA-%d Hard-Disk (%04u GBytes)\n",version,(Bit16u)(sizeinmb>>10));
2768 break;
2769 case ATA_TYPE_ATAPI:
2770 printf("ata%d %s: ",channel,slave?" slave":"master");
2771 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2772 if(read_byte(ebda_seg,&EbdaData->ata.devices[device].device)==ATA_DEVICE_CDROM)
2773 printf(" ATAPI-%d CD-Rom/DVD-Rom\n",version);
2774 else
2775 printf(" ATAPI-%d Device\n",version);
2776 break;
2777 case ATA_TYPE_UNKNOWN:
2778 printf("ata%d %s: Unknown device\n",channel,slave?" slave":"master");
2779 break;
2784 // Store the devices counts
2785 write_byte(ebda_seg,&EbdaData->ata.hdcount, hdcount);
2786 write_byte(ebda_seg,&EbdaData->ata.cdcount, cdcount);
2787 write_byte(0x40,0x75, hdcount);
2789 printf("\n");
2791 // FIXME : should use bios=cmos|auto|disable bits
2792 // FIXME : should know about translation bits
2793 // FIXME : move hard_drive_post here
2797 // ---------------------------------------------------------------------------
2798 // ATA/ATAPI driver : software reset
2799 // ---------------------------------------------------------------------------
2800 // ATA-3
2801 // 8.2.1 Software reset - Device 0
2803 void ata_reset(device)
2804 Bit16u device;
2806 Bit16u ebda_seg=read_word(0x0040,0x000E);
2807 Bit16u iobase1, iobase2;
2808 Bit8u channel, slave, sn, sc;
2809 Bit16u max;
2811 channel = device / 2;
2812 slave = device % 2;
2814 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2815 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2817 // Reset
2819 // 8.2.1 (a) -- set SRST in DC
2820 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN | ATA_CB_DC_SRST);
2822 // 8.2.1 (b) -- wait for BSY
2823 max=0xff;
2824 while(--max>0) {
2825 Bit8u status = inb(iobase1+ATA_CB_STAT);
2826 if ((status & ATA_CB_STAT_BSY) != 0) break;
2829 // 8.2.1 (f) -- clear SRST
2830 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2832 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_NONE) {
2834 // 8.2.1 (g) -- check for sc==sn==0x01
2835 // select device
2836 outb(iobase1+ATA_CB_DH, slave?ATA_CB_DH_DEV1:ATA_CB_DH_DEV0);
2837 sc = inb(iobase1+ATA_CB_SC);
2838 sn = inb(iobase1+ATA_CB_SN);
2840 if ( (sc==0x01) && (sn==0x01) ) {
2842 // 8.2.1 (h) -- wait for not BSY
2843 max=0xff;
2844 while(--max>0) {
2845 Bit8u status = inb(iobase1+ATA_CB_STAT);
2846 if ((status & ATA_CB_STAT_BSY) == 0) break;
2851 // 8.2.1 (i) -- wait for DRDY
2852 max=0xfff;
2853 while(--max>0) {
2854 Bit8u status = inb(iobase1+ATA_CB_STAT);
2855 if ((status & ATA_CB_STAT_RDY) != 0) break;
2858 // Enable interrupts
2859 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2862 // ---------------------------------------------------------------------------
2863 // ATA/ATAPI driver : execute a non data command
2864 // ---------------------------------------------------------------------------
2866 Bit16u ata_cmd_non_data()
2867 {return 0;}
2869 // ---------------------------------------------------------------------------
2870 // ATA/ATAPI driver : execute a data-in command
2871 // ---------------------------------------------------------------------------
2872 // returns
2873 // 0 : no error
2874 // 1 : BUSY bit set
2875 // 2 : read error
2876 // 3 : expected DRQ=1
2877 // 4 : no sectors left to read/verify
2878 // 5 : more sectors to read/verify
2879 // 6 : no sectors left to write
2880 // 7 : more sectors to write
2881 Bit16u ata_cmd_data_in(device, command, count, cylinder, head, sector, lba, segment, offset)
2882 Bit16u device, command, count, cylinder, head, sector, segment, offset;
2883 Bit32u lba;
2885 Bit16u ebda_seg=read_word(0x0040,0x000E);
2886 Bit16u iobase1, iobase2, blksize;
2887 Bit8u channel, slave;
2888 Bit8u status, current, mode;
2890 channel = device / 2;
2891 slave = device % 2;
2893 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2894 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2895 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2896 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2897 if (mode == ATA_MODE_PIO32) blksize>>=2;
2898 else blksize>>=1;
2900 // Reset count of transferred data
2901 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2902 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2903 current = 0;
2905 status = inb(iobase1 + ATA_CB_STAT);
2906 if (status & ATA_CB_STAT_BSY) return 1;
2908 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2910 // sector will be 0 only on lba access. Convert to lba-chs
2911 if (sector == 0) {
2912 if ((count >= 1 << 8) || (lba + count >= 1UL << 28)) {
2913 outb(iobase1 + ATA_CB_FR, 0x00);
2914 outb(iobase1 + ATA_CB_SC, (count >> 8) & 0xff);
2915 outb(iobase1 + ATA_CB_SN, lba >> 24);
2916 outb(iobase1 + ATA_CB_CL, 0);
2917 outb(iobase1 + ATA_CB_CH, 0);
2918 command |= 0x04;
2919 count &= (1UL << 8) - 1;
2920 lba &= (1UL << 24) - 1;
2922 sector = (Bit16u) (lba & 0x000000ffL);
2923 lba >>= 8;
2924 cylinder = (Bit16u) (lba & 0x0000ffffL);
2925 lba >>= 16;
2926 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
2929 outb(iobase1 + ATA_CB_FR, 0x00);
2930 outb(iobase1 + ATA_CB_SC, count);
2931 outb(iobase1 + ATA_CB_SN, sector);
2932 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2933 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2934 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
2935 outb(iobase1 + ATA_CB_CMD, command);
2937 while (1) {
2938 status = inb(iobase1 + ATA_CB_STAT);
2939 if ( !(status & ATA_CB_STAT_BSY) ) break;
2942 if (status & ATA_CB_STAT_ERR) {
2943 BX_DEBUG_ATA("ata_cmd_data_in : read error\n");
2944 return 2;
2945 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2946 BX_DEBUG_ATA("ata_cmd_data_in : DRQ not set (status %02x)\n", (unsigned) status);
2947 return 3;
2950 // FIXME : move seg/off translation here
2952 ASM_START
2953 sti ;; enable higher priority interrupts
2954 ASM_END
2956 while (1) {
2958 ASM_START
2959 push bp
2960 mov bp, sp
2961 mov di, _ata_cmd_data_in.offset + 2[bp]
2962 mov ax, _ata_cmd_data_in.segment + 2[bp]
2963 mov cx, _ata_cmd_data_in.blksize + 2[bp]
2965 ;; adjust if there will be an overrun. 2K max sector size
2966 cmp di, #0xf800 ;;
2967 jbe ata_in_no_adjust
2969 ata_in_adjust:
2970 sub di, #0x0800 ;; sub 2 kbytes from offset
2971 add ax, #0x0080 ;; add 2 Kbytes to segment
2973 ata_in_no_adjust:
2974 mov es, ax ;; segment in es
2976 mov dx, _ata_cmd_data_in.iobase1 + 2[bp] ;; ATA data read port
2978 mov ah, _ata_cmd_data_in.mode + 2[bp]
2979 cmp ah, #ATA_MODE_PIO32
2980 je ata_in_32
2982 ata_in_16:
2983 rep
2984 insw ;; CX words transfered from port(DX) to ES:[DI]
2985 jmp ata_in_done
2987 ata_in_32:
2988 rep
2989 insd ;; CX dwords transfered from port(DX) to ES:[DI]
2991 ata_in_done:
2992 mov _ata_cmd_data_in.offset + 2[bp], di
2993 mov _ata_cmd_data_in.segment + 2[bp], es
2994 pop bp
2995 ASM_END
2997 current++;
2998 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
2999 count--;
3000 status = inb(iobase1 + ATA_CB_STAT);
3001 if (count == 0) {
3002 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3003 != ATA_CB_STAT_RDY ) {
3004 BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n", (unsigned) status);
3005 return 4;
3007 break;
3009 else {
3010 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3011 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3012 BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n", (unsigned) status);
3013 return 5;
3015 continue;
3018 // Enable interrupts
3019 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3020 return 0;
3023 // ---------------------------------------------------------------------------
3024 // ATA/ATAPI driver : execute a data-out command
3025 // ---------------------------------------------------------------------------
3026 // returns
3027 // 0 : no error
3028 // 1 : BUSY bit set
3029 // 2 : read error
3030 // 3 : expected DRQ=1
3031 // 4 : no sectors left to read/verify
3032 // 5 : more sectors to read/verify
3033 // 6 : no sectors left to write
3034 // 7 : more sectors to write
3035 Bit16u ata_cmd_data_out(device, command, count, cylinder, head, sector, lba, segment, offset)
3036 Bit16u device, command, count, cylinder, head, sector, segment, offset;
3037 Bit32u lba;
3039 Bit16u ebda_seg=read_word(0x0040,0x000E);
3040 Bit16u iobase1, iobase2, blksize;
3041 Bit8u channel, slave;
3042 Bit8u status, current, mode;
3044 channel = device / 2;
3045 slave = device % 2;
3047 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
3048 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
3049 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
3050 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
3051 if (mode == ATA_MODE_PIO32) blksize>>=2;
3052 else blksize>>=1;
3054 // Reset count of transferred data
3055 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
3056 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
3057 current = 0;
3059 status = inb(iobase1 + ATA_CB_STAT);
3060 if (status & ATA_CB_STAT_BSY) return 1;
3062 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
3064 // sector will be 0 only on lba access. Convert to lba-chs
3065 if (sector == 0) {
3066 if ((count >= 1 << 8) || (lba + count >= 1UL << 28)) {
3067 outb(iobase1 + ATA_CB_FR, 0x00);
3068 outb(iobase1 + ATA_CB_SC, (count >> 8) & 0xff);
3069 outb(iobase1 + ATA_CB_SN, lba >> 24);
3070 outb(iobase1 + ATA_CB_CL, 0);
3071 outb(iobase1 + ATA_CB_CH, 0);
3072 command |= 0x04;
3073 count &= (1UL << 8) - 1;
3074 lba &= (1UL << 24) - 1;
3076 sector = (Bit16u) (lba & 0x000000ffL);
3077 lba >>= 8;
3078 cylinder = (Bit16u) (lba & 0x0000ffffL);
3079 lba >>= 16;
3080 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
3083 outb(iobase1 + ATA_CB_FR, 0x00);
3084 outb(iobase1 + ATA_CB_SC, count);
3085 outb(iobase1 + ATA_CB_SN, sector);
3086 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
3087 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
3088 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
3089 outb(iobase1 + ATA_CB_CMD, command);
3091 while (1) {
3092 status = inb(iobase1 + ATA_CB_STAT);
3093 if ( !(status & ATA_CB_STAT_BSY) ) break;
3096 if (status & ATA_CB_STAT_ERR) {
3097 BX_DEBUG_ATA("ata_cmd_data_out : read error\n");
3098 return 2;
3099 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
3100 BX_DEBUG_ATA("ata_cmd_data_out : DRQ not set (status %02x)\n", (unsigned) status);
3101 return 3;
3104 // FIXME : move seg/off translation here
3106 ASM_START
3107 sti ;; enable higher priority interrupts
3108 ASM_END
3110 while (1) {
3112 ASM_START
3113 push bp
3114 mov bp, sp
3115 mov si, _ata_cmd_data_out.offset + 2[bp]
3116 mov ax, _ata_cmd_data_out.segment + 2[bp]
3117 mov cx, _ata_cmd_data_out.blksize + 2[bp]
3119 ;; adjust if there will be an overrun. 2K max sector size
3120 cmp si, #0xf800 ;;
3121 jbe ata_out_no_adjust
3123 ata_out_adjust:
3124 sub si, #0x0800 ;; sub 2 kbytes from offset
3125 add ax, #0x0080 ;; add 2 Kbytes to segment
3127 ata_out_no_adjust:
3128 mov es, ax ;; segment in es
3130 mov dx, _ata_cmd_data_out.iobase1 + 2[bp] ;; ATA data write port
3132 mov ah, _ata_cmd_data_out.mode + 2[bp]
3133 cmp ah, #ATA_MODE_PIO32
3134 je ata_out_32
3136 ata_out_16:
3137 seg ES
3138 rep
3139 outsw ;; CX words transfered from port(DX) to ES:[SI]
3140 jmp ata_out_done
3142 ata_out_32:
3143 seg ES
3144 rep
3145 outsd ;; CX dwords transfered from port(DX) to ES:[SI]
3147 ata_out_done:
3148 mov _ata_cmd_data_out.offset + 2[bp], si
3149 mov _ata_cmd_data_out.segment + 2[bp], es
3150 pop bp
3151 ASM_END
3153 current++;
3154 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
3155 count--;
3156 status = inb(iobase1 + ATA_CB_STAT);
3157 if (count == 0) {
3158 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3159 != ATA_CB_STAT_RDY ) {
3160 BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n", (unsigned) status);
3161 return 6;
3163 break;
3165 else {
3166 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3167 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3168 BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n", (unsigned) status);
3169 return 7;
3171 continue;
3174 // Enable interrupts
3175 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3176 return 0;
3179 // ---------------------------------------------------------------------------
3180 // ATA/ATAPI driver : execute a packet command
3181 // ---------------------------------------------------------------------------
3182 // returns
3183 // 0 : no error
3184 // 1 : error in parameters
3185 // 2 : BUSY bit set
3186 // 3 : error
3187 // 4 : not ready
3188 Bit16u ata_cmd_packet(device, cmdlen, cmdseg, cmdoff, header, length, inout, bufseg, bufoff)
3189 Bit8u cmdlen,inout;
3190 Bit16u device,cmdseg, cmdoff, bufseg, bufoff;
3191 Bit16u header;
3192 Bit32u length;
3194 Bit16u ebda_seg=read_word(0x0040,0x000E);
3195 Bit16u iobase1, iobase2;
3196 Bit16u lcount, lbefore, lafter, count;
3197 Bit8u channel, slave;
3198 Bit8u status, mode, lmode;
3199 Bit32u total, transfer;
3201 channel = device / 2;
3202 slave = device % 2;
3204 // Data out is not supported yet
3205 if (inout == ATA_DATA_OUT) {
3206 BX_INFO("ata_cmd_packet: DATA_OUT not supported yet\n");
3207 return 1;
3210 // The header length must be even
3211 if (header & 1) {
3212 BX_DEBUG_ATA("ata_cmd_packet : header must be even (%04x)\n",header);
3213 return 1;
3216 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
3217 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
3218 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
3219 transfer= 0L;
3221 if (cmdlen < 12) cmdlen=12;
3222 if (cmdlen > 12) cmdlen=16;
3223 cmdlen>>=1;
3225 // Reset count of transferred data
3226 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
3227 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
3229 status = inb(iobase1 + ATA_CB_STAT);
3230 if (status & ATA_CB_STAT_BSY) return 2;
3232 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
3233 // outb(iobase1 + ATA_CB_FR, 0x00);
3234 // outb(iobase1 + ATA_CB_SC, 0x00);
3235 // outb(iobase1 + ATA_CB_SN, 0x00);
3236 outb(iobase1 + ATA_CB_CL, 0xfff0 & 0x00ff);
3237 outb(iobase1 + ATA_CB_CH, 0xfff0 >> 8);
3238 outb(iobase1 + ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
3239 outb(iobase1 + ATA_CB_CMD, ATA_CMD_PACKET);
3241 // Device should ok to receive command
3242 while (1) {
3243 status = inb(iobase1 + ATA_CB_STAT);
3244 if ( !(status & ATA_CB_STAT_BSY) ) break;
3247 if (status & ATA_CB_STAT_ERR) {
3248 BX_DEBUG_ATA("ata_cmd_packet : error, status is %02x\n",status);
3249 return 3;
3250 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
3251 BX_DEBUG_ATA("ata_cmd_packet : DRQ not set (status %02x)\n", (unsigned) status);
3252 return 4;
3255 // Normalize address
3256 cmdseg += (cmdoff / 16);
3257 cmdoff %= 16;
3259 // Send command to device
3260 ASM_START
3261 sti ;; enable higher priority interrupts
3263 push bp
3264 mov bp, sp
3266 mov si, _ata_cmd_packet.cmdoff + 2[bp]
3267 mov ax, _ata_cmd_packet.cmdseg + 2[bp]
3268 mov cx, _ata_cmd_packet.cmdlen + 2[bp]
3269 mov es, ax ;; segment in es
3271 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data write port
3273 seg ES
3274 rep
3275 outsw ;; CX words transfered from port(DX) to ES:[SI]
3277 pop bp
3278 ASM_END
3280 if (inout == ATA_DATA_NO) {
3281 status = inb(iobase1 + ATA_CB_STAT);
3283 else {
3284 while (1) {
3286 status = inb(iobase1 + ATA_CB_STAT);
3288 // Check if command completed
3289 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_DRQ) ) ==0 ) break;
3291 if (status & ATA_CB_STAT_ERR) {
3292 BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status);
3293 return 3;
3296 // Device must be ready to send data
3297 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3298 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3299 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", status);
3300 return 4;
3303 // Normalize address
3304 bufseg += (bufoff / 16);
3305 bufoff %= 16;
3307 // Get the byte count
3308 lcount = ((Bit16u)(inb(iobase1 + ATA_CB_CH))<<8)+inb(iobase1 + ATA_CB_CL);
3310 // adjust to read what we want
3311 if(header>lcount) {
3312 lbefore=lcount;
3313 header-=lcount;
3314 lcount=0;
3316 else {
3317 lbefore=header;
3318 header=0;
3319 lcount-=lbefore;
3322 if(lcount>length) {
3323 lafter=lcount-length;
3324 lcount=length;
3325 length=0;
3327 else {
3328 lafter=0;
3329 length-=lcount;
3332 // Save byte count
3333 count = lcount;
3335 BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore+lcount+lafter,lbefore,lcount,lafter);
3336 BX_DEBUG_ATA("to 0x%04x:0x%04x\n",bufseg,bufoff);
3338 // If counts not dividable by 4, use 16bits mode
3339 lmode = mode;
3340 if (lbefore & 0x03) lmode=ATA_MODE_PIO16;
3341 if (lcount & 0x03) lmode=ATA_MODE_PIO16;
3342 if (lafter & 0x03) lmode=ATA_MODE_PIO16;
3344 // adds an extra byte if count are odd. before is always even
3345 if (lcount & 0x01) {
3346 lcount+=1;
3347 if ((lafter > 0) && (lafter & 0x01)) {
3348 lafter-=1;
3352 if (lmode == ATA_MODE_PIO32) {
3353 lcount>>=2; lbefore>>=2; lafter>>=2;
3355 else {
3356 lcount>>=1; lbefore>>=1; lafter>>=1;
3359 ; // FIXME bcc bug
3361 ASM_START
3362 push bp
3363 mov bp, sp
3365 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data read port
3367 mov cx, _ata_cmd_packet.lbefore + 2[bp]
3368 jcxz ata_packet_no_before
3370 mov ah, _ata_cmd_packet.lmode + 2[bp]
3371 cmp ah, #ATA_MODE_PIO32
3372 je ata_packet_in_before_32
3374 ata_packet_in_before_16:
3375 in ax, dx
3376 loop ata_packet_in_before_16
3377 jmp ata_packet_no_before
3379 ata_packet_in_before_32:
3380 push eax
3381 ata_packet_in_before_32_loop:
3382 in eax, dx
3383 loop ata_packet_in_before_32_loop
3384 pop eax
3386 ata_packet_no_before:
3387 mov cx, _ata_cmd_packet.lcount + 2[bp]
3388 jcxz ata_packet_after
3390 mov di, _ata_cmd_packet.bufoff + 2[bp]
3391 mov ax, _ata_cmd_packet.bufseg + 2[bp]
3392 mov es, ax
3394 mov ah, _ata_cmd_packet.lmode + 2[bp]
3395 cmp ah, #ATA_MODE_PIO32
3396 je ata_packet_in_32
3398 ata_packet_in_16:
3399 rep
3400 insw ;; CX words transfered tp port(DX) to ES:[DI]
3401 jmp ata_packet_after
3403 ata_packet_in_32:
3404 rep
3405 insd ;; CX dwords transfered to port(DX) to ES:[DI]
3407 ata_packet_after:
3408 mov cx, _ata_cmd_packet.lafter + 2[bp]
3409 jcxz ata_packet_done
3411 mov ah, _ata_cmd_packet.lmode + 2[bp]
3412 cmp ah, #ATA_MODE_PIO32
3413 je ata_packet_in_after_32
3415 ata_packet_in_after_16:
3416 in ax, dx
3417 loop ata_packet_in_after_16
3418 jmp ata_packet_done
3420 ata_packet_in_after_32:
3421 push eax
3422 ata_packet_in_after_32_loop:
3423 in eax, dx
3424 loop ata_packet_in_after_32_loop
3425 pop eax
3427 ata_packet_done:
3428 pop bp
3429 ASM_END
3431 // Compute new buffer address
3432 bufoff += count;
3434 // Save transferred bytes count
3435 transfer += count;
3436 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,transfer);
3440 // Final check, device must be ready
3441 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3442 != ATA_CB_STAT_RDY ) {
3443 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", (unsigned) status);
3444 return 4;
3447 // Enable interrupts
3448 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3449 return 0;
3452 // ---------------------------------------------------------------------------
3453 // End of ATA/ATAPI Driver
3454 // ---------------------------------------------------------------------------
3456 // ---------------------------------------------------------------------------
3457 // Start of ATA/ATAPI generic functions
3458 // ---------------------------------------------------------------------------
3460 Bit16u
3461 atapi_get_sense(device)
3462 Bit16u device;
3464 Bit8u atacmd[12];
3465 Bit8u buffer[16];
3466 Bit8u i;
3468 memsetb(get_SS(),atacmd,0,12);
3470 // Request SENSE
3471 atacmd[0]=0x03;
3472 atacmd[4]=0x20;
3473 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 16L, ATA_DATA_IN, get_SS(), buffer) != 0)
3474 return 0x0002;
3476 if ((buffer[0] & 0x7e) == 0x70) {
3477 return (((Bit16u)buffer[2]&0x0f)*0x100)+buffer[12];
3480 return 0;
3483 Bit16u
3484 atapi_is_ready(device)
3485 Bit16u device;
3487 Bit8u atacmd[12];
3488 Bit8u buffer[];
3490 memsetb(get_SS(),atacmd,0,12);
3492 // Test Unit Ready
3493 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3494 return 0x000f;
3496 if (atapi_get_sense(device) !=0 ) {
3497 memsetb(get_SS(),atacmd,0,12);
3499 // try to send Test Unit Ready again
3500 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3501 return 0x000f;
3503 return atapi_get_sense(device);
3505 return 0;
3508 Bit16u
3509 atapi_is_cdrom(device)
3510 Bit8u device;
3512 Bit16u ebda_seg=read_word(0x0040,0x000E);
3514 if (device >= BX_MAX_ATA_DEVICES)
3515 return 0;
3517 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_ATAPI)
3518 return 0;
3520 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].device) != ATA_DEVICE_CDROM)
3521 return 0;
3523 return 1;
3526 // ---------------------------------------------------------------------------
3527 // End of ATA/ATAPI generic functions
3528 // ---------------------------------------------------------------------------
3530 #endif // BX_USE_ATADRV
3532 #if BX_ELTORITO_BOOT
3534 // ---------------------------------------------------------------------------
3535 // Start of El-Torito boot functions
3536 // ---------------------------------------------------------------------------
3538 void
3539 cdemu_init()
3541 Bit16u ebda_seg=read_word(0x0040,0x000E);
3543 // the only important data is this one for now
3544 write_byte(ebda_seg,&EbdaData->cdemu.active,0x00);
3547 Bit8u
3548 cdemu_isactive()
3550 Bit16u ebda_seg=read_word(0x0040,0x000E);
3552 return(read_byte(ebda_seg,&EbdaData->cdemu.active));
3555 Bit8u
3556 cdemu_emulated_drive()
3558 Bit16u ebda_seg=read_word(0x0040,0x000E);
3560 return(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
3563 static char isotag[6]="CD001";
3564 static char eltorito[24]="EL TORITO SPECIFICATION";
3565 //
3566 // Returns ah: emulated drive, al: error code
3567 //
3568 Bit16u
3569 cdrom_boot()
3571 Bit16u ebda_seg=read_word(0x0040,0x000E);
3572 Bit8u atacmd[12], buffer[2048];
3573 Bit32u lba;
3574 Bit16u boot_segment, nbsectors, i, error;
3575 Bit8u device;
3577 // Find out the first cdrom
3578 for (device=0; device<BX_MAX_ATA_DEVICES;device++) {
3579 if (atapi_is_cdrom(device)) break;
3582 // if not found
3583 if(device >= BX_MAX_ATA_DEVICES) return 2;
3585 // Read the Boot Record Volume Descriptor
3586 memsetb(get_SS(),atacmd,0,12);
3587 atacmd[0]=0x28; // READ command
3588 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3589 atacmd[8]=(0x01 & 0x00ff); // Sectors
3590 atacmd[2]=(0x11 & 0xff000000) >> 24; // LBA
3591 atacmd[3]=(0x11 & 0x00ff0000) >> 16;
3592 atacmd[4]=(0x11 & 0x0000ff00) >> 8;
3593 atacmd[5]=(0x11 & 0x000000ff);
3594 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3595 return 3;
3597 // Validity checks
3598 if(buffer[0]!=0)return 4;
3599 for(i=0;i<5;i++){
3600 if(buffer[1+i]!=read_byte(0xf000,&isotag[i]))return 5;
3602 for(i=0;i<23;i++)
3603 if(buffer[7+i]!=read_byte(0xf000,&eltorito[i]))return 6;
3605 // ok, now we calculate the Boot catalog address
3606 lba=buffer[0x4A]*0x1000000+buffer[0x49]*0x10000+buffer[0x48]*0x100+buffer[0x47];
3608 // And we read the Boot Catalog
3609 memsetb(get_SS(),atacmd,0,12);
3610 atacmd[0]=0x28; // READ command
3611 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3612 atacmd[8]=(0x01 & 0x00ff); // Sectors
3613 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3614 atacmd[3]=(lba & 0x00ff0000) >> 16;
3615 atacmd[4]=(lba & 0x0000ff00) >> 8;
3616 atacmd[5]=(lba & 0x000000ff);
3617 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3618 return 7;
3620 // Validation entry
3621 if(buffer[0x00]!=0x01)return 8; // Header
3622 if(buffer[0x01]!=0x00)return 9; // Platform
3623 if(buffer[0x1E]!=0x55)return 10; // key 1
3624 if(buffer[0x1F]!=0xAA)return 10; // key 2
3626 // Initial/Default Entry
3627 if(buffer[0x20]!=0x88)return 11; // Bootable
3629 #if BX_TCGBIOS
3630 /* specs: 8.2.3 step 5 and 8.2.5.6, measure El Torito boot catalog */
3631 /* measure 2048 bytes (one sector) */
3632 tcpa_add_bootdevice((Bit32u)1L, (Bit32u)0L); /* bootcd = 1 */
3633 tcpa_ipl((Bit32u)2L,(Bit32u)get_SS(),(Bit32u)buffer,(Bit32u)2048L);
3634 #endif
3636 write_byte(ebda_seg,&EbdaData->cdemu.media,buffer[0x21]);
3637 if(buffer[0x21]==0){
3638 // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
3639 // Win2000 cd boot needs to know it booted from cd
3640 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0xE0);
3642 else if(buffer[0x21]<4)
3643 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x00);
3644 else
3645 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x80);
3647 write_byte(ebda_seg,&EbdaData->cdemu.controller_index,device/2);
3648 write_byte(ebda_seg,&EbdaData->cdemu.device_spec,device%2);
3650 boot_segment=buffer[0x23]*0x100+buffer[0x22];
3651 if(boot_segment==0x0000)boot_segment=0x07C0;
3653 write_word(ebda_seg,&EbdaData->cdemu.load_segment,boot_segment);
3654 write_word(ebda_seg,&EbdaData->cdemu.buffer_segment,0x0000);
3656 nbsectors=buffer[0x27]*0x100+buffer[0x26];
3657 write_word(ebda_seg,&EbdaData->cdemu.sector_count,nbsectors);
3659 lba=buffer[0x2B]*0x1000000+buffer[0x2A]*0x10000+buffer[0x29]*0x100+buffer[0x28];
3660 write_dword(ebda_seg,&EbdaData->cdemu.ilba,lba);
3662 // And we read the image in memory
3663 memsetb(get_SS(),atacmd,0,12);
3664 atacmd[0]=0x28; // READ command
3665 atacmd[7]=((1+(nbsectors-1)/4) & 0xff00) >> 8; // Sectors
3666 atacmd[8]=((1+(nbsectors-1)/4) & 0x00ff); // Sectors
3667 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3668 atacmd[3]=(lba & 0x00ff0000) >> 16;
3669 atacmd[4]=(lba & 0x0000ff00) >> 8;
3670 atacmd[5]=(lba & 0x000000ff);
3671 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, nbsectors*512L, ATA_DATA_IN, boot_segment,0)) != 0)
3672 return 12;
3674 #if BX_TCGBIOS
3675 /* specs: 8.2.3 step 4 and 8.2.5.6, measure El Torito boot image */
3676 /* measure 1st 512 bytes */
3677 tcpa_ipl((Bit32u)1L,(Bit32u)boot_segment,(Bit32u)0L,(Bit32u)512L);
3678 #endif
3681 // Remember the media type
3682 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
3683 case 0x01: // 1.2M floppy
3684 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,15);
3685 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3686 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3687 break;
3688 case 0x02: // 1.44M floppy
3689 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,18);
3690 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3691 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3692 break;
3693 case 0x03: // 2.88M floppy
3694 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,36);
3695 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3696 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3697 break;
3698 case 0x04: // Harddrive
3699 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,read_byte(boot_segment,446+6)&0x3f);
3700 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,
3701 (read_byte(boot_segment,446+6)<<2) + read_byte(boot_segment,446+7) + 1);
3702 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,read_byte(boot_segment,446+5) + 1);
3703 break;
3706 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0) {
3707 // Increase bios installed hardware number of devices
3708 if(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)==0x00)
3709 write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
3710 else
3711 write_byte(ebda_seg, &EbdaData->ata.hdcount, read_byte(ebda_seg, &EbdaData->ata.hdcount) + 1);
3715 // everything is ok, so from now on, the emulation is active
3716 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0)
3717 write_byte(ebda_seg,&EbdaData->cdemu.active,0x01);
3719 // return the boot drive + no error
3720 return (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)*0x100)+0;
3723 // ---------------------------------------------------------------------------
3724 // End of El-Torito boot functions
3725 // ---------------------------------------------------------------------------
3726 #endif // BX_ELTORITO_BOOT
3728 void
3729 int14_function(regs, ds, iret_addr)
3730 pusha_regs_t regs; // regs pushed from PUSHA instruction
3731 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
3732 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
3734 Bit16u addr,timer,val16;
3735 Bit8u timeout;
3737 ASM_START
3738 sti
3739 ASM_END
3741 addr = read_word(0x0040, (regs.u.r16.dx << 1));
3742 timeout = read_byte(0x0040, 0x007C + regs.u.r16.dx);
3743 if ((regs.u.r16.dx < 4) && (addr > 0)) {
3744 switch (regs.u.r8.ah) {
3745 case 0:
3746 outb(addr+3, inb(addr+3) | 0x80);
3747 if (regs.u.r8.al & 0xE0 == 0) {
3748 outb(addr, 0x17);
3749 outb(addr+1, 0x04);
3750 } else {
3751 val16 = 0x600 >> ((regs.u.r8.al & 0xE0) >> 5);
3752 outb(addr, val16 & 0xFF);
3753 outb(addr+1, val16 >> 8);
3755 outb(addr+3, regs.u.r8.al & 0x1F);
3756 regs.u.r8.ah = inb(addr+5);
3757 regs.u.r8.al = inb(addr+6);
3758 ClearCF(iret_addr.flags);
3759 break;
3760 case 1:
3761 timer = read_word(0x0040, 0x006C);
3762 while (((inb(addr+5) & 0x60) != 0x60) && (timeout)) {
3763 val16 = read_word(0x0040, 0x006C);
3764 if (val16 != timer) {
3765 timer = val16;
3766 timeout--;
3769 if (timeout) outb(addr, regs.u.r8.al);
3770 regs.u.r8.ah = inb(addr+5);
3771 if (!timeout) regs.u.r8.ah |= 0x80;
3772 ClearCF(iret_addr.flags);
3773 break;
3774 case 2:
3775 timer = read_word(0x0040, 0x006C);
3776 while (((inb(addr+5) & 0x01) == 0) && (timeout)) {
3777 val16 = read_word(0x0040, 0x006C);
3778 if (val16 != timer) {
3779 timer = val16;
3780 timeout--;
3783 if (timeout) {
3784 regs.u.r8.ah = 0;
3785 regs.u.r8.al = inb(addr);
3786 } else {
3787 regs.u.r8.ah = inb(addr+5);
3789 ClearCF(iret_addr.flags);
3790 break;
3791 case 3:
3792 regs.u.r8.ah = inb(addr+5);
3793 regs.u.r8.al = inb(addr+6);
3794 ClearCF(iret_addr.flags);
3795 break;
3796 default:
3797 SetCF(iret_addr.flags); // Unsupported
3799 } else {
3800 SetCF(iret_addr.flags); // Unsupported
3804 void
3805 int15_function(regs, ES, DS, FLAGS)
3806 pusha_regs_t regs; // REGS pushed via pusha
3807 Bit16u ES, DS, FLAGS;
3809 Bit16u ebda_seg=read_word(0x0040,0x000E);
3810 bx_bool prev_a20_enable;
3811 Bit16u base15_00;
3812 Bit8u base23_16;
3813 Bit16u ss;
3814 Bit16u CX,DX;
3816 Bit16u bRegister;
3817 Bit8u irqDisable;
3819 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
3821 switch (regs.u.r8.ah) {
3822 case 0x24: /* A20 Control */
3823 switch (regs.u.r8.al) {
3824 case 0x00:
3825 set_enable_a20(0);
3826 CLEAR_CF();
3827 regs.u.r8.ah = 0;
3828 break;
3829 case 0x01:
3830 set_enable_a20(1);
3831 CLEAR_CF();
3832 regs.u.r8.ah = 0;
3833 break;
3834 case 0x02:
3835 regs.u.r8.al = (inb(0x92) >> 1) & 0x01;
3836 CLEAR_CF();
3837 regs.u.r8.ah = 0;
3838 break;
3839 case 0x03:
3840 CLEAR_CF();
3841 regs.u.r8.ah = 0;
3842 regs.u.r16.bx = 3;
3843 break;
3844 default:
3845 BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs.u.r8.al);
3846 SET_CF();
3847 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3849 break;
3851 case 0x41:
3852 SET_CF();
3853 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3854 break;
3856 case 0x4f:
3857 /* keyboard intercept */
3858 #if BX_CPU < 2
3859 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3860 #else
3861 // nop
3862 #endif
3863 SET_CF();
3864 break;
3866 case 0x52: // removable media eject
3867 CLEAR_CF();
3868 regs.u.r8.ah = 0; // "ok ejection may proceed"
3869 break;
3871 case 0x83: {
3872 if( regs.u.r8.al == 0 ) {
3873 // Set Interval requested.
3874 if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
3875 // Interval not already set.
3876 write_byte( 0x40, 0xA0, 1 ); // Set status byte.
3877 write_word( 0x40, 0x98, ES ); // Byte location, segment
3878 write_word( 0x40, 0x9A, regs.u.r16.bx ); // Byte location, offset
3879 write_word( 0x40, 0x9C, regs.u.r16.dx ); // Low word, delay
3880 write_word( 0x40, 0x9E, regs.u.r16.cx ); // High word, delay.
3881 CLEAR_CF( );
3882 irqDisable = inb( 0xA1 );
3883 outb( 0xA1, irqDisable & 0xFE );
3884 bRegister = inb_cmos( 0xB ); // Unmask IRQ8 so INT70 will get through.
3885 outb_cmos( 0xB, bRegister | 0x40 ); // Turn on the Periodic Interrupt timer
3886 } else {
3887 // Interval already set.
3888 BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
3889 SET_CF();
3890 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3892 } else if( regs.u.r8.al == 1 ) {
3893 // Clear Interval requested
3894 write_byte( 0x40, 0xA0, 0 ); // Clear status byte
3895 CLEAR_CF( );
3896 bRegister = inb_cmos( 0xB );
3897 outb_cmos( 0xB, bRegister & ~0x40 ); // Turn off the Periodic Interrupt timer
3898 } else {
3899 BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
3900 SET_CF();
3901 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3902 regs.u.r8.al--;
3905 break;
3908 case 0x87:
3909 #if BX_CPU < 3
3910 # error "Int15 function 87h not supported on < 80386"
3911 #endif
3912 // +++ should probably have descriptor checks
3913 // +++ should have exception handlers
3915 // turn off interrupts
3916 ASM_START
3917 cli
3918 ASM_END
3920 prev_a20_enable = set_enable_a20(1); // enable A20 line
3922 // 128K max of transfer on 386+ ???
3923 // source == destination ???
3925 // ES:SI points to descriptor table
3926 // offset use initially comments
3927 // ==============================================
3928 // 00..07 Unused zeros Null descriptor
3929 // 08..0f GDT zeros filled in by BIOS
3930 // 10..17 source ssssssss source of data
3931 // 18..1f dest dddddddd destination of data
3932 // 20..27 CS zeros filled in by BIOS
3933 // 28..2f SS zeros filled in by BIOS
3935 //es:si
3936 //eeee0
3937 //0ssss
3938 //-----
3940 // check for access rights of source & dest here
3942 // Initialize GDT descriptor
3943 base15_00 = (ES << 4) + regs.u.r16.si;
3944 base23_16 = ES >> 12;
3945 if (base15_00 < (ES<<4))
3946 base23_16++;
3947 write_word(ES, regs.u.r16.si+0x08+0, 47); // limit 15:00 = 6 * 8bytes/descriptor
3948 write_word(ES, regs.u.r16.si+0x08+2, base15_00);// base 15:00
3949 write_byte(ES, regs.u.r16.si+0x08+4, base23_16);// base 23:16
3950 write_byte(ES, regs.u.r16.si+0x08+5, 0x93); // access
3951 write_word(ES, regs.u.r16.si+0x08+6, 0x0000); // base 31:24/reserved/limit 19:16
3953 // Initialize CS descriptor
3954 write_word(ES, regs.u.r16.si+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
3955 write_word(ES, regs.u.r16.si+0x20+2, 0x0000);// base 15:00
3956 write_byte(ES, regs.u.r16.si+0x20+4, 0x000f);// base 23:16
3957 write_byte(ES, regs.u.r16.si+0x20+5, 0x9b); // access
3958 write_word(ES, regs.u.r16.si+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
3960 // Initialize SS descriptor
3961 ss = get_SS();
3962 base15_00 = ss << 4;
3963 base23_16 = ss >> 12;
3964 write_word(ES, regs.u.r16.si+0x28+0, 0xffff); // limit 15:00 = normal 64K limit
3965 write_word(ES, regs.u.r16.si+0x28+2, base15_00);// base 15:00
3966 write_byte(ES, regs.u.r16.si+0x28+4, base23_16);// base 23:16
3967 write_byte(ES, regs.u.r16.si+0x28+5, 0x93); // access
3968 write_word(ES, regs.u.r16.si+0x28+6, 0x0000); // base 31:24/reserved/limit 19:16
3970 CX = regs.u.r16.cx;
3971 ASM_START
3972 // Compile generates locals offset info relative to SP.
3973 // Get CX (word count) from stack.
3974 mov bx, sp
3975 SEG SS
3976 mov cx, _int15_function.CX [bx]
3978 // since we need to set SS:SP, save them to the BDA
3979 // for future restore
3980 push eax
3981 xor eax, eax
3982 mov ds, ax
3983 mov 0x0469, ss
3984 mov 0x0467, sp
3986 SEG ES
3987 lgdt [si + 0x08]
3988 SEG CS
3989 lidt [pmode_IDT_info]
3990 ;; perhaps do something with IDT here
3992 ;; set PE bit in CR0
3993 mov eax, cr0
3994 or al, #0x01
3995 mov cr0, eax
3996 ;; far jump to flush CPU queue after transition to protected mode
3997 JMP_AP(0x0020, protected_mode)
3999 protected_mode:
4000 ;; GDT points to valid descriptor table, now load SS, DS, ES
4001 mov ax, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
4002 mov ss, ax
4003 mov ax, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
4004 mov ds, ax
4005 mov ax, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
4006 mov es, ax
4007 xor si, si
4008 xor di, di
4009 cld
4010 rep
4011 movsw ;; move CX words from DS:SI to ES:DI
4013 ;; make sure DS and ES limits are 64KB
4014 mov ax, #0x28
4015 mov ds, ax
4016 mov es, ax
4018 ;; reset PG bit in CR0 ???
4019 mov eax, cr0
4020 and al, #0xFE
4021 mov cr0, eax
4023 ;; far jump to flush CPU queue after transition to real mode
4024 JMP_AP(0xf000, real_mode)
4026 real_mode:
4027 ;; restore IDT to normal real-mode defaults
4028 SEG CS
4029 lidt [rmode_IDT_info]
4031 // restore SS:SP from the BDA
4032 xor ax, ax
4033 mov ds, ax
4034 mov ss, 0x0469
4035 mov sp, 0x0467
4036 pop eax
4037 ASM_END
4039 set_enable_a20(prev_a20_enable);
4041 // turn back on interrupts
4042 ASM_START
4043 sti
4044 ASM_END
4046 regs.u.r8.ah = 0;
4047 CLEAR_CF();
4048 break;
4051 case 0x88:
4052 // Get the amount of extended memory (above 1M)
4053 #if BX_CPU < 2
4054 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4055 SET_CF();
4056 #else
4057 regs.u.r8.al = inb_cmos(0x30);
4058 regs.u.r8.ah = inb_cmos(0x31);
4060 // limit to 15M
4061 if(regs.u.r16.ax > 0x3c00)
4062 regs.u.r16.ax = 0x3c00;
4064 CLEAR_CF();
4065 #endif
4066 break;
4068 case 0x90:
4069 /* Device busy interrupt. Called by Int 16h when no key available */
4070 break;
4072 case 0x91:
4073 /* Interrupt complete. Called by Int 16h when key becomes available */
4074 break;
4076 case 0xbf:
4077 BX_INFO("*** int 15h function AH=bf not yet supported!\n");
4078 SET_CF();
4079 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4080 break;
4082 case 0xC0:
4083 #if 0
4084 SET_CF();
4085 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4086 break;
4087 #endif
4088 CLEAR_CF();
4089 regs.u.r8.ah = 0;
4090 regs.u.r16.bx = BIOS_CONFIG_TABLE;
4091 ES = 0xF000;
4092 break;
4094 case 0xc1:
4095 ES = ebda_seg;
4096 CLEAR_CF();
4097 break;
4099 case 0xd8:
4100 bios_printf(BIOS_PRINTF_DEBUG, "EISA BIOS not present\n");
4101 SET_CF();
4102 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4103 break;
4105 default:
4106 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4107 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4108 SET_CF();
4109 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4110 break;
4114 #if BX_USE_PS2_MOUSE
4115 void
4116 int15_function_mouse(regs, ES, DS, FLAGS)
4117 pusha_regs_t regs; // REGS pushed via pusha
4118 Bit16u ES, DS, FLAGS;
4120 Bit16u ebda_seg=read_word(0x0040,0x000E);
4121 Bit8u mouse_flags_1, mouse_flags_2;
4122 Bit16u mouse_driver_seg;
4123 Bit16u mouse_driver_offset;
4124 Bit8u comm_byte, prev_command_byte;
4125 Bit8u ret, mouse_data1, mouse_data2, mouse_data3;
4127 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4129 switch (regs.u.r8.ah) {
4130 case 0xC2:
4131 // Return Codes status in AH
4132 // =========================
4133 // 00: success
4134 // 01: invalid subfunction (AL > 7)
4135 // 02: invalid input value (out of allowable range)
4136 // 03: interface error
4137 // 04: resend command received from mouse controller,
4138 // device driver should attempt command again
4139 // 05: cannot enable mouse, since no far call has been installed
4140 // 80/86: mouse service not implemented
4142 switch (regs.u.r8.al) {
4143 case 0: // Disable/Enable Mouse
4144 BX_DEBUG_INT15("case 0:\n");
4145 switch (regs.u.r8.bh) {
4146 case 0: // Disable Mouse
4147 BX_DEBUG_INT15("case 0: disable mouse\n");
4148 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4149 ret = send_to_mouse_ctrl(0xF5); // disable mouse command
4150 if (ret == 0) {
4151 ret = get_mouse_data(&mouse_data1);
4152 if ( (ret == 0) || (mouse_data1 == 0xFA) ) {
4153 CLEAR_CF();
4154 regs.u.r8.ah = 0;
4155 return;
4159 // error
4160 SET_CF();
4161 regs.u.r8.ah = ret;
4162 return;
4163 break;
4165 case 1: // Enable Mouse
4166 BX_DEBUG_INT15("case 1: enable mouse\n");
4167 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4168 if ( (mouse_flags_2 & 0x80) == 0 ) {
4169 BX_DEBUG_INT15("INT 15h C2 Enable Mouse, no far call handler\n");
4170 SET_CF(); // error
4171 regs.u.r8.ah = 5; // no far call installed
4172 return;
4174 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4175 ret = send_to_mouse_ctrl(0xF4); // enable mouse command
4176 if (ret == 0) {
4177 ret = get_mouse_data(&mouse_data1);
4178 if ( (ret == 0) && (mouse_data1 == 0xFA) ) {
4179 enable_mouse_int_and_events(); // turn IRQ12 and packet generation on
4180 CLEAR_CF();
4181 regs.u.r8.ah = 0;
4182 return;
4185 SET_CF();
4186 regs.u.r8.ah = ret;
4187 return;
4189 default: // invalid subfunction
4190 BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs.u.r8.bh);
4191 SET_CF(); // error
4192 regs.u.r8.ah = 1; // invalid subfunction
4193 return;
4195 break;
4197 case 1: // Reset Mouse
4198 case 5: // Initialize Mouse
4199 BX_DEBUG_INT15("case 1 or 5:\n");
4200 if (regs.u.r8.al == 5) {
4201 if (regs.u.r8.bh != 3) {
4202 SET_CF();
4203 regs.u.r8.ah = 0x02; // invalid input
4204 return;
4206 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4207 mouse_flags_2 = (mouse_flags_2 & 0x00) | regs.u.r8.bh;
4208 mouse_flags_1 = 0x00;
4209 write_byte(ebda_seg, 0x0026, mouse_flags_1);
4210 write_byte(ebda_seg, 0x0027, mouse_flags_2);
4213 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4214 ret = send_to_mouse_ctrl(0xFF); // reset mouse command
4215 if (ret == 0) {
4216 ret = get_mouse_data(&mouse_data3);
4217 // if no mouse attached, it will return RESEND
4218 if (mouse_data3 == 0xfe) {
4219 SET_CF();
4220 return;
4222 if (mouse_data3 != 0xfa)
4223 BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3);
4224 if ( ret == 0 ) {
4225 ret = get_mouse_data(&mouse_data1);
4226 if ( ret == 0 ) {
4227 ret = get_mouse_data(&mouse_data2);
4228 if ( ret == 0 ) {
4229 // turn IRQ12 and packet generation on
4230 enable_mouse_int_and_events();
4231 CLEAR_CF();
4232 regs.u.r8.ah = 0;
4233 regs.u.r8.bl = mouse_data1;
4234 regs.u.r8.bh = mouse_data2;
4235 return;
4241 // error
4242 SET_CF();
4243 regs.u.r8.ah = ret;
4244 return;
4246 case 2: // Set Sample Rate
4247 BX_DEBUG_INT15("case 2:\n");
4248 switch (regs.u.r8.bh) {
4249 case 0: mouse_data1 = 10; break; // 10 reports/sec
4250 case 1: mouse_data1 = 20; break; // 20 reports/sec
4251 case 2: mouse_data1 = 40; break; // 40 reports/sec
4252 case 3: mouse_data1 = 60; break; // 60 reports/sec
4253 case 4: mouse_data1 = 80; break; // 80 reports/sec
4254 case 5: mouse_data1 = 100; break; // 100 reports/sec (default)
4255 case 6: mouse_data1 = 200; break; // 200 reports/sec
4256 default: mouse_data1 = 0;
4258 if (mouse_data1 > 0) {
4259 ret = send_to_mouse_ctrl(0xF3); // set sample rate command
4260 if (ret == 0) {
4261 ret = get_mouse_data(&mouse_data2);
4262 ret = send_to_mouse_ctrl(mouse_data1);
4263 ret = get_mouse_data(&mouse_data2);
4264 CLEAR_CF();
4265 regs.u.r8.ah = 0;
4266 } else {
4267 // error
4268 SET_CF();
4269 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4271 } else {
4272 // error
4273 SET_CF();
4274 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4276 break;
4278 case 3: // Set Resolution
4279 BX_DEBUG_INT15("case 3:\n");
4280 // BX:
4281 // 0 = 25 dpi, 1 count per millimeter
4282 // 1 = 50 dpi, 2 counts per millimeter
4283 // 2 = 100 dpi, 4 counts per millimeter
4284 // 3 = 200 dpi, 8 counts per millimeter
4285 CLEAR_CF();
4286 regs.u.r8.ah = 0;
4287 break;
4289 case 4: // Get Device ID
4290 BX_DEBUG_INT15("case 4:\n");
4291 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4292 ret = send_to_mouse_ctrl(0xF2); // get mouse ID command
4293 if (ret == 0) {
4294 ret = get_mouse_data(&mouse_data1);
4295 ret = get_mouse_data(&mouse_data2);
4296 CLEAR_CF();
4297 regs.u.r8.ah = 0;
4298 regs.u.r8.bh = mouse_data2;
4299 } else {
4300 // error
4301 SET_CF();
4302 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4304 break;
4306 case 6: // Return Status & Set Scaling Factor...
4307 BX_DEBUG_INT15("case 6:\n");
4308 switch (regs.u.r8.bh) {
4309 case 0: // Return Status
4310 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4311 ret = send_to_mouse_ctrl(0xE9); // get mouse info command
4312 if (ret == 0) {
4313 ret = get_mouse_data(&mouse_data1);
4314 if (mouse_data1 != 0xfa)
4315 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4316 if (ret == 0) {
4317 ret = get_mouse_data(&mouse_data1);
4318 if ( ret == 0 ) {
4319 ret = get_mouse_data(&mouse_data2);
4320 if ( ret == 0 ) {
4321 ret = get_mouse_data(&mouse_data3);
4322 if ( ret == 0 ) {
4323 CLEAR_CF();
4324 regs.u.r8.ah = 0;
4325 regs.u.r8.bl = mouse_data1;
4326 regs.u.r8.cl = mouse_data2;
4327 regs.u.r8.dl = mouse_data3;
4328 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
4329 return;
4336 // error
4337 SET_CF();
4338 regs.u.r8.ah = ret;
4339 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
4340 return;
4342 case 1: // Set Scaling Factor to 1:1
4343 case 2: // Set Scaling Factor to 2:1
4344 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4345 if (regs.u.r8.bh == 1) {
4346 ret = send_to_mouse_ctrl(0xE6);
4347 } else {
4348 ret = send_to_mouse_ctrl(0xE7);
4350 if (ret == 0) {
4351 get_mouse_data(&mouse_data1);
4352 ret = (mouse_data1 != 0xFA);
4354 if (ret == 0) {
4355 CLEAR_CF();
4356 regs.u.r8.ah = 0;
4357 } else {
4358 // error
4359 SET_CF();
4360 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4362 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
4363 break;
4365 default:
4366 BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs.u.r8.bh);
4368 break;
4370 case 7: // Set Mouse Handler Address
4371 BX_DEBUG_INT15("case 7:\n");
4372 mouse_driver_seg = ES;
4373 mouse_driver_offset = regs.u.r16.bx;
4374 write_word(ebda_seg, 0x0022, mouse_driver_offset);
4375 write_word(ebda_seg, 0x0024, mouse_driver_seg);
4376 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4377 if (mouse_driver_offset == 0 && mouse_driver_seg == 0) {
4378 /* remove handler */
4379 if ( (mouse_flags_2 & 0x80) != 0 ) {
4380 mouse_flags_2 &= ~0x80;
4381 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4384 else {
4385 /* install handler */
4386 mouse_flags_2 |= 0x80;
4388 write_byte(ebda_seg, 0x0027, mouse_flags_2);
4389 CLEAR_CF();
4390 regs.u.r8.ah = 0;
4391 break;
4393 default:
4394 BX_DEBUG_INT15("case default:\n");
4395 regs.u.r8.ah = 1; // invalid function
4396 SET_CF();
4398 break;
4400 default:
4401 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4402 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4403 SET_CF();
4404 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4405 break;
4408 #endif
4410 void
4411 int15_function32(regs, ES, DS, FLAGS)
4412 pushad_regs_t regs; // REGS pushed via pushad
4413 Bit16u ES, DS, FLAGS;
4415 Bit32u extended_memory_size=0; // 64bits long
4416 Bit16u CX,DX;
4418 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4420 switch (regs.u.r8.ah) {
4421 case 0x86:
4422 // Wait for CX:DX microseconds. currently using the
4423 // refresh request port 0x61 bit4, toggling every 15usec
4425 CX = regs.u.r16.cx;
4426 DX = regs.u.r16.dx;
4428 ASM_START
4429 ;; Get the count in eax
4430 mov ax, .int15_function32.CX [bp]
4431 shl eax, #16
4432 mov ax, .int15_function32.DX [bp]
4434 ;; convert to numbers of 15usec ticks
4435 mov ebx, #15
4436 xor edx, edx
4437 div eax, ebx
4438 mov ecx, eax
4440 ;; wait for ecx number of refresh requests
4441 in al, #0x61
4442 and al,#0x10
4443 mov ah, al
4445 or ecx, ecx
4446 je int1586_tick_end
4447 int1586_tick:
4448 in al, #0x61
4449 and al,#0x10
4450 cmp al, ah
4451 je int1586_tick
4452 mov ah, al
4453 dec ecx
4454 jnz int1586_tick
4455 int1586_tick_end:
4456 ASM_END
4458 break;
4460 case 0xe8:
4461 switch(regs.u.r8.al)
4463 case 0x20: {
4464 Bit16u e820_table_size = read_word(0xe000, 0x8) * 0x14;
4466 if (regs.u.r32.edx != 0x534D4150) /* SMAP */
4467 goto int15_unimplemented;
4469 if ((regs.u.r16.bx / 0x14) * 0x14 == regs.u.r16.bx) {
4470 if (regs.u.r16.bx + 0x14 <= e820_table_size)
4471 memcpyb(ES, regs.u.r16.di,
4472 0xe000, 0x10 + regs.u.r16.bx, 0x14);
4473 regs.u.r32.ebx += 0x14;
4474 if ((regs.u.r32.ebx + 0x14 - 1) > e820_table_size)
4475 regs.u.r32.ebx = 0;
4476 } else if (regs.u.r16.bx == 1) {
4477 Bit32u base, type;
4478 Bit16u off;
4479 for (off = 0; off < e820_table_size; off += 0x14) {
4480 base = read_dword(0xe000, 0x10 + off);
4481 type = read_dword(0xe000, 0x20 + off);
4482 if ((base >= 0x100000) && (type == 1))
4483 break;
4485 if (off == e820_table_size) {
4486 SET_CF();
4487 break;
4489 memcpyb(ES, regs.u.r16.di, 0xe000, 0x10 + off, 0x14);
4490 regs.u.r32.ebx = 0;
4491 } else { /* AX=E820, DX=534D4150, BX unrecognized */
4492 goto int15_unimplemented;
4495 regs.u.r32.eax = 0x534D4150;
4496 regs.u.r32.ecx = 0x14;
4497 CLEAR_CF();
4498 break;
4501 case 0x01: {
4502 Bit16u off, e820_table_size = read_word(0xe000, 0x8) * 0x14;
4503 Bit32u base, type, size;
4505 // do we have any reason to fail here ?
4506 CLEAR_CF();
4508 // Get the amount of extended memory (above 1M)
4509 regs.u.r8.cl = inb_cmos(0x30);
4510 regs.u.r8.ch = inb_cmos(0x31);
4512 // limit to 15M
4513 if (regs.u.r16.cx > (15*1024))
4514 regs.u.r16.cx = 15*1024;
4516 // Find first RAM E820 entry >= 1MB.
4517 for (off = 0; off < e820_table_size; off += 0x14) {
4518 base = read_dword(0xe000, 0x10 + off);
4519 type = read_dword(0xe000, 0x20 + off);
4520 if ((base >= 0x100000) && (type == 1))
4521 break;
4524 // If there is RAM above 16MB, return amount in 64kB chunks.
4525 regs.u.r16.dx = 0;
4526 if (off != e820_table_size) {
4527 size = base + read_dword(0xe000, 0x18 + off);
4528 if (size > 0x1000000) {
4529 size -= 0x1000000;
4530 regs.u.r16.dx = (Bit16u)(size >> 16);
4534 // Set configured memory equal to extended memory
4535 regs.u.r16.ax = regs.u.r16.cx;
4536 regs.u.r16.bx = regs.u.r16.dx;
4537 break;
4539 default: /* AH=0xE8?? but not implemented */
4540 goto int15_unimplemented;
4542 break;
4543 int15_unimplemented:
4544 // fall into the default
4545 default:
4546 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4547 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4548 SET_CF();
4549 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4550 break;
4554 void
4555 int16_function(DI, SI, BP, SP, BX, DX, CX, AX, FLAGS)
4556 Bit16u DI, SI, BP, SP, BX, DX, CX, AX, FLAGS;
4558 Bit8u scan_code, ascii_code, shift_flags, count;
4559 Bit16u kbd_code, max;
4561 BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX, BX, CX, DX);
4563 switch (GET_AH()) {
4564 case 0x00: /* read keyboard input */
4566 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4567 BX_PANIC("KBD: int16h: out of keyboard input\n");
4569 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4570 else if (ascii_code == 0xE0) ascii_code = 0;
4571 AX = (scan_code << 8) | ascii_code;
4572 break;
4574 case 0x01: /* check keyboard status */
4575 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4576 SET_ZF();
4577 return;
4579 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4580 else if (ascii_code == 0xE0) ascii_code = 0;
4581 AX = (scan_code << 8) | ascii_code;
4582 CLEAR_ZF();
4583 break;
4585 case 0x02: /* get shift flag status */
4586 shift_flags = read_byte(0x0040, 0x17);
4587 SET_AL(shift_flags);
4588 break;
4590 case 0x05: /* store key-stroke into buffer */
4591 if ( !enqueue_key(GET_CH(), GET_CL()) ) {
4592 SET_AL(1);
4594 else {
4595 SET_AL(0);
4597 break;
4599 case 0x09: /* GET KEYBOARD FUNCTIONALITY */
4600 // bit Bochs Description
4601 // 7 0 reserved
4602 // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
4603 // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
4604 // 4 1 INT 16/AH=0Ah supported
4605 // 3 0 INT 16/AX=0306h supported
4606 // 2 0 INT 16/AX=0305h supported
4607 // 1 0 INT 16/AX=0304h supported
4608 // 0 0 INT 16/AX=0300h supported
4609 //
4610 SET_AL(0x30);
4611 break;
4613 case 0x0A: /* GET KEYBOARD ID */
4614 count = 2;
4615 kbd_code = 0x0;
4616 outb(0x60, 0xf2);
4617 /* Wait for data */
4618 max=0xffff;
4619 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4620 if (max>0x0) {
4621 if ((inb(0x60) == 0xfa)) {
4622 do {
4623 max=0xffff;
4624 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4625 if (max>0x0) {
4626 kbd_code >>= 8;
4627 kbd_code |= (inb(0x60) << 8);
4629 } while (--count>0);
4632 BX=kbd_code;
4633 break;
4635 case 0x10: /* read MF-II keyboard input */
4637 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4638 BX_PANIC("KBD: int16h: out of keyboard input\n");
4640 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4641 AX = (scan_code << 8) | ascii_code;
4642 break;
4644 case 0x11: /* check MF-II keyboard status */
4645 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4646 SET_ZF();
4647 return;
4649 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4650 AX = (scan_code << 8) | ascii_code;
4651 CLEAR_ZF();
4652 break;
4654 case 0x12: /* get extended keyboard status */
4655 shift_flags = read_byte(0x0040, 0x17);
4656 SET_AL(shift_flags);
4657 shift_flags = read_byte(0x0040, 0x18);
4658 SET_AH(shift_flags);
4659 BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX);
4660 break;
4662 case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
4663 SET_AH(0x80); // function int16 ah=0x10-0x12 supported
4664 break;
4666 case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
4667 // don't change AH : function int16 ah=0x20-0x22 NOT supported
4668 break;
4670 case 0x6F:
4671 if (GET_AL() == 0x08)
4672 SET_AH(0x02); // unsupported, aka normal keyboard
4674 default:
4675 BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
4679 unsigned int
4680 dequeue_key(scan_code, ascii_code, incr)
4681 Bit8u *scan_code;
4682 Bit8u *ascii_code;
4683 unsigned int incr;
4685 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail;
4686 Bit16u ss;
4687 Bit8u acode, scode;
4689 #if BX_CPU < 2
4690 buffer_start = 0x001E;
4691 buffer_end = 0x003E;
4692 #else
4693 buffer_start = read_word(0x0040, 0x0080);
4694 buffer_end = read_word(0x0040, 0x0082);
4695 #endif
4697 buffer_head = read_word(0x0040, 0x001a);
4698 buffer_tail = read_word(0x0040, 0x001c);
4700 if (buffer_head != buffer_tail) {
4701 ss = get_SS();
4702 acode = read_byte(0x0040, buffer_head);
4703 scode = read_byte(0x0040, buffer_head+1);
4704 write_byte(ss, ascii_code, acode);
4705 write_byte(ss, scan_code, scode);
4707 if (incr) {
4708 buffer_head += 2;
4709 if (buffer_head >= buffer_end)
4710 buffer_head = buffer_start;
4711 write_word(0x0040, 0x001a, buffer_head);
4713 return(1);
4715 else {
4716 return(0);
4720 static char panic_msg_keyb_buffer_full[] = "%s: keyboard input buffer full\n";
4722 Bit8u
4723 inhibit_mouse_int_and_events()
4725 Bit8u command_byte, prev_command_byte;
4727 // Turn off IRQ generation and aux data line
4728 if ( inb(0x64) & 0x02 )
4729 BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
4730 outb(0x64, 0x20); // get command byte
4731 while ( (inb(0x64) & 0x01) != 0x01 );
4732 prev_command_byte = inb(0x60);
4733 command_byte = prev_command_byte;
4734 //while ( (inb(0x64) & 0x02) );
4735 if ( inb(0x64) & 0x02 )
4736 BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
4737 command_byte &= 0xfd; // turn off IRQ 12 generation
4738 command_byte |= 0x20; // disable mouse serial clock line
4739 outb(0x64, 0x60); // write command byte
4740 outb(0x60, command_byte);
4741 return(prev_command_byte);
4744 void
4745 enable_mouse_int_and_events()
4747 Bit8u command_byte;
4749 // Turn on IRQ generation and aux data line
4750 if ( inb(0x64) & 0x02 )
4751 BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
4752 outb(0x64, 0x20); // get command byte
4753 while ( (inb(0x64) & 0x01) != 0x01 );
4754 command_byte = inb(0x60);
4755 //while ( (inb(0x64) & 0x02) );
4756 if ( inb(0x64) & 0x02 )
4757 BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
4758 command_byte |= 0x02; // turn on IRQ 12 generation
4759 command_byte &= 0xdf; // enable mouse serial clock line
4760 outb(0x64, 0x60); // write command byte
4761 outb(0x60, command_byte);
4764 Bit8u
4765 send_to_mouse_ctrl(sendbyte)
4766 Bit8u sendbyte;
4768 Bit8u response;
4770 // wait for chance to write to ctrl
4771 if ( inb(0x64) & 0x02 )
4772 BX_PANIC(panic_msg_keyb_buffer_full,"sendmouse");
4773 outb(0x64, 0xD4);
4774 outb(0x60, sendbyte);
4775 return(0);
4779 Bit8u
4780 get_mouse_data(data)
4781 Bit8u *data;
4783 Bit8u response;
4784 Bit16u ss;
4786 while ( (inb(0x64) & 0x21) != 0x21 ) {
4789 response = inb(0x60);
4791 ss = get_SS();
4792 write_byte(ss, data, response);
4793 return(0);
4796 void
4797 set_kbd_command_byte(command_byte)
4798 Bit8u command_byte;
4800 if ( inb(0x64) & 0x02 )
4801 BX_PANIC(panic_msg_keyb_buffer_full,"setkbdcomm");
4802 outb(0x64, 0xD4);
4804 outb(0x64, 0x60); // write command byte
4805 outb(0x60, command_byte);
4808 void
4809 int09_function(DI, SI, BP, SP, BX, DX, CX, AX)
4810 Bit16u DI, SI, BP, SP, BX, DX, CX, AX;
4812 Bit8u scancode, asciicode, shift_flags;
4813 Bit8u mf2_flags, mf2_state, led_flags;
4815 //
4816 // DS has been set to F000 before call
4817 //
4820 scancode = GET_AL();
4822 if (scancode == 0) {
4823 BX_INFO("KBD: int09 handler: AL=0\n");
4824 return;
4828 shift_flags = read_byte(0x0040, 0x17);
4829 mf2_flags = read_byte(0x0040, 0x18);
4830 mf2_state = read_byte(0x0040, 0x96);
4831 led_flags = read_byte(0x0040, 0x97);
4832 asciicode = 0;
4834 switch (scancode) {
4835 case 0x3a: /* Caps Lock press */
4836 shift_flags ^= 0x40;
4837 write_byte(0x0040, 0x17, shift_flags);
4838 mf2_flags |= 0x40;
4839 write_byte(0x0040, 0x18, mf2_flags);
4840 led_flags ^= 0x04;
4841 write_byte(0x0040, 0x97, led_flags);
4842 break;
4843 case 0xba: /* Caps Lock release */
4844 mf2_flags &= ~0x40;
4845 write_byte(0x0040, 0x18, mf2_flags);
4846 break;
4848 case 0x2a: /* L Shift press */
4849 /*shift_flags &= ~0x40;*/
4850 shift_flags |= 0x02;
4851 write_byte(0x0040, 0x17, shift_flags);
4852 led_flags &= ~0x04;
4853 write_byte(0x0040, 0x97, led_flags);
4854 break;
4855 case 0xaa: /* L Shift release */
4856 shift_flags &= ~0x02;
4857 write_byte(0x0040, 0x17, shift_flags);
4858 break;
4860 case 0x36: /* R Shift press */
4861 /*shift_flags &= ~0x40;*/
4862 shift_flags |= 0x01;
4863 write_byte(0x0040, 0x17, shift_flags);
4864 led_flags &= ~0x04;
4865 write_byte(0x0040, 0x97, led_flags);
4866 break;
4867 case 0xb6: /* R Shift release */
4868 shift_flags &= ~0x01;
4869 write_byte(0x0040, 0x17, shift_flags);
4870 break;
4872 case 0x1d: /* Ctrl press */
4873 shift_flags |= 0x04;
4874 write_byte(0x0040, 0x17, shift_flags);
4875 if (mf2_state & 0x01) {
4876 mf2_flags |= 0x04;
4877 } else {
4878 mf2_flags |= 0x01;
4880 write_byte(0x0040, 0x18, mf2_flags);
4881 break;
4882 case 0x9d: /* Ctrl release */
4883 shift_flags &= ~0x04;
4884 write_byte(0x0040, 0x17, shift_flags);
4885 if (mf2_state & 0x01) {
4886 mf2_flags &= ~0x04;
4887 } else {
4888 mf2_flags &= ~0x01;
4890 write_byte(0x0040, 0x18, mf2_flags);
4891 break;
4893 case 0x38: /* Alt press */
4894 shift_flags |= 0x08;
4895 write_byte(0x0040, 0x17, shift_flags);
4896 if (mf2_state & 0x01) {
4897 mf2_flags |= 0x08;
4898 } else {
4899 mf2_flags |= 0x02;
4901 write_byte(0x0040, 0x18, mf2_flags);
4902 break;
4903 case 0xb8: /* Alt release */
4904 shift_flags &= ~0x08;
4905 write_byte(0x0040, 0x17, shift_flags);
4906 if (mf2_state & 0x01) {
4907 mf2_flags &= ~0x08;
4908 } else {
4909 mf2_flags &= ~0x02;
4911 write_byte(0x0040, 0x18, mf2_flags);
4912 break;
4914 case 0x45: /* Num Lock press */
4915 if ((mf2_state & 0x01) == 0) {
4916 mf2_flags |= 0x20;
4917 write_byte(0x0040, 0x18, mf2_flags);
4918 shift_flags ^= 0x20;
4919 led_flags ^= 0x02;
4920 write_byte(0x0040, 0x17, shift_flags);
4921 write_byte(0x0040, 0x97, led_flags);
4923 break;
4924 case 0xc5: /* Num Lock release */
4925 if ((mf2_state & 0x01) == 0) {
4926 mf2_flags &= ~0x20;
4927 write_byte(0x0040, 0x18, mf2_flags);
4929 break;
4931 case 0x46: /* Scroll Lock press */
4932 mf2_flags |= 0x10;
4933 write_byte(0x0040, 0x18, mf2_flags);
4934 shift_flags ^= 0x10;
4935 led_flags ^= 0x01;
4936 write_byte(0x0040, 0x17, shift_flags);
4937 write_byte(0x0040, 0x97, led_flags);
4938 break;
4940 case 0xc6: /* Scroll Lock release */
4941 mf2_flags &= ~0x10;
4942 write_byte(0x0040, 0x18, mf2_flags);
4943 break;
4945 case 0x53: /* Del */
4946 if ((shift_flags & 0x0c) == 0x0c) /* Ctrl + Alt */
4947 machine_reset();
4948 /* Fall through */
4949 default:
4950 if (scancode & 0x80) return; /* toss key releases ... */
4951 if (scancode > MAX_SCAN_CODE) {
4952 BX_INFO("KBD: int09h_handler(): unknown scancode (%x) read!\n", scancode);
4953 return;
4955 if (shift_flags & 0x08) { /* ALT */
4956 asciicode = scan_to_scanascii[scancode].alt;
4957 scancode = scan_to_scanascii[scancode].alt >> 8;
4959 else if (shift_flags & 0x04) { /* CONTROL */
4960 asciicode = scan_to_scanascii[scancode].control;
4961 scancode = scan_to_scanascii[scancode].control >> 8;
4963 else if (shift_flags & 0x03) { /* LSHIFT + RSHIFT */
4964 /* check if lock state should be ignored
4965 * because a SHIFT key are pressed */
4967 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
4968 asciicode = scan_to_scanascii[scancode].normal;
4969 scancode = scan_to_scanascii[scancode].normal >> 8;
4971 else {
4972 asciicode = scan_to_scanascii[scancode].shift;
4973 scancode = scan_to_scanascii[scancode].shift >> 8;
4976 else {
4977 /* check if lock is on */
4978 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
4979 asciicode = scan_to_scanascii[scancode].shift;
4980 scancode = scan_to_scanascii[scancode].shift >> 8;
4982 else {
4983 asciicode = scan_to_scanascii[scancode].normal;
4984 scancode = scan_to_scanascii[scancode].normal >> 8;
4987 if (scancode==0 && asciicode==0) {
4988 BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
4990 enqueue_key(scancode, asciicode);
4991 break;
4993 mf2_state &= ~0x01;
4996 unsigned int
4997 enqueue_key(scan_code, ascii_code)
4998 Bit8u scan_code, ascii_code;
5000 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail, temp_tail;
5002 //BX_INFO("KBD: enqueue_key() called scan:%02x, ascii:%02x\n",
5003 // scan_code, ascii_code);
5005 #if BX_CPU < 2
5006 buffer_start = 0x001E;
5007 buffer_end = 0x003E;
5008 #else
5009 buffer_start = read_word(0x0040, 0x0080);
5010 buffer_end = read_word(0x0040, 0x0082);
5011 #endif
5013 buffer_head = read_word(0x0040, 0x001A);
5014 buffer_tail = read_word(0x0040, 0x001C);
5016 temp_tail = buffer_tail;
5017 buffer_tail += 2;
5018 if (buffer_tail >= buffer_end)
5019 buffer_tail = buffer_start;
5021 if (buffer_tail == buffer_head) {
5022 return(0);
5025 write_byte(0x0040, temp_tail, ascii_code);
5026 write_byte(0x0040, temp_tail+1, scan_code);
5027 write_word(0x0040, 0x001C, buffer_tail);
5028 return(1);
5032 void
5033 int74_function(make_farcall, Z, Y, X, status)
5034 Bit16u make_farcall, Z, Y, X, status;
5036 Bit16u ebda_seg=read_word(0x0040,0x000E);
5037 Bit8u in_byte, index, package_count;
5038 Bit8u mouse_flags_1, mouse_flags_2;
5040 BX_DEBUG_INT74("entering int74_function\n");
5041 make_farcall = 0;
5043 in_byte = inb(0x64);
5044 if ( (in_byte & 0x21) != 0x21 ) {
5045 return;
5047 in_byte = inb(0x60);
5048 BX_DEBUG_INT74("int74: read byte %02x\n", in_byte);
5050 mouse_flags_1 = read_byte(ebda_seg, 0x0026);
5051 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
5053 if ( (mouse_flags_2 & 0x80) != 0x80 ) {
5054 // BX_PANIC("int74_function:\n");
5055 return;
5058 package_count = mouse_flags_2 & 0x07;
5059 index = mouse_flags_1 & 0x07;
5060 write_byte(ebda_seg, 0x28 + index, in_byte);
5062 if ( (index+1) >= package_count ) {
5063 BX_DEBUG_INT74("int74_function: make_farcall=1\n");
5064 status = read_byte(ebda_seg, 0x0028 + 0);
5065 X = read_byte(ebda_seg, 0x0028 + 1);
5066 Y = read_byte(ebda_seg, 0x0028 + 2);
5067 Z = 0;
5068 mouse_flags_1 = 0;
5069 // check if far call handler installed
5070 if (mouse_flags_2 & 0x80)
5071 make_farcall = 1;
5073 else {
5074 mouse_flags_1++;
5076 write_byte(ebda_seg, 0x0026, mouse_flags_1);
5079 #define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
5081 #if BX_USE_ATADRV
5083 void
5084 int13_harddisk(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5085 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5087 Bit32u lba;
5088 Bit16u ebda_seg=read_word(0x0040,0x000E);
5089 Bit16u cylinder, head, sector;
5090 Bit16u segment, offset;
5091 Bit16u npc, nph, npspt, nlc, nlh, nlspt;
5092 Bit16u size, count;
5093 Bit8u device, status;
5095 BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5097 write_byte(0x0040, 0x008e, 0); // clear completion flag
5099 // basic check : device has to be defined
5100 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES) ) {
5101 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5102 goto int13_fail;
5105 // Get the ata channel
5106 device=read_byte(ebda_seg,&EbdaData->ata.hdidmap[GET_ELDL()-0x80]);
5108 // basic check : device has to be valid
5109 if (device >= BX_MAX_ATA_DEVICES) {
5110 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5111 goto int13_fail;
5114 switch (GET_AH()) {
5116 case 0x00: /* disk controller reset */
5117 ata_reset (device);
5118 goto int13_success;
5119 break;
5121 case 0x01: /* read disk status */
5122 status = read_byte(0x0040, 0x0074);
5123 SET_AH(status);
5124 SET_DISK_RET_STATUS(0);
5125 /* set CF if error status read */
5126 if (status) goto int13_fail_nostatus;
5127 else goto int13_success_noah;
5128 break;
5130 case 0x02: // read disk sectors
5131 case 0x03: // write disk sectors
5132 case 0x04: // verify disk sectors
5134 count = GET_AL();
5135 cylinder = GET_CH();
5136 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
5137 sector = (GET_CL() & 0x3f);
5138 head = GET_DH();
5140 segment = ES;
5141 offset = BX;
5143 if ( (count > 128) || (count == 0) ) {
5144 BX_INFO("int13_harddisk: function %02x, count out of range!\n",GET_AH());
5145 goto int13_fail;
5148 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
5149 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
5150 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
5152 // sanity check on cyl heads, sec
5153 if( (cylinder >= nlc) || (head >= nlh) || (sector > nlspt )) {
5154 BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder, head, sector);
5155 goto int13_fail;
5158 // FIXME verify
5159 if ( GET_AH() == 0x04 ) goto int13_success;
5161 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5162 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5164 // if needed, translate lchs to lba, and execute command
5165 if ( (nph != nlh) || (npspt != nlspt)) {
5166 lba = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
5167 sector = 0; // this forces the command to be lba
5170 if ( GET_AH() == 0x02 )
5171 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, cylinder, head, sector, lba, segment, offset);
5172 else
5173 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, cylinder, head, sector, lba, segment, offset);
5175 // Set nb of sector transferred
5176 SET_AL(read_word(ebda_seg, &EbdaData->ata.trsfsectors));
5178 if (status != 0) {
5179 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5180 SET_AH(0x0c);
5181 goto int13_fail_noah;
5184 goto int13_success;
5185 break;
5187 case 0x05: /* format disk track */
5188 BX_INFO("format disk track called\n");
5189 goto int13_success;
5190 return;
5191 break;
5193 case 0x08: /* read disk drive parameters */
5195 // Get logical geometry from table
5196 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
5197 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
5198 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
5199 count = read_byte(ebda_seg, &EbdaData->ata.hdcount);
5201 nlc = nlc - 2; /* 0 based , last sector not used */
5202 SET_AL(0);
5203 SET_CH(nlc & 0xff);
5204 SET_CL(((nlc >> 2) & 0xc0) | (nlspt & 0x3f));
5205 SET_DH(nlh - 1);
5206 SET_DL(count); /* FIXME returns 0, 1, or n hard drives */
5208 // FIXME should set ES & DI
5210 goto int13_success;
5211 break;
5213 case 0x10: /* check drive ready */
5214 // should look at 40:8E also???
5216 // Read the status from controller
5217 status = inb(read_word(ebda_seg, &EbdaData->ata.channels[device/2].iobase1) + ATA_CB_STAT);
5218 if ( (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY ) {
5219 goto int13_success;
5221 else {
5222 SET_AH(0xAA);
5223 goto int13_fail_noah;
5225 break;
5227 case 0x15: /* read disk drive size */
5229 // Get physical geometry from table
5230 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5231 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5232 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5234 // Compute sector count seen by int13
5235 lba = (Bit32u)(npc - 1) * (Bit32u)nph * (Bit32u)npspt;
5236 CX = lba >> 16;
5237 DX = lba & 0xffff;
5239 SET_AH(3); // hard disk accessible
5240 goto int13_success_noah;
5241 break;
5243 case 0x41: // IBM/MS installation check
5244 BX=0xaa55; // install check
5245 SET_AH(0x30); // EDD 3.0
5246 CX=0x0007; // ext disk access and edd, removable supported
5247 goto int13_success_noah;
5248 break;
5250 case 0x42: // IBM/MS extended read
5251 case 0x43: // IBM/MS extended write
5252 case 0x44: // IBM/MS verify
5253 case 0x47: // IBM/MS extended seek
5255 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5256 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5257 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5259 // Can't use 64 bits lba
5260 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5261 if (lba != 0L) {
5262 BX_PANIC("int13_harddisk: function %02x. Can't use 64bits lba\n",GET_AH());
5263 goto int13_fail;
5266 // Get 32 bits lba and check
5267 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5268 if (lba >= read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors) ) {
5269 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5270 goto int13_fail;
5273 // If verify or seek
5274 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5275 goto int13_success;
5277 // Execute the command
5278 if ( GET_AH() == 0x42 )
5279 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba, segment, offset);
5280 else
5281 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
5283 count=read_word(ebda_seg, &EbdaData->ata.trsfsectors);
5284 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5286 if (status != 0) {
5287 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5288 SET_AH(0x0c);
5289 goto int13_fail_noah;
5292 goto int13_success;
5293 break;
5295 case 0x45: // IBM/MS lock/unlock drive
5296 case 0x49: // IBM/MS extended media change
5297 goto int13_success; // Always success for HD
5298 break;
5300 case 0x46: // IBM/MS eject media
5301 SET_AH(0xb2); // Volume Not Removable
5302 goto int13_fail_noah; // Always fail for HD
5303 break;
5305 case 0x48: // IBM/MS get drive parameters
5306 size=read_word(DS,SI+(Bit16u)&Int13DPT->size);
5308 // Buffer is too small
5309 if(size < 0x1a)
5310 goto int13_fail;
5312 // EDD 1.x
5313 if(size >= 0x1a) {
5314 Bit16u blksize;
5316 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5317 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5318 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5319 lba = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors);
5320 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5322 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5323 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x02); // geometry is valid
5324 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, (Bit32u)npc);
5325 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, (Bit32u)nph);
5326 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, (Bit32u)npspt);
5327 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, lba); // FIXME should be Bit64
5328 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0L);
5329 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5332 // EDD 2.x
5333 if(size >= 0x1e) {
5334 Bit8u channel, dev, irq, mode, checksum, i, translation;
5335 Bit16u iobase1, iobase2, options;
5337 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5339 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5340 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5342 // Fill in dpte
5343 channel = device / 2;
5344 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5345 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5346 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5347 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5348 translation = read_byte(ebda_seg, &EbdaData->ata.devices[device].translation);
5350 options = (translation==ATA_TRANSLATION_NONE?0:1<<3); // chs translation
5351 options |= (1<<4); // lba translation
5352 options |= (mode==ATA_MODE_PIO32?1:0<<7);
5353 options |= (translation==ATA_TRANSLATION_LBA?1:0<<9);
5354 options |= (translation==ATA_TRANSLATION_RECHS?3:0<<9);
5356 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5357 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5358 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5359 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5360 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5361 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5362 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5363 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5364 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5365 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5366 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5368 checksum=0;
5369 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5370 checksum = ~checksum;
5371 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5374 // EDD 3.x
5375 if(size >= 0x42) {
5376 Bit8u channel, iface, checksum, i;
5377 Bit16u iobase1;
5379 channel = device / 2;
5380 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5381 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5383 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5384 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5385 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5386 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5387 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5389 if (iface==ATA_IFACE_ISA) {
5390 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5391 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5392 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5393 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5395 else {
5396 // FIXME PCI
5398 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5399 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5400 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5401 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5403 if (iface==ATA_IFACE_ISA) {
5404 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5405 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5406 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5408 else {
5409 // FIXME PCI
5411 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5412 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5413 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5414 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5416 checksum=0;
5417 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5418 checksum = ~checksum;
5419 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5422 goto int13_success;
5423 break;
5425 case 0x4e: // // IBM/MS set hardware configuration
5426 // DMA, prefetch, PIO maximum not supported
5427 switch (GET_AL()) {
5428 case 0x01:
5429 case 0x03:
5430 case 0x04:
5431 case 0x06:
5432 goto int13_success;
5433 break;
5434 default :
5435 goto int13_fail;
5437 break;
5439 case 0x09: /* initialize drive parameters */
5440 case 0x0c: /* seek to specified cylinder */
5441 case 0x0d: /* alternate disk reset */
5442 case 0x11: /* recalibrate */
5443 case 0x14: /* controller internal diagnostic */
5444 BX_INFO("int13h_harddisk function %02xh unimplemented, returns success\n", GET_AH());
5445 goto int13_success;
5446 break;
5448 case 0x0a: /* read disk sectors with ECC */
5449 case 0x0b: /* write disk sectors with ECC */
5450 case 0x18: // set media type for format
5451 case 0x50: // IBM/MS send packet command
5452 default:
5453 BX_INFO("int13_harddisk function %02xh unsupported, returns fail\n", GET_AH());
5454 goto int13_fail;
5455 break;
5458 int13_fail:
5459 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5460 int13_fail_noah:
5461 SET_DISK_RET_STATUS(GET_AH());
5462 int13_fail_nostatus:
5463 SET_CF(); // error occurred
5464 return;
5466 int13_success:
5467 SET_AH(0x00); // no error
5468 int13_success_noah:
5469 SET_DISK_RET_STATUS(0x00);
5470 CLEAR_CF(); // no error
5471 return;
5474 // ---------------------------------------------------------------------------
5475 // Start of int13 for cdrom
5476 // ---------------------------------------------------------------------------
5478 void
5479 int13_cdrom(EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5480 Bit16u EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5482 Bit16u ebda_seg=read_word(0x0040,0x000E);
5483 Bit8u device, status, locks;
5484 Bit8u atacmd[12];
5485 Bit32u lba;
5486 Bit16u count, segment, offset, i, size;
5488 BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5489 // BX_DEBUG_INT13_CD("int13_cdrom: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
5491 SET_DISK_RET_STATUS(0x00);
5493 /* basic check : device should be 0xE0+ */
5494 if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES) ) {
5495 BX_INFO("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5496 goto int13_fail;
5499 // Get the ata channel
5500 device=read_byte(ebda_seg,&EbdaData->ata.cdidmap[GET_ELDL()-0xE0]);
5502 /* basic check : device has to be valid */
5503 if (device >= BX_MAX_ATA_DEVICES) {
5504 BX_INFO("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5505 goto int13_fail;
5508 switch (GET_AH()) {
5510 // all those functions return SUCCESS
5511 case 0x00: /* disk controller reset */
5512 case 0x09: /* initialize drive parameters */
5513 case 0x0c: /* seek to specified cylinder */
5514 case 0x0d: /* alternate disk reset */
5515 case 0x10: /* check drive ready */
5516 case 0x11: /* recalibrate */
5517 case 0x14: /* controller internal diagnostic */
5518 case 0x16: /* detect disk change */
5519 goto int13_success;
5520 break;
5522 // all those functions return disk write-protected
5523 case 0x03: /* write disk sectors */
5524 case 0x05: /* format disk track */
5525 case 0x43: // IBM/MS extended write
5526 SET_AH(0x03);
5527 goto int13_fail_noah;
5528 break;
5530 case 0x01: /* read disk status */
5531 status = read_byte(0x0040, 0x0074);
5532 SET_AH(status);
5533 SET_DISK_RET_STATUS(0);
5535 /* set CF if error status read */
5536 if (status) goto int13_fail_nostatus;
5537 else goto int13_success_noah;
5538 break;
5540 case 0x15: /* read disk drive size */
5541 SET_AH(0x02);
5542 goto int13_fail_noah;
5543 break;
5545 case 0x41: // IBM/MS installation check
5546 BX=0xaa55; // install check
5547 SET_AH(0x30); // EDD 2.1
5548 CX=0x0007; // ext disk access, removable and edd
5549 goto int13_success_noah;
5550 break;
5552 case 0x42: // IBM/MS extended read
5553 case 0x44: // IBM/MS verify sectors
5554 case 0x47: // IBM/MS extended seek
5556 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5557 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5558 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5560 // Can't use 64 bits lba
5561 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5562 if (lba != 0L) {
5563 BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
5564 goto int13_fail;
5567 // Get 32 bits lba
5568 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5570 // If verify or seek
5571 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5572 goto int13_success;
5574 memsetb(get_SS(),atacmd,0,12);
5575 atacmd[0]=0x28; // READ command
5576 atacmd[7]=(count & 0xff00) >> 8; // Sectors
5577 atacmd[8]=(count & 0x00ff); // Sectors
5578 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
5579 atacmd[3]=(lba & 0x00ff0000) >> 16;
5580 atacmd[4]=(lba & 0x0000ff00) >> 8;
5581 atacmd[5]=(lba & 0x000000ff);
5582 status = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, count*2048L, ATA_DATA_IN, segment,offset);
5584 count = (Bit16u)(read_dword(ebda_seg, &EbdaData->ata.trsfbytes) >> 11);
5585 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5587 if (status != 0) {
5588 BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status);
5589 SET_AH(0x0c);
5590 goto int13_fail_noah;
5593 goto int13_success;
5594 break;
5596 case 0x45: // IBM/MS lock/unlock drive
5597 if (GET_AL() > 2) goto int13_fail;
5599 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
5601 switch (GET_AL()) {
5602 case 0 : // lock
5603 if (locks == 0xff) {
5604 SET_AH(0xb4);
5605 SET_AL(1);
5606 goto int13_fail_noah;
5608 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, ++locks);
5609 SET_AL(1);
5610 break;
5611 case 1 : // unlock
5612 if (locks == 0x00) {
5613 SET_AH(0xb0);
5614 SET_AL(0);
5615 goto int13_fail_noah;
5617 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, --locks);
5618 SET_AL(locks==0?0:1);
5619 break;
5620 case 2 : // status
5621 SET_AL(locks==0?0:1);
5622 break;
5624 goto int13_success;
5625 break;
5627 case 0x46: // IBM/MS eject media
5628 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
5630 if (locks != 0) {
5631 SET_AH(0xb1); // media locked
5632 goto int13_fail_noah;
5634 // FIXME should handle 0x31 no media in device
5635 // FIXME should handle 0xb5 valid request failed
5637 // Call removable media eject
5638 ASM_START
5639 push bp
5640 mov bp, sp
5642 mov ah, #0x52
5643 int 15
5644 mov _int13_cdrom.status + 2[bp], ah
5645 jnc int13_cdrom_rme_end
5646 mov _int13_cdrom.status, #1
5647 int13_cdrom_rme_end:
5648 pop bp
5649 ASM_END
5651 if (status != 0) {
5652 SET_AH(0xb1); // media locked
5653 goto int13_fail_noah;
5656 goto int13_success;
5657 break;
5659 case 0x48: // IBM/MS get drive parameters
5660 size = read_word(DS,SI+(Bit16u)&Int13Ext->size);
5662 // Buffer is too small
5663 if(size < 0x1a)
5664 goto int13_fail;
5666 // EDD 1.x
5667 if(size >= 0x1a) {
5668 Bit16u cylinders, heads, spt, blksize;
5670 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5672 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5673 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x74); // removable, media change, lockable, max values
5674 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, 0xffffffff);
5675 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, 0xffffffff);
5676 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, 0xffffffff);
5677 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, 0xffffffff); // FIXME should be Bit64
5678 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0xffffffff);
5679 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5682 // EDD 2.x
5683 if(size >= 0x1e) {
5684 Bit8u channel, dev, irq, mode, checksum, i;
5685 Bit16u iobase1, iobase2, options;
5687 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5689 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5690 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5692 // Fill in dpte
5693 channel = device / 2;
5694 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5695 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5696 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5697 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5699 // FIXME atapi device
5700 options = (1<<4); // lba translation
5701 options |= (1<<5); // removable device
5702 options |= (1<<6); // atapi device
5703 options |= (mode==ATA_MODE_PIO32?1:0<<7);
5705 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5706 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5707 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5708 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5709 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5710 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5711 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5712 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5713 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5714 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5715 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5717 checksum=0;
5718 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5719 checksum = ~checksum;
5720 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5723 // EDD 3.x
5724 if(size >= 0x42) {
5725 Bit8u channel, iface, checksum, i;
5726 Bit16u iobase1;
5728 channel = device / 2;
5729 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5730 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5732 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5733 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5734 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5735 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5736 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5738 if (iface==ATA_IFACE_ISA) {
5739 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5740 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5741 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5742 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5744 else {
5745 // FIXME PCI
5747 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5748 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5749 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5750 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5752 if (iface==ATA_IFACE_ISA) {
5753 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5754 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5755 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5757 else {
5758 // FIXME PCI
5760 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5761 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5762 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5763 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5765 checksum=0;
5766 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5767 checksum = ~checksum;
5768 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5771 goto int13_success;
5772 break;
5774 case 0x49: // IBM/MS extended media change
5775 // always send changed ??
5776 SET_AH(06);
5777 goto int13_fail_nostatus;
5778 break;
5780 case 0x4e: // // IBM/MS set hardware configuration
5781 // DMA, prefetch, PIO maximum not supported
5782 switch (GET_AL()) {
5783 case 0x01:
5784 case 0x03:
5785 case 0x04:
5786 case 0x06:
5787 goto int13_success;
5788 break;
5789 default :
5790 goto int13_fail;
5792 break;
5794 // all those functions return unimplemented
5795 case 0x02: /* read sectors */
5796 case 0x04: /* verify sectors */
5797 case 0x08: /* read disk drive parameters */
5798 case 0x0a: /* read disk sectors with ECC */
5799 case 0x0b: /* write disk sectors with ECC */
5800 case 0x18: /* set media type for format */
5801 case 0x50: // ? - send packet command
5802 default:
5803 BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
5804 goto int13_fail;
5805 break;
5808 int13_fail:
5809 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5810 int13_fail_noah:
5811 SET_DISK_RET_STATUS(GET_AH());
5812 int13_fail_nostatus:
5813 SET_CF(); // error occurred
5814 return;
5816 int13_success:
5817 SET_AH(0x00); // no error
5818 int13_success_noah:
5819 SET_DISK_RET_STATUS(0x00);
5820 CLEAR_CF(); // no error
5821 return;
5824 // ---------------------------------------------------------------------------
5825 // End of int13 for cdrom
5826 // ---------------------------------------------------------------------------
5828 #if BX_ELTORITO_BOOT
5829 // ---------------------------------------------------------------------------
5830 // Start of int13 for eltorito functions
5831 // ---------------------------------------------------------------------------
5833 void
5834 int13_eltorito(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
5835 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
5837 Bit16u ebda_seg=read_word(0x0040,0x000E);
5839 BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5840 // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
5842 switch (GET_AH()) {
5844 // FIXME ElTorito Various. Should be implemented
5845 case 0x4a: // ElTorito - Initiate disk emu
5846 case 0x4c: // ElTorito - Initiate disk emu and boot
5847 case 0x4d: // ElTorito - Return Boot catalog
5848 BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX);
5849 goto int13_fail;
5850 break;
5852 case 0x4b: // ElTorito - Terminate disk emu
5853 // FIXME ElTorito Hardcoded
5854 write_byte(DS,SI+0x00,0x13);
5855 write_byte(DS,SI+0x01,read_byte(ebda_seg,&EbdaData->cdemu.media));
5856 write_byte(DS,SI+0x02,read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
5857 write_byte(DS,SI+0x03,read_byte(ebda_seg,&EbdaData->cdemu.controller_index));
5858 write_dword(DS,SI+0x04,read_dword(ebda_seg,&EbdaData->cdemu.ilba));
5859 write_word(DS,SI+0x08,read_word(ebda_seg,&EbdaData->cdemu.device_spec));
5860 write_word(DS,SI+0x0a,read_word(ebda_seg,&EbdaData->cdemu.buffer_segment));
5861 write_word(DS,SI+0x0c,read_word(ebda_seg,&EbdaData->cdemu.load_segment));
5862 write_word(DS,SI+0x0e,read_word(ebda_seg,&EbdaData->cdemu.sector_count));
5863 write_byte(DS,SI+0x10,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.cylinders));
5864 write_byte(DS,SI+0x11,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.spt));
5865 write_byte(DS,SI+0x12,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.heads));
5867 // If we have to terminate emulation
5868 if(GET_AL() == 0x00) {
5869 // FIXME ElTorito Various. Should be handled accordingly to spec
5870 write_byte(ebda_seg,&EbdaData->cdemu.active, 0x00); // bye bye
5873 goto int13_success;
5874 break;
5876 default:
5877 BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
5878 goto int13_fail;
5879 break;
5882 int13_fail:
5883 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5884 SET_DISK_RET_STATUS(GET_AH());
5885 SET_CF(); // error occurred
5886 return;
5888 int13_success:
5889 SET_AH(0x00); // no error
5890 SET_DISK_RET_STATUS(0x00);
5891 CLEAR_CF(); // no error
5892 return;
5895 // ---------------------------------------------------------------------------
5896 // End of int13 for eltorito functions
5897 // ---------------------------------------------------------------------------
5899 // ---------------------------------------------------------------------------
5900 // Start of int13 when emulating a device from the cd
5901 // ---------------------------------------------------------------------------
5903 void
5904 int13_cdemu(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
5905 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
5907 Bit16u ebda_seg=read_word(0x0040,0x000E);
5908 Bit8u device, status;
5909 Bit16u vheads, vspt, vcylinders;
5910 Bit16u head, sector, cylinder, nbsectors;
5911 Bit32u vlba, ilba, slba, elba;
5912 Bit16u before, segment, offset;
5913 Bit8u atacmd[12];
5915 BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5916 //BX_DEBUG_INT13_ET("int13_cdemu: SS=%04x ES=%04x DI=%04x SI=%04x\n", get_SS(), ES, DI, SI);
5918 /* at this point, we are emulating a floppy/harddisk */
5920 // Recompute the device number
5921 device = read_byte(ebda_seg,&EbdaData->cdemu.controller_index) * 2;
5922 device += read_byte(ebda_seg,&EbdaData->cdemu.device_spec);
5924 SET_DISK_RET_STATUS(0x00);
5926 /* basic checks : emulation should be active, dl should equal the emulated drive */
5927 if( (read_byte(ebda_seg,&EbdaData->cdemu.active) ==0 )
5928 || (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive ) != GET_DL())) {
5929 BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
5930 goto int13_fail;
5934 switch (GET_AH()) {
5936 // all those functions return SUCCESS
5937 case 0x00: /* disk controller reset */
5938 case 0x09: /* initialize drive parameters */
5939 case 0x0c: /* seek to specified cylinder */
5940 case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
5941 case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
5942 case 0x11: /* recalibrate */
5943 case 0x14: /* controller internal diagnostic */
5944 case 0x16: /* detect disk change */
5945 goto int13_success;
5946 break;
5948 // all those functions return disk write-protected
5949 case 0x03: /* write disk sectors */
5950 case 0x05: /* format disk track */
5951 SET_AH(0x03);
5952 goto int13_fail_noah;
5953 break;
5955 case 0x01: /* read disk status */
5956 status=read_byte(0x0040, 0x0074);
5957 SET_AH(status);
5958 SET_DISK_RET_STATUS(0);
5960 /* set CF if error status read */
5961 if (status) goto int13_fail_nostatus;
5962 else goto int13_success_noah;
5963 break;
5965 case 0x02: // read disk sectors
5966 case 0x04: // verify disk sectors
5967 vspt = read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
5968 vcylinders = read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders);
5969 vheads = read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads);
5971 ilba = read_dword(ebda_seg,&EbdaData->cdemu.ilba);
5973 sector = GET_CL() & 0x003f;
5974 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
5975 head = GET_DH();
5976 nbsectors = GET_AL();
5977 segment = ES;
5978 offset = BX;
5980 // no sector to read ?
5981 if(nbsectors==0) goto int13_success;
5983 // sanity checks sco openserver needs this!
5984 if ((sector > vspt)
5985 || (cylinder >= vcylinders)
5986 || (head >= vheads)) {
5987 goto int13_fail;
5990 // After controls, verify do nothing
5991 if (GET_AH() == 0x04) goto int13_success;
5993 segment = ES+(BX / 16);
5994 offset = BX % 16;
5996 // calculate the virtual lba inside the image
5997 vlba=((((Bit32u)cylinder*(Bit32u)vheads)+(Bit32u)head)*(Bit32u)vspt)+((Bit32u)(sector-1));
5999 // In advance so we don't loose the count
6000 SET_AL(nbsectors);
6002 // start lba on cd
6003 slba = (Bit32u)vlba/4;
6004 before= (Bit16u)vlba%4;
6006 // end lba on cd
6007 elba = (Bit32u)(vlba+nbsectors-1)/4;
6009 memsetb(get_SS(),atacmd,0,12);
6010 atacmd[0]=0x28; // READ command
6011 atacmd[7]=((Bit16u)(elba-slba+1) & 0xff00) >> 8; // Sectors
6012 atacmd[8]=((Bit16u)(elba-slba+1) & 0x00ff); // Sectors
6013 atacmd[2]=(ilba+slba & 0xff000000) >> 24; // LBA
6014 atacmd[3]=(ilba+slba & 0x00ff0000) >> 16;
6015 atacmd[4]=(ilba+slba & 0x0000ff00) >> 8;
6016 atacmd[5]=(ilba+slba & 0x000000ff);
6017 if((status = ata_cmd_packet(device, 12, get_SS(), atacmd, before*512, nbsectors*512L, ATA_DATA_IN, segment,offset)) != 0) {
6018 BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status);
6019 SET_AH(0x02);
6020 SET_AL(0);
6021 goto int13_fail_noah;
6024 goto int13_success;
6025 break;
6027 case 0x08: /* read disk drive parameters */
6028 vspt=read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
6029 vcylinders=read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders) - 1;
6030 vheads=read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads) - 1;
6032 SET_AL( 0x00 );
6033 SET_BL( 0x00 );
6034 SET_CH( vcylinders & 0xff );
6035 SET_CL((( vcylinders >> 2) & 0xc0) | ( vspt & 0x3f ));
6036 SET_DH( vheads );
6037 SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2
6038 // FIXME ElTorito Harddisk. should send the HD count
6040 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
6041 case 0x01: SET_BL( 0x02 ); break;
6042 case 0x02: SET_BL( 0x04 ); break;
6043 case 0x03: SET_BL( 0x06 ); break;
6046 ASM_START
6047 push bp
6048 mov bp, sp
6049 mov ax, #diskette_param_table2
6050 mov _int13_cdemu.DI+2[bp], ax
6051 mov _int13_cdemu.ES+2[bp], cs
6052 pop bp
6053 ASM_END
6054 goto int13_success;
6055 break;
6057 case 0x15: /* read disk drive size */
6058 // FIXME ElTorito Harddisk. What geometry to send ?
6059 SET_AH(0x03);
6060 goto int13_success_noah;
6061 break;
6063 // all those functions return unimplemented
6064 case 0x0a: /* read disk sectors with ECC */
6065 case 0x0b: /* write disk sectors with ECC */
6066 case 0x18: /* set media type for format */
6067 case 0x41: // IBM/MS installation check
6068 // FIXME ElTorito Harddisk. Darwin would like to use EDD
6069 case 0x42: // IBM/MS extended read
6070 case 0x43: // IBM/MS extended write
6071 case 0x44: // IBM/MS verify sectors
6072 case 0x45: // IBM/MS lock/unlock drive
6073 case 0x46: // IBM/MS eject media
6074 case 0x47: // IBM/MS extended seek
6075 case 0x48: // IBM/MS get drive parameters
6076 case 0x49: // IBM/MS extended media change
6077 case 0x4e: // ? - set hardware configuration
6078 case 0x50: // ? - send packet command
6079 default:
6080 BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
6081 goto int13_fail;
6082 break;
6085 int13_fail:
6086 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6087 int13_fail_noah:
6088 SET_DISK_RET_STATUS(GET_AH());
6089 int13_fail_nostatus:
6090 SET_CF(); // error occurred
6091 return;
6093 int13_success:
6094 SET_AH(0x00); // no error
6095 int13_success_noah:
6096 SET_DISK_RET_STATUS(0x00);
6097 CLEAR_CF(); // no error
6098 return;
6101 // ---------------------------------------------------------------------------
6102 // End of int13 when emulating a device from the cd
6103 // ---------------------------------------------------------------------------
6105 #endif // BX_ELTORITO_BOOT
6107 #else //BX_USE_ATADRV
6109 void
6110 outLBA(cylinder,hd_heads,head,hd_sectors,sector,dl)
6111 Bit16u cylinder;
6112 Bit16u hd_heads;
6113 Bit16u head;
6114 Bit16u hd_sectors;
6115 Bit16u sector;
6116 Bit16u dl;
6118 ASM_START
6119 push bp
6120 mov bp, sp
6121 push eax
6122 push ebx
6123 push edx
6124 xor eax,eax
6125 mov ax,4[bp] // cylinder
6126 xor ebx,ebx
6127 mov bl,6[bp] // hd_heads
6128 imul ebx
6130 mov bl,8[bp] // head
6131 add eax,ebx
6132 mov bl,10[bp] // hd_sectors
6133 imul ebx
6134 mov bl,12[bp] // sector
6135 add eax,ebx
6137 dec eax
6138 mov dx,#0x1f3
6139 out dx,al
6140 mov dx,#0x1f4
6141 mov al,ah
6142 out dx,al
6143 shr eax,#16
6144 mov dx,#0x1f5
6145 out dx,al
6146 and ah,#0xf
6147 mov bl,14[bp] // dl
6148 and bl,#1
6149 shl bl,#4
6150 or ah,bl
6151 or ah,#0xe0
6152 mov al,ah
6153 mov dx,#0x01f6
6154 out dx,al
6155 pop edx
6156 pop ebx
6157 pop eax
6158 pop bp
6159 ASM_END
6162 void
6163 int13_harddisk(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
6164 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
6166 Bit8u drive, num_sectors, sector, head, status, mod;
6167 Bit8u drive_map;
6168 Bit8u n_drives;
6169 Bit16u cyl_mod, ax;
6170 Bit16u max_cylinder, cylinder, total_sectors;
6171 Bit16u hd_cylinders;
6172 Bit8u hd_heads, hd_sectors;
6173 Bit16u val16;
6174 Bit8u sector_count;
6175 unsigned int i;
6176 Bit16u tempbx;
6177 Bit16u dpsize;
6179 Bit16u count, segment, offset;
6180 Bit32u lba;
6181 Bit16u error;
6183 BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6185 write_byte(0x0040, 0x008e, 0); // clear completion flag
6187 /* at this point, DL is >= 0x80 to be passed from the floppy int13h
6188 handler code */
6189 /* check how many disks first (cmos reg 0x12), return an error if
6190 drive not present */
6191 drive_map = inb_cmos(0x12);
6192 drive_map = (((drive_map & 0xf0)==0) ? 0 : 1) |
6193 (((drive_map & 0x0f)==0) ? 0 : 2);
6194 n_drives = (drive_map==0) ? 0 :
6195 ((drive_map==3) ? 2 : 1);
6197 if (!(drive_map & (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
6198 SET_AH(0x01);
6199 SET_DISK_RET_STATUS(0x01);
6200 SET_CF(); /* error occurred */
6201 return;
6204 switch (GET_AH()) {
6206 case 0x00: /* disk controller reset */
6207 BX_DEBUG_INT13_HD("int13_f00\n");
6209 SET_AH(0);
6210 SET_DISK_RET_STATUS(0);
6211 set_diskette_ret_status(0);
6212 set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
6213 set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
6214 CLEAR_CF(); /* successful */
6215 return;
6216 break;
6218 case 0x01: /* read disk status */
6219 BX_DEBUG_INT13_HD("int13_f01\n");
6220 status = read_byte(0x0040, 0x0074);
6221 SET_AH(status);
6222 SET_DISK_RET_STATUS(0);
6223 /* set CF if error status read */
6224 if (status) SET_CF();
6225 else CLEAR_CF();
6226 return;
6227 break;
6229 case 0x04: // verify disk sectors
6230 case 0x02: // read disk sectors
6231 drive = GET_ELDL();
6232 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6234 num_sectors = GET_AL();
6235 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
6236 sector = (GET_CL() & 0x3f);
6237 head = GET_DH();
6240 if (hd_cylinders > 1024) {
6241 if (hd_cylinders <= 2048) {
6242 cylinder <<= 1;
6244 else if (hd_cylinders <= 4096) {
6245 cylinder <<= 2;
6247 else if (hd_cylinders <= 8192) {
6248 cylinder <<= 3;
6250 else { // hd_cylinders <= 16384
6251 cylinder <<= 4;
6254 ax = head / hd_heads;
6255 cyl_mod = ax & 0xff;
6256 head = ax >> 8;
6257 cylinder |= cyl_mod;
6260 if ( (cylinder >= hd_cylinders) ||
6261 (sector > hd_sectors) ||
6262 (head >= hd_heads) ) {
6263 SET_AH(1);
6264 SET_DISK_RET_STATUS(1);
6265 SET_CF(); /* error occurred */
6266 return;
6269 if ( (num_sectors > 128) || (num_sectors == 0) )
6270 BX_PANIC("int13_harddisk(): num_sectors out of range!\n");
6272 if (head > 15)
6273 BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
6275 if ( GET_AH() == 0x04 ) {
6276 SET_AH(0);
6277 SET_DISK_RET_STATUS(0);
6278 CLEAR_CF();
6279 return;
6282 status = inb(0x1f7);
6283 if (status & 0x80) {
6284 BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
6286 outb(0x01f2, num_sectors);
6287 /* activate LBA? (tomv) */
6288 if (hd_heads > 16) {
6289 BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder, head, sector);
6290 outLBA(cylinder,hd_heads,head,hd_sectors,sector,drive);
6292 else {
6293 outb(0x01f3, sector);
6294 outb(0x01f4, cylinder & 0x00ff);
6295 outb(0x01f5, cylinder >> 8);
6296 outb(0x01f6, 0xa0 | ((drive & 0x01)<<4) | (head & 0x0f));
6298 outb(0x01f7, 0x20);
6300 while (1) {
6301 status = inb(0x1f7);
6302 if ( !(status & 0x80) ) break;
6305 if (status & 0x01) {
6306 BX_PANIC("hard drive BIOS:(read/verify) read error\n");
6307 } else if ( !(status & 0x08) ) {
6308 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6309 BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
6312 sector_count = 0;
6313 tempbx = BX;
6315 ASM_START
6316 sti ;; enable higher priority interrupts
6317 ASM_END
6319 while (1) {
6320 ASM_START
6321 ;; store temp bx in real DI register
6322 push bp
6323 mov bp, sp
6324 mov di, _int13_harddisk.tempbx + 2 [bp]
6325 pop bp
6327 ;; adjust if there will be an overrun
6328 cmp di, #0xfe00
6329 jbe i13_f02_no_adjust
6330 i13_f02_adjust:
6331 sub di, #0x0200 ; sub 512 bytes from offset
6332 mov ax, es
6333 add ax, #0x0020 ; add 512 to segment
6334 mov es, ax
6336 i13_f02_no_adjust:
6337 mov cx, #0x0100 ;; counter (256 words = 512b)
6338 mov dx, #0x01f0 ;; AT data read port
6340 rep
6341 insw ;; CX words transfered from port(DX) to ES:[DI]
6343 i13_f02_done:
6344 ;; store real DI register back to temp bx
6345 push bp
6346 mov bp, sp
6347 mov _int13_harddisk.tempbx + 2 [bp], di
6348 pop bp
6349 ASM_END
6351 sector_count++;
6352 num_sectors--;
6353 if (num_sectors == 0) {
6354 status = inb(0x1f7);
6355 if ( (status & 0xc9) != 0x40 )
6356 BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status);
6357 break;
6359 else {
6360 status = inb(0x1f7);
6361 if ( (status & 0xc9) != 0x48 )
6362 BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status);
6363 continue;
6367 SET_AH(0);
6368 SET_DISK_RET_STATUS(0);
6369 SET_AL(sector_count);
6370 CLEAR_CF(); /* successful */
6371 return;
6372 break;
6375 case 0x03: /* write disk sectors */
6376 BX_DEBUG_INT13_HD("int13_f03\n");
6377 drive = GET_ELDL ();
6378 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6380 num_sectors = GET_AL();
6381 cylinder = GET_CH();
6382 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
6383 sector = (GET_CL() & 0x3f);
6384 head = GET_DH();
6386 if (hd_cylinders > 1024) {
6387 if (hd_cylinders <= 2048) {
6388 cylinder <<= 1;
6390 else if (hd_cylinders <= 4096) {
6391 cylinder <<= 2;
6393 else if (hd_cylinders <= 8192) {
6394 cylinder <<= 3;
6396 else { // hd_cylinders <= 16384
6397 cylinder <<= 4;
6400 ax = head / hd_heads;
6401 cyl_mod = ax & 0xff;
6402 head = ax >> 8;
6403 cylinder |= cyl_mod;
6406 if ( (cylinder >= hd_cylinders) ||
6407 (sector > hd_sectors) ||
6408 (head >= hd_heads) ) {
6409 SET_AH( 1);
6410 SET_DISK_RET_STATUS(1);
6411 SET_CF(); /* error occurred */
6412 return;
6415 if ( (num_sectors > 128) || (num_sectors == 0) )
6416 BX_PANIC("int13_harddisk(): num_sectors out of range!\n");
6418 if (head > 15)
6419 BX_PANIC("hard drive BIOS:(read) head > 15\n");
6421 status = inb(0x1f7);
6422 if (status & 0x80) {
6423 BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
6425 // should check for Drive Ready Bit also in status reg
6426 outb(0x01f2, num_sectors);
6428 /* activate LBA? (tomv) */
6429 if (hd_heads > 16) {
6430 BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder, head, sector);
6431 outLBA(cylinder,hd_heads,head,hd_sectors,sector,GET_ELDL());
6433 else {
6434 outb(0x01f3, sector);
6435 outb(0x01f4, cylinder & 0x00ff);
6436 outb(0x01f5, cylinder >> 8);
6437 outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head & 0x0f));
6439 outb(0x01f7, 0x30);
6441 // wait for busy bit to turn off after seeking
6442 while (1) {
6443 status = inb(0x1f7);
6444 if ( !(status & 0x80) ) break;
6447 if ( !(status & 0x08) ) {
6448 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6449 BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
6452 sector_count = 0;
6453 tempbx = BX;
6455 ASM_START
6456 sti ;; enable higher priority interrupts
6457 ASM_END
6459 while (1) {
6460 ASM_START
6461 ;; store temp bx in real SI register
6462 push bp
6463 mov bp, sp
6464 mov si, _int13_harddisk.tempbx + 2 [bp]
6465 pop bp
6467 ;; adjust if there will be an overrun
6468 cmp si, #0xfe00
6469 jbe i13_f03_no_adjust
6470 i13_f03_adjust:
6471 sub si, #0x0200 ; sub 512 bytes from offset
6472 mov ax, es
6473 add ax, #0x0020 ; add 512 to segment
6474 mov es, ax
6476 i13_f03_no_adjust:
6477 mov cx, #0x0100 ;; counter (256 words = 512b)
6478 mov dx, #0x01f0 ;; AT data read port
6480 seg ES
6481 rep
6482 outsw ;; CX words tranfered from ES:[SI] to port(DX)
6484 ;; store real SI register back to temp bx
6485 push bp
6486 mov bp, sp
6487 mov _int13_harddisk.tempbx + 2 [bp], si
6488 pop bp
6489 ASM_END
6491 sector_count++;
6492 num_sectors--;
6493 if (num_sectors == 0) {
6494 status = inb(0x1f7);
6495 if ( (status & 0xe9) != 0x40 )
6496 BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status);
6497 break;
6499 else {
6500 status = inb(0x1f7);
6501 if ( (status & 0xc9) != 0x48 )
6502 BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status);
6503 continue;
6507 SET_AH(0);
6508 SET_DISK_RET_STATUS(0);
6509 SET_AL(sector_count);
6510 CLEAR_CF(); /* successful */
6511 return;
6512 break;
6514 case 0x05: /* format disk track */
6515 BX_DEBUG_INT13_HD("int13_f05\n");
6516 BX_PANIC("format disk track called\n");
6517 /* nop */
6518 SET_AH(0);
6519 SET_DISK_RET_STATUS(0);
6520 CLEAR_CF(); /* successful */
6521 return;
6522 break;
6524 case 0x08: /* read disk drive parameters */
6525 BX_DEBUG_INT13_HD("int13_f08\n");
6527 drive = GET_ELDL ();
6528 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6530 // translate CHS
6531 //
6532 if (hd_cylinders <= 1024) {
6533 // hd_cylinders >>= 0;
6534 // hd_heads <<= 0;
6536 else if (hd_cylinders <= 2048) {
6537 hd_cylinders >>= 1;
6538 hd_heads <<= 1;
6540 else if (hd_cylinders <= 4096) {
6541 hd_cylinders >>= 2;
6542 hd_heads <<= 2;
6544 else if (hd_cylinders <= 8192) {
6545 hd_cylinders >>= 3;
6546 hd_heads <<= 3;
6548 else { // hd_cylinders <= 16384
6549 hd_cylinders >>= 4;
6550 hd_heads <<= 4;
6553 max_cylinder = hd_cylinders - 2; /* 0 based */
6554 SET_AL(0);
6555 SET_CH(max_cylinder & 0xff);
6556 SET_CL(((max_cylinder >> 2) & 0xc0) | (hd_sectors & 0x3f));
6557 SET_DH(hd_heads - 1);
6558 SET_DL(n_drives); /* returns 0, 1, or 2 hard drives */
6559 SET_AH(0);
6560 SET_DISK_RET_STATUS(0);
6561 CLEAR_CF(); /* successful */
6563 return;
6564 break;
6566 case 0x09: /* initialize drive parameters */
6567 BX_DEBUG_INT13_HD("int13_f09\n");
6568 SET_AH(0);
6569 SET_DISK_RET_STATUS(0);
6570 CLEAR_CF(); /* successful */
6571 return;
6572 break;
6574 case 0x0a: /* read disk sectors with ECC */
6575 BX_DEBUG_INT13_HD("int13_f0a\n");
6576 case 0x0b: /* write disk sectors with ECC */
6577 BX_DEBUG_INT13_HD("int13_f0b\n");
6578 BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
6579 return;
6580 break;
6582 case 0x0c: /* seek to specified cylinder */
6583 BX_DEBUG_INT13_HD("int13_f0c\n");
6584 BX_INFO("int13h function 0ch (seek) not implemented!\n");
6585 SET_AH(0);
6586 SET_DISK_RET_STATUS(0);
6587 CLEAR_CF(); /* successful */
6588 return;
6589 break;
6591 case 0x0d: /* alternate disk reset */
6592 BX_DEBUG_INT13_HD("int13_f0d\n");
6593 SET_AH(0);
6594 SET_DISK_RET_STATUS(0);
6595 CLEAR_CF(); /* successful */
6596 return;
6597 break;
6599 case 0x10: /* check drive ready */
6600 BX_DEBUG_INT13_HD("int13_f10\n");
6601 //SET_AH(0);
6602 //SET_DISK_RET_STATUS(0);
6603 //CLEAR_CF(); /* successful */
6604 //return;
6605 //break;
6607 // should look at 40:8E also???
6608 status = inb(0x01f7);
6609 if ( (status & 0xc0) == 0x40 ) {
6610 SET_AH(0);
6611 SET_DISK_RET_STATUS(0);
6612 CLEAR_CF(); // drive ready
6613 return;
6615 else {
6616 SET_AH(0xAA);
6617 SET_DISK_RET_STATUS(0xAA);
6618 SET_CF(); // not ready
6619 return;
6621 break;
6623 case 0x11: /* recalibrate */
6624 BX_DEBUG_INT13_HD("int13_f11\n");
6625 SET_AH(0);
6626 SET_DISK_RET_STATUS(0);
6627 CLEAR_CF(); /* successful */
6628 return;
6629 break;
6631 case 0x14: /* controller internal diagnostic */
6632 BX_DEBUG_INT13_HD("int13_f14\n");
6633 SET_AH(0);
6634 SET_DISK_RET_STATUS(0);
6635 CLEAR_CF(); /* successful */
6636 SET_AL(0);
6637 return;
6638 break;
6640 case 0x15: /* read disk drive size */
6641 drive = GET_ELDL();
6642 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6643 ASM_START
6644 push bp
6645 mov bp, sp
6646 mov al, _int13_harddisk.hd_heads + 2 [bp]
6647 mov ah, _int13_harddisk.hd_sectors + 2 [bp]
6648 mul al, ah ;; ax = heads * sectors
6649 mov bx, _int13_harddisk.hd_cylinders + 2 [bp]
6650 dec bx ;; use (cylinders - 1) ???
6651 mul ax, bx ;; dx:ax = (cylinders -1) * (heads * sectors)
6652 ;; now we need to move the 32bit result dx:ax to what the
6653 ;; BIOS wants which is cx:dx.
6654 ;; and then into CX:DX on the stack
6655 mov _int13_harddisk.CX + 2 [bp], dx
6656 mov _int13_harddisk.DX + 2 [bp], ax
6657 pop bp
6658 ASM_END
6659 SET_AH(3); // hard disk accessible
6660 SET_DISK_RET_STATUS(0); // ??? should this be 0
6661 CLEAR_CF(); // successful
6662 return;
6663 break;
6665 case 0x18: // set media type for format
6666 case 0x41: // IBM/MS
6667 case 0x42: // IBM/MS
6668 case 0x43: // IBM/MS
6669 case 0x44: // IBM/MS
6670 case 0x45: // IBM/MS lock/unlock drive
6671 case 0x46: // IBM/MS eject media
6672 case 0x47: // IBM/MS extended seek
6673 case 0x49: // IBM/MS extended media change
6674 case 0x50: // IBM/MS send packet command
6675 default:
6676 BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
6678 SET_AH(1); // code=invalid function in AH or invalid parameter
6679 SET_DISK_RET_STATUS(1);
6680 SET_CF(); /* unsuccessful */
6681 return;
6682 break;
6686 static char panic_msg_reg12h[] = "HD%d cmos reg 12h not type F\n";
6687 static char panic_msg_reg19h[] = "HD%d cmos reg %02xh not user definable type 47\n";
6689 void
6690 get_hd_geometry(drive, hd_cylinders, hd_heads, hd_sectors)
6691 Bit8u drive;
6692 Bit16u *hd_cylinders;
6693 Bit8u *hd_heads;
6694 Bit8u *hd_sectors;
6696 Bit8u hd_type;
6697 Bit16u ss;
6698 Bit16u cylinders;
6699 Bit8u iobase;
6701 ss = get_SS();
6702 if (drive == 0x80) {
6703 hd_type = inb_cmos(0x12) & 0xf0;
6704 if (hd_type != 0xf0)
6705 BX_INFO(panic_msg_reg12h,0);
6706 hd_type = inb_cmos(0x19); // HD0: extended type
6707 if (hd_type != 47)
6708 BX_INFO(panic_msg_reg19h,0,0x19);
6709 iobase = 0x1b;
6710 } else {
6711 hd_type = inb_cmos(0x12) & 0x0f;
6712 if (hd_type != 0x0f)
6713 BX_INFO(panic_msg_reg12h,1);
6714 hd_type = inb_cmos(0x1a); // HD0: extended type
6715 if (hd_type != 47)
6716 BX_INFO(panic_msg_reg19h,0,0x1a);
6717 iobase = 0x24;
6720 // cylinders
6721 cylinders = inb_cmos(iobase) | (inb_cmos(iobase+1) << 8);
6722 write_word(ss, hd_cylinders, cylinders);
6724 // heads
6725 write_byte(ss, hd_heads, inb_cmos(iobase+2));
6727 // sectors per track
6728 write_byte(ss, hd_sectors, inb_cmos(iobase+8));
6731 #endif //else BX_USE_ATADRV
6734 //////////////////////
6735 // FLOPPY functions //
6736 //////////////////////
6738 bx_bool
6739 floppy_media_known(drive)
6740 Bit16u drive;
6742 Bit8u val8;
6743 Bit16u media_state_offset;
6745 val8 = read_byte(0x0040, 0x003e); // diskette recal status
6746 if (drive)
6747 val8 >>= 1;
6748 val8 &= 0x01;
6749 if (val8 == 0)
6750 return(0);
6752 media_state_offset = 0x0090;
6753 if (drive)
6754 media_state_offset += 1;
6756 val8 = read_byte(0x0040, media_state_offset);
6757 val8 = (val8 >> 4) & 0x01;
6758 if (val8 == 0)
6759 return(0);
6761 // check pass, return KNOWN
6762 return(1);
6765 bx_bool
6766 floppy_media_sense(drive)
6767 Bit16u drive;
6769 bx_bool retval;
6770 Bit16u media_state_offset;
6771 Bit8u drive_type, config_data, media_state;
6773 if (floppy_drive_recal(drive) == 0) {
6774 return(0);
6777 // for now cheat and get drive type from CMOS,
6778 // assume media is same as drive type
6780 // ** config_data **
6781 // Bitfields for diskette media control:
6782 // Bit(s) Description (Table M0028)
6783 // 7-6 last data rate set by controller
6784 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6785 // 5-4 last diskette drive step rate selected
6786 // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
6787 // 3-2 {data rate at start of operation}
6788 // 1-0 reserved
6790 // ** media_state **
6791 // Bitfields for diskette drive media state:
6792 // Bit(s) Description (Table M0030)
6793 // 7-6 data rate
6794 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6795 // 5 double stepping required (e.g. 360kB in 1.2MB)
6796 // 4 media type established
6797 // 3 drive capable of supporting 4MB media
6798 // 2-0 on exit from BIOS, contains
6799 // 000 trying 360kB in 360kB
6800 // 001 trying 360kB in 1.2MB
6801 // 010 trying 1.2MB in 1.2MB
6802 // 011 360kB in 360kB established
6803 // 100 360kB in 1.2MB established
6804 // 101 1.2MB in 1.2MB established
6805 // 110 reserved
6806 // 111 all other formats/drives
6808 drive_type = inb_cmos(0x10);
6809 if (drive == 0)
6810 drive_type >>= 4;
6811 else
6812 drive_type &= 0x0f;
6813 if ( drive_type == 1 ) {
6814 // 360K 5.25" drive
6815 config_data = 0x00; // 0000 0000
6816 media_state = 0x25; // 0010 0101
6817 retval = 1;
6819 else if ( drive_type == 2 ) {
6820 // 1.2 MB 5.25" drive
6821 config_data = 0x00; // 0000 0000
6822 media_state = 0x25; // 0010 0101 // need double stepping??? (bit 5)
6823 retval = 1;
6825 else if ( drive_type == 3 ) {
6826 // 720K 3.5" drive
6827 config_data = 0x00; // 0000 0000 ???
6828 media_state = 0x17; // 0001 0111
6829 retval = 1;
6831 else if ( drive_type == 4 ) {
6832 // 1.44 MB 3.5" drive
6833 config_data = 0x00; // 0000 0000
6834 media_state = 0x17; // 0001 0111
6835 retval = 1;
6837 else if ( drive_type == 5 ) {
6838 // 2.88 MB 3.5" drive
6839 config_data = 0xCC; // 1100 1100
6840 media_state = 0xD7; // 1101 0111
6841 retval = 1;
6843 //
6844 // Extended floppy size uses special cmos setting
6845 else if ( drive_type == 6 ) {
6846 // 160k 5.25" drive
6847 config_data = 0x00; // 0000 0000
6848 media_state = 0x27; // 0010 0111
6849 retval = 1;
6851 else if ( drive_type == 7 ) {
6852 // 180k 5.25" drive
6853 config_data = 0x00; // 0000 0000
6854 media_state = 0x27; // 0010 0111
6855 retval = 1;
6857 else if ( drive_type == 8 ) {
6858 // 320k 5.25" drive
6859 config_data = 0x00; // 0000 0000
6860 media_state = 0x27; // 0010 0111
6861 retval = 1;
6864 else {
6865 // not recognized
6866 config_data = 0x00; // 0000 0000
6867 media_state = 0x00; // 0000 0000
6868 retval = 0;
6871 if (drive == 0)
6872 media_state_offset = 0x90;
6873 else
6874 media_state_offset = 0x91;
6875 write_byte(0x0040, 0x008B, config_data);
6876 write_byte(0x0040, media_state_offset, media_state);
6878 return(retval);
6881 bx_bool
6882 floppy_drive_recal(drive)
6883 Bit16u drive;
6885 Bit8u val8, dor;
6886 Bit16u curr_cyl_offset;
6888 // set 40:3e bit 7 to 0
6889 val8 = read_byte(0x0000, 0x043e);
6890 val8 &= 0x7f;
6891 write_byte(0x0000, 0x043e, val8);
6893 // turn on motor of selected drive, DMA & int enabled, normal operation
6894 if (drive)
6895 dor = 0x20;
6896 else
6897 dor = 0x10;
6898 dor |= 0x0c;
6899 dor |= drive;
6900 outb(0x03f2, dor);
6902 // reset the disk motor timeout value of INT 08
6903 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
6905 // check port 3f4 for drive readiness
6906 val8 = inb(0x3f4);
6907 if ( (val8 & 0xf0) != 0x80 )
6908 BX_PANIC("floppy recal:f07: ctrl not ready\n");
6910 // send Recalibrate command (2 bytes) to controller
6911 outb(0x03f5, 0x07); // 07: Recalibrate
6912 outb(0x03f5, drive); // 0=drive0, 1=drive1
6914 // turn on interrupts
6915 ASM_START
6916 sti
6917 ASM_END
6919 // wait on 40:3e bit 7 to become 1
6920 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6921 while ( val8 == 0 ) {
6922 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6925 val8 = 0; // separate asm from while() loop
6926 // turn off interrupts
6927 ASM_START
6928 cli
6929 ASM_END
6931 // set 40:3e bit 7 to 0, and calibrated bit
6932 val8 = read_byte(0x0000, 0x043e);
6933 val8 &= 0x7f;
6934 if (drive) {
6935 val8 |= 0x02; // Drive 1 calibrated
6936 curr_cyl_offset = 0x0095;
6938 else {
6939 val8 |= 0x01; // Drive 0 calibrated
6940 curr_cyl_offset = 0x0094;
6942 write_byte(0x0040, 0x003e, val8);
6943 write_byte(0x0040, curr_cyl_offset, 0); // current cylinder is 0
6945 return(1);
6950 bx_bool
6951 floppy_drive_exists(drive)
6952 Bit16u drive;
6954 Bit8u drive_type;
6956 // check CMOS to see if drive exists
6957 drive_type = inb_cmos(0x10);
6958 if (drive == 0)
6959 drive_type >>= 4;
6960 else
6961 drive_type &= 0x0f;
6962 if ( drive_type == 0 )
6963 return(0);
6964 else
6965 return(1);
6968 #if BX_SUPPORT_FLOPPY
6969 void
6970 int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
6971 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
6973 Bit8u drive, num_sectors, track, sector, head, status;
6974 Bit16u base_address, base_count, base_es;
6975 Bit8u page, mode_register, val8, dor;
6976 Bit8u return_status[7];
6977 Bit8u drive_type, num_floppies, ah;
6978 Bit16u es, last_addr;
6980 BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6981 // BX_DEBUG_INT13_FL("int13_diskette: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), get_DS(), ES, DI, SI);
6983 ah = GET_AH();
6985 switch ( ah ) {
6986 case 0x00: // diskette controller reset
6987 BX_DEBUG_INT13_FL("floppy f00\n");
6988 drive = GET_ELDL();
6989 if (drive > 1) {
6990 SET_AH(1); // invalid param
6991 set_diskette_ret_status(1);
6992 SET_CF();
6993 return;
6995 drive_type = inb_cmos(0x10);
6997 if (drive == 0)
6998 drive_type >>= 4;
6999 else
7000 drive_type &= 0x0f;
7001 if (drive_type == 0) {
7002 SET_AH(0x80); // drive not responding
7003 set_diskette_ret_status(0x80);
7004 SET_CF();
7005 return;
7007 SET_AH(0);
7008 set_diskette_ret_status(0);
7009 CLEAR_CF(); // successful
7010 set_diskette_current_cyl(drive, 0); // current cylinder
7011 return;
7013 case 0x01: // Read Diskette Status
7014 CLEAR_CF();
7015 val8 = read_byte(0x0000, 0x0441);
7016 SET_AH(val8);
7017 if (val8) {
7018 SET_CF();
7020 return;
7022 case 0x02: // Read Diskette Sectors
7023 case 0x03: // Write Diskette Sectors
7024 case 0x04: // Verify Diskette Sectors
7025 num_sectors = GET_AL();
7026 track = GET_CH();
7027 sector = GET_CL();
7028 head = GET_DH();
7029 drive = GET_ELDL();
7031 if ( (drive > 1) || (head > 1) ||
7032 (num_sectors == 0) || (num_sectors > 72) ) {
7033 BX_INFO("floppy: drive>1 || head>1 ...\n");
7034 SET_AH(1);
7035 set_diskette_ret_status(1);
7036 SET_AL(0); // no sectors read
7037 SET_CF(); // error occurred
7038 return;
7041 // see if drive exists
7042 if (floppy_drive_exists(drive) == 0) {
7043 SET_AH(0x80); // not responding
7044 set_diskette_ret_status(0x80);
7045 SET_AL(0); // no sectors read
7046 SET_CF(); // error occurred
7047 return;
7050 // see if media in drive, and type is known
7051 if (floppy_media_known(drive) == 0) {
7052 if (floppy_media_sense(drive) == 0) {
7053 SET_AH(0x0C); // Media type not found
7054 set_diskette_ret_status(0x0C);
7055 SET_AL(0); // no sectors read
7056 SET_CF(); // error occurred
7057 return;
7061 if (ah == 0x02) {
7062 // Read Diskette Sectors
7064 //-----------------------------------
7065 // set up DMA controller for transfer
7066 //-----------------------------------
7068 // es:bx = pointer to where to place information from diskette
7069 // port 04: DMA-1 base and current address, channel 2
7070 // port 05: DMA-1 base and current count, channel 2
7071 page = (ES >> 12); // upper 4 bits
7072 base_es = (ES << 4); // lower 16bits contributed by ES
7073 base_address = base_es + BX; // lower 16 bits of address
7074 // contributed by ES:BX
7075 if ( base_address < base_es ) {
7076 // in case of carry, adjust page by 1
7077 page++;
7079 base_count = (num_sectors * 512) - 1;
7081 // check for 64K boundary overrun
7082 last_addr = base_address + base_count;
7083 if (last_addr < base_address) {
7084 SET_AH(0x09);
7085 set_diskette_ret_status(0x09);
7086 SET_AL(0); // no sectors read
7087 SET_CF(); // error occurred
7088 return;
7091 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7092 outb(0x000a, 0x06);
7094 BX_DEBUG_INT13_FL("clear flip-flop\n");
7095 outb(0x000c, 0x00); // clear flip-flop
7096 outb(0x0004, base_address);
7097 outb(0x0004, base_address>>8);
7098 BX_DEBUG_INT13_FL("clear flip-flop\n");
7099 outb(0x000c, 0x00); // clear flip-flop
7100 outb(0x0005, base_count);
7101 outb(0x0005, base_count>>8);
7103 // port 0b: DMA-1 Mode Register
7104 mode_register = 0x46; // single mode, increment, autoinit disable,
7105 // transfer type=write, channel 2
7106 BX_DEBUG_INT13_FL("setting mode register\n");
7107 outb(0x000b, mode_register);
7109 BX_DEBUG_INT13_FL("setting page register\n");
7110 // port 81: DMA-1 Page Register, channel 2
7111 outb(0x0081, page);
7113 BX_DEBUG_INT13_FL("unmask chan 2\n");
7114 outb(0x000a, 0x02); // unmask channel 2
7116 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7117 outb(0x000a, 0x02);
7119 //--------------------------------------
7120 // set up floppy controller for transfer
7121 //--------------------------------------
7123 // set 40:3e bit 7 to 0
7124 val8 = read_byte(0x0000, 0x043e);
7125 val8 &= 0x7f;
7126 write_byte(0x0000, 0x043e, val8);
7128 // turn on motor of selected drive, DMA & int enabled, normal operation
7129 if (drive)
7130 dor = 0x20;
7131 else
7132 dor = 0x10;
7133 dor |= 0x0c;
7134 dor |= drive;
7135 outb(0x03f2, dor);
7137 // reset the disk motor timeout value of INT 08
7138 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
7140 // check port 3f4 for drive readiness
7141 val8 = inb(0x3f4);
7142 if ( (val8 & 0xf0) != 0x80 )
7143 BX_PANIC("int13_diskette:f02: ctrl not ready\n");
7145 // send read-normal-data command (9 bytes) to controller
7146 outb(0x03f5, 0xe6); // e6: read normal data
7147 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7148 outb(0x03f5, track);
7149 outb(0x03f5, head);
7150 outb(0x03f5, sector);
7151 outb(0x03f5, 2); // 512 byte sector size
7152 outb(0x03f5, 0); // last sector number possible on track
7153 outb(0x03f5, 0); // Gap length
7154 outb(0x03f5, 0xff); // Gap length
7156 // turn on interrupts
7157 ASM_START
7158 sti
7159 ASM_END
7161 // wait on 40:3e bit 7 to become 1
7162 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7163 while ( val8 == 0 ) {
7164 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7167 val8 = 0; // separate asm from while() loop
7168 // turn off interrupts
7169 ASM_START
7170 cli
7171 ASM_END
7173 // set 40:3e bit 7 to 0
7174 val8 = read_byte(0x0000, 0x043e);
7175 val8 &= 0x7f;
7176 write_byte(0x0000, 0x043e, val8);
7178 // check port 3f4 for accessibility to status bytes
7179 val8 = inb(0x3f4);
7180 if ( (val8 & 0xc0) != 0xc0 )
7181 BX_PANIC("int13_diskette: ctrl not ready\n");
7183 // read 7 return status bytes from controller
7184 // using loop index broken, have to unroll...
7185 return_status[0] = inb(0x3f5);
7186 return_status[1] = inb(0x3f5);
7187 return_status[2] = inb(0x3f5);
7188 return_status[3] = inb(0x3f5);
7189 return_status[4] = inb(0x3f5);
7190 return_status[5] = inb(0x3f5);
7191 return_status[6] = inb(0x3f5);
7192 // record in BIOS Data Area
7193 write_byte(0x0040, 0x0042, return_status[0]);
7194 write_byte(0x0040, 0x0043, return_status[1]);
7195 write_byte(0x0040, 0x0044, return_status[2]);
7196 write_byte(0x0040, 0x0045, return_status[3]);
7197 write_byte(0x0040, 0x0046, return_status[4]);
7198 write_byte(0x0040, 0x0047, return_status[5]);
7199 write_byte(0x0040, 0x0048, return_status[6]);
7201 if ( (return_status[0] & 0xc0) != 0 ) {
7202 SET_AH(0x20);
7203 set_diskette_ret_status(0x20);
7204 SET_AL(0); // no sectors read
7205 SET_CF(); // error occurred
7206 return;
7209 // ??? should track be new val from return_status[3] ?
7210 set_diskette_current_cyl(drive, track);
7211 // AL = number of sectors read (same value as passed)
7212 SET_AH(0x00); // success
7213 CLEAR_CF(); // success
7214 return;
7216 else if (ah == 0x03) {
7217 // Write Diskette Sectors
7219 //-----------------------------------
7220 // set up DMA controller for transfer
7221 //-----------------------------------
7223 // es:bx = pointer to where to place information from diskette
7224 // port 04: DMA-1 base and current address, channel 2
7225 // port 05: DMA-1 base and current count, channel 2
7226 page = (ES >> 12); // upper 4 bits
7227 base_es = (ES << 4); // lower 16bits contributed by ES
7228 base_address = base_es + BX; // lower 16 bits of address
7229 // contributed by ES:BX
7230 if ( base_address < base_es ) {
7231 // in case of carry, adjust page by 1
7232 page++;
7234 base_count = (num_sectors * 512) - 1;
7236 // check for 64K boundary overrun
7237 last_addr = base_address + base_count;
7238 if (last_addr < base_address) {
7239 SET_AH(0x09);
7240 set_diskette_ret_status(0x09);
7241 SET_AL(0); // no sectors read
7242 SET_CF(); // error occurred
7243 return;
7246 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7247 outb(0x000a, 0x06);
7249 outb(0x000c, 0x00); // clear flip-flop
7250 outb(0x0004, base_address);
7251 outb(0x0004, base_address>>8);
7252 outb(0x000c, 0x00); // clear flip-flop
7253 outb(0x0005, base_count);
7254 outb(0x0005, base_count>>8);
7256 // port 0b: DMA-1 Mode Register
7257 mode_register = 0x4a; // single mode, increment, autoinit disable,
7258 // transfer type=read, channel 2
7259 outb(0x000b, mode_register);
7261 // port 81: DMA-1 Page Register, channel 2
7262 outb(0x0081, page);
7264 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7265 outb(0x000a, 0x02);
7267 //--------------------------------------
7268 // set up floppy controller for transfer
7269 //--------------------------------------
7271 // set 40:3e bit 7 to 0
7272 val8 = read_byte(0x0000, 0x043e);
7273 val8 &= 0x7f;
7274 write_byte(0x0000, 0x043e, val8);
7276 // turn on motor of selected drive, DMA & int enabled, normal operation
7277 if (drive)
7278 dor = 0x20;
7279 else
7280 dor = 0x10;
7281 dor |= 0x0c;
7282 dor |= drive;
7283 outb(0x03f2, dor);
7285 // reset the disk motor timeout value of INT 08
7286 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
7288 // check port 3f4 for drive readiness
7289 val8 = inb(0x3f4);
7290 if ( (val8 & 0xf0) != 0x80 )
7291 BX_PANIC("int13_diskette:f03: ctrl not ready\n");
7293 // send read-normal-data command (9 bytes) to controller
7294 outb(0x03f5, 0xc5); // c5: write normal data
7295 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7296 outb(0x03f5, track);
7297 outb(0x03f5, head);
7298 outb(0x03f5, sector);
7299 outb(0x03f5, 2); // 512 byte sector size
7300 outb(0x03f5, 0); // last sector number possible on track
7301 outb(0x03f5, 0); // Gap length
7302 outb(0x03f5, 0xff); // Gap length
7304 // turn on interrupts
7305 ASM_START
7306 sti
7307 ASM_END
7309 // wait on 40:3e bit 7 to become 1
7310 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7311 while ( val8 == 0 ) {
7312 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7315 val8 = 0; // separate asm from while() loop
7316 // turn off interrupts
7317 ASM_START
7318 cli
7319 ASM_END
7321 // set 40:3e bit 7 to 0
7322 val8 = read_byte(0x0000, 0x043e);
7323 val8 &= 0x7f;
7324 write_byte(0x0000, 0x043e, val8);
7326 // check port 3f4 for accessibility to status bytes
7327 val8 = inb(0x3f4);
7328 if ( (val8 & 0xc0) != 0xc0 )
7329 BX_PANIC("int13_diskette: ctrl not ready\n");
7331 // read 7 return status bytes from controller
7332 // using loop index broken, have to unroll...
7333 return_status[0] = inb(0x3f5);
7334 return_status[1] = inb(0x3f5);
7335 return_status[2] = inb(0x3f5);
7336 return_status[3] = inb(0x3f5);
7337 return_status[4] = inb(0x3f5);
7338 return_status[5] = inb(0x3f5);
7339 return_status[6] = inb(0x3f5);
7340 // record in BIOS Data Area
7341 write_byte(0x0040, 0x0042, return_status[0]);
7342 write_byte(0x0040, 0x0043, return_status[1]);
7343 write_byte(0x0040, 0x0044, return_status[2]);
7344 write_byte(0x0040, 0x0045, return_status[3]);
7345 write_byte(0x0040, 0x0046, return_status[4]);
7346 write_byte(0x0040, 0x0047, return_status[5]);
7347 write_byte(0x0040, 0x0048, return_status[6]);
7349 if ( (return_status[0] & 0xc0) != 0 ) {
7350 if ( (return_status[1] & 0x02) != 0 ) {
7351 // diskette not writable.
7352 // AH=status code=0x03 (tried to write on write-protected disk)
7353 // AL=number of sectors written=0
7354 AX = 0x0300;
7355 SET_CF();
7356 return;
7357 } else {
7358 BX_PANIC("int13_diskette_function: read error\n");
7362 // ??? should track be new val from return_status[3] ?
7363 set_diskette_current_cyl(drive, track);
7364 // AL = number of sectors read (same value as passed)
7365 SET_AH(0x00); // success
7366 CLEAR_CF(); // success
7367 return;
7369 else { // if (ah == 0x04)
7370 // Verify Diskette Sectors
7372 // ??? should track be new val from return_status[3] ?
7373 set_diskette_current_cyl(drive, track);
7374 // AL = number of sectors verified (same value as passed)
7375 CLEAR_CF(); // success
7376 SET_AH(0x00); // success
7377 return;
7381 case 0x05: // format diskette track
7382 BX_DEBUG_INT13_FL("floppy f05\n");
7384 num_sectors = GET_AL();
7385 track = GET_CH();
7386 head = GET_DH();
7387 drive = GET_ELDL();
7389 if ((drive > 1) || (head > 1) || (track > 79) ||
7390 (num_sectors == 0) || (num_sectors > 18)) {
7391 SET_AH(1);
7392 set_diskette_ret_status(1);
7393 SET_CF(); // error occurred
7396 // see if drive exists
7397 if (floppy_drive_exists(drive) == 0) {
7398 SET_AH(0x80); // drive not responding
7399 set_diskette_ret_status(0x80);
7400 SET_CF(); // error occurred
7401 return;
7404 // see if media in drive, and type is known
7405 if (floppy_media_known(drive) == 0) {
7406 if (floppy_media_sense(drive) == 0) {
7407 SET_AH(0x0C); // Media type not found
7408 set_diskette_ret_status(0x0C);
7409 SET_AL(0); // no sectors read
7410 SET_CF(); // error occurred
7411 return;
7415 // set up DMA controller for transfer
7416 page = (ES >> 12); // upper 4 bits
7417 base_es = (ES << 4); // lower 16bits contributed by ES
7418 base_address = base_es + BX; // lower 16 bits of address
7419 // contributed by ES:BX
7420 if ( base_address < base_es ) {
7421 // in case of carry, adjust page by 1
7422 page++;
7424 base_count = (num_sectors * 4) - 1;
7426 // check for 64K boundary overrun
7427 last_addr = base_address + base_count;
7428 if (last_addr < base_address) {
7429 SET_AH(0x09);
7430 set_diskette_ret_status(0x09);
7431 SET_AL(0); // no sectors read
7432 SET_CF(); // error occurred
7433 return;
7436 outb(0x000a, 0x06);
7437 outb(0x000c, 0x00); // clear flip-flop
7438 outb(0x0004, base_address);
7439 outb(0x0004, base_address>>8);
7440 outb(0x000c, 0x00); // clear flip-flop
7441 outb(0x0005, base_count);
7442 outb(0x0005, base_count>>8);
7443 mode_register = 0x4a; // single mode, increment, autoinit disable,
7444 // transfer type=read, channel 2
7445 outb(0x000b, mode_register);
7446 // port 81: DMA-1 Page Register, channel 2
7447 outb(0x0081, page);
7448 outb(0x000a, 0x02);
7450 // set up floppy controller for transfer
7451 val8 = read_byte(0x0000, 0x043e);
7452 val8 &= 0x7f;
7453 write_byte(0x0000, 0x043e, val8);
7454 // turn on motor of selected drive, DMA & int enabled, normal operation
7455 if (drive)
7456 dor = 0x20;
7457 else
7458 dor = 0x10;
7459 dor |= 0x0c;
7460 dor |= drive;
7461 outb(0x03f2, dor);
7463 // reset the disk motor timeout value of INT 08
7464 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
7466 // check port 3f4 for drive readiness
7467 val8 = inb(0x3f4);
7468 if ( (val8 & 0xf0) != 0x80 )
7469 BX_PANIC("int13_diskette:f05: ctrl not ready\n");
7471 // send read-normal-data command (6 bytes) to controller
7472 outb(0x03f5, 0x4d); // 4d: format track
7473 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7474 outb(0x03f5, 2); // 512 byte sector size
7475 outb(0x03f5, num_sectors); // number of sectors per track
7476 outb(0x03f5, 0); // Gap length
7477 outb(0x03f5, 0xf6); // Fill byte
7478 // turn on interrupts
7479 ASM_START
7480 sti
7481 ASM_END
7482 // wait on 40:3e bit 7 to become 1
7483 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7484 while ( val8 == 0 ) {
7485 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7487 val8 = 0; // separate asm from while() loop
7488 // turn off interrupts
7489 ASM_START
7490 cli
7491 ASM_END
7492 // set 40:3e bit 7 to 0
7493 val8 = read_byte(0x0000, 0x043e);
7494 val8 &= 0x7f;
7495 write_byte(0x0000, 0x043e, val8);
7496 // check port 3f4 for accessibility to status bytes
7497 val8 = inb(0x3f4);
7498 if ( (val8 & 0xc0) != 0xc0 )
7499 BX_PANIC("int13_diskette: ctrl not ready\n");
7501 // read 7 return status bytes from controller
7502 // using loop index broken, have to unroll...
7503 return_status[0] = inb(0x3f5);
7504 return_status[1] = inb(0x3f5);
7505 return_status[2] = inb(0x3f5);
7506 return_status[3] = inb(0x3f5);
7507 return_status[4] = inb(0x3f5);
7508 return_status[5] = inb(0x3f5);
7509 return_status[6] = inb(0x3f5);
7510 // record in BIOS Data Area
7511 write_byte(0x0040, 0x0042, return_status[0]);
7512 write_byte(0x0040, 0x0043, return_status[1]);
7513 write_byte(0x0040, 0x0044, return_status[2]);
7514 write_byte(0x0040, 0x0045, return_status[3]);
7515 write_byte(0x0040, 0x0046, return_status[4]);
7516 write_byte(0x0040, 0x0047, return_status[5]);
7517 write_byte(0x0040, 0x0048, return_status[6]);
7519 if ( (return_status[0] & 0xc0) != 0 ) {
7520 if ( (return_status[1] & 0x02) != 0 ) {
7521 // diskette not writable.
7522 // AH=status code=0x03 (tried to write on write-protected disk)
7523 // AL=number of sectors written=0
7524 AX = 0x0300;
7525 SET_CF();
7526 return;
7527 } else {
7528 BX_PANIC("int13_diskette_function: write error\n");
7532 SET_AH(0);
7533 set_diskette_ret_status(0);
7534 set_diskette_current_cyl(drive, 0);
7535 CLEAR_CF(); // successful
7536 return;
7539 case 0x08: // read diskette drive parameters
7540 BX_DEBUG_INT13_FL("floppy f08\n");
7541 drive = GET_ELDL();
7543 if (drive > 1) {
7544 AX = 0;
7545 BX = 0;
7546 CX = 0;
7547 DX = 0;
7548 ES = 0;
7549 DI = 0;
7550 SET_DL(num_floppies);
7551 SET_CF();
7552 return;
7555 drive_type = inb_cmos(0x10);
7556 num_floppies = 0;
7557 if (drive_type & 0xf0)
7558 num_floppies++;
7559 if (drive_type & 0x0f)
7560 num_floppies++;
7562 if (drive == 0)
7563 drive_type >>= 4;
7564 else
7565 drive_type &= 0x0f;
7567 SET_BH(0);
7568 SET_BL(drive_type);
7569 SET_AH(0);
7570 SET_AL(0);
7571 SET_DL(num_floppies);
7573 switch (drive_type) {
7574 case 0: // none
7575 CX = 0;
7576 SET_DH(0); // max head #
7577 break;
7579 case 1: // 360KB, 5.25"
7580 CX = 0x2709; // 40 tracks, 9 sectors
7581 SET_DH(1); // max head #
7582 break;
7584 case 2: // 1.2MB, 5.25"
7585 CX = 0x4f0f; // 80 tracks, 15 sectors
7586 SET_DH(1); // max head #
7587 break;
7589 case 3: // 720KB, 3.5"
7590 CX = 0x4f09; // 80 tracks, 9 sectors
7591 SET_DH(1); // max head #
7592 break;
7594 case 4: // 1.44MB, 3.5"
7595 CX = 0x4f12; // 80 tracks, 18 sectors
7596 SET_DH(1); // max head #
7597 break;
7599 case 5: // 2.88MB, 3.5"
7600 CX = 0x4f24; // 80 tracks, 36 sectors
7601 SET_DH(1); // max head #
7602 break;
7604 case 6: // 160k, 5.25"
7605 CX = 0x2708; // 40 tracks, 8 sectors
7606 SET_DH(0); // max head #
7607 break;
7609 case 7: // 180k, 5.25"
7610 CX = 0x2709; // 40 tracks, 9 sectors
7611 SET_DH(0); // max head #
7612 break;
7614 case 8: // 320k, 5.25"
7615 CX = 0x2708; // 40 tracks, 8 sectors
7616 SET_DH(1); // max head #
7617 break;
7619 default: // ?
7620 BX_PANIC("floppy: int13: bad floppy type\n");
7623 /* set es & di to point to 11 byte diskette param table in ROM */
7624 ASM_START
7625 push bp
7626 mov bp, sp
7627 mov ax, #diskette_param_table2
7628 mov _int13_diskette_function.DI+2[bp], ax
7629 mov _int13_diskette_function.ES+2[bp], cs
7630 pop bp
7631 ASM_END
7632 CLEAR_CF(); // success
7633 /* disk status not changed upon success */
7634 return;
7637 case 0x15: // read diskette drive type
7638 BX_DEBUG_INT13_FL("floppy f15\n");
7639 drive = GET_ELDL();
7640 if (drive > 1) {
7641 SET_AH(0); // only 2 drives supported
7642 // set_diskette_ret_status here ???
7643 SET_CF();
7644 return;
7646 drive_type = inb_cmos(0x10);
7648 if (drive == 0)
7649 drive_type >>= 4;
7650 else
7651 drive_type &= 0x0f;
7652 CLEAR_CF(); // successful, not present
7653 if (drive_type==0) {
7654 SET_AH(0); // drive not present
7656 else {
7657 SET_AH(1); // drive present, does not support change line
7660 return;
7662 case 0x16: // get diskette change line status
7663 BX_DEBUG_INT13_FL("floppy f16\n");
7664 drive = GET_ELDL();
7665 if (drive > 1) {
7666 SET_AH(0x01); // invalid drive
7667 set_diskette_ret_status(0x01);
7668 SET_CF();
7669 return;
7672 SET_AH(0x06); // change line not supported
7673 set_diskette_ret_status(0x06);
7674 SET_CF();
7675 return;
7677 case 0x17: // set diskette type for format(old)
7678 BX_DEBUG_INT13_FL("floppy f17\n");
7679 /* not used for 1.44M floppies */
7680 SET_AH(0x01); // not supported
7681 set_diskette_ret_status(1); /* not supported */
7682 SET_CF();
7683 return;
7685 case 0x18: // set diskette type for format(new)
7686 BX_DEBUG_INT13_FL("floppy f18\n");
7687 SET_AH(0x01); // do later
7688 set_diskette_ret_status(1);
7689 SET_CF();
7690 return;
7692 default:
7693 BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
7695 // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
7696 SET_AH(0x01); // ???
7697 set_diskette_ret_status(1);
7698 SET_CF();
7699 return;
7700 // }
7703 #else // #if BX_SUPPORT_FLOPPY
7704 void
7705 int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
7706 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
7708 Bit8u val8;
7710 switch ( GET_AH() ) {
7712 case 0x01: // Read Diskette Status
7713 CLEAR_CF();
7714 val8 = read_byte(0x0000, 0x0441);
7715 SET_AH(val8);
7716 if (val8) {
7717 SET_CF();
7719 return;
7721 default:
7722 SET_CF();
7723 write_byte(0x0000, 0x0441, 0x01);
7724 SET_AH(0x01);
7727 #endif // #if BX_SUPPORT_FLOPPY
7729 void
7730 set_diskette_ret_status(value)
7731 Bit8u value;
7733 write_byte(0x0040, 0x0041, value);
7736 void
7737 set_diskette_current_cyl(drive, cyl)
7738 Bit8u drive;
7739 Bit8u cyl;
7741 if (drive > 1)
7742 BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
7743 write_byte(0x0040, 0x0094+drive, cyl);
7746 void
7747 determine_floppy_media(drive)
7748 Bit16u drive;
7750 #if 0
7751 Bit8u val8, DOR, ctrl_info;
7753 ctrl_info = read_byte(0x0040, 0x008F);
7754 if (drive==1)
7755 ctrl_info >>= 4;
7756 else
7757 ctrl_info &= 0x0f;
7759 #if 0
7760 if (drive == 0) {
7761 DOR = 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
7763 else {
7764 DOR = 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
7766 #endif
7768 if ( (ctrl_info & 0x04) != 0x04 ) {
7769 // Drive not determined means no drive exists, done.
7770 return;
7773 #if 0
7774 // check Main Status Register for readiness
7775 val8 = inb(0x03f4) & 0x80; // Main Status Register
7776 if (val8 != 0x80)
7777 BX_PANIC("d_f_m: MRQ bit not set\n");
7779 // change line
7781 // existing BDA values
7783 // turn on drive motor
7784 outb(0x03f2, DOR); // Digital Output Register
7785 //
7786 #endif
7787 BX_PANIC("d_f_m: OK so far\n");
7788 #endif
7791 void
7792 int17_function(regs, ds, iret_addr)
7793 pusha_regs_t regs; // regs pushed from PUSHA instruction
7794 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
7795 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
7797 Bit16u addr,timeout;
7798 Bit8u val8;
7800 ASM_START
7801 sti
7802 ASM_END
7804 addr = read_word(0x0040, (regs.u.r16.dx << 1) + 8);
7805 if ((regs.u.r8.ah < 3) && (regs.u.r16.dx < 3) && (addr > 0)) {
7806 timeout = read_byte(0x0040, 0x0078 + regs.u.r16.dx) << 8;
7807 if (regs.u.r8.ah == 0) {
7808 outb(addr, regs.u.r8.al);
7809 val8 = inb(addr+2);
7810 outb(addr+2, val8 | 0x01); // send strobe
7811 ASM_START
7812 nop
7813 ASM_END
7814 outb(addr+2, val8 & ~0x01);
7815 while (((inb(addr+1) & 0x40) == 0x40) && (timeout)) {
7816 timeout--;
7819 if (regs.u.r8.ah == 1) {
7820 val8 = inb(addr+2);
7821 outb(addr+2, val8 & ~0x04); // send init
7822 ASM_START
7823 nop
7824 ASM_END
7825 outb(addr+2, val8 | 0x04);
7827 val8 = inb(addr+1);
7828 regs.u.r8.ah = (val8 ^ 0x48);
7829 if (!timeout) regs.u.r8.ah |= 0x01;
7830 ClearCF(iret_addr.flags);
7831 } else {
7832 SetCF(iret_addr.flags); // Unsupported
7836 void
7837 int18_function(seq_nr)
7838 Bit16u seq_nr;
7840 Bit16u ebda_seg=read_word(0x0040,0x000E);
7841 Bit16u bootdev;
7842 Bit8u bootdrv;
7843 Bit8u bootchk;
7844 Bit16u bootseg;
7845 Bit16u bootip;
7846 Bit16u status;
7848 struct ipl_entry e;
7850 // if BX_ELTORITO_BOOT is not defined, old behavior
7851 // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
7852 // in preparation for the intial INT 13h (0=floppy A:, 0x80=C:)
7853 // 0: system boot sequence, first drive C: then A:
7854 // 1: system boot sequence, first drive A: then C:
7855 // else BX_ELTORITO_BOOT is defined
7856 // CMOS regs 0x3D and 0x38 contain the boot sequence:
7857 // CMOS reg 0x3D & 0x0f : 1st boot device
7858 // CMOS reg 0x3D & 0xf0 : 2nd boot device
7859 // CMOS reg 0x38 & 0xf0 : 3rd boot device
7860 // boot device codes:
7861 // 0x00 : not defined
7862 // 0x01 : first floppy
7863 // 0x02 : first harddrive
7864 // 0x03 : first cdrom
7865 // 0x04 - 0x0f : PnP expansion ROMs (e.g. Etherboot)
7866 // else : boot failure
7868 // Get the boot sequence
7869 #if BX_ELTORITO_BOOT
7870 bootdev = inb_cmos(0x3d);
7871 bootdev |= ((inb_cmos(0x38) & 0xf0) << 4);
7872 bootdev >>= 4 * seq_nr;
7873 bootdev &= 0xf;
7874 if (bootdev == 0) BX_PANIC("No bootable device.\n");
7876 /* Translate from CMOS runes to an IPL table offset by subtracting 1 */
7877 bootdev -= 1;
7878 #else
7879 if (seq_nr ==2) BX_PANIC("No more boot devices.");
7880 if (!!(inb_cmos(0x2d) & 0x20) ^ (seq_nr == 1))
7881 /* Boot from floppy if the bit is set or it's the second boot */
7882 bootdev = 0x00;
7883 else
7884 bootdev = 0x01;
7885 #endif
7887 /* Read the boot device from the IPL table */
7888 if (get_boot_vector(bootdev, &e) == 0) {
7889 BX_INFO("Invalid boot device (0x%x)\n", bootdev);
7890 return;
7893 /* Do the loading, and set up vector as a far pointer to the boot
7894 * address, and bootdrv as the boot drive */
7895 print_boot_device(e.type);
7897 switch(e.type) {
7898 case 0x01: /* FDD */
7899 case 0x02: /* HDD */
7901 bootdrv = (e.type == 0x02) ? 0x80 : 0x00;
7902 bootseg = 0x07c0;
7903 status = 0;
7905 ASM_START
7906 push bp
7907 mov bp, sp
7908 push ax
7909 push bx
7910 push cx
7911 push dx
7913 mov dl, _int18_function.bootdrv + 2[bp]
7914 mov ax, _int18_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 _int18_function.status + 2[bp], ax
7927 int19_load_done:
7928 pop dx
7929 pop cx
7930 pop bx
7931 pop ax
7932 pop bp
7933 ASM_END
7935 if (status != 0) {
7936 print_boot_failure(e.type, 1);
7937 return;
7940 /* Always check the signature on a HDD boot sector; on FDD, only do
7941 * the check if the CMOS doesn't tell us to skip it */
7942 if (e.type != 0x00 || !((inb_cmos(0x38) & 0x01))) {
7943 if (read_word(bootseg,0x1fe) != 0xaa55) {
7944 print_boot_failure(e.type, 0);
7945 return;
7949 #if BX_TCGBIOS
7950 tcpa_add_bootdevice((Bit32u)0L, (Bit32u)bootdrv);
7951 tcpa_ipl((Bit32u)0L,(Bit32u)bootseg,(Bit32u)0L,(Bit32u)512L); /* specs: 8.2.3 steps 4 and 5 */
7952 #endif
7954 /* Canonicalize bootseg:bootip */
7955 bootip = (bootseg & 0x0fff) << 4;
7956 bootseg &= 0xf000;
7957 break;
7959 #if BX_ELTORITO_BOOT
7960 case 0x03: /* CD-ROM */
7961 status = cdrom_boot();
7963 // If failure
7964 if ( (status & 0x00ff) !=0 ) {
7965 print_cdromboot_failure(status);
7966 print_boot_failure(e.type, 1);
7967 return;
7970 bootdrv = (Bit8u)(status>>8);
7971 bootseg = read_word(ebda_seg,&EbdaData->cdemu.load_segment);
7973 /* Canonicalize bootseg:bootip */
7974 bootip = (bootseg & 0x0fff) << 4;
7975 bootseg &= 0xf000;
7976 break;
7977 #endif
7979 case 0x80: /* Expansion ROM with a Bootstrap Entry Vector (a far pointer) */
7980 bootseg = e.vector >> 16;
7981 bootip = e.vector & 0xffff;
7982 break;
7984 default: return;
7988 /* Jump to the boot vector */
7989 ASM_START
7990 mov bp, sp
7991 ;; Build an iret stack frame that will take us to the boot vector.
7992 ;; iret pops ip, then cs, then flags, so push them in the opposite order.
7993 pushf
7994 mov ax, _int18_function.bootseg + 0[bp]
7995 push ax
7996 mov ax, _int18_function.bootip + 0[bp]
7997 push ax
7998 ;; Set the magic number in ax and the boot drive in dl.
7999 mov ax, #0xaa55
8000 mov dl, _int18_function.bootdrv + 0[bp]
8001 ;; Zero some of the other registers.
8002 xor bx, bx
8003 mov ds, bx
8004 mov es, bx
8005 mov bp, bx
8006 ;; Go!
8007 iret
8008 ASM_END
8011 void
8012 int1a_function(regs, ds, iret_addr)
8013 pusha_regs_t regs; // regs pushed from PUSHA instruction
8014 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8015 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8017 Bit8u val8;
8019 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);
8021 ASM_START
8022 sti
8023 ASM_END
8025 switch (regs.u.r8.ah) {
8026 case 0: // get current clock count
8027 ASM_START
8028 cli
8029 ASM_END
8030 regs.u.r16.cx = BiosData->ticks_high;
8031 regs.u.r16.dx = BiosData->ticks_low;
8032 regs.u.r8.al = BiosData->midnight_flag;
8033 BiosData->midnight_flag = 0; // reset flag
8034 ASM_START
8035 sti
8036 ASM_END
8037 // AH already 0
8038 ClearCF(iret_addr.flags); // OK
8039 break;
8041 case 1: // Set Current Clock Count
8042 ASM_START
8043 cli
8044 ASM_END
8045 BiosData->ticks_high = regs.u.r16.cx;
8046 BiosData->ticks_low = regs.u.r16.dx;
8047 BiosData->midnight_flag = 0; // reset flag
8048 ASM_START
8049 sti
8050 ASM_END
8051 regs.u.r8.ah = 0;
8052 ClearCF(iret_addr.flags); // OK
8053 break;
8056 case 2: // Read CMOS Time
8057 if (rtc_updating()) {
8058 SetCF(iret_addr.flags);
8059 break;
8062 regs.u.r8.dh = inb_cmos(0x00); // Seconds
8063 regs.u.r8.cl = inb_cmos(0x02); // Minutes
8064 regs.u.r8.ch = inb_cmos(0x04); // Hours
8065 regs.u.r8.dl = inb_cmos(0x0b) & 0x01; // Stat Reg B
8066 regs.u.r8.ah = 0;
8067 regs.u.r8.al = regs.u.r8.ch;
8068 ClearCF(iret_addr.flags); // OK
8069 break;
8071 case 3: // Set CMOS Time
8072 // Using a debugger, I notice the following masking/setting
8073 // of bits in Status Register B, by setting Reg B to
8074 // a few values and getting its value after INT 1A was called.
8075 //
8076 // try#1 try#2 try#3
8077 // before 1111 1101 0111 1101 0000 0000
8078 // after 0110 0010 0110 0010 0000 0010
8079 //
8080 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8081 // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
8082 if (rtc_updating()) {
8083 init_rtc();
8084 // fall through as if an update were not in progress
8086 outb_cmos(0x00, regs.u.r8.dh); // Seconds
8087 outb_cmos(0x02, regs.u.r8.cl); // Minutes
8088 outb_cmos(0x04, regs.u.r8.ch); // Hours
8089 // Set Daylight Savings time enabled bit to requested value
8090 val8 = (inb_cmos(0x0b) & 0x60) | 0x02 | (regs.u.r8.dl & 0x01);
8091 // (reg B already selected)
8092 outb_cmos(0x0b, val8);
8093 regs.u.r8.ah = 0;
8094 regs.u.r8.al = val8; // val last written to Reg B
8095 ClearCF(iret_addr.flags); // OK
8096 break;
8098 case 4: // Read CMOS Date
8099 regs.u.r8.ah = 0;
8100 if (rtc_updating()) {
8101 SetCF(iret_addr.flags);
8102 break;
8104 regs.u.r8.cl = inb_cmos(0x09); // Year
8105 regs.u.r8.dh = inb_cmos(0x08); // Month
8106 regs.u.r8.dl = inb_cmos(0x07); // Day of Month
8107 regs.u.r8.ch = inb_cmos(0x32); // Century
8108 regs.u.r8.al = regs.u.r8.ch;
8109 ClearCF(iret_addr.flags); // OK
8110 break;
8112 case 5: // Set CMOS Date
8113 // Using a debugger, I notice the following masking/setting
8114 // of bits in Status Register B, by setting Reg B to
8115 // a few values and getting its value after INT 1A was called.
8116 //
8117 // try#1 try#2 try#3 try#4
8118 // before 1111 1101 0111 1101 0000 0010 0000 0000
8119 // after 0110 1101 0111 1101 0000 0010 0000 0000
8120 //
8121 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8122 // My assumption: RegB = (RegB & 01111111b)
8123 if (rtc_updating()) {
8124 init_rtc();
8125 SetCF(iret_addr.flags);
8126 break;
8128 outb_cmos(0x09, regs.u.r8.cl); // Year
8129 outb_cmos(0x08, regs.u.r8.dh); // Month
8130 outb_cmos(0x07, regs.u.r8.dl); // Day of Month
8131 outb_cmos(0x32, regs.u.r8.ch); // Century
8132 val8 = inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
8133 outb_cmos(0x0b, val8);
8134 regs.u.r8.ah = 0;
8135 regs.u.r8.al = val8; // AL = val last written to Reg B
8136 ClearCF(iret_addr.flags); // OK
8137 break;
8139 case 6: // Set Alarm Time in CMOS
8140 // Using a debugger, I notice the following masking/setting
8141 // of bits in Status Register B, by setting Reg B to
8142 // a few values and getting its value after INT 1A was called.
8143 //
8144 // try#1 try#2 try#3
8145 // before 1101 1111 0101 1111 0000 0000
8146 // after 0110 1111 0111 1111 0010 0000
8147 //
8148 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8149 // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
8150 val8 = inb_cmos(0x0b); // Get Status Reg B
8151 regs.u.r16.ax = 0;
8152 if (val8 & 0x20) {
8153 // Alarm interrupt enabled already
8154 SetCF(iret_addr.flags); // Error: alarm in use
8155 break;
8157 if (rtc_updating()) {
8158 init_rtc();
8159 // fall through as if an update were not in progress
8161 outb_cmos(0x01, regs.u.r8.dh); // Seconds alarm
8162 outb_cmos(0x03, regs.u.r8.cl); // Minutes alarm
8163 outb_cmos(0x05, regs.u.r8.ch); // Hours alarm
8164 outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
8165 // enable Status Reg B alarm bit, clear halt clock bit
8166 outb_cmos(0x0b, (val8 & 0x7f) | 0x20);
8167 ClearCF(iret_addr.flags); // OK
8168 break;
8170 case 7: // Turn off Alarm
8171 // Using a debugger, I notice the following masking/setting
8172 // of bits in Status Register B, by setting Reg B to
8173 // a few values and getting its value after INT 1A was called.
8174 //
8175 // try#1 try#2 try#3 try#4
8176 // before 1111 1101 0111 1101 0010 0000 0010 0010
8177 // after 0100 0101 0101 0101 0000 0000 0000 0010
8178 //
8179 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8180 // My assumption: RegB = (RegB & 01010111b)
8181 val8 = inb_cmos(0x0b); // Get Status Reg B
8182 // clear clock-halt bit, disable alarm bit
8183 outb_cmos(0x0b, val8 & 0x57); // disable alarm bit
8184 regs.u.r8.ah = 0;
8185 regs.u.r8.al = val8; // val last written to Reg B
8186 ClearCF(iret_addr.flags); // OK
8187 break;
8188 #if BX_PCIBIOS
8189 case 0xb1:
8190 // real mode PCI BIOS functions now handled in assembler code
8191 // this C code handles the error code for information only
8192 if (regs.u.r8.bl == 0xff) {
8193 BX_INFO("PCI BIOS: PCI not present\n");
8194 } else if (regs.u.r8.bl == 0x81) {
8195 BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs.u.r8.al);
8196 } else if (regs.u.r8.bl == 0x83) {
8197 BX_INFO("bad PCI vendor ID %04x\n", regs.u.r16.dx);
8198 } else if (regs.u.r8.bl == 0x86) {
8199 BX_INFO("PCI device %04x:%04x not found\n", regs.u.r16.dx, regs.u.r16.cx);
8201 regs.u.r8.ah = regs.u.r8.bl;
8202 SetCF(iret_addr.flags);
8203 break;
8204 #endif
8206 default:
8207 SetCF(iret_addr.flags); // Unsupported
8211 void
8212 int70_function(regs, ds, iret_addr)
8213 pusha_regs_t regs; // regs pushed from PUSHA instruction
8214 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8215 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8217 // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
8218 Bit8u registerB = 0, registerC = 0;
8220 // Check which modes are enabled and have occurred.
8221 registerB = inb_cmos( 0xB );
8222 registerC = inb_cmos( 0xC );
8224 if( ( registerB & 0x60 ) != 0 ) {
8225 if( ( registerC & 0x20 ) != 0 ) {
8226 // Handle Alarm Interrupt.
8227 ASM_START
8228 sti
8229 int #0x4a
8230 cli
8231 ASM_END
8233 if( ( registerC & 0x40 ) != 0 ) {
8234 // Handle Periodic Interrupt.
8236 if( read_byte( 0x40, 0xA0 ) != 0 ) {
8237 // Wait Interval (Int 15, AH=83) active.
8238 Bit32u time, toggle;
8240 time = read_dword( 0x40, 0x9C ); // Time left in microseconds.
8241 if( time < 0x3D1 ) {
8242 // Done waiting.
8243 Bit16u segment, offset;
8245 offset = read_word( 0x40, 0x98 );
8246 segment = read_word( 0x40, 0x9A );
8247 write_byte( 0x40, 0xA0, 0 ); // Turn of status byte.
8248 outb_cmos( 0xB, registerB & 0x37 ); // Clear the Periodic Interrupt.
8249 write_byte( segment, offset, 0x80 ); // Write to specified flag byte.
8250 } else {
8251 // Continue waiting.
8252 time -= 0x3D1;
8253 write_dword( 0x40, 0x9C, time );
8259 ASM_START
8260 call eoi_both_pics
8261 ASM_END
8265 ASM_START
8266 ;------------------------------------------
8267 ;- INT74h : PS/2 mouse hardware interrupt -
8268 ;------------------------------------------
8269 int74_handler:
8270 sti
8271 pusha
8272 push ds ;; save DS
8273 push #0x00 ;; placeholder for status
8274 push #0x00 ;; placeholder for X
8275 push #0x00 ;; placeholder for Y
8276 push #0x00 ;; placeholder for Z
8277 push #0x00 ;; placeholder for make_far_call boolean
8278 call _int74_function
8279 pop cx ;; remove make_far_call from stack
8280 jcxz int74_done
8282 ;; make far call to EBDA:0022
8283 push #0x00
8284 pop ds
8285 push 0x040E ;; push 0000:040E (opcodes 0xff, 0x36, 0x0E, 0x04)
8286 pop ds
8287 //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
8288 call far ptr[0x22]
8289 int74_done:
8290 cli
8291 call eoi_both_pics
8292 add sp, #8 ;; pop status, x, y, z
8294 pop ds ;; restore DS
8295 popa
8296 iret
8299 ;; This will perform an IRET, but will retain value of current CF
8300 ;; by altering flags on stack. Better than RETF #02.
8301 iret_modify_cf:
8302 jc carry_set
8303 push bp
8304 mov bp, sp
8305 and BYTE [bp + 0x06], #0xfe
8306 pop bp
8307 iret
8308 carry_set:
8309 push bp
8310 mov bp, sp
8311 or BYTE [bp + 0x06], #0x01
8312 pop bp
8313 iret
8316 ;----------------------
8317 ;- INT13h (relocated) -
8318 ;----------------------
8320 ; int13_relocated is a little bit messed up since I played with it
8321 ; I have to rewrite it:
8322 ; - call a function that detect which function to call
8323 ; - make all called C function get the same parameters list
8325 int13_relocated:
8327 #if BX_ELTORITO_BOOT
8328 ;; check for an eltorito function
8329 cmp ah,#0x4a
8330 jb int13_not_eltorito
8331 cmp ah,#0x4d
8332 ja int13_not_eltorito
8334 pusha
8335 push es
8336 push ds
8337 push ss
8338 pop ds
8340 push #int13_out
8341 jmp _int13_eltorito ;; ELDX not used
8343 int13_not_eltorito:
8344 push ax
8345 push bx
8346 push cx
8347 push dx
8349 ;; check if emulation active
8350 call _cdemu_isactive
8351 cmp al,#0x00
8352 je int13_cdemu_inactive
8354 ;; check if access to the emulated drive
8355 call _cdemu_emulated_drive
8356 pop dx
8357 push dx
8358 cmp al,dl ;; int13 on emulated drive
8359 jne int13_nocdemu
8361 pop dx
8362 pop cx
8363 pop bx
8364 pop ax
8366 pusha
8367 push es
8368 push ds
8369 push ss
8370 pop ds
8372 push #int13_out
8373 jmp _int13_cdemu ;; ELDX not used
8375 int13_nocdemu:
8376 and dl,#0xE0 ;; mask to get device class, including cdroms
8377 cmp al,dl ;; al is 0x00 or 0x80
8378 jne int13_cdemu_inactive ;; inactive for device class
8380 pop dx
8381 pop cx
8382 pop bx
8383 pop ax
8385 push ax
8386 push cx
8387 push dx
8388 push bx
8390 dec dl ;; real drive is dl - 1
8391 jmp int13_legacy
8393 int13_cdemu_inactive:
8394 pop dx
8395 pop cx
8396 pop bx
8397 pop ax
8399 #endif // BX_ELTORITO_BOOT
8401 int13_noeltorito:
8403 push ax
8404 push cx
8405 push dx
8406 push bx
8408 int13_legacy:
8410 push dx ;; push eltorito value of dx instead of sp
8412 push bp
8413 push si
8414 push di
8416 push es
8417 push ds
8418 push ss
8419 pop ds
8421 ;; now the 16-bit registers can be restored with:
8422 ;; pop ds; pop es; popa; iret
8423 ;; arguments passed to functions should be
8424 ;; DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS
8426 test dl, #0x80
8427 jnz int13_notfloppy
8429 push #int13_out
8430 jmp _int13_diskette_function
8432 int13_notfloppy:
8434 #if BX_USE_ATADRV
8436 cmp dl, #0xE0
8437 jb int13_notcdrom
8439 // ebx is modified: BSD 5.2.1 boot loader problem
8440 // someone should figure out which 32 bit register that actually are used
8442 shr ebx, #16
8443 push bx
8445 call _int13_cdrom
8447 pop bx
8448 shl ebx, #16
8450 jmp int13_out
8452 int13_notcdrom:
8454 #endif
8456 int13_disk:
8457 call _int13_harddisk
8459 int13_out:
8460 pop ds
8461 pop es
8462 popa
8463 iret
8465 ;----------
8466 ;- INT18h -
8467 ;----------
8468 int18_handler: ;; Boot Failure recovery: try the next device.
8470 ;; Reset SP and SS
8471 mov ax, #0xfffe
8472 mov sp, ax
8473 xor ax, ax
8474 mov ss, ax
8476 ;; Get the boot sequence number out of the IPL memory
8477 ;; The first time we do this it will have been set to -1 so
8478 ;; we will start from device 0.
8479 mov bx, #IPL_SEG
8480 mov ds, bx ;; Set segment
8481 mov bx, IPL_SEQUENCE_OFFSET ;; BX is now the sequence number
8482 inc bx ;; ++
8483 mov IPL_SEQUENCE_OFFSET, bx ;; Write it back
8484 mov ds, ax ;; and reset the segment to zero.
8486 ;; Call the C code for the next boot device
8487 push bx
8488 call _int18_function
8490 ;; Boot failed: invoke the boot recovery function...
8491 int #0x18
8493 ;----------
8494 ;- INT19h -
8495 ;----------
8496 int19_relocated: ;; Boot function, relocated
8497 ;;
8498 ;; *** Warning: INT 19h resets the whole machine ***
8499 ;;
8500 ;; Because PV drivers in HVM guests detach some of the emulated devices,
8501 ;; it is not safe to do a soft reboot by just dropping to real mode and
8502 ;; invoking INT 19h -- the boot drives might have disappeared!
8503 ;; If the user asks for a soft reboot, the only thing we can do is
8504 ;; reset the whole machine. When it comes back up, the normal BIOS
8505 ;; boot sequence will start, which is more or less the required behaviour.
8506 ;;
8507 ;; Reset SP and SS
8508 mov ax, #0xfffe
8509 mov sp, ax
8510 xor ax, ax
8511 mov ss, ax
8512 call _machine_reset
8514 ;----------
8515 ;- INT1Ch -
8516 ;----------
8517 int1c_handler: ;; User Timer Tick
8518 iret
8521 ;----------------------
8522 ;- POST: Floppy Drive -
8523 ;----------------------
8524 floppy_drive_post:
8525 mov ax, #0x0000
8526 mov ds, ax
8528 mov al, #0x00
8529 mov 0x043e, al ;; drive 0 & 1 uncalibrated, no interrupt has occurred
8531 mov 0x043f, al ;; diskette motor status: read op, drive0, motors off
8533 mov 0x0440, al ;; diskette motor timeout counter: not active
8534 mov 0x0441, al ;; diskette controller status return code
8536 mov 0x0442, al ;; disk & diskette controller status register 0
8537 mov 0x0443, al ;; diskette controller status register 1
8538 mov 0x0444, al ;; diskette controller status register 2
8539 mov 0x0445, al ;; diskette controller cylinder number
8540 mov 0x0446, al ;; diskette controller head number
8541 mov 0x0447, al ;; diskette controller sector number
8542 mov 0x0448, al ;; diskette controller bytes written
8544 mov 0x048b, al ;; diskette configuration data
8546 ;; -----------------------------------------------------------------
8547 ;; (048F) diskette controller information
8548 ;;
8549 mov al, #0x10 ;; get CMOS diskette drive type
8550 out 0x70, AL
8551 in AL, 0x71
8552 mov ah, al ;; save byte to AH
8554 look_drive0:
8555 shr al, #4 ;; look at top 4 bits for drive 0
8556 jz f0_missing ;; jump if no drive0
8557 mov bl, #0x07 ;; drive0 determined, multi-rate, has changed line
8558 jmp look_drive1
8559 f0_missing:
8560 mov bl, #0x00 ;; no drive0
8562 look_drive1:
8563 mov al, ah ;; restore from AH
8564 and al, #0x0f ;; look at bottom 4 bits for drive 1
8565 jz f1_missing ;; jump if no drive1
8566 or bl, #0x70 ;; drive1 determined, multi-rate, has changed line
8567 f1_missing:
8568 ;; leave high bits in BL zerod
8569 mov 0x048f, bl ;; put new val in BDA (diskette controller information)
8570 ;; -----------------------------------------------------------------
8572 mov al, #0x00
8573 mov 0x0490, al ;; diskette 0 media state
8574 mov 0x0491, al ;; diskette 1 media state
8576 ;; diskette 0,1 operational starting state
8577 ;; drive type has not been determined,
8578 ;; has no changed detection line
8579 mov 0x0492, al
8580 mov 0x0493, al
8582 mov 0x0494, al ;; diskette 0 current cylinder
8583 mov 0x0495, al ;; diskette 1 current cylinder
8585 mov al, #0x02
8586 out #0x0a, al ;; clear DMA-1 channel 2 mask bit
8588 SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
8589 SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
8590 SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
8592 ret
8595 ;--------------------
8596 ;- POST: HARD DRIVE -
8597 ;--------------------
8598 ; relocated here because the primary POST area isnt big enough.
8599 hard_drive_post:
8600 // IRQ 14 = INT 76h
8601 // INT 76h calls INT 15h function ax=9100
8603 mov al, #0x0a ; 0000 1010 = reserved, disable IRQ 14
8604 mov dx, #0x03f6
8605 out dx, al
8607 mov ax, #0x0000
8608 mov ds, ax
8609 mov 0x0474, al /* hard disk status of last operation */
8610 mov 0x0477, al /* hard disk port offset (XT only ???) */
8611 mov 0x048c, al /* hard disk status register */
8612 mov 0x048d, al /* hard disk error register */
8613 mov 0x048e, al /* hard disk task complete flag */
8614 mov al, #0x01
8615 mov 0x0475, al /* hard disk number attached */
8616 mov al, #0xc0
8617 mov 0x0476, al /* hard disk control byte */
8618 SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
8619 SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
8620 ;; INT 41h: hard disk 0 configuration pointer
8621 ;; INT 46h: hard disk 1 configuration pointer
8622 SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D)
8623 SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D)
8625 ;; move disk geometry data from CMOS to EBDA disk parameter table(s)
8626 mov al, #0x12
8627 out #0x70, al
8628 in al, #0x71
8629 and al, #0xf0
8630 cmp al, #0xf0
8631 je post_d0_extended
8632 jmp check_for_hd1
8633 post_d0_extended:
8634 mov al, #0x19
8635 out #0x70, al
8636 in al, #0x71
8637 cmp al, #47 ;; decimal 47 - user definable
8638 je post_d0_type47
8639 HALT(__LINE__)
8640 post_d0_type47:
8641 ;; CMOS purpose param table offset
8642 ;; 1b cylinders low 0
8643 ;; 1c cylinders high 1
8644 ;; 1d heads 2
8645 ;; 1e write pre-comp low 5
8646 ;; 1f write pre-comp high 6
8647 ;; 20 retries/bad map/heads>8 8
8648 ;; 21 landing zone low C
8649 ;; 22 landing zone high D
8650 ;; 23 sectors/track E
8652 mov ax, #EBDA_SEG
8653 mov ds, ax
8655 ;;; Filling EBDA table for hard disk 0.
8656 mov al, #0x1f
8657 out #0x70, al
8658 in al, #0x71
8659 mov ah, al
8660 mov al, #0x1e
8661 out #0x70, al
8662 in al, #0x71
8663 mov (0x003d + 0x05), ax ;; write precomp word
8665 mov al, #0x20
8666 out #0x70, al
8667 in al, #0x71
8668 mov (0x003d + 0x08), al ;; drive control byte
8670 mov al, #0x22
8671 out #0x70, al
8672 in al, #0x71
8673 mov ah, al
8674 mov al, #0x21
8675 out #0x70, al
8676 in al, #0x71
8677 mov (0x003d + 0x0C), ax ;; landing zone word
8679 mov al, #0x1c ;; get cylinders word in AX
8680 out #0x70, al
8681 in al, #0x71 ;; high byte
8682 mov ah, al
8683 mov al, #0x1b
8684 out #0x70, al
8685 in al, #0x71 ;; low byte
8686 mov bx, ax ;; BX = cylinders
8688 mov al, #0x1d
8689 out #0x70, al
8690 in al, #0x71
8691 mov cl, al ;; CL = heads
8693 mov al, #0x23
8694 out #0x70, al
8695 in al, #0x71
8696 mov dl, al ;; DL = sectors
8698 cmp bx, #1024
8699 jnbe hd0_post_logical_chs ;; if cylinders > 1024, use translated style CHS
8701 hd0_post_physical_chs:
8702 ;; no logical CHS mapping used, just physical CHS
8703 ;; use Standard Fixed Disk Parameter Table (FDPT)
8704 mov (0x003d + 0x00), bx ;; number of physical cylinders
8705 mov (0x003d + 0x02), cl ;; number of physical heads
8706 mov (0x003d + 0x0E), dl ;; number of physical sectors
8707 jmp check_for_hd1
8709 hd0_post_logical_chs:
8710 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
8711 mov (0x003d + 0x09), bx ;; number of physical cylinders
8712 mov (0x003d + 0x0b), cl ;; number of physical heads
8713 mov (0x003d + 0x04), dl ;; number of physical sectors
8714 mov (0x003d + 0x0e), dl ;; number of logical sectors (same)
8715 mov al, #0xa0
8716 mov (0x003d + 0x03), al ;; A0h signature, indicates translated table
8718 cmp bx, #2048
8719 jnbe hd0_post_above_2048
8720 ;; 1024 < c <= 2048 cylinders
8721 shr bx, #0x01
8722 shl cl, #0x01
8723 jmp hd0_post_store_logical
8725 hd0_post_above_2048:
8726 cmp bx, #4096
8727 jnbe hd0_post_above_4096
8728 ;; 2048 < c <= 4096 cylinders
8729 shr bx, #0x02
8730 shl cl, #0x02
8731 jmp hd0_post_store_logical
8733 hd0_post_above_4096:
8734 cmp bx, #8192
8735 jnbe hd0_post_above_8192
8736 ;; 4096 < c <= 8192 cylinders
8737 shr bx, #0x03
8738 shl cl, #0x03
8739 jmp hd0_post_store_logical
8741 hd0_post_above_8192:
8742 ;; 8192 < c <= 16384 cylinders
8743 shr bx, #0x04
8744 shl cl, #0x04
8746 hd0_post_store_logical:
8747 mov (0x003d + 0x00), bx ;; number of physical cylinders
8748 mov (0x003d + 0x02), cl ;; number of physical heads
8749 ;; checksum
8750 mov cl, #0x0f ;; repeat count
8751 mov si, #0x003d ;; offset to disk0 FDPT
8752 mov al, #0x00 ;; sum
8753 hd0_post_checksum_loop:
8754 add al, [si]
8755 inc si
8756 dec cl
8757 jnz hd0_post_checksum_loop
8758 not al ;; now take 2s complement
8759 inc al
8760 mov [si], al
8761 ;;; Done filling EBDA table for hard disk 0.
8764 check_for_hd1:
8765 ;; is there really a second hard disk? if not, return now
8766 mov al, #0x12
8767 out #0x70, al
8768 in al, #0x71
8769 and al, #0x0f
8770 jnz post_d1_exists
8771 ret
8772 post_d1_exists:
8773 ;; check that the hd type is really 0x0f.
8774 cmp al, #0x0f
8775 jz post_d1_extended
8776 HALT(__LINE__)
8777 post_d1_extended:
8778 ;; check that the extended type is 47 - user definable
8779 mov al, #0x1a
8780 out #0x70, al
8781 in al, #0x71
8782 cmp al, #47 ;; decimal 47 - user definable
8783 je post_d1_type47
8784 HALT(__LINE__)
8785 post_d1_type47:
8786 ;; Table for disk1.
8787 ;; CMOS purpose param table offset
8788 ;; 0x24 cylinders low 0
8789 ;; 0x25 cylinders high 1
8790 ;; 0x26 heads 2
8791 ;; 0x27 write pre-comp low 5
8792 ;; 0x28 write pre-comp high 6
8793 ;; 0x29 heads>8 8
8794 ;; 0x2a landing zone low C
8795 ;; 0x2b landing zone high D
8796 ;; 0x2c sectors/track E
8797 ;;; Fill EBDA table for hard disk 1.
8798 mov ax, #EBDA_SEG
8799 mov ds, ax
8800 mov al, #0x28
8801 out #0x70, al
8802 in al, #0x71
8803 mov ah, al
8804 mov al, #0x27
8805 out #0x70, al
8806 in al, #0x71
8807 mov (0x004d + 0x05), ax ;; write precomp word
8809 mov al, #0x29
8810 out #0x70, al
8811 in al, #0x71
8812 mov (0x004d + 0x08), al ;; drive control byte
8814 mov al, #0x2b
8815 out #0x70, al
8816 in al, #0x71
8817 mov ah, al
8818 mov al, #0x2a
8819 out #0x70, al
8820 in al, #0x71
8821 mov (0x004d + 0x0C), ax ;; landing zone word
8823 mov al, #0x25 ;; get cylinders word in AX
8824 out #0x70, al
8825 in al, #0x71 ;; high byte
8826 mov ah, al
8827 mov al, #0x24
8828 out #0x70, al
8829 in al, #0x71 ;; low byte
8830 mov bx, ax ;; BX = cylinders
8832 mov al, #0x26
8833 out #0x70, al
8834 in al, #0x71
8835 mov cl, al ;; CL = heads
8837 mov al, #0x2c
8838 out #0x70, al
8839 in al, #0x71
8840 mov dl, al ;; DL = sectors
8842 cmp bx, #1024
8843 jnbe hd1_post_logical_chs ;; if cylinders > 1024, use translated style CHS
8845 hd1_post_physical_chs:
8846 ;; no logical CHS mapping used, just physical CHS
8847 ;; use Standard Fixed Disk Parameter Table (FDPT)
8848 mov (0x004d + 0x00), bx ;; number of physical cylinders
8849 mov (0x004d + 0x02), cl ;; number of physical heads
8850 mov (0x004d + 0x0E), dl ;; number of physical sectors
8851 ret
8853 hd1_post_logical_chs:
8854 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
8855 mov (0x004d + 0x09), bx ;; number of physical cylinders
8856 mov (0x004d + 0x0b), cl ;; number of physical heads
8857 mov (0x004d + 0x04), dl ;; number of physical sectors
8858 mov (0x004d + 0x0e), dl ;; number of logical sectors (same)
8859 mov al, #0xa0
8860 mov (0x004d + 0x03), al ;; A0h signature, indicates translated table
8862 cmp bx, #2048
8863 jnbe hd1_post_above_2048
8864 ;; 1024 < c <= 2048 cylinders
8865 shr bx, #0x01
8866 shl cl, #0x01
8867 jmp hd1_post_store_logical
8869 hd1_post_above_2048:
8870 cmp bx, #4096
8871 jnbe hd1_post_above_4096
8872 ;; 2048 < c <= 4096 cylinders
8873 shr bx, #0x02
8874 shl cl, #0x02
8875 jmp hd1_post_store_logical
8877 hd1_post_above_4096:
8878 cmp bx, #8192
8879 jnbe hd1_post_above_8192
8880 ;; 4096 < c <= 8192 cylinders
8881 shr bx, #0x03
8882 shl cl, #0x03
8883 jmp hd1_post_store_logical
8885 hd1_post_above_8192:
8886 ;; 8192 < c <= 16384 cylinders
8887 shr bx, #0x04
8888 shl cl, #0x04
8890 hd1_post_store_logical:
8891 mov (0x004d + 0x00), bx ;; number of physical cylinders
8892 mov (0x004d + 0x02), cl ;; number of physical heads
8893 ;; checksum
8894 mov cl, #0x0f ;; repeat count
8895 mov si, #0x004d ;; offset to disk0 FDPT
8896 mov al, #0x00 ;; sum
8897 hd1_post_checksum_loop:
8898 add al, [si]
8899 inc si
8900 dec cl
8901 jnz hd1_post_checksum_loop
8902 not al ;; now take 2s complement
8903 inc al
8904 mov [si], al
8905 ;;; Done filling EBDA table for hard disk 1.
8907 ret
8909 ;--------------------
8910 ;- POST: EBDA segment
8911 ;--------------------
8912 ; relocated here because the primary POST area isnt big enough.
8913 ebda_post:
8914 #if BX_USE_EBDA
8915 mov ax, #EBDA_SEG
8916 mov ds, ax
8917 mov byte ptr [0x0], #EBDA_SIZE
8918 #endif
8919 xor ax, ax ; mov EBDA seg into 40E
8920 mov ds, ax
8921 mov word ptr [0x40E], #EBDA_SEG
8922 ret;;
8924 ;--------------------
8925 ;- POST: EOI + jmp via [0x40:67)
8926 ;--------------------
8927 ; relocated here because the primary POST area isnt big enough.
8928 eoi_jmp_post:
8929 call eoi_both_pics
8931 xor ax, ax
8932 mov ds, ax
8934 jmp far ptr [0x467]
8937 ;--------------------
8938 eoi_both_pics:
8939 mov al, #0x20
8940 out #0xA0, al ;; slave PIC EOI
8941 eoi_master_pic:
8942 mov al, #0x20
8943 out #0x20, al ;; master PIC EOI
8944 ret
8946 ;--------------------
8947 BcdToBin:
8948 ;; in: AL in BCD format
8949 ;; out: AL in binary format, AH will always be 0
8950 ;; trashes BX
8951 mov bl, al
8952 and bl, #0x0f ;; bl has low digit
8953 shr al, #4 ;; al has high digit
8954 mov bh, #10
8955 mul al, bh ;; multiply high digit by 10 (result in AX)
8956 add al, bl ;; then add low digit
8957 ret
8959 ;--------------------
8960 timer_tick_post:
8961 ;; Setup the Timer Ticks Count (0x46C:dword) and
8962 ;; Timer Ticks Roller Flag (0x470:byte)
8963 ;; The Timer Ticks Count needs to be set according to
8964 ;; the current CMOS time, as if ticks have been occurring
8965 ;; at 18.2hz since midnight up to this point. Calculating
8966 ;; this is a little complicated. Here are the factors I gather
8967 ;; regarding this. 14,318,180 hz was the original clock speed,
8968 ;; chosen so it could be divided by either 3 to drive the 5Mhz CPU
8969 ;; at the time, or 4 to drive the CGA video adapter. The div3
8970 ;; source was divided again by 4 to feed a 1.193Mhz signal to
8971 ;; the timer. With a maximum 16bit timer count, this is again
8972 ;; divided down by 65536 to 18.2hz.
8973 ;;
8974 ;; 14,318,180 Hz clock
8975 ;; /3 = 4,772,726 Hz fed to orginal 5Mhz CPU
8976 ;; /4 = 1,193,181 Hz fed to timer
8977 ;; /65536 (maximum timer count) = 18.20650736 ticks/second
8978 ;; 1 second = 18.20650736 ticks
8979 ;; 1 minute = 1092.390442 ticks
8980 ;; 1 hour = 65543.42651 ticks
8981 ;;
8982 ;; Given the values in the CMOS clock, one could calculate
8983 ;; the number of ticks by the following:
8984 ;; ticks = (BcdToBin(seconds) * 18.206507) +
8985 ;; (BcdToBin(minutes) * 1092.3904)
8986 ;; (BcdToBin(hours) * 65543.427)
8987 ;; To get a little more accuracy, since Im using integer
8988 ;; arithmatic, I use:
8989 ;; ticks = (BcdToBin(seconds) * 18206507) / 1000000 +
8990 ;; (BcdToBin(minutes) * 10923904) / 10000 +
8991 ;; (BcdToBin(hours) * 65543427) / 1000
8993 ;; assuming DS=0000
8995 ;; get CMOS seconds
8996 xor eax, eax ;; clear EAX
8997 mov al, #0x00
8998 out #0x70, al
8999 in al, #0x71 ;; AL has CMOS seconds in BCD
9000 call BcdToBin ;; EAX now has seconds in binary
9001 mov edx, #18206507
9002 mul eax, edx
9003 mov ebx, #1000000
9004 xor edx, edx
9005 div eax, ebx
9006 mov ecx, eax ;; ECX will accumulate total ticks
9008 ;; get CMOS minutes
9009 xor eax, eax ;; clear EAX
9010 mov al, #0x02
9011 out #0x70, al
9012 in al, #0x71 ;; AL has CMOS minutes in BCD
9013 call BcdToBin ;; EAX now has minutes in binary
9014 mov edx, #10923904
9015 mul eax, edx
9016 mov ebx, #10000
9017 xor edx, edx
9018 div eax, ebx
9019 add ecx, eax ;; add to total ticks
9021 ;; get CMOS hours
9022 xor eax, eax ;; clear EAX
9023 mov al, #0x04
9024 out #0x70, al
9025 in al, #0x71 ;; AL has CMOS hours in BCD
9026 call BcdToBin ;; EAX now has hours in binary
9027 mov edx, #65543427
9028 mul eax, edx
9029 mov ebx, #1000
9030 xor edx, edx
9031 div eax, ebx
9032 add ecx, eax ;; add to total ticks
9034 mov 0x46C, ecx ;; Timer Ticks Count
9035 xor al, al
9036 mov 0x470, al ;; Timer Ticks Rollover Flag
9037 ret
9039 ;--------------------
9040 int76_handler:
9041 ;; record completion in BIOS task complete flag
9042 push ax
9043 push ds
9044 mov ax, #0x0040
9045 mov ds, ax
9046 mov 0x008E, #0xff
9047 call eoi_both_pics
9048 pop ds
9049 pop ax
9050 iret
9053 ;--------------------
9054 #if BX_APM
9056 use32 386
9057 #define APM_PROT32
9058 #include "apmbios.S"
9060 use16 386
9061 #define APM_PROT16
9062 #include "apmbios.S"
9064 #define APM_REAL
9065 #include "apmbios.S"
9067 #endif
9069 ASM_END
9070 #include "32bitgateway.c"
9071 ASM_START
9073 ;--------------------
9074 #if BX_PCIBIOS
9075 use32 386
9076 .align 16
9077 bios32_structure:
9078 db 0x5f, 0x33, 0x32, 0x5f ;; "_32_" signature
9079 dw bios32_entry_point, 0xf ;; 32 bit physical address
9080 db 0 ;; revision level
9081 ;; length in paragraphs and checksum stored in a word to prevent errors
9082 dw (~(((bios32_entry_point >> 8) + (bios32_entry_point & 0xff) + 0x32) \
9083 & 0xff) << 8) + 0x01
9084 db 0,0,0,0,0 ;; reserved
9086 .align 16
9087 bios32_entry_point:
9088 pushf
9089 cmp eax, #0x49435024
9090 jne unknown_service
9091 mov eax, #0x80000000
9092 mov dx, #0x0cf8
9093 out dx, eax
9094 mov dx, #0x0cfc
9095 in eax, dx
9096 cmp eax, #0x12378086
9097 jne unknown_service
9098 mov ebx, #0x000f0000
9099 mov ecx, #0
9100 mov edx, #pcibios_protected
9101 xor al, al
9102 jmp bios32_end
9103 unknown_service:
9104 mov al, #0x80
9105 bios32_end:
9106 popf
9107 retf
9109 .align 16
9110 pcibios_protected:
9111 pushf
9112 cli
9113 push esi
9114 push edi
9115 cmp al, #0x01 ;; installation check
9116 jne pci_pro_f02
9117 mov bx, #0x0210
9118 mov cx, #0
9119 mov edx, #0x20494350
9120 mov al, #0x01
9121 jmp pci_pro_ok
9122 pci_pro_f02: ;; find pci device
9123 cmp al, #0x02
9124 jne pci_pro_f08
9125 shl ecx, #16
9126 mov cx, dx
9127 mov bx, #0x0000
9128 mov di, #0x00
9129 pci_pro_devloop:
9130 call pci_pro_select_reg
9131 mov dx, #0x0cfc
9132 in eax, dx
9133 cmp eax, ecx
9134 jne pci_pro_nextdev
9135 cmp si, #0
9136 je pci_pro_ok
9137 dec si
9138 pci_pro_nextdev:
9139 inc bx
9140 cmp bx, #0x0100
9141 jne pci_pro_devloop
9142 mov ah, #0x86
9143 jmp pci_pro_fail
9144 pci_pro_f08: ;; read configuration byte
9145 cmp al, #0x08
9146 jne pci_pro_f09
9147 call pci_pro_select_reg
9148 push edx
9149 mov dx, di
9150 and dx, #0x03
9151 add dx, #0x0cfc
9152 in al, dx
9153 pop edx
9154 mov cl, al
9155 jmp pci_pro_ok
9156 pci_pro_f09: ;; read configuration word
9157 cmp al, #0x09
9158 jne pci_pro_f0a
9159 call pci_pro_select_reg
9160 push edx
9161 mov dx, di
9162 and dx, #0x02
9163 add dx, #0x0cfc
9164 in ax, dx
9165 pop edx
9166 mov cx, ax
9167 jmp pci_pro_ok
9168 pci_pro_f0a: ;; read configuration dword
9169 cmp al, #0x0a
9170 jne pci_pro_f0b
9171 call pci_pro_select_reg
9172 push edx
9173 mov dx, #0x0cfc
9174 in eax, dx
9175 pop edx
9176 mov ecx, eax
9177 jmp pci_pro_ok
9178 pci_pro_f0b: ;; write configuration byte
9179 cmp al, #0x0b
9180 jne pci_pro_f0c
9181 call pci_pro_select_reg
9182 push edx
9183 mov dx, di
9184 and dx, #0x03
9185 add dx, #0x0cfc
9186 mov al, cl
9187 out dx, al
9188 pop edx
9189 jmp pci_pro_ok
9190 pci_pro_f0c: ;; write configuration word
9191 cmp al, #0x0c
9192 jne pci_pro_f0d
9193 call pci_pro_select_reg
9194 push edx
9195 mov dx, di
9196 and dx, #0x02
9197 add dx, #0x0cfc
9198 mov ax, cx
9199 out dx, ax
9200 pop edx
9201 jmp pci_pro_ok
9202 pci_pro_f0d: ;; write configuration dword
9203 cmp al, #0x0d
9204 jne pci_pro_unknown
9205 call pci_pro_select_reg
9206 push edx
9207 mov dx, #0x0cfc
9208 mov eax, ecx
9209 out dx, eax
9210 pop edx
9211 jmp pci_pro_ok
9212 pci_pro_unknown:
9213 mov ah, #0x81
9214 pci_pro_fail:
9215 pop edi
9216 pop esi
9217 sti
9218 popf
9219 stc
9220 retf
9221 pci_pro_ok:
9222 xor ah, ah
9223 pop edi
9224 pop esi
9225 sti
9226 popf
9227 clc
9228 retf
9230 pci_pro_select_reg:
9231 push edx
9232 mov eax, #0x800000
9233 mov ax, bx
9234 shl eax, #8
9235 and di, #0xff
9236 or ax, di
9237 and al, #0xfc
9238 mov dx, #0x0cf8
9239 out dx, eax
9240 pop edx
9241 ret
9243 use16 386
9245 pcibios_real:
9246 push eax
9247 push dx
9248 mov eax, #0x80000000
9249 mov dx, #0x0cf8
9250 out dx, eax
9251 mov dx, #0x0cfc
9252 in eax, dx
9253 cmp eax, #0x12378086
9254 je pci_present
9255 pop dx
9256 pop eax
9257 mov ah, #0xff
9258 stc
9259 ret
9260 pci_present:
9261 pop dx
9262 pop eax
9263 cmp al, #0x01 ;; installation check
9264 jne pci_real_f02
9265 mov ax, #0x0001
9266 mov bx, #0x0210
9267 mov cx, #0
9268 mov edx, #0x20494350
9269 mov edi, #0xf0000
9270 mov di, #pcibios_protected
9271 clc
9272 ret
9273 pci_real_f02: ;; find pci device
9274 push esi
9275 push edi
9276 cmp al, #0x02
9277 jne pci_real_f08
9278 shl ecx, #16
9279 mov cx, dx
9280 mov bx, #0x0000
9281 mov di, #0x00
9282 pci_real_devloop:
9283 call pci_real_select_reg
9284 mov dx, #0x0cfc
9285 in eax, dx
9286 cmp eax, ecx
9287 jne pci_real_nextdev
9288 cmp si, #0
9289 je pci_real_ok
9290 dec si
9291 pci_real_nextdev:
9292 inc bx
9293 cmp bx, #0x0100
9294 jne pci_real_devloop
9295 mov dx, cx
9296 shr ecx, #16
9297 mov ah, #0x86
9298 jmp pci_real_fail
9299 pci_real_f08: ;; read configuration byte
9300 cmp al, #0x08
9301 jne pci_real_f09
9302 call pci_real_select_reg
9303 push dx
9304 mov dx, di
9305 and dx, #0x03
9306 add dx, #0x0cfc
9307 in al, dx
9308 pop dx
9309 mov cl, al
9310 jmp pci_real_ok
9311 pci_real_f09: ;; read configuration word
9312 cmp al, #0x09
9313 jne pci_real_f0a
9314 call pci_real_select_reg
9315 push dx
9316 mov dx, di
9317 and dx, #0x02
9318 add dx, #0x0cfc
9319 in ax, dx
9320 pop dx
9321 mov cx, ax
9322 jmp pci_real_ok
9323 pci_real_f0a: ;; read configuration dword
9324 cmp al, #0x0a
9325 jne pci_real_f0b
9326 call pci_real_select_reg
9327 push dx
9328 mov dx, #0x0cfc
9329 in eax, dx
9330 pop dx
9331 mov ecx, eax
9332 jmp pci_real_ok
9333 pci_real_f0b: ;; write configuration byte
9334 cmp al, #0x0b
9335 jne pci_real_f0c
9336 call pci_real_select_reg
9337 push dx
9338 mov dx, di
9339 and dx, #0x03
9340 add dx, #0x0cfc
9341 mov al, cl
9342 out dx, al
9343 pop dx
9344 jmp pci_real_ok
9345 pci_real_f0c: ;; write configuration word
9346 cmp al, #0x0c
9347 jne pci_real_f0d
9348 call pci_real_select_reg
9349 push dx
9350 mov dx, di
9351 and dx, #0x02
9352 add dx, #0x0cfc
9353 mov ax, cx
9354 out dx, ax
9355 pop dx
9356 jmp pci_real_ok
9357 pci_real_f0d: ;; write configuration dword
9358 cmp al, #0x0d
9359 jne pci_real_unknown
9360 call pci_real_select_reg
9361 push dx
9362 mov dx, #0x0cfc
9363 mov eax, ecx
9364 out dx, eax
9365 pop dx
9366 jmp pci_real_ok
9367 pci_real_unknown:
9368 mov ah, #0x81
9369 pci_real_fail:
9370 pop edi
9371 pop esi
9372 stc
9373 ret
9374 pci_real_ok:
9375 xor ah, ah
9376 pop edi
9377 pop esi
9378 clc
9379 ret
9381 pci_real_select_reg:
9382 push dx
9383 mov eax, #0x800000
9384 mov ax, bx
9385 shl eax, #8
9386 and di, #0xff
9387 or ax, di
9388 and al, #0xfc
9389 mov dx, #0x0cf8
9390 out dx, eax
9391 pop dx
9392 ret
9394 .align 16
9395 pci_routing_table_structure:
9396 db 0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature
9397 db 0, 1 ;; version
9398 dw 32 + (6 * 16) ;; table size
9399 db 0 ;; PCI interrupt router bus
9400 db 0x08 ;; PCI interrupt router DevFunc
9401 dw 0x0000 ;; PCI exclusive IRQs
9402 dw 0x8086 ;; compatible PCI interrupt router vendor ID
9403 dw 0x7000 ;; compatible PCI interrupt router device ID
9404 dw 0,0 ;; Miniport data
9405 db 0,0,0,0,0,0,0,0,0,0,0 ;; reserved
9406 db 0x07 ;; checksum
9407 ;; first slot entry PCI-to-ISA (embedded)
9408 db 0 ;; pci bus number
9409 db 0x08 ;; pci device number (bit 7-3)
9410 db 0x61 ;; link value INTA#: pointer into PCI2ISA config space
9411 dw 0x0c20 ;; IRQ bitmap INTA#
9412 db 0x62 ;; link value INTB#
9413 dw 0x0c20 ;; IRQ bitmap INTB#
9414 db 0x63 ;; link value INTC#
9415 dw 0x0c20 ;; IRQ bitmap INTC#
9416 db 0x60 ;; link value INTD#
9417 dw 0x0c20 ;; IRQ bitmap INTD#
9418 db 0 ;; physical slot (0 = embedded)
9419 db 0 ;; reserved
9420 ;; second slot entry: 1st PCI slot
9421 db 0 ;; pci bus number
9422 db 0x10 ;; pci device number (bit 7-3)
9423 db 0x62 ;; link value INTA#
9424 dw 0x0c20 ;; IRQ bitmap INTA#
9425 db 0x63 ;; link value INTB#
9426 dw 0x0c20 ;; IRQ bitmap INTB#
9427 db 0x60 ;; link value INTC#
9428 dw 0x0c20 ;; IRQ bitmap INTC#
9429 db 0x61 ;; link value INTD#
9430 dw 0x0c20 ;; IRQ bitmap INTD#
9431 db 1 ;; physical slot (0 = embedded)
9432 db 0 ;; reserved
9433 ;; third slot entry: 2nd PCI slot
9434 db 0 ;; pci bus number
9435 db 0x18 ;; pci device number (bit 7-3)
9436 db 0x63 ;; link value INTA#
9437 dw 0x0c20 ;; IRQ bitmap INTA#
9438 db 0x60 ;; link value INTB#
9439 dw 0x0c20 ;; IRQ bitmap INTB#
9440 db 0x61 ;; link value INTC#
9441 dw 0x0c20 ;; IRQ bitmap INTC#
9442 db 0x62 ;; link value INTD#
9443 dw 0x0c20 ;; IRQ bitmap INTD#
9444 db 2 ;; physical slot (0 = embedded)
9445 db 0 ;; reserved
9446 ;; 4th slot entry: 3rd PCI slot
9447 db 0 ;; pci bus number
9448 db 0x20 ;; pci device number (bit 7-3)
9449 db 0x60 ;; link value INTA#
9450 dw 0x0c20 ;; IRQ bitmap INTA#
9451 db 0x61 ;; link value INTB#
9452 dw 0x0c20 ;; IRQ bitmap INTB#
9453 db 0x62 ;; link value INTC#
9454 dw 0x0c20 ;; IRQ bitmap INTC#
9455 db 0x63 ;; link value INTD#
9456 dw 0x0c20 ;; IRQ bitmap INTD#
9457 db 3 ;; physical slot (0 = embedded)
9458 db 0 ;; reserved
9459 ;; 5th slot entry: 4rd PCI slot
9460 db 0 ;; pci bus number
9461 db 0x28 ;; pci device number (bit 7-3)
9462 db 0x61 ;; link value INTA#
9463 dw 0x0c20 ;; IRQ bitmap INTA#
9464 db 0x62 ;; link value INTB#
9465 dw 0x0c20 ;; IRQ bitmap INTB#
9466 db 0x63 ;; link value INTC#
9467 dw 0x0c20 ;; IRQ bitmap INTC#
9468 db 0x60 ;; link value INTD#
9469 dw 0x0c20 ;; IRQ bitmap INTD#
9470 db 4 ;; physical slot (0 = embedded)
9471 db 0 ;; reserved
9472 ;; 6th slot entry: 5rd PCI slot
9473 db 0 ;; pci bus number
9474 db 0x30 ;; pci device number (bit 7-3)
9475 db 0x62 ;; link value INTA#
9476 dw 0x0c20 ;; IRQ bitmap INTA#
9477 db 0x63 ;; link value INTB#
9478 dw 0x0c20 ;; IRQ bitmap INTB#
9479 db 0x60 ;; link value INTC#
9480 dw 0x0c20 ;; IRQ bitmap INTC#
9481 db 0x61 ;; link value INTD#
9482 dw 0x0c20 ;; IRQ bitmap INTD#
9483 db 5 ;; physical slot (0 = embedded)
9484 db 0 ;; reserved
9485 #endif // BX_PCIBIOS
9487 ; parallel port detection: base address in DX, index in BX, timeout in CL
9488 detect_parport:
9489 push dx
9490 add dx, #2
9491 in al, dx
9492 and al, #0xdf ; clear input mode
9493 out dx, al
9494 pop dx
9495 mov al, #0xaa
9496 out dx, al
9497 in al, dx
9498 cmp al, #0xaa
9499 jne no_parport
9500 push bx
9501 shl bx, #1
9502 mov [bx+0x408], dx ; Parallel I/O address
9503 pop bx
9504 mov [bx+0x478], cl ; Parallel printer timeout
9505 inc bx
9506 no_parport:
9507 ret
9509 ; serial port detection: base address in DX, index in BX, timeout in CL
9510 detect_serial:
9511 push dx
9512 inc dx
9513 mov al, #0x02
9514 out dx, al
9515 in al, dx
9516 cmp al, #0x02
9517 jne no_serial
9518 inc dx
9519 in al, dx
9520 cmp al, #0x02
9521 jne no_serial
9522 dec dx
9523 xor al, al
9524 out dx, al
9525 pop dx
9526 push bx
9527 shl bx, #1
9528 mov [bx+0x400], dx ; Serial I/O address
9529 pop bx
9530 mov [bx+0x47c], cl ; Serial timeout
9531 inc bx
9532 ret
9533 no_serial:
9534 pop dx
9535 ret
9537 rom_checksum:
9538 push ax
9539 push bx
9540 push cx
9541 xor ax, ax
9542 xor bx, bx
9543 xor cx, cx
9544 mov ch, [2]
9545 shl cx, #1
9546 checksum_loop:
9547 add al, [bx]
9548 inc bx
9549 loop checksum_loop
9550 and al, #0xff
9551 pop cx
9552 pop bx
9553 pop ax
9554 ret
9557 ;; We need a copy of this string, but we are not actually a PnP BIOS,
9558 ;; so make sure it is *not* aligned, so OSes will not see it if they scan.
9559 .align 16
9560 db 0
9561 pnp_string:
9562 .ascii "$PnP"
9565 rom_scan:
9566 ;; Scan for existence of valid expansion ROMS.
9567 ;; Video ROM: from 0xC0000..0xC7FFF in 2k increments
9568 ;; General ROM: from 0xC8000..0xDFFFF in 2k increments
9569 ;; System ROM: only 0xE0000
9570 ;;
9571 ;; Header:
9572 ;; Offset Value
9573 ;; 0 0x55
9574 ;; 1 0xAA
9575 ;; 2 ROM length in 512-byte blocks
9576 ;; 3 ROM initialization entry point (FAR CALL)
9578 #if BX_TCGBIOS
9579 call _tcpa_start_option_rom_scan /* specs: 3.2.3.3 + 10.4.3 */
9580 #endif
9581 mov cx, #0xc000
9582 rom_scan_loop:
9583 mov ds, cx
9584 mov ax, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
9585 cmp [0], #0xAA55 ;; look for signature
9586 jne rom_scan_increment
9587 call rom_checksum
9588 jnz rom_scan_increment
9589 mov al, [2] ;; change increment to ROM length in 512-byte blocks
9591 ;; We want our increment in 512-byte quantities, rounded to
9592 ;; the nearest 2k quantity, since we only scan at 2k intervals.
9593 test al, #0x03
9594 jz block_count_rounded
9595 and al, #0xfc ;; needs rounding up
9596 add al, #0x04
9597 block_count_rounded:
9599 #if BX_TCGBIOS
9600 push ax
9601 push ds
9602 push ecx
9603 xor ax, ax
9604 mov ds, ax
9605 and ecx, #0xffff
9606 push ecx ;; segment where option rom is located at
9607 call _tcpa_option_rom /* specs: 3.2.3.3 */
9608 add sp, #4 ;; pop segment
9609 pop ecx ;; original ecx
9610 pop ds
9611 pop ax
9612 #endif
9613 xor bx, bx ;; Restore DS back to 0000:
9614 mov ds, bx
9615 push ax ;; Save AX
9616 push di ;; Save DI
9617 ;; Push addr of ROM entry point
9618 push cx ;; Push seg
9619 push #0x0003 ;; Push offset
9621 ;; Point ES:DI at "$PnP", which tells the ROM that we are a PnP BIOS.
9622 ;; That should stop it grabbing INT 19h; we will use its BEV instead.
9623 mov ax, #0xf000
9624 mov es, ax
9625 lea di, pnp_string
9627 mov bp, sp ;; Call ROM init routine using seg:off on stack
9628 db 0xff ;; call_far ss:[bp+0]
9629 db 0x5e
9630 db 0
9631 cli ;; In case expansion ROM BIOS turns IF on
9632 add sp, #2 ;; Pop offset value
9633 pop cx ;; Pop seg value (restore CX)
9635 ;; Look at the ROM's PnP Expansion header. Properly, we're supposed
9636 ;; to init all the ROMs and then go back and build an IPL table of
9637 ;; all the bootable devices, but we can get away with one pass.
9638 mov ds, cx ;; ROM base
9639 mov bx, 0x001a ;; 0x1A is the offset into ROM header that contains...
9640 mov ax, [bx] ;; the offset of PnP expansion header, where...
9641 cmp ax, #0x5024 ;; we look for signature "$PnP"
9642 jne no_bev
9643 mov ax, 2[bx]
9644 cmp ax, #0x506e
9645 jne no_bev
9646 mov ax, 0x1a[bx] ;; 0x1A is also the offset into the expansion header of...
9647 cmp ax, #0x0000 ;; the Bootstrap Entry Vector, or zero if there is none.
9648 je no_bev
9650 ;; Found a device that thinks it can boot the system. Record its BEV.
9651 mov bx, #IPL_SEG ;; Go to the segment where the IPL table lives
9652 mov ds, bx
9653 mov bx, IPL_COUNT_OFFSET ;; Read the number of entries so far
9654 cmp bx, #IPL_TABLE_ENTRIES
9655 je no_bev ;; Get out if the table is full
9656 shl bx, #0x4 ;; Turn count into offset (entries are 16 bytes)
9657 mov 0[bx], #0x80 ;; This entry is a BEV device
9658 mov 6[bx], cx ;; Build a far pointer from the segment...
9659 mov 4[bx], ax ;; and the offset
9660 shr bx, #0x4 ;; Turn the offset back into a count
9661 inc bx ;; We have one more entry now
9662 mov IPL_COUNT_OFFSET, bx ;; Remember that.
9664 no_bev:
9665 pop di ;; Restore DI
9666 pop ax ;; Restore AX
9667 rom_scan_increment:
9668 shl ax, #5 ;; convert 512-bytes blocks to 16-byte increments
9669 ;; because the segment selector is shifted left 4 bits.
9670 add cx, ax
9671 cmp cx, #0xe000
9672 jbe rom_scan_loop
9674 xor ax, ax ;; Restore DS back to 0000:
9675 mov ds, ax
9676 ret
9678 #ifdef HVMASSIST
9680 ; Copy the SMBIOS entry point from where hvmloader left it.
9681 ; The entry point must be somewhere in 0xf0000-0xfffff on a 16-byte boundary,
9682 ; but the tables themselves can be elsewhere.
9683 smbios_init:
9684 push ax
9685 push cx
9686 push es
9687 push ds
9688 push di
9689 push si
9691 mov cx, #0x001f ; 0x1f bytes to copy
9692 mov ax, #0xf000
9693 mov es, ax ; destination segment is 0xf0000
9694 mov di, #smbios_entry_point ; destination offset
9695 mov ax, #(SMBIOS_PHYSICAL_ADDRESS>>4)
9696 mov ds, ax
9697 mov si, #(SMBIOS_PHYSICAL_ADDRESS&15)
9698 cld
9699 rep
9700 movsb
9702 pop si
9703 pop di
9704 pop ds
9705 pop es
9706 pop cx
9707 pop ax
9709 ret
9711 #endif
9715 ;; for 'C' strings and other data, insert them here with
9716 ;; a the following hack:
9717 ;; DATA_SEG_DEFS_HERE
9720 ;--------
9721 ;- POST -
9722 ;--------
9723 .org 0xe05b ; POST Entry Point
9724 post:
9726 xor ax, ax
9728 ;; first reset the DMA controllers
9729 out 0x0d,al
9730 out 0xda,al
9732 ;; then initialize the DMA controllers
9733 mov al, #0xC0
9734 out 0xD6, al ; cascade mode of channel 4 enabled
9735 mov al, #0x00
9736 out 0xD4, al ; unmask channel 4
9738 ;; Examine CMOS shutdown status.
9739 mov AL, #0x0f
9740 out 0x70, AL
9741 in AL, 0x71
9743 ;; backup status
9744 mov bl, al
9746 ;; Reset CMOS shutdown status.
9747 mov AL, #0x0f
9748 out 0x70, AL ; select CMOS register Fh
9749 mov AL, #0x00
9750 out 0x71, AL ; set shutdown action to normal
9752 ;; Examine CMOS shutdown status.
9753 mov al, bl
9755 ;; 0x00, 0x09, 0x0D+ = normal startup
9756 cmp AL, #0x00
9757 jz normal_post
9758 cmp AL, #0x0d
9759 jae normal_post
9760 cmp AL, #0x09
9761 je normal_post
9763 ;; 0x05 = eoi + jmp via [0x40:0x67] jump
9764 cmp al, #0x05
9765 je eoi_jmp_post
9767 ;; Examine CMOS shutdown status.
9768 ;; 0x01,0x02,0x03,0x04,0x06,0x07,0x08, 0x0a, 0x0b, 0x0c = Unimplemented shutdown status.
9769 push bx
9770 call _shutdown_status_panic
9772 #if 0
9773 HALT(__LINE__)
9775 ;#if 0
9776 ; 0xb0, 0x20, /* mov al, #0x20 */
9777 ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */
9778 ;#endif
9780 pop es
9781 pop ds
9782 popa
9783 iret
9784 #endif
9786 normal_post:
9787 ; case 0: normal startup
9789 cli
9790 mov ax, #0xfffe
9791 mov sp, ax
9792 mov ax, #0x0000
9793 mov ds, ax
9794 mov ss, ax
9796 ;; zero out BIOS data area (40:00..40:ff)
9797 mov es, ax
9798 mov cx, #0x0080 ;; 128 words
9799 mov di, #0x0400
9800 cld
9801 rep
9802 stosw
9804 call _log_bios_start
9806 call _clobber_entry_point
9808 ;; set all interrupts to default handler
9809 mov bx, #0x0000 ;; offset index
9810 mov cx, #0x0100 ;; counter (256 interrupts)
9811 mov ax, #dummy_iret_handler
9812 mov dx, #0xF000
9814 post_default_ints:
9815 mov [bx], ax
9816 inc bx
9817 inc bx
9818 mov [bx], dx
9819 inc bx
9820 inc bx
9821 loop post_default_ints
9823 ;; set vector 0x79 to zero
9824 ;; this is used by 'gardian angel' protection system
9825 SET_INT_VECTOR(0x79, #0, #0)
9827 ;; base memory in K 40:13 (word)
9828 mov ax, #BASE_MEM_IN_K
9829 mov 0x0413, ax
9832 ;; Manufacturing Test 40:12
9833 ;; zerod out above
9835 ;; Warm Boot Flag 0040:0072
9836 ;; value of 1234h = skip memory checks
9837 ;; zerod out above
9840 ;; Printer Services vector
9841 SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
9843 ;; Bootstrap failure vector
9844 SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
9846 ;; Bootstrap Loader vector
9847 SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
9849 ;; User Timer Tick vector
9850 SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
9852 ;; Memory Size Check vector
9853 SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
9855 ;; Equipment Configuration Check vector
9856 SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
9858 ;; System Services
9859 SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
9861 ;; EBDA setup
9862 call ebda_post
9864 ;; PIT setup
9865 SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
9866 ;; int 1C already points at dummy_iret_handler (above)
9867 mov al, #0x34 ; timer0: binary count, 16bit count, mode 2
9868 out 0x43, al
9869 #ifdef HVMASSIST
9870 mov al, #0x0b ; #0xe90b = 20 Hz (temporary, until we fix xen/vmx support)
9871 out 0x40, al ; lsb
9872 mov al, #0xe9
9873 out 0x40, al ; msb
9874 #else
9875 mov al, #0x00 ; maximum count of 0000H = 18.2Hz
9876 out 0x40, al
9877 out 0x40, al
9878 #endif
9880 ;; Keyboard
9881 SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
9882 SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
9884 xor ax, ax
9885 mov ds, ax
9886 mov 0x0417, al /* keyboard shift flags, set 1 */
9887 mov 0x0418, al /* keyboard shift flags, set 2 */
9888 mov 0x0419, al /* keyboard alt-numpad work area */
9889 mov 0x0471, al /* keyboard ctrl-break flag */
9890 mov 0x0497, al /* keyboard status flags 4 */
9891 mov al, #0x10
9892 mov 0x0496, al /* keyboard status flags 3 */
9895 /* keyboard head of buffer pointer */
9896 mov bx, #0x001E
9897 mov 0x041A, bx
9899 /* keyboard end of buffer pointer */
9900 mov 0x041C, bx
9902 /* keyboard pointer to start of buffer */
9903 mov bx, #0x001E
9904 mov 0x0480, bx
9906 /* keyboard pointer to end of buffer */
9907 mov bx, #0x003E
9908 mov 0x0482, bx
9910 /* init the keyboard */
9911 call _keyboard_init
9913 ;; mov CMOS Equipment Byte to BDA Equipment Word
9914 mov ax, 0x0410
9915 mov al, #0x14
9916 out 0x70, al
9917 in al, 0x71
9918 mov 0x0410, ax
9920 #if BX_TCGBIOS
9921 call _tcpa_acpi_init
9923 push dword #0
9924 call _tcpa_initialize_tpm
9925 add sp, #4
9927 call _tcpa_do_measure_POSTs
9928 call _tcpa_wake_event /* specs: 3.2.3.7 */
9929 #endif
9931 ;; Parallel setup
9932 SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
9933 xor ax, ax
9934 mov ds, ax
9935 xor bx, bx
9936 mov cl, #0x14 ; timeout value
9937 mov dx, #0x378 ; Parallel I/O address, port 1
9938 call detect_parport
9939 mov dx, #0x278 ; Parallel I/O address, port 2
9940 call detect_parport
9941 shl bx, #0x0e
9942 mov ax, 0x410 ; Equipment word bits 14..15 determing # parallel ports
9943 and ax, #0x3fff
9944 or ax, bx ; set number of parallel ports
9945 mov 0x410, ax
9947 ;; Serial setup
9948 SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
9949 SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
9950 xor bx, bx
9951 mov cl, #0x0a ; timeout value
9952 mov dx, #0x03f8 ; Serial I/O address, port 1
9953 call detect_serial
9954 mov dx, #0x02f8 ; Serial I/O address, port 2
9955 call detect_serial
9956 mov dx, #0x03e8 ; Serial I/O address, port 3
9957 call detect_serial
9958 mov dx, #0x02e8 ; Serial I/O address, port 4
9959 call detect_serial
9960 shl bx, #0x09
9961 mov ax, 0x410 ; Equipment word bits 9..11 determing # serial ports
9962 and ax, #0xf1ff
9963 or ax, bx ; set number of serial port
9964 mov 0x410, ax
9966 ;; CMOS RTC
9967 SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
9968 SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
9969 SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
9970 ;; BIOS DATA AREA 0x4CE ???
9971 call timer_tick_post
9973 ;; PS/2 mouse setup
9974 SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
9976 ;; IRQ13 (FPU exception) setup
9977 SET_INT_VECTOR(0x75, #0xF000, #int75_handler)
9979 ;; Video setup
9980 SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
9982 ;; PIC
9983 mov al, #0x11 ; send initialisation commands
9984 out 0x20, al
9985 out 0xa0, al
9986 mov al, #0x08
9987 out 0x21, al
9988 mov al, #0x70
9989 out 0xa1, al
9990 mov al, #0x04
9991 out 0x21, al
9992 mov al, #0x02
9993 out 0xa1, al
9994 mov al, #0x01
9995 out 0x21, al
9996 out 0xa1, al
9997 mov al, #0xb8
9998 out 0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6
9999 #if BX_USE_PS2_MOUSE
10000 mov al, #0x8f
10001 #else
10002 mov al, #0x9f
10003 #endif
10004 out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14
10006 #ifdef HVMASSIST
10007 call _copy_e820_table
10008 call smbios_init
10009 #endif
10011 call _init_boot_vectors
10013 call rom_scan
10015 call _print_bios_banner
10017 ;;
10018 ;; Floppy setup
10019 ;;
10020 call floppy_drive_post
10022 #if BX_USE_ATADRV
10024 ;;
10025 ;; Hard Drive setup
10026 ;;
10027 call hard_drive_post
10029 ;;
10030 ;; ATA/ATAPI driver setup
10031 ;;
10032 call _ata_init
10033 call _ata_detect
10034 ;;
10035 #else // BX_USE_ATADRV
10037 ;;
10038 ;; Hard Drive setup
10039 ;;
10040 call hard_drive_post
10042 #endif // BX_USE_ATADRV
10044 #if BX_ELTORITO_BOOT
10045 ;;
10046 ;; eltorito floppy/harddisk emulation from cd
10047 ;;
10048 call _cdemu_init
10049 ;;
10050 #endif // BX_ELTORITO_BOOT
10052 call _interactive_bootkey
10054 #if BX_TCGBIOS
10055 call _tcpa_calling_int19h /* specs: 8.2.3 step 1 */
10056 call _tcpa_add_event_separators /* specs: 8.2.3 step 2 */
10057 /* we do not call int 19h handler but keep following eventlog */
10058 call _tcpa_returned_int19h /* specs: 8.2.3 step 3/7 */
10059 #endif
10061 ;; Start the boot sequence. See the comments in int19_relocated
10062 ;; for why we use INT 18h instead of INT 19h here.
10063 int #0x18
10065 .org 0xe2c3 ; NMI Handler Entry Point
10066 nmi:
10067 ;; FIXME the NMI handler should not panic
10068 ;; but iret when called from int75 (fpu exception)
10069 call _nmi_handler_msg
10070 iret
10072 int75_handler:
10073 out 0xf0, al // clear irq13
10074 call eoi_both_pics // clear interrupt
10075 int 2 // legacy nmi call
10076 iret
10078 ;-------------------------------------------
10079 ;- INT 13h Fixed Disk Services Entry Point -
10080 ;-------------------------------------------
10081 .org 0xe3fe ; INT 13h Fixed Disk Services Entry Point
10082 int13_handler:
10083 //JMPL(int13_relocated)
10084 jmp int13_relocated
10086 .org 0xe401 ; Fixed Disk Parameter Table
10088 ;----------
10089 ;- INT19h -
10090 ;----------
10091 .org 0xe6f2 ; INT 19h Boot Load Service Entry Point
10092 int19_handler:
10094 jmp int19_relocated
10095 ;-------------------------------------------
10096 ;- System BIOS Configuration Data Table
10097 ;-------------------------------------------
10098 .org BIOS_CONFIG_TABLE
10099 db 0x08 ; Table size (bytes) -Lo
10100 db 0x00 ; Table size (bytes) -Hi
10101 db SYS_MODEL_ID
10102 db SYS_SUBMODEL_ID
10103 db BIOS_REVISION
10104 ; Feature byte 1
10105 ; b7: 1=DMA channel 3 used by hard disk
10106 ; b6: 1=2 interrupt controllers present
10107 ; b5: 1=RTC present
10108 ; b4: 1=BIOS calls int 15h/4Fh every key
10109 ; b3: 1=wait for extern event supported (Int 15h/41h)
10110 ; b2: 1=extended BIOS data area used
10111 ; b1: 0=AT or ESDI bus, 1=MicroChannel
10112 ; b0: 1=Dual bus (MicroChannel + ISA)
10113 db (0 << 7) | \
10114 (1 << 6) | \
10115 (1 << 5) | \
10116 (BX_CALL_INT15_4F << 4) | \
10117 (0 << 3) | \
10118 (BX_USE_EBDA << 2) | \
10119 (0 << 1) | \
10120 (0 << 0)
10121 ; Feature byte 2
10122 ; b7: 1=32-bit DMA supported
10123 ; b6: 1=int16h, function 9 supported
10124 ; b5: 1=int15h/C6h (get POS data) supported
10125 ; b4: 1=int15h/C7h (get mem map info) supported
10126 ; b3: 1=int15h/C8h (en/dis CPU) supported
10127 ; b2: 1=non-8042 kb controller
10128 ; b1: 1=data streaming supported
10129 ; b0: reserved
10130 db (0 << 7) | \
10131 (1 << 6) | \
10132 (0 << 5) | \
10133 (0 << 4) | \
10134 (0 << 3) | \
10135 (0 << 2) | \
10136 (0 << 1) | \
10137 (0 << 0)
10138 ; Feature byte 3
10139 ; b7: not used
10140 ; b6: reserved
10141 ; b5: reserved
10142 ; b4: POST supports ROM-to-RAM enable/disable
10143 ; b3: SCSI on system board
10144 ; b2: info panel installed
10145 ; b1: Initial Machine Load (IML) system - BIOS on disk
10146 ; b0: SCSI supported in IML
10147 db 0x00
10148 ; Feature byte 4
10149 ; b7: IBM private
10150 ; b6: EEPROM present
10151 ; b5-3: ABIOS presence (011 = not supported)
10152 ; b2: private
10153 ; b1: memory split above 16Mb supported
10154 ; b0: POSTEXT directly supported by POST
10155 db 0x00
10156 ; Feature byte 5 (IBM)
10157 ; b1: enhanced mouse
10158 ; b0: flash EPROM
10159 db 0x00
10163 .org 0xe729 ; Baud Rate Generator Table
10165 ;----------
10166 ;- INT14h -
10167 ;----------
10168 .org 0xe739 ; INT 14h Serial Communications Service Entry Point
10169 int14_handler:
10170 push ds
10171 pusha
10172 mov ax, #0x0000
10173 mov ds, ax
10174 call _int14_function
10175 popa
10176 pop ds
10177 iret
10180 ;----------------------------------------
10181 ;- INT 16h Keyboard Service Entry Point -
10182 ;----------------------------------------
10183 .org 0xe82e
10184 int16_handler:
10186 sti
10187 push ds
10188 pushf
10189 pusha
10191 cmp ah, #0x00
10192 je int16_F00
10193 cmp ah, #0x10
10194 je int16_F00
10196 mov bx, #0xf000