debuggers.hg

view tools/firmware/rombios/rombios.c @ 17939:3edc443ae8ce

hvm rombios: Move function calls out of 'post' function section

Through recent additions to the rombios the code section of the post
function has filled up considerably. When I enable the BX_TCGBIOS
compile time option the BIOS crashes since the post section code
(starts at $e05b) spills over into the nmi entry point (starts at
$e2c3). as86 doesn't cause an error when building.

Signed-off-by: Stefan Berger <stefanb@us.ibm.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Jun 27 14:43:29 2008 +0100 (2008-06-27)
parents fe60bf79d96f
children b41e07aa555a
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);
1847 #define CMOS_SHUTDOWN_S3 0xFE
1848 //--------------------------------------------------------------------------
1849 // machine_reset
1850 //--------------------------------------------------------------------------
1851 void
1852 machine_reset()
1854 ASM_START
1855 ;we must check whether CMOS_SHUTDOWN_S3 is set or not
1856 ;if it is s3 resume, just jmp back to normal Post Entry
1857 ;below port io will prevent s3 resume
1858 mov al, #0x0f
1859 out 0x70, al
1860 in al, 0x71
1861 cmp al, #0xFE
1862 jz post
1863 ASM_END
1864 /* Frob the keyboard reset line to reset the processor */
1865 outb(0x64, 0x60); /* Map the flags register at data port (0x60) */
1866 outb(0x60, 0x14); /* Set the flags to system|disable */
1867 outb(0x64, 0xfe); /* Pulse output 0 (system reset) low */
1868 BX_PANIC("Couldn't reset the machine\n");
1871 //--------------------------------------------------------------------------
1872 // clobber_entry_point
1873 // Because PV drivers in HVM guests detach some of the emulated devices,
1874 // it is not safe to do a soft reboot by just dropping to real mode and
1875 // jumping at ffff:0000. -- the boot drives might have disappeared!
1876 // This rather foul function overwrites(!) the BIOS entry point
1877 // to point at machine-reset, which will cause the Xen tools to
1878 // rebuild the whole machine from scratch.
1879 //--------------------------------------------------------------------------
1880 void
1881 clobber_entry_point()
1883 /* The instruction at the entry point is one byte (0xea) for the
1884 * jump opcode, then two bytes of address, then two of segment.
1885 * Overwrite the address bytes.*/
1886 write_word(0xffff, 0x0001, machine_reset);
1890 //--------------------------------------------------------------------------
1891 // shutdown_status_panic
1892 // called when the shutdown statsu is not implemented, displays the status
1893 //--------------------------------------------------------------------------
1894 void
1895 shutdown_status_panic(status)
1896 Bit16u status;
1898 BX_PANIC("Unimplemented shutdown status: %02x\n",(Bit8u)status);
1901 //--------------------------------------------------------------------------
1902 // print_bios_banner
1903 // displays a the bios version
1904 //--------------------------------------------------------------------------
1905 void
1906 print_bios_banner()
1908 printf(BX_APPNAME" BIOS, %d cpu%s, ", BX_SMP_PROCESSORS, BX_SMP_PROCESSORS>1?"s":"");
1909 printf("%s %s\n", bios_cvs_version_string, bios_date_string);
1910 #if BX_TCGBIOS
1911 printf("TCG-enabled BIOS.\n");
1912 #endif
1913 printf("\n");
1917 //--------------------------------------------------------------------------
1918 // BIOS Boot Specification 1.0.1 compatibility
1919 //
1920 // Very basic support for the BIOS Boot Specification, which allows expansion
1921 // ROMs to register themselves as boot devices, instead of just stealing the
1922 // INT 19h boot vector.
1923 //
1924 // This is a hack: to do it properly requires a proper PnP BIOS and we aren't
1925 // one; we just lie to the option ROMs to make them behave correctly.
1926 // We also don't support letting option ROMs register as bootable disk
1927 // drives (BCVs), only as bootable devices (BEVs).
1928 //
1929 // http://www.phoenix.com/en/Customer+Services/White+Papers-Specs/pc+industry+specifications.htm
1930 //--------------------------------------------------------------------------
1932 /* 256 bytes at 0x9ff00 -- 0x9ffff is used for the IPL boot table. */
1933 #define IPL_SEG 0x9ff0
1934 #define IPL_TABLE_OFFSET 0x0000
1935 #define IPL_TABLE_ENTRIES 8
1936 #define IPL_COUNT_OFFSET 0x0080 /* u16: number of valid table entries */
1937 #define IPL_SEQUENCE_OFFSET 0x0082 /* u16: next boot device */
1939 struct ipl_entry {
1940 Bit16u type;
1941 Bit16u flags;
1942 Bit32u vector;
1943 Bit32u description;
1944 Bit32u reserved;
1945 };
1947 static void
1948 init_boot_vectors()
1950 struct ipl_entry e;
1951 Bit16u count = 0;
1952 Bit16u ss = get_SS();
1954 /* Clear out the IPL table. */
1955 memsetb(IPL_SEG, IPL_TABLE_OFFSET, 0, 0xff);
1957 /* Floppy drive */
1958 e.type = 1; e.flags = 0; e.vector = 0; e.description = 0; e.reserved = 0;
1959 memcpyb(IPL_SEG, IPL_TABLE_OFFSET + count * sizeof (e), ss, &e, sizeof (e));
1960 count++;
1962 /* First HDD */
1963 e.type = 2; e.flags = 0; e.vector = 0; e.description = 0; e.reserved = 0;
1964 memcpyb(IPL_SEG, IPL_TABLE_OFFSET + count * sizeof (e), ss, &e, sizeof (e));
1965 count++;
1967 #if BX_ELTORITO_BOOT
1968 /* CDROM */
1969 e.type = 3; e.flags = 0; e.vector = 0; e.description = 0; e.reserved = 0;
1970 memcpyb(IPL_SEG, IPL_TABLE_OFFSET + count * sizeof (e), ss, &e, sizeof (e));
1971 count++;
1972 #endif
1974 /* Remember how many devices we have */
1975 write_word(IPL_SEG, IPL_COUNT_OFFSET, count);
1976 /* Not tried booting anything yet */
1977 write_word(IPL_SEG, IPL_SEQUENCE_OFFSET, 0xffff);
1980 static Bit8u
1981 get_boot_vector(i, e)
1982 Bit16u i; struct ipl_entry *e;
1984 Bit16u count;
1985 Bit16u ss = get_SS();
1986 /* Get the count of boot devices, and refuse to overrun the array */
1987 count = read_word(IPL_SEG, IPL_COUNT_OFFSET);
1988 if (i >= count) return 0;
1989 /* OK to read this device */
1990 memcpyb(ss, e, IPL_SEG, IPL_TABLE_OFFSET + i * sizeof (*e), sizeof (*e));
1991 return 1;
1995 //--------------------------------------------------------------------------
1996 // print_boot_device
1997 // displays the boot device
1998 //--------------------------------------------------------------------------
2000 static char drivetypes[][10]={"", "Floppy","Hard Disk","CD-Rom", "Network"};
2002 void
2003 print_boot_device(type)
2004 Bit16u type;
2006 /* NIC appears as type 0x80 */
2007 if (type == 0x80 ) type = 0x4;
2008 if (type == 0 || type > 0x4) BX_PANIC("Bad drive type\n");
2009 printf("Booting from %s...\n", drivetypes[type]);
2012 //--------------------------------------------------------------------------
2013 // print_boot_failure
2014 // displays the reason why boot failed
2015 //--------------------------------------------------------------------------
2016 void
2017 print_boot_failure(type, reason)
2018 Bit16u type; Bit8u reason;
2020 if (type == 0 || type > 0x3) BX_PANIC("Bad drive type\n");
2022 printf("Boot from %s failed", drivetypes[type]);
2023 if (type < 4) {
2024 /* Report the reason too */
2025 if (reason==0)
2026 printf(": not a bootable disk");
2027 else
2028 printf(": could not read the boot disk");
2030 printf("\n");
2033 //--------------------------------------------------------------------------
2034 // print_cdromboot_failure
2035 // displays the reason why boot failed
2036 //--------------------------------------------------------------------------
2037 void
2038 print_cdromboot_failure( code )
2039 Bit16u code;
2041 bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "CDROM boot failure code : %04x\n",code);
2043 return;
2046 #define WAIT_HZ 18
2047 /**
2048 * Check for keystroke.
2049 * @returns True if keystroke available, False if not.
2050 */
2051 Bit8u check_for_keystroke()
2053 ASM_START
2054 mov ax, #0x100
2055 int #0x16
2056 jz no_key
2057 mov al, #1
2058 jmp done
2059 no_key:
2060 xor al, al
2061 done:
2062 ASM_END
2065 /**
2066 * Get keystroke.
2067 * @returns BIOS scan code.
2068 */
2069 Bit8u get_keystroke()
2071 ASM_START
2072 mov ax, #0x0
2073 int #0x16
2074 xchg ah, al
2075 ASM_END
2078 /**
2079 * Waits (sleeps) for the given number of ticks.
2080 * Checks for keystroke.
2082 * @returns BIOS scan code if available, 0 if not.
2083 * @param ticks Number of ticks to sleep.
2084 * @param stop_on_key Whether to stop immediately upon keypress.
2085 */
2086 Bit8u wait(ticks, stop_on_key)
2087 Bit16u ticks;
2088 Bit8u stop_on_key;
2090 long ticks_to_wait, delta;
2091 Bit32u prev_ticks, t;
2092 Bit8u scan_code = 0;
2094 /*
2095 * The 0:046c wraps around at 'midnight' according to a 18.2Hz clock.
2096 * We also have to be careful about interrupt storms.
2097 */
2098 ticks_to_wait = ticks;
2099 prev_ticks = read_dword(0x0, 0x46c);
2100 do
2102 t = read_dword(0x0, 0x46c);
2103 if (t > prev_ticks)
2105 delta = t - prev_ticks; /* The temp var is required or bcc screws up. */
2106 ticks_to_wait -= delta;
2108 else if (t < prev_ticks)
2109 ticks_to_wait -= t; /* wrapped */
2110 prev_ticks = t;
2112 if (check_for_keystroke())
2114 scan_code = get_keystroke();
2115 bios_printf(BIOS_PRINTF_DEBUG, "Key pressed: %x\n", scan_code);
2116 if (stop_on_key)
2117 return scan_code;
2119 } while (ticks_to_wait > 0);
2120 return scan_code;
2123 static void clearscreen() {
2124 /* Hide cursor, clear screen and move cursor to starting position */
2125 ASM_START
2126 push bx
2127 push cx
2128 push dx
2130 mov ax, #0x100
2131 mov cx, #0x1000
2132 int #0x10
2134 mov ax, #0x700
2135 mov bh, #7
2136 xor cx, cx
2137 mov dx, #0x184f
2138 int #0x10
2140 mov ax, #0x200
2141 xor bx, bx
2142 xor dx, dx
2143 int #0x10
2145 pop dx
2146 pop cx
2147 pop bx
2148 ASM_END
2151 int bootmenu(selected)
2152 int selected;
2154 Bit8u scode;
2155 int max;
2157 /* get the number of boot devices */
2158 max = read_word(IPL_SEG, IPL_COUNT_OFFSET);
2160 for(;;) {
2161 if (selected > max || selected < 1) selected = 1;
2162 clearscreen();
2163 bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "\n\n\n\n\n\n\n");
2164 bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, " Select boot device\n\n");
2165 bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, " 1. Floppy\n");
2166 bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, " 2. Hard drive\n");
2167 bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, " 3. CD-ROM\n");
2168 if (max == 4)
2169 bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, " 4. Network\n");
2170 bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "\n\n Currently selected: %d\n", selected);
2172 do {
2173 scode = wait(WAIT_HZ, 1);
2174 } while (scode == 0);
2175 switch(scode) {
2176 case 0x02:
2177 case 0x03:
2178 case 0x04:
2179 selected = scode - 1;
2180 break;
2181 case 0x05:
2182 if (max == 4)
2183 selected = scode -1 ;
2184 else
2185 scode = 0;
2186 break;
2187 case 0x48:
2188 selected -= 1;
2189 if (selected < 1)
2190 selected = 1;
2191 scode = 0;
2192 break;
2193 case 0x50:
2194 selected += 1;
2195 if (selected > max)
2196 selected = max;
2197 scode = 0;
2198 break;
2199 case 0x1c:
2200 break;
2201 default:
2202 scode = 0;
2203 break;
2205 if (scode != 0)
2206 break;
2209 switch (selected) {
2210 case 1:
2211 return 0x3D;
2212 case 2:
2213 return 0x3E;
2214 case 3:
2215 return 0x3F;
2216 case 4:
2217 return 0x58;
2218 default:
2219 return 0;
2223 void interactive_bootkey()
2225 Bit16u i;
2226 Bit8u scan = 0;
2228 bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO,
2229 "\n\nPress F10 to select boot device.\n");
2231 scan = wait(1, 0);
2232 if (scan == 0x44)
2233 scan = bootmenu(inb_cmos(0x3d) & 0x0f);
2235 /* set the default based on the keypress or menu */
2236 switch(scan) {
2237 case 0x3D:
2238 outb_cmos(0x3d, 0x01);
2239 break;
2240 case 0x3E:
2241 outb_cmos(0x3d, 0x02);
2242 break;
2243 case 0x3F:
2244 outb_cmos(0x3d, 0x03);
2245 break;
2246 case 0x58:
2247 outb_cmos(0x3d, 0x04);
2248 break;
2249 default:
2250 break;
2255 void
2256 nmi_handler_msg()
2258 BX_PANIC("NMI Handler called\n");
2261 void
2262 int18_panic_msg()
2264 BX_PANIC("INT18: BOOT FAILURE\n");
2267 void
2268 log_bios_start()
2270 #if BX_DEBUG_SERIAL
2271 outb(BX_DEBUG_PORT+UART_LCR, 0x03); /* setup for serial logging: 8N1 */
2272 #endif
2273 BX_INFO("%s\n", bios_version_string);
2276 bx_bool
2277 set_enable_a20(val)
2278 bx_bool val;
2280 Bit8u oldval;
2282 // Use PS2 System Control port A to set A20 enable
2284 // get current setting first
2285 oldval = inb(0x92);
2287 // change A20 status
2288 if (val)
2289 outb(0x92, oldval | 0x02);
2290 else
2291 outb(0x92, oldval & 0xfd);
2293 return((oldval & 0x02) != 0);
2296 void
2297 debugger_on()
2299 outb(0xfedc, 0x01);
2302 void
2303 debugger_off()
2305 outb(0xfedc, 0x00);
2308 /* according to memory layout defined in acpi_build_tables(),
2309 acpi FACS table is located in ACPI_PHYSICAL_ADDRESS(0xEA000) */
2310 #define ACPI_FACS_ADDRESS 0xEA000
2311 #define ACPI_FACS_OFFSET 0x10
2312 /* S3 resume status in CMOS 0Fh shutdown status byte*/
2314 Bit32u facs_get32(offs)
2315 Bit16u offs;
2317 ASM_START
2318 push bp
2319 mov bp, sp
2321 push ds
2322 mov ax, #(ACPI_FACS_ADDRESS >> 4)
2323 mov ds, ax
2325 mov bx, 4[bp]
2326 mov ax, [bx]
2327 mov dx, 2[bx]
2328 pop ds
2330 pop bp
2331 ASM_END
2335 void
2336 s3_resume()
2338 Bit32u s3_wakeup_vector;
2339 extern Bit16u s3_wakeup_ip;
2340 extern Bit16u s3_wakeup_cs;
2341 extern Bit8u s3_resume_flag;
2343 ASM_START
2344 push ds
2345 mov ax, #0xF000
2346 mov ds, ax
2347 ASM_END
2349 if (s3_resume_flag!=CMOS_SHUTDOWN_S3){
2350 goto s3_out;
2352 s3_resume_flag = 0;
2354 /* get x_firmware_waking_vector */
2355 s3_wakeup_vector = facs_get32(ACPI_FACS_OFFSET+24);
2356 if (!s3_wakeup_vector) {
2357 /* get firmware_waking_vector */
2358 s3_wakeup_vector = facs_get32(ACPI_FACS_OFFSET+12);
2359 if (!s3_wakeup_vector) {
2360 goto s3_out;
2364 /* setup wakeup vector */
2365 s3_wakeup_ip = s3_wakeup_vector & 0xF;
2366 s3_wakeup_cs = s3_wakeup_vector >> 4;
2368 ASM_START
2369 jmpf [_s3_wakeup_ip]
2371 ; S3 data
2372 _s3_wakeup_ip: dw 0x0a
2373 _s3_wakeup_cs: dw 0x0
2374 _s3_resume_flag: db 0 ; set at POST time by CMOS[0xF] shutdown status
2375 ASM_END
2377 s3_out:
2378 ASM_START
2379 pop ds
2380 ASM_END
2383 #if BX_USE_ATADRV
2385 // ---------------------------------------------------------------------------
2386 // Start of ATA/ATAPI Driver
2387 // ---------------------------------------------------------------------------
2389 // Global defines -- ATA register and register bits.
2390 // command block & control block regs
2391 #define ATA_CB_DATA 0 // data reg in/out pio_base_addr1+0
2392 #define ATA_CB_ERR 1 // error in pio_base_addr1+1
2393 #define ATA_CB_FR 1 // feature reg out pio_base_addr1+1
2394 #define ATA_CB_SC 2 // sector count in/out pio_base_addr1+2
2395 #define ATA_CB_SN 3 // sector number in/out pio_base_addr1+3
2396 #define ATA_CB_CL 4 // cylinder low in/out pio_base_addr1+4
2397 #define ATA_CB_CH 5 // cylinder high in/out pio_base_addr1+5
2398 #define ATA_CB_DH 6 // device head in/out pio_base_addr1+6
2399 #define ATA_CB_STAT 7 // primary status in pio_base_addr1+7
2400 #define ATA_CB_CMD 7 // command out pio_base_addr1+7
2401 #define ATA_CB_ASTAT 6 // alternate status in pio_base_addr2+6
2402 #define ATA_CB_DC 6 // device control out pio_base_addr2+6
2403 #define ATA_CB_DA 7 // device address in pio_base_addr2+7
2405 #define ATA_CB_ER_ICRC 0x80 // ATA Ultra DMA bad CRC
2406 #define ATA_CB_ER_BBK 0x80 // ATA bad block
2407 #define ATA_CB_ER_UNC 0x40 // ATA uncorrected error
2408 #define ATA_CB_ER_MC 0x20 // ATA media change
2409 #define ATA_CB_ER_IDNF 0x10 // ATA id not found
2410 #define ATA_CB_ER_MCR 0x08 // ATA media change request
2411 #define ATA_CB_ER_ABRT 0x04 // ATA command aborted
2412 #define ATA_CB_ER_NTK0 0x02 // ATA track 0 not found
2413 #define ATA_CB_ER_NDAM 0x01 // ATA address mark not found
2415 #define ATA_CB_ER_P_SNSKEY 0xf0 // ATAPI sense key (mask)
2416 #define ATA_CB_ER_P_MCR 0x08 // ATAPI Media Change Request
2417 #define ATA_CB_ER_P_ABRT 0x04 // ATAPI command abort
2418 #define ATA_CB_ER_P_EOM 0x02 // ATAPI End of Media
2419 #define ATA_CB_ER_P_ILI 0x01 // ATAPI Illegal Length Indication
2421 // ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC)
2422 #define ATA_CB_SC_P_TAG 0xf8 // ATAPI tag (mask)
2423 #define ATA_CB_SC_P_REL 0x04 // ATAPI release
2424 #define ATA_CB_SC_P_IO 0x02 // ATAPI I/O
2425 #define ATA_CB_SC_P_CD 0x01 // ATAPI C/D
2427 // bits 7-4 of the device/head (CB_DH) reg
2428 #define ATA_CB_DH_DEV0 0xa0 // select device 0
2429 #define ATA_CB_DH_DEV1 0xb0 // select device 1
2431 // status reg (CB_STAT and CB_ASTAT) bits
2432 #define ATA_CB_STAT_BSY 0x80 // busy
2433 #define ATA_CB_STAT_RDY 0x40 // ready
2434 #define ATA_CB_STAT_DF 0x20 // device fault
2435 #define ATA_CB_STAT_WFT 0x20 // write fault (old name)
2436 #define ATA_CB_STAT_SKC 0x10 // seek complete
2437 #define ATA_CB_STAT_SERV 0x10 // service
2438 #define ATA_CB_STAT_DRQ 0x08 // data request
2439 #define ATA_CB_STAT_CORR 0x04 // corrected
2440 #define ATA_CB_STAT_IDX 0x02 // index
2441 #define ATA_CB_STAT_ERR 0x01 // error (ATA)
2442 #define ATA_CB_STAT_CHK 0x01 // check (ATAPI)
2444 // device control reg (CB_DC) bits
2445 #define ATA_CB_DC_HD15 0x08 // bit should always be set to one
2446 #define ATA_CB_DC_SRST 0x04 // soft reset
2447 #define ATA_CB_DC_NIEN 0x02 // disable interrupts
2449 // Most mandtory and optional ATA commands (from ATA-3),
2450 #define ATA_CMD_CFA_ERASE_SECTORS 0xC0
2451 #define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03
2452 #define ATA_CMD_CFA_TRANSLATE_SECTOR 0x87
2453 #define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD
2454 #define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38
2455 #define ATA_CMD_CHECK_POWER_MODE1 0xE5
2456 #define ATA_CMD_CHECK_POWER_MODE2 0x98
2457 #define ATA_CMD_DEVICE_RESET 0x08
2458 #define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90
2459 #define ATA_CMD_FLUSH_CACHE 0xE7
2460 #define ATA_CMD_FORMAT_TRACK 0x50
2461 #define ATA_CMD_IDENTIFY_DEVICE 0xEC
2462 #define ATA_CMD_IDENTIFY_DEVICE_PACKET 0xA1
2463 #define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xA1
2464 #define ATA_CMD_IDLE1 0xE3
2465 #define ATA_CMD_IDLE2 0x97
2466 #define ATA_CMD_IDLE_IMMEDIATE1 0xE1
2467 #define ATA_CMD_IDLE_IMMEDIATE2 0x95
2468 #define ATA_CMD_INITIALIZE_DRIVE_PARAMETERS 0x91
2469 #define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
2470 #define ATA_CMD_NOP 0x00
2471 #define ATA_CMD_PACKET 0xA0
2472 #define ATA_CMD_READ_BUFFER 0xE4
2473 #define ATA_CMD_READ_DMA 0xC8
2474 #define ATA_CMD_READ_DMA_QUEUED 0xC7
2475 #define ATA_CMD_READ_MULTIPLE 0xC4
2476 #define ATA_CMD_READ_SECTORS 0x20
2477 #define ATA_CMD_READ_VERIFY_SECTORS 0x40
2478 #define ATA_CMD_RECALIBRATE 0x10
2479 #define ATA_CMD_SEEK 0x70
2480 #define ATA_CMD_SET_FEATURES 0xEF
2481 #define ATA_CMD_SET_MULTIPLE_MODE 0xC6
2482 #define ATA_CMD_SLEEP1 0xE6
2483 #define ATA_CMD_SLEEP2 0x99
2484 #define ATA_CMD_STANDBY1 0xE2
2485 #define ATA_CMD_STANDBY2 0x96
2486 #define ATA_CMD_STANDBY_IMMEDIATE1 0xE0
2487 #define ATA_CMD_STANDBY_IMMEDIATE2 0x94
2488 #define ATA_CMD_WRITE_BUFFER 0xE8
2489 #define ATA_CMD_WRITE_DMA 0xCA
2490 #define ATA_CMD_WRITE_DMA_QUEUED 0xCC
2491 #define ATA_CMD_WRITE_MULTIPLE 0xC5
2492 #define ATA_CMD_WRITE_SECTORS 0x30
2493 #define ATA_CMD_WRITE_VERIFY 0x3C
2495 #define ATA_IFACE_NONE 0x00
2496 #define ATA_IFACE_ISA 0x00
2497 #define ATA_IFACE_PCI 0x01
2499 #define ATA_TYPE_NONE 0x00
2500 #define ATA_TYPE_UNKNOWN 0x01
2501 #define ATA_TYPE_ATA 0x02
2502 #define ATA_TYPE_ATAPI 0x03
2504 #define ATA_DEVICE_NONE 0x00
2505 #define ATA_DEVICE_HD 0xFF
2506 #define ATA_DEVICE_CDROM 0x05
2508 #define ATA_MODE_NONE 0x00
2509 #define ATA_MODE_PIO16 0x00
2510 #define ATA_MODE_PIO32 0x01
2511 #define ATA_MODE_ISADMA 0x02
2512 #define ATA_MODE_PCIDMA 0x03
2513 #define ATA_MODE_USEIRQ 0x10
2515 #define ATA_TRANSLATION_NONE 0
2516 #define ATA_TRANSLATION_LBA 1
2517 #define ATA_TRANSLATION_LARGE 2
2518 #define ATA_TRANSLATION_RECHS 3
2520 #define ATA_DATA_NO 0x00
2521 #define ATA_DATA_IN 0x01
2522 #define ATA_DATA_OUT 0x02
2524 // ---------------------------------------------------------------------------
2525 // ATA/ATAPI driver : initialization
2526 // ---------------------------------------------------------------------------
2527 void ata_init( )
2529 Bit16u ebda_seg=read_word(0x0040,0x000E);
2530 Bit8u channel, device;
2532 // Channels info init.
2533 for (channel=0; channel<BX_MAX_ATA_INTERFACES; channel++) {
2534 write_byte(ebda_seg,&EbdaData->ata.channels[channel].iface,ATA_IFACE_NONE);
2535 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1,0x0);
2536 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2,0x0);
2537 write_byte(ebda_seg,&EbdaData->ata.channels[channel].irq,0);
2540 // Devices info init.
2541 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2542 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
2543 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_NONE);
2544 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable,0);
2545 write_byte(ebda_seg,&EbdaData->ata.devices[device].lock,0);
2546 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode,ATA_MODE_NONE);
2547 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,0);
2548 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation,ATA_TRANSLATION_NONE);
2549 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads,0);
2550 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders,0);
2551 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt,0);
2552 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads,0);
2553 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders,0);
2554 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt,0);
2556 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors,0L);
2559 // hdidmap and cdidmap init.
2560 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2561 write_byte(ebda_seg,&EbdaData->ata.hdidmap[device],BX_MAX_ATA_DEVICES);
2562 write_byte(ebda_seg,&EbdaData->ata.cdidmap[device],BX_MAX_ATA_DEVICES);
2565 write_byte(ebda_seg,&EbdaData->ata.hdcount,0);
2566 write_byte(ebda_seg,&EbdaData->ata.cdcount,0);
2569 // ---------------------------------------------------------------------------
2570 // ATA/ATAPI driver : device detection
2571 // ---------------------------------------------------------------------------
2573 void ata_detect( )
2575 Bit16u ebda_seg=read_word(0x0040,0x000E);
2576 Bit8u hdcount, cdcount, device, type;
2577 Bit8u buffer[0x0200];
2579 #if BX_MAX_ATA_INTERFACES > 0
2580 write_byte(ebda_seg,&EbdaData->ata.channels[0].iface,ATA_IFACE_ISA);
2581 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase1,0x1f0);
2582 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase2,0x3f0);
2583 write_byte(ebda_seg,&EbdaData->ata.channels[0].irq,14);
2584 #endif
2585 #if BX_MAX_ATA_INTERFACES > 1
2586 write_byte(ebda_seg,&EbdaData->ata.channels[1].iface,ATA_IFACE_ISA);
2587 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase1,0x170);
2588 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase2,0x370);
2589 write_byte(ebda_seg,&EbdaData->ata.channels[1].irq,15);
2590 #endif
2591 #if BX_MAX_ATA_INTERFACES > 2
2592 write_byte(ebda_seg,&EbdaData->ata.channels[2].iface,ATA_IFACE_ISA);
2593 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase1,0x1e8);
2594 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase2,0x3e0);
2595 write_byte(ebda_seg,&EbdaData->ata.channels[2].irq,12);
2596 #endif
2597 #if BX_MAX_ATA_INTERFACES > 3
2598 write_byte(ebda_seg,&EbdaData->ata.channels[3].iface,ATA_IFACE_ISA);
2599 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase1,0x168);
2600 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase2,0x360);
2601 write_byte(ebda_seg,&EbdaData->ata.channels[3].irq,11);
2602 #endif
2603 #if BX_MAX_ATA_INTERFACES > 4
2604 #error Please fill the ATA interface informations
2605 #endif
2607 // Device detection
2608 hdcount=cdcount=0;
2610 for(device=0; device<BX_MAX_ATA_DEVICES; device++) {
2611 Bit16u iobase1, iobase2;
2612 Bit8u channel, slave, shift;
2613 Bit8u sc, sn, cl, ch, st;
2615 channel = device / 2;
2616 slave = device % 2;
2618 iobase1 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1);
2619 iobase2 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2);
2621 // Disable interrupts
2622 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2624 // Look for device
2625 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2626 outb(iobase1+ATA_CB_SC, 0x55);
2627 outb(iobase1+ATA_CB_SN, 0xaa);
2628 outb(iobase1+ATA_CB_SC, 0xaa);
2629 outb(iobase1+ATA_CB_SN, 0x55);
2630 outb(iobase1+ATA_CB_SC, 0x55);
2631 outb(iobase1+ATA_CB_SN, 0xaa);
2633 // If we found something
2634 sc = inb(iobase1+ATA_CB_SC);
2635 sn = inb(iobase1+ATA_CB_SN);
2637 if ( (sc == 0x55) && (sn == 0xaa) ) {
2638 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_UNKNOWN);
2640 // reset the channel
2641 ata_reset (device);
2643 // check for ATA or ATAPI
2644 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2645 sc = inb(iobase1+ATA_CB_SC);
2646 sn = inb(iobase1+ATA_CB_SN);
2647 if ( (sc==0x01) && (sn==0x01) ) {
2648 cl = inb(iobase1+ATA_CB_CL);
2649 ch = inb(iobase1+ATA_CB_CH);
2650 st = inb(iobase1+ATA_CB_STAT);
2652 if ( (cl==0x14) && (ch==0xeb) ) {
2653 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATAPI);
2655 else if ( (cl==0x00) && (ch==0x00) && (st!=0x00) ) {
2656 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATA);
2661 type=read_byte(ebda_seg,&EbdaData->ata.devices[device].type);
2663 // Now we send a IDENTIFY command to ATA device
2664 if(type == ATA_TYPE_ATA) {
2665 Bit32u sectors;
2666 Bit16u cylinders, heads, spt, blksize;
2667 Bit8u translation, removable, mode;
2669 // default mode to PIO16
2670 mode = ATA_MODE_PIO16;
2672 //Temporary values to do the transfer
2673 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2674 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2676 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE, 1, 0, 0, 0, 0L, get_SS(),buffer) !=0 )
2677 BX_PANIC("ata-detect: Failed to detect ATA device\n");
2679 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2680 #ifndef NO_PIO32
2681 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2682 #endif
2684 blksize = read_word(get_SS(),buffer+10);
2686 cylinders = read_word(get_SS(),buffer+(1*2)); // word 1
2687 heads = read_word(get_SS(),buffer+(3*2)); // word 3
2688 spt = read_word(get_SS(),buffer+(6*2)); // word 6
2690 sectors = read_dword(get_SS(),buffer+(60*2)); // word 60 and word 61
2692 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2693 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2694 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2695 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2696 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads, heads);
2697 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders, cylinders);
2698 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt, spt);
2699 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors, sectors);
2700 BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel, slave,cylinders, heads, spt);
2702 translation = inb_cmos(0x39 + channel/2);
2703 for (shift=device%4; shift>0; shift--) translation >>= 2;
2704 translation &= 0x03;
2706 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation, translation);
2708 switch (translation) {
2709 case ATA_TRANSLATION_NONE:
2710 BX_INFO("none");
2711 break;
2712 case ATA_TRANSLATION_LBA:
2713 BX_INFO("lba");
2714 break;
2715 case ATA_TRANSLATION_LARGE:
2716 BX_INFO("large");
2717 break;
2718 case ATA_TRANSLATION_RECHS:
2719 BX_INFO("r-echs");
2720 break;
2722 switch (translation) {
2723 case ATA_TRANSLATION_NONE:
2724 break;
2725 case ATA_TRANSLATION_LBA:
2726 spt = 63;
2727 sectors /= 63;
2728 heads = sectors / 1024;
2729 if (heads>128) heads = 255;
2730 else if (heads>64) heads = 128;
2731 else if (heads>32) heads = 64;
2732 else if (heads>16) heads = 32;
2733 else heads=16;
2734 cylinders = sectors / heads;
2735 break;
2736 case ATA_TRANSLATION_RECHS:
2737 // Take care not to overflow
2738 if (heads==16) {
2739 if(cylinders>61439) cylinders=61439;
2740 heads=15;
2741 cylinders = (Bit16u)((Bit32u)(cylinders)*16/15);
2743 // then go through the large bitshift process
2744 case ATA_TRANSLATION_LARGE:
2745 while(cylinders > 1024) {
2746 cylinders >>= 1;
2747 heads <<= 1;
2749 // If we max out the head count
2750 if (heads > 127) break;
2752 break;
2754 // clip to 1024 cylinders in lchs
2755 if (cylinders > 1024) cylinders=1024;
2756 BX_INFO(" LCHS=%d/%d/%d\n", cylinders, heads, spt);
2758 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, heads);
2759 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, cylinders);
2760 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, spt);
2762 // fill hdidmap
2763 write_byte(ebda_seg,&EbdaData->ata.hdidmap[hdcount], device);
2764 hdcount++;
2767 // Now we send a IDENTIFY command to ATAPI device
2768 if(type == ATA_TYPE_ATAPI) {
2770 Bit8u type, removable, mode;
2771 Bit16u blksize;
2773 // default mode to PIO16
2774 mode = ATA_MODE_PIO16;
2776 //Temporary values to do the transfer
2777 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_CDROM);
2778 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2780 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE_PACKET, 1, 0, 0, 0, 0L, get_SS(),buffer) != 0)
2781 BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
2783 type = read_byte(get_SS(),buffer+1) & 0x1f;
2784 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2785 #ifndef NO_PIO32
2786 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2787 #endif
2788 blksize = 2048;
2790 write_byte(ebda_seg,&EbdaData->ata.devices[device].device, type);
2791 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2792 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2793 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2795 // fill cdidmap
2796 write_byte(ebda_seg,&EbdaData->ata.cdidmap[cdcount], device);
2797 cdcount++;
2801 Bit32u sizeinmb;
2802 Bit16u ataversion;
2803 Bit8u c, i, version, model[41];
2805 switch (type) {
2806 case ATA_TYPE_ATA:
2807 sizeinmb = read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors);
2808 sizeinmb >>= 11;
2809 case ATA_TYPE_ATAPI:
2810 // Read ATA/ATAPI version
2811 ataversion=((Bit16u)(read_byte(get_SS(),buffer+161))<<8)|read_byte(get_SS(),buffer+160);
2812 for(version=15;version>0;version--) {
2813 if((ataversion&(1<<version))!=0)
2814 break;
2817 // Read model name
2818 for(i=0;i<20;i++){
2819 write_byte(get_SS(),model+(i*2),read_byte(get_SS(),buffer+(i*2)+54+1));
2820 write_byte(get_SS(),model+(i*2)+1,read_byte(get_SS(),buffer+(i*2)+54));
2823 // Reformat
2824 write_byte(get_SS(),model+40,0x00);
2825 for(i=39;i>0;i--){
2826 if(read_byte(get_SS(),model+i)==0x20)
2827 write_byte(get_SS(),model+i,0x00);
2828 else break;
2830 break;
2833 switch (type) {
2834 case ATA_TYPE_ATA:
2835 printf("ata%d %s: ",channel,slave?" slave":"master");
2836 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2837 if (sizeinmb < 1UL<<16)
2838 printf(" ATA-%d Hard-Disk (%04u MBytes)\n",version,(Bit16u)sizeinmb);
2839 else
2840 printf(" ATA-%d Hard-Disk (%04u GBytes)\n",version,(Bit16u)(sizeinmb>>10));
2841 break;
2842 case ATA_TYPE_ATAPI:
2843 printf("ata%d %s: ",channel,slave?" slave":"master");
2844 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2845 if(read_byte(ebda_seg,&EbdaData->ata.devices[device].device)==ATA_DEVICE_CDROM)
2846 printf(" ATAPI-%d CD-Rom/DVD-Rom\n",version);
2847 else
2848 printf(" ATAPI-%d Device\n",version);
2849 break;
2850 case ATA_TYPE_UNKNOWN:
2851 printf("ata%d %s: Unknown device\n",channel,slave?" slave":"master");
2852 break;
2857 // Store the devices counts
2858 write_byte(ebda_seg,&EbdaData->ata.hdcount, hdcount);
2859 write_byte(ebda_seg,&EbdaData->ata.cdcount, cdcount);
2860 write_byte(0x40,0x75, hdcount);
2862 printf("\n");
2864 // FIXME : should use bios=cmos|auto|disable bits
2865 // FIXME : should know about translation bits
2866 // FIXME : move hard_drive_post here
2870 // ---------------------------------------------------------------------------
2871 // ATA/ATAPI driver : software reset
2872 // ---------------------------------------------------------------------------
2873 // ATA-3
2874 // 8.2.1 Software reset - Device 0
2876 void ata_reset(device)
2877 Bit16u device;
2879 Bit16u ebda_seg=read_word(0x0040,0x000E);
2880 Bit16u iobase1, iobase2;
2881 Bit8u channel, slave, sn, sc;
2882 Bit16u max;
2884 channel = device / 2;
2885 slave = device % 2;
2887 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2888 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2890 // Reset
2892 // 8.2.1 (a) -- set SRST in DC
2893 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN | ATA_CB_DC_SRST);
2895 // 8.2.1 (b) -- wait for BSY
2896 max=0xff;
2897 while(--max>0) {
2898 Bit8u status = inb(iobase1+ATA_CB_STAT);
2899 if ((status & ATA_CB_STAT_BSY) != 0) break;
2902 // 8.2.1 (f) -- clear SRST
2903 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2905 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_NONE) {
2907 // 8.2.1 (g) -- check for sc==sn==0x01
2908 // select device
2909 outb(iobase1+ATA_CB_DH, slave?ATA_CB_DH_DEV1:ATA_CB_DH_DEV0);
2910 sc = inb(iobase1+ATA_CB_SC);
2911 sn = inb(iobase1+ATA_CB_SN);
2913 if ( (sc==0x01) && (sn==0x01) ) {
2915 // 8.2.1 (h) -- wait for not BSY
2916 max=0xff;
2917 while(--max>0) {
2918 Bit8u status = inb(iobase1+ATA_CB_STAT);
2919 if ((status & ATA_CB_STAT_BSY) == 0) break;
2924 // 8.2.1 (i) -- wait for DRDY
2925 max=0xfff;
2926 while(--max>0) {
2927 Bit8u status = inb(iobase1+ATA_CB_STAT);
2928 if ((status & ATA_CB_STAT_RDY) != 0) break;
2931 // Enable interrupts
2932 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2935 // ---------------------------------------------------------------------------
2936 // ATA/ATAPI driver : execute a non data command
2937 // ---------------------------------------------------------------------------
2939 Bit16u ata_cmd_non_data()
2940 {return 0;}
2942 // ---------------------------------------------------------------------------
2943 // ATA/ATAPI driver : execute a data-in command
2944 // ---------------------------------------------------------------------------
2945 // returns
2946 // 0 : no error
2947 // 1 : BUSY bit set
2948 // 2 : read error
2949 // 3 : expected DRQ=1
2950 // 4 : no sectors left to read/verify
2951 // 5 : more sectors to read/verify
2952 // 6 : no sectors left to write
2953 // 7 : more sectors to write
2954 Bit16u ata_cmd_data_in(device, command, count, cylinder, head, sector, lba, segment, offset)
2955 Bit16u device, command, count, cylinder, head, sector, segment, offset;
2956 Bit32u lba;
2958 Bit16u ebda_seg=read_word(0x0040,0x000E);
2959 Bit16u iobase1, iobase2, blksize;
2960 Bit8u channel, slave;
2961 Bit8u status, current, mode;
2963 channel = device / 2;
2964 slave = device % 2;
2966 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2967 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2968 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2969 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2970 if (mode == ATA_MODE_PIO32) blksize>>=2;
2971 else blksize>>=1;
2973 // Reset count of transferred data
2974 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2975 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2976 current = 0;
2978 status = inb(iobase1 + ATA_CB_STAT);
2979 if (status & ATA_CB_STAT_BSY) return 1;
2981 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2983 // sector will be 0 only on lba access. Convert to lba-chs
2984 if (sector == 0) {
2985 if ((count >= 1 << 8) || (lba + count >= 1UL << 28)) {
2986 outb(iobase1 + ATA_CB_FR, 0x00);
2987 outb(iobase1 + ATA_CB_SC, (count >> 8) & 0xff);
2988 outb(iobase1 + ATA_CB_SN, lba >> 24);
2989 outb(iobase1 + ATA_CB_CL, 0);
2990 outb(iobase1 + ATA_CB_CH, 0);
2991 command |= 0x04;
2992 count &= (1UL << 8) - 1;
2993 lba &= (1UL << 24) - 1;
2995 sector = (Bit16u) (lba & 0x000000ffL);
2996 lba >>= 8;
2997 cylinder = (Bit16u) (lba & 0x0000ffffL);
2998 lba >>= 16;
2999 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
3002 outb(iobase1 + ATA_CB_FR, 0x00);
3003 outb(iobase1 + ATA_CB_SC, count);
3004 outb(iobase1 + ATA_CB_SN, sector);
3005 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
3006 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
3007 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
3008 outb(iobase1 + ATA_CB_CMD, command);
3010 while (1) {
3011 status = inb(iobase1 + ATA_CB_STAT);
3012 if ( !(status & ATA_CB_STAT_BSY) ) break;
3015 if (status & ATA_CB_STAT_ERR) {
3016 BX_DEBUG_ATA("ata_cmd_data_in : read error\n");
3017 return 2;
3018 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
3019 BX_DEBUG_ATA("ata_cmd_data_in : DRQ not set (status %02x)\n", (unsigned) status);
3020 return 3;
3023 // FIXME : move seg/off translation here
3025 ASM_START
3026 sti ;; enable higher priority interrupts
3027 ASM_END
3029 while (1) {
3031 ASM_START
3032 push bp
3033 mov bp, sp
3034 mov di, _ata_cmd_data_in.offset + 2[bp]
3035 mov ax, _ata_cmd_data_in.segment + 2[bp]
3036 mov cx, _ata_cmd_data_in.blksize + 2[bp]
3038 ;; adjust if there will be an overrun. 2K max sector size
3039 cmp di, #0xf800 ;;
3040 jbe ata_in_no_adjust
3042 ata_in_adjust:
3043 sub di, #0x0800 ;; sub 2 kbytes from offset
3044 add ax, #0x0080 ;; add 2 Kbytes to segment
3046 ata_in_no_adjust:
3047 mov es, ax ;; segment in es
3049 mov dx, _ata_cmd_data_in.iobase1 + 2[bp] ;; ATA data read port
3051 mov ah, _ata_cmd_data_in.mode + 2[bp]
3052 cmp ah, #ATA_MODE_PIO32
3053 je ata_in_32
3055 ata_in_16:
3056 rep
3057 insw ;; CX words transfered from port(DX) to ES:[DI]
3058 jmp ata_in_done
3060 ata_in_32:
3061 rep
3062 insd ;; CX dwords transfered from port(DX) to ES:[DI]
3064 ata_in_done:
3065 mov _ata_cmd_data_in.offset + 2[bp], di
3066 mov _ata_cmd_data_in.segment + 2[bp], es
3067 pop bp
3068 ASM_END
3070 current++;
3071 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
3072 count--;
3073 status = inb(iobase1 + ATA_CB_STAT);
3074 if (count == 0) {
3075 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3076 != ATA_CB_STAT_RDY ) {
3077 BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n", (unsigned) status);
3078 return 4;
3080 break;
3082 else {
3083 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3084 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3085 BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n", (unsigned) status);
3086 return 5;
3088 continue;
3091 // Enable interrupts
3092 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3093 return 0;
3096 // ---------------------------------------------------------------------------
3097 // ATA/ATAPI driver : execute a data-out command
3098 // ---------------------------------------------------------------------------
3099 // returns
3100 // 0 : no error
3101 // 1 : BUSY bit set
3102 // 2 : read error
3103 // 3 : expected DRQ=1
3104 // 4 : no sectors left to read/verify
3105 // 5 : more sectors to read/verify
3106 // 6 : no sectors left to write
3107 // 7 : more sectors to write
3108 Bit16u ata_cmd_data_out(device, command, count, cylinder, head, sector, lba, segment, offset)
3109 Bit16u device, command, count, cylinder, head, sector, segment, offset;
3110 Bit32u lba;
3112 Bit16u ebda_seg=read_word(0x0040,0x000E);
3113 Bit16u iobase1, iobase2, blksize;
3114 Bit8u channel, slave;
3115 Bit8u status, current, mode;
3117 channel = device / 2;
3118 slave = device % 2;
3120 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
3121 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
3122 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
3123 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
3124 if (mode == ATA_MODE_PIO32) blksize>>=2;
3125 else blksize>>=1;
3127 // Reset count of transferred data
3128 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
3129 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
3130 current = 0;
3132 status = inb(iobase1 + ATA_CB_STAT);
3133 if (status & ATA_CB_STAT_BSY) return 1;
3135 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
3137 // sector will be 0 only on lba access. Convert to lba-chs
3138 if (sector == 0) {
3139 if ((count >= 1 << 8) || (lba + count >= 1UL << 28)) {
3140 outb(iobase1 + ATA_CB_FR, 0x00);
3141 outb(iobase1 + ATA_CB_SC, (count >> 8) & 0xff);
3142 outb(iobase1 + ATA_CB_SN, lba >> 24);
3143 outb(iobase1 + ATA_CB_CL, 0);
3144 outb(iobase1 + ATA_CB_CH, 0);
3145 command |= 0x04;
3146 count &= (1UL << 8) - 1;
3147 lba &= (1UL << 24) - 1;
3149 sector = (Bit16u) (lba & 0x000000ffL);
3150 lba >>= 8;
3151 cylinder = (Bit16u) (lba & 0x0000ffffL);
3152 lba >>= 16;
3153 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
3156 outb(iobase1 + ATA_CB_FR, 0x00);
3157 outb(iobase1 + ATA_CB_SC, count);
3158 outb(iobase1 + ATA_CB_SN, sector);
3159 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
3160 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
3161 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
3162 outb(iobase1 + ATA_CB_CMD, command);
3164 while (1) {
3165 status = inb(iobase1 + ATA_CB_STAT);
3166 if ( !(status & ATA_CB_STAT_BSY) ) break;
3169 if (status & ATA_CB_STAT_ERR) {
3170 BX_DEBUG_ATA("ata_cmd_data_out : read error\n");
3171 return 2;
3172 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
3173 BX_DEBUG_ATA("ata_cmd_data_out : DRQ not set (status %02x)\n", (unsigned) status);
3174 return 3;
3177 // FIXME : move seg/off translation here
3179 ASM_START
3180 sti ;; enable higher priority interrupts
3181 ASM_END
3183 while (1) {
3185 ASM_START
3186 push bp
3187 mov bp, sp
3188 mov si, _ata_cmd_data_out.offset + 2[bp]
3189 mov ax, _ata_cmd_data_out.segment + 2[bp]
3190 mov cx, _ata_cmd_data_out.blksize + 2[bp]
3192 ;; adjust if there will be an overrun. 2K max sector size
3193 cmp si, #0xf800 ;;
3194 jbe ata_out_no_adjust
3196 ata_out_adjust:
3197 sub si, #0x0800 ;; sub 2 kbytes from offset
3198 add ax, #0x0080 ;; add 2 Kbytes to segment
3200 ata_out_no_adjust:
3201 mov es, ax ;; segment in es
3203 mov dx, _ata_cmd_data_out.iobase1 + 2[bp] ;; ATA data write port
3205 mov ah, _ata_cmd_data_out.mode + 2[bp]
3206 cmp ah, #ATA_MODE_PIO32
3207 je ata_out_32
3209 ata_out_16:
3210 seg ES
3211 rep
3212 outsw ;; CX words transfered from port(DX) to ES:[SI]
3213 jmp ata_out_done
3215 ata_out_32:
3216 seg ES
3217 rep
3218 outsd ;; CX dwords transfered from port(DX) to ES:[SI]
3220 ata_out_done:
3221 mov _ata_cmd_data_out.offset + 2[bp], si
3222 mov _ata_cmd_data_out.segment + 2[bp], es
3223 pop bp
3224 ASM_END
3226 current++;
3227 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
3228 count--;
3229 status = inb(iobase1 + ATA_CB_STAT);
3230 if (count == 0) {
3231 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3232 != ATA_CB_STAT_RDY ) {
3233 BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n", (unsigned) status);
3234 return 6;
3236 break;
3238 else {
3239 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3240 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3241 BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n", (unsigned) status);
3242 return 7;
3244 continue;
3247 // Enable interrupts
3248 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3249 return 0;
3252 // ---------------------------------------------------------------------------
3253 // ATA/ATAPI driver : execute a packet command
3254 // ---------------------------------------------------------------------------
3255 // returns
3256 // 0 : no error
3257 // 1 : error in parameters
3258 // 2 : BUSY bit set
3259 // 3 : error
3260 // 4 : not ready
3261 Bit16u ata_cmd_packet(device, cmdlen, cmdseg, cmdoff, header, length, inout, bufseg, bufoff)
3262 Bit8u cmdlen,inout;
3263 Bit16u device,cmdseg, cmdoff, bufseg, bufoff;
3264 Bit16u header;
3265 Bit32u length;
3267 Bit16u ebda_seg=read_word(0x0040,0x000E);
3268 Bit16u iobase1, iobase2;
3269 Bit16u lcount, lbefore, lafter, count;
3270 Bit8u channel, slave;
3271 Bit8u status, mode, lmode;
3272 Bit32u total, transfer;
3274 channel = device / 2;
3275 slave = device % 2;
3277 // Data out is not supported yet
3278 if (inout == ATA_DATA_OUT) {
3279 BX_INFO("ata_cmd_packet: DATA_OUT not supported yet\n");
3280 return 1;
3283 // The header length must be even
3284 if (header & 1) {
3285 BX_DEBUG_ATA("ata_cmd_packet : header must be even (%04x)\n",header);
3286 return 1;
3289 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
3290 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
3291 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
3292 transfer= 0L;
3294 if (cmdlen < 12) cmdlen=12;
3295 if (cmdlen > 12) cmdlen=16;
3296 cmdlen>>=1;
3298 // Reset count of transferred data
3299 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
3300 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
3302 status = inb(iobase1 + ATA_CB_STAT);
3303 if (status & ATA_CB_STAT_BSY) return 2;
3305 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
3306 // outb(iobase1 + ATA_CB_FR, 0x00);
3307 // outb(iobase1 + ATA_CB_SC, 0x00);
3308 // outb(iobase1 + ATA_CB_SN, 0x00);
3309 outb(iobase1 + ATA_CB_CL, 0xfff0 & 0x00ff);
3310 outb(iobase1 + ATA_CB_CH, 0xfff0 >> 8);
3311 outb(iobase1 + ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
3312 outb(iobase1 + ATA_CB_CMD, ATA_CMD_PACKET);
3314 // Device should ok to receive command
3315 while (1) {
3316 status = inb(iobase1 + ATA_CB_STAT);
3317 if ( !(status & ATA_CB_STAT_BSY) ) break;
3320 if (status & ATA_CB_STAT_ERR) {
3321 BX_DEBUG_ATA("ata_cmd_packet : error, status is %02x\n",status);
3322 return 3;
3323 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
3324 BX_DEBUG_ATA("ata_cmd_packet : DRQ not set (status %02x)\n", (unsigned) status);
3325 return 4;
3328 // Normalize address
3329 cmdseg += (cmdoff / 16);
3330 cmdoff %= 16;
3332 // Send command to device
3333 ASM_START
3334 sti ;; enable higher priority interrupts
3336 push bp
3337 mov bp, sp
3339 mov si, _ata_cmd_packet.cmdoff + 2[bp]
3340 mov ax, _ata_cmd_packet.cmdseg + 2[bp]
3341 mov cx, _ata_cmd_packet.cmdlen + 2[bp]
3342 mov es, ax ;; segment in es
3344 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data write port
3346 seg ES
3347 rep
3348 outsw ;; CX words transfered from port(DX) to ES:[SI]
3350 pop bp
3351 ASM_END
3353 if (inout == ATA_DATA_NO) {
3354 status = inb(iobase1 + ATA_CB_STAT);
3356 else {
3357 while (1) {
3359 status = inb(iobase1 + ATA_CB_STAT);
3361 // Check if command completed
3362 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_DRQ) ) ==0 ) break;
3364 if (status & ATA_CB_STAT_ERR) {
3365 BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status);
3366 return 3;
3369 // Device must be ready to send data
3370 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3371 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3372 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", status);
3373 return 4;
3376 // Normalize address
3377 bufseg += (bufoff / 16);
3378 bufoff %= 16;
3380 // Get the byte count
3381 lcount = ((Bit16u)(inb(iobase1 + ATA_CB_CH))<<8)+inb(iobase1 + ATA_CB_CL);
3383 // adjust to read what we want
3384 if(header>lcount) {
3385 lbefore=lcount;
3386 header-=lcount;
3387 lcount=0;
3389 else {
3390 lbefore=header;
3391 header=0;
3392 lcount-=lbefore;
3395 if(lcount>length) {
3396 lafter=lcount-length;
3397 lcount=length;
3398 length=0;
3400 else {
3401 lafter=0;
3402 length-=lcount;
3405 // Save byte count
3406 count = lcount;
3408 BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore+lcount+lafter,lbefore,lcount,lafter);
3409 BX_DEBUG_ATA("to 0x%04x:0x%04x\n",bufseg,bufoff);
3411 // If counts not dividable by 4, use 16bits mode
3412 lmode = mode;
3413 if (lbefore & 0x03) lmode=ATA_MODE_PIO16;
3414 if (lcount & 0x03) lmode=ATA_MODE_PIO16;
3415 if (lafter & 0x03) lmode=ATA_MODE_PIO16;
3417 // adds an extra byte if count are odd. before is always even
3418 if (lcount & 0x01) {
3419 lcount+=1;
3420 if ((lafter > 0) && (lafter & 0x01)) {
3421 lafter-=1;
3425 if (lmode == ATA_MODE_PIO32) {
3426 lcount>>=2; lbefore>>=2; lafter>>=2;
3428 else {
3429 lcount>>=1; lbefore>>=1; lafter>>=1;
3432 ; // FIXME bcc bug
3434 ASM_START
3435 push bp
3436 mov bp, sp
3438 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data read port
3440 mov cx, _ata_cmd_packet.lbefore + 2[bp]
3441 jcxz ata_packet_no_before
3443 mov ah, _ata_cmd_packet.lmode + 2[bp]
3444 cmp ah, #ATA_MODE_PIO32
3445 je ata_packet_in_before_32
3447 ata_packet_in_before_16:
3448 in ax, dx
3449 loop ata_packet_in_before_16
3450 jmp ata_packet_no_before
3452 ata_packet_in_before_32:
3453 push eax
3454 ata_packet_in_before_32_loop:
3455 in eax, dx
3456 loop ata_packet_in_before_32_loop
3457 pop eax
3459 ata_packet_no_before:
3460 mov cx, _ata_cmd_packet.lcount + 2[bp]
3461 jcxz ata_packet_after
3463 mov di, _ata_cmd_packet.bufoff + 2[bp]
3464 mov ax, _ata_cmd_packet.bufseg + 2[bp]
3465 mov es, ax
3467 mov ah, _ata_cmd_packet.lmode + 2[bp]
3468 cmp ah, #ATA_MODE_PIO32
3469 je ata_packet_in_32
3471 ata_packet_in_16:
3472 rep
3473 insw ;; CX words transfered tp port(DX) to ES:[DI]
3474 jmp ata_packet_after
3476 ata_packet_in_32:
3477 rep
3478 insd ;; CX dwords transfered to port(DX) to ES:[DI]
3480 ata_packet_after:
3481 mov cx, _ata_cmd_packet.lafter + 2[bp]
3482 jcxz ata_packet_done
3484 mov ah, _ata_cmd_packet.lmode + 2[bp]
3485 cmp ah, #ATA_MODE_PIO32
3486 je ata_packet_in_after_32
3488 ata_packet_in_after_16:
3489 in ax, dx
3490 loop ata_packet_in_after_16
3491 jmp ata_packet_done
3493 ata_packet_in_after_32:
3494 push eax
3495 ata_packet_in_after_32_loop:
3496 in eax, dx
3497 loop ata_packet_in_after_32_loop
3498 pop eax
3500 ata_packet_done:
3501 pop bp
3502 ASM_END
3504 // Compute new buffer address
3505 bufoff += count;
3507 // Save transferred bytes count
3508 transfer += count;
3509 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,transfer);
3513 // Final check, device must be ready
3514 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3515 != ATA_CB_STAT_RDY ) {
3516 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", (unsigned) status);
3517 return 4;
3520 // Enable interrupts
3521 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3522 return 0;
3525 // ---------------------------------------------------------------------------
3526 // End of ATA/ATAPI Driver
3527 // ---------------------------------------------------------------------------
3529 // ---------------------------------------------------------------------------
3530 // Start of ATA/ATAPI generic functions
3531 // ---------------------------------------------------------------------------
3533 Bit16u
3534 atapi_get_sense(device)
3535 Bit16u device;
3537 Bit8u atacmd[12];
3538 Bit8u buffer[16];
3539 Bit8u i;
3541 memsetb(get_SS(),atacmd,0,12);
3543 // Request SENSE
3544 atacmd[0]=0x03;
3545 atacmd[4]=0x20;
3546 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 16L, ATA_DATA_IN, get_SS(), buffer) != 0)
3547 return 0x0002;
3549 if ((buffer[0] & 0x7e) == 0x70) {
3550 return (((Bit16u)buffer[2]&0x0f)*0x100)+buffer[12];
3553 return 0;
3556 Bit16u
3557 atapi_is_ready(device)
3558 Bit16u device;
3560 Bit8u atacmd[12];
3561 Bit8u buffer[];
3563 memsetb(get_SS(),atacmd,0,12);
3565 // Test Unit Ready
3566 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3567 return 0x000f;
3569 if (atapi_get_sense(device) !=0 ) {
3570 memsetb(get_SS(),atacmd,0,12);
3572 // try to send Test Unit Ready again
3573 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3574 return 0x000f;
3576 return atapi_get_sense(device);
3578 return 0;
3581 Bit16u
3582 atapi_is_cdrom(device)
3583 Bit8u device;
3585 Bit16u ebda_seg=read_word(0x0040,0x000E);
3587 if (device >= BX_MAX_ATA_DEVICES)
3588 return 0;
3590 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_ATAPI)
3591 return 0;
3593 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].device) != ATA_DEVICE_CDROM)
3594 return 0;
3596 return 1;
3599 // ---------------------------------------------------------------------------
3600 // End of ATA/ATAPI generic functions
3601 // ---------------------------------------------------------------------------
3603 #endif // BX_USE_ATADRV
3605 #if BX_ELTORITO_BOOT
3607 // ---------------------------------------------------------------------------
3608 // Start of El-Torito boot functions
3609 // ---------------------------------------------------------------------------
3611 void
3612 cdemu_init()
3614 Bit16u ebda_seg=read_word(0x0040,0x000E);
3616 // the only important data is this one for now
3617 write_byte(ebda_seg,&EbdaData->cdemu.active,0x00);
3620 Bit8u
3621 cdemu_isactive()
3623 Bit16u ebda_seg=read_word(0x0040,0x000E);
3625 return(read_byte(ebda_seg,&EbdaData->cdemu.active));
3628 Bit8u
3629 cdemu_emulated_drive()
3631 Bit16u ebda_seg=read_word(0x0040,0x000E);
3633 return(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
3636 static char isotag[6]="CD001";
3637 static char eltorito[24]="EL TORITO SPECIFICATION";
3638 //
3639 // Returns ah: emulated drive, al: error code
3640 //
3641 Bit16u
3642 cdrom_boot()
3644 Bit16u ebda_seg=read_word(0x0040,0x000E);
3645 Bit8u atacmd[12], buffer[2048];
3646 Bit32u lba;
3647 Bit16u boot_segment, nbsectors, i, error;
3648 Bit8u device;
3650 // Find out the first cdrom
3651 for (device=0; device<BX_MAX_ATA_DEVICES;device++) {
3652 if (atapi_is_cdrom(device)) break;
3655 // if not found
3656 if(device >= BX_MAX_ATA_DEVICES) return 2;
3658 // Read the Boot Record Volume Descriptor
3659 memsetb(get_SS(),atacmd,0,12);
3660 atacmd[0]=0x28; // READ command
3661 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3662 atacmd[8]=(0x01 & 0x00ff); // Sectors
3663 atacmd[2]=(0x11 & 0xff000000) >> 24; // LBA
3664 atacmd[3]=(0x11 & 0x00ff0000) >> 16;
3665 atacmd[4]=(0x11 & 0x0000ff00) >> 8;
3666 atacmd[5]=(0x11 & 0x000000ff);
3667 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3668 return 3;
3670 // Validity checks
3671 if(buffer[0]!=0)return 4;
3672 for(i=0;i<5;i++){
3673 if(buffer[1+i]!=read_byte(0xf000,&isotag[i]))return 5;
3675 for(i=0;i<23;i++)
3676 if(buffer[7+i]!=read_byte(0xf000,&eltorito[i]))return 6;
3678 // ok, now we calculate the Boot catalog address
3679 lba=buffer[0x4A]*0x1000000+buffer[0x49]*0x10000+buffer[0x48]*0x100+buffer[0x47];
3681 // And we read the Boot Catalog
3682 memsetb(get_SS(),atacmd,0,12);
3683 atacmd[0]=0x28; // READ command
3684 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3685 atacmd[8]=(0x01 & 0x00ff); // Sectors
3686 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3687 atacmd[3]=(lba & 0x00ff0000) >> 16;
3688 atacmd[4]=(lba & 0x0000ff00) >> 8;
3689 atacmd[5]=(lba & 0x000000ff);
3690 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3691 return 7;
3693 // Validation entry
3694 if(buffer[0x00]!=0x01)return 8; // Header
3695 if(buffer[0x01]!=0x00)return 9; // Platform
3696 if(buffer[0x1E]!=0x55)return 10; // key 1
3697 if(buffer[0x1F]!=0xAA)return 10; // key 2
3699 // Initial/Default Entry
3700 if(buffer[0x20]!=0x88)return 11; // Bootable
3702 #if BX_TCGBIOS
3703 /* specs: 8.2.3 step 5 and 8.2.5.6, measure El Torito boot catalog */
3704 /* measure 2048 bytes (one sector) */
3705 tcpa_add_bootdevice((Bit32u)1L, (Bit32u)0L); /* bootcd = 1 */
3706 tcpa_ipl((Bit32u)2L,(Bit32u)get_SS(),(Bit32u)buffer,(Bit32u)2048L);
3707 #endif
3709 write_byte(ebda_seg,&EbdaData->cdemu.media,buffer[0x21]);
3710 if(buffer[0x21]==0){
3711 // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
3712 // Win2000 cd boot needs to know it booted from cd
3713 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0xE0);
3715 else if(buffer[0x21]<4)
3716 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x00);
3717 else
3718 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x80);
3720 write_byte(ebda_seg,&EbdaData->cdemu.controller_index,device/2);
3721 write_byte(ebda_seg,&EbdaData->cdemu.device_spec,device%2);
3723 boot_segment=buffer[0x23]*0x100+buffer[0x22];
3724 if(boot_segment==0x0000)boot_segment=0x07C0;
3726 write_word(ebda_seg,&EbdaData->cdemu.load_segment,boot_segment);
3727 write_word(ebda_seg,&EbdaData->cdemu.buffer_segment,0x0000);
3729 nbsectors=buffer[0x27]*0x100+buffer[0x26];
3730 write_word(ebda_seg,&EbdaData->cdemu.sector_count,nbsectors);
3732 lba=buffer[0x2B]*0x1000000+buffer[0x2A]*0x10000+buffer[0x29]*0x100+buffer[0x28];
3733 write_dword(ebda_seg,&EbdaData->cdemu.ilba,lba);
3735 // And we read the image in memory
3736 memsetb(get_SS(),atacmd,0,12);
3737 atacmd[0]=0x28; // READ command
3738 atacmd[7]=((1+(nbsectors-1)/4) & 0xff00) >> 8; // Sectors
3739 atacmd[8]=((1+(nbsectors-1)/4) & 0x00ff); // Sectors
3740 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3741 atacmd[3]=(lba & 0x00ff0000) >> 16;
3742 atacmd[4]=(lba & 0x0000ff00) >> 8;
3743 atacmd[5]=(lba & 0x000000ff);
3744 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, nbsectors*512L, ATA_DATA_IN, boot_segment,0)) != 0)
3745 return 12;
3747 #if BX_TCGBIOS
3748 /* specs: 8.2.3 step 4 and 8.2.5.6, measure El Torito boot image */
3749 /* measure 1st 512 bytes */
3750 tcpa_ipl((Bit32u)1L,(Bit32u)boot_segment,(Bit32u)0L,(Bit32u)512L);
3751 #endif
3754 // Remember the media type
3755 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
3756 case 0x01: // 1.2M floppy
3757 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,15);
3758 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3759 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3760 break;
3761 case 0x02: // 1.44M floppy
3762 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,18);
3763 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3764 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3765 break;
3766 case 0x03: // 2.88M floppy
3767 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,36);
3768 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3769 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3770 break;
3771 case 0x04: // Harddrive
3772 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,read_byte(boot_segment,446+6)&0x3f);
3773 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,
3774 (read_byte(boot_segment,446+6)<<2) + read_byte(boot_segment,446+7) + 1);
3775 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,read_byte(boot_segment,446+5) + 1);
3776 break;
3779 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0) {
3780 // Increase bios installed hardware number of devices
3781 if(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)==0x00)
3782 write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
3783 else
3784 write_byte(ebda_seg, &EbdaData->ata.hdcount, read_byte(ebda_seg, &EbdaData->ata.hdcount) + 1);
3788 // everything is ok, so from now on, the emulation is active
3789 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0)
3790 write_byte(ebda_seg,&EbdaData->cdemu.active,0x01);
3792 // return the boot drive + no error
3793 return (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)*0x100)+0;
3796 // ---------------------------------------------------------------------------
3797 // End of El-Torito boot functions
3798 // ---------------------------------------------------------------------------
3799 #endif // BX_ELTORITO_BOOT
3801 void
3802 int14_function(regs, ds, iret_addr)
3803 pusha_regs_t regs; // regs pushed from PUSHA instruction
3804 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
3805 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
3807 Bit16u addr,timer,val16;
3808 Bit8u timeout;
3810 ASM_START
3811 sti
3812 ASM_END
3814 addr = read_word(0x0040, (regs.u.r16.dx << 1));
3815 timeout = read_byte(0x0040, 0x007C + regs.u.r16.dx);
3816 if ((regs.u.r16.dx < 4) && (addr > 0)) {
3817 switch (regs.u.r8.ah) {
3818 case 0:
3819 outb(addr+3, inb(addr+3) | 0x80);
3820 if (regs.u.r8.al & 0xE0 == 0) {
3821 outb(addr, 0x17);
3822 outb(addr+1, 0x04);
3823 } else {
3824 val16 = 0x600 >> ((regs.u.r8.al & 0xE0) >> 5);
3825 outb(addr, val16 & 0xFF);
3826 outb(addr+1, val16 >> 8);
3828 outb(addr+3, regs.u.r8.al & 0x1F);
3829 regs.u.r8.ah = inb(addr+5);
3830 regs.u.r8.al = inb(addr+6);
3831 ClearCF(iret_addr.flags);
3832 break;
3833 case 1:
3834 timer = read_word(0x0040, 0x006C);
3835 while (((inb(addr+5) & 0x60) != 0x60) && (timeout)) {
3836 val16 = read_word(0x0040, 0x006C);
3837 if (val16 != timer) {
3838 timer = val16;
3839 timeout--;
3842 if (timeout) outb(addr, regs.u.r8.al);
3843 regs.u.r8.ah = inb(addr+5);
3844 if (!timeout) regs.u.r8.ah |= 0x80;
3845 ClearCF(iret_addr.flags);
3846 break;
3847 case 2:
3848 timer = read_word(0x0040, 0x006C);
3849 while (((inb(addr+5) & 0x01) == 0) && (timeout)) {
3850 val16 = read_word(0x0040, 0x006C);
3851 if (val16 != timer) {
3852 timer = val16;
3853 timeout--;
3856 if (timeout) {
3857 regs.u.r8.ah = 0;
3858 regs.u.r8.al = inb(addr);
3859 } else {
3860 regs.u.r8.ah = inb(addr+5);
3862 ClearCF(iret_addr.flags);
3863 break;
3864 case 3:
3865 regs.u.r8.ah = inb(addr+5);
3866 regs.u.r8.al = inb(addr+6);
3867 ClearCF(iret_addr.flags);
3868 break;
3869 default:
3870 SetCF(iret_addr.flags); // Unsupported
3872 } else {
3873 SetCF(iret_addr.flags); // Unsupported
3877 void
3878 int15_function(regs, ES, DS, FLAGS)
3879 pusha_regs_t regs; // REGS pushed via pusha
3880 Bit16u ES, DS, FLAGS;
3882 Bit16u ebda_seg=read_word(0x0040,0x000E);
3883 bx_bool prev_a20_enable;
3884 Bit16u base15_00;
3885 Bit8u base23_16;
3886 Bit16u ss;
3887 Bit16u CX,DX;
3889 Bit16u bRegister;
3890 Bit8u irqDisable;
3892 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
3894 switch (regs.u.r8.ah) {
3895 case 0x24: /* A20 Control */
3896 switch (regs.u.r8.al) {
3897 case 0x00:
3898 set_enable_a20(0);
3899 CLEAR_CF();
3900 regs.u.r8.ah = 0;
3901 break;
3902 case 0x01:
3903 set_enable_a20(1);
3904 CLEAR_CF();
3905 regs.u.r8.ah = 0;
3906 break;
3907 case 0x02:
3908 regs.u.r8.al = (inb(0x92) >> 1) & 0x01;
3909 CLEAR_CF();
3910 regs.u.r8.ah = 0;
3911 break;
3912 case 0x03:
3913 CLEAR_CF();
3914 regs.u.r8.ah = 0;
3915 regs.u.r16.bx = 3;
3916 break;
3917 default:
3918 BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs.u.r8.al);
3919 SET_CF();
3920 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3922 break;
3924 case 0x41:
3925 SET_CF();
3926 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3927 break;
3929 case 0x4f:
3930 /* keyboard intercept */
3931 #if BX_CPU < 2
3932 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3933 #else
3934 // nop
3935 #endif
3936 SET_CF();
3937 break;
3939 case 0x52: // removable media eject
3940 CLEAR_CF();
3941 regs.u.r8.ah = 0; // "ok ejection may proceed"
3942 break;
3944 case 0x83: {
3945 if( regs.u.r8.al == 0 ) {
3946 // Set Interval requested.
3947 if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
3948 // Interval not already set.
3949 write_byte( 0x40, 0xA0, 1 ); // Set status byte.
3950 write_word( 0x40, 0x98, ES ); // Byte location, segment
3951 write_word( 0x40, 0x9A, regs.u.r16.bx ); // Byte location, offset
3952 write_word( 0x40, 0x9C, regs.u.r16.dx ); // Low word, delay
3953 write_word( 0x40, 0x9E, regs.u.r16.cx ); // High word, delay.
3954 CLEAR_CF( );
3955 irqDisable = inb( 0xA1 );
3956 outb( 0xA1, irqDisable & 0xFE );
3957 bRegister = inb_cmos( 0xB ); // Unmask IRQ8 so INT70 will get through.
3958 outb_cmos( 0xB, bRegister | 0x40 ); // Turn on the Periodic Interrupt timer
3959 } else {
3960 // Interval already set.
3961 BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
3962 SET_CF();
3963 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3965 } else if( regs.u.r8.al == 1 ) {
3966 // Clear Interval requested
3967 write_byte( 0x40, 0xA0, 0 ); // Clear status byte
3968 CLEAR_CF( );
3969 bRegister = inb_cmos( 0xB );
3970 outb_cmos( 0xB, bRegister & ~0x40 ); // Turn off the Periodic Interrupt timer
3971 } else {
3972 BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
3973 SET_CF();
3974 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3975 regs.u.r8.al--;
3978 break;
3981 case 0x87:
3982 #if BX_CPU < 3
3983 # error "Int15 function 87h not supported on < 80386"
3984 #endif
3985 // +++ should probably have descriptor checks
3986 // +++ should have exception handlers
3988 // turn off interrupts
3989 ASM_START
3990 cli
3991 ASM_END
3993 prev_a20_enable = set_enable_a20(1); // enable A20 line
3995 // 128K max of transfer on 386+ ???
3996 // source == destination ???
3998 // ES:SI points to descriptor table
3999 // offset use initially comments
4000 // ==============================================
4001 // 00..07 Unused zeros Null descriptor
4002 // 08..0f GDT zeros filled in by BIOS
4003 // 10..17 source ssssssss source of data
4004 // 18..1f dest dddddddd destination of data
4005 // 20..27 CS zeros filled in by BIOS
4006 // 28..2f SS zeros filled in by BIOS
4008 //es:si
4009 //eeee0
4010 //0ssss
4011 //-----
4013 // check for access rights of source & dest here
4015 // Initialize GDT descriptor
4016 base15_00 = (ES << 4) + regs.u.r16.si;
4017 base23_16 = ES >> 12;
4018 if (base15_00 < (ES<<4))
4019 base23_16++;
4020 write_word(ES, regs.u.r16.si+0x08+0, 47); // limit 15:00 = 6 * 8bytes/descriptor
4021 write_word(ES, regs.u.r16.si+0x08+2, base15_00);// base 15:00
4022 write_byte(ES, regs.u.r16.si+0x08+4, base23_16);// base 23:16
4023 write_byte(ES, regs.u.r16.si+0x08+5, 0x93); // access
4024 write_word(ES, regs.u.r16.si+0x08+6, 0x0000); // base 31:24/reserved/limit 19:16
4026 // Initialize CS descriptor
4027 write_word(ES, regs.u.r16.si+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
4028 write_word(ES, regs.u.r16.si+0x20+2, 0x0000);// base 15:00
4029 write_byte(ES, regs.u.r16.si+0x20+4, 0x000f);// base 23:16
4030 write_byte(ES, regs.u.r16.si+0x20+5, 0x9b); // access
4031 write_word(ES, regs.u.r16.si+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
4033 // Initialize SS descriptor
4034 ss = get_SS();
4035 base15_00 = ss << 4;
4036 base23_16 = ss >> 12;
4037 write_word(ES, regs.u.r16.si+0x28+0, 0xffff); // limit 15:00 = normal 64K limit
4038 write_word(ES, regs.u.r16.si+0x28+2, base15_00);// base 15:00
4039 write_byte(ES, regs.u.r16.si+0x28+4, base23_16);// base 23:16
4040 write_byte(ES, regs.u.r16.si+0x28+5, 0x93); // access
4041 write_word(ES, regs.u.r16.si+0x28+6, 0x0000); // base 31:24/reserved/limit 19:16
4043 CX = regs.u.r16.cx;
4044 ASM_START
4045 // Compile generates locals offset info relative to SP.
4046 // Get CX (word count) from stack.
4047 mov bx, sp
4048 SEG SS
4049 mov cx, _int15_function.CX [bx]
4051 // since we need to set SS:SP, save them to the BDA
4052 // for future restore
4053 push eax
4054 xor eax, eax
4055 mov ds, ax
4056 mov 0x0469, ss
4057 mov 0x0467, sp
4059 SEG ES
4060 lgdt [si + 0x08]
4061 SEG CS
4062 lidt [pmode_IDT_info]
4063 ;; perhaps do something with IDT here
4065 ;; set PE bit in CR0
4066 mov eax, cr0
4067 or al, #0x01
4068 mov cr0, eax
4069 ;; far jump to flush CPU queue after transition to protected mode
4070 JMP_AP(0x0020, protected_mode)
4072 protected_mode:
4073 ;; GDT points to valid descriptor table, now load SS, DS, ES
4074 mov ax, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
4075 mov ss, ax
4076 mov ax, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
4077 mov ds, ax
4078 mov ax, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
4079 mov es, ax
4080 xor si, si
4081 xor di, di
4082 cld
4083 rep
4084 movsw ;; move CX words from DS:SI to ES:DI
4086 ;; make sure DS and ES limits are 64KB
4087 mov ax, #0x28
4088 mov ds, ax
4089 mov es, ax
4091 ;; reset PG bit in CR0 ???
4092 mov eax, cr0
4093 and al, #0xFE
4094 mov cr0, eax
4096 ;; far jump to flush CPU queue after transition to real mode
4097 JMP_AP(0xf000, real_mode)
4099 real_mode:
4100 ;; restore IDT to normal real-mode defaults
4101 SEG CS
4102 lidt [rmode_IDT_info]
4104 // restore SS:SP from the BDA
4105 xor ax, ax
4106 mov ds, ax
4107 mov ss, 0x0469
4108 mov sp, 0x0467
4109 pop eax
4110 ASM_END
4112 set_enable_a20(prev_a20_enable);
4114 // turn back on interrupts
4115 ASM_START
4116 sti
4117 ASM_END
4119 regs.u.r8.ah = 0;
4120 CLEAR_CF();
4121 break;
4124 case 0x88:
4125 // Get the amount of extended memory (above 1M)
4126 #if BX_CPU < 2
4127 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4128 SET_CF();
4129 #else
4130 regs.u.r8.al = inb_cmos(0x30);
4131 regs.u.r8.ah = inb_cmos(0x31);
4133 // limit to 15M
4134 if(regs.u.r16.ax > 0x3c00)
4135 regs.u.r16.ax = 0x3c00;
4137 CLEAR_CF();
4138 #endif
4139 break;
4141 case 0x90:
4142 /* Device busy interrupt. Called by Int 16h when no key available */
4143 break;
4145 case 0x91:
4146 /* Interrupt complete. Called by Int 16h when key becomes available */
4147 break;
4149 case 0xbf:
4150 BX_INFO("*** int 15h function AH=bf not yet supported!\n");
4151 SET_CF();
4152 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4153 break;
4155 case 0xC0:
4156 #if 0
4157 SET_CF();
4158 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4159 break;
4160 #endif
4161 CLEAR_CF();
4162 regs.u.r8.ah = 0;
4163 regs.u.r16.bx = BIOS_CONFIG_TABLE;
4164 ES = 0xF000;
4165 break;
4167 case 0xc1:
4168 ES = ebda_seg;
4169 CLEAR_CF();
4170 break;
4172 case 0xd8:
4173 bios_printf(BIOS_PRINTF_DEBUG, "EISA BIOS not present\n");
4174 SET_CF();
4175 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4176 break;
4178 default:
4179 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4180 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4181 SET_CF();
4182 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4183 break;
4187 #if BX_USE_PS2_MOUSE
4188 void
4189 int15_function_mouse(regs, ES, DS, FLAGS)
4190 pusha_regs_t regs; // REGS pushed via pusha
4191 Bit16u ES, DS, FLAGS;
4193 Bit16u ebda_seg=read_word(0x0040,0x000E);
4194 Bit8u mouse_flags_1, mouse_flags_2;
4195 Bit16u mouse_driver_seg;
4196 Bit16u mouse_driver_offset;
4197 Bit8u comm_byte, prev_command_byte;
4198 Bit8u ret, mouse_data1, mouse_data2, mouse_data3;
4200 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4202 switch (regs.u.r8.ah) {
4203 case 0xC2:
4204 // Return Codes status in AH
4205 // =========================
4206 // 00: success
4207 // 01: invalid subfunction (AL > 7)
4208 // 02: invalid input value (out of allowable range)
4209 // 03: interface error
4210 // 04: resend command received from mouse controller,
4211 // device driver should attempt command again
4212 // 05: cannot enable mouse, since no far call has been installed
4213 // 80/86: mouse service not implemented
4215 switch (regs.u.r8.al) {
4216 case 0: // Disable/Enable Mouse
4217 BX_DEBUG_INT15("case 0:\n");
4218 switch (regs.u.r8.bh) {
4219 case 0: // Disable Mouse
4220 BX_DEBUG_INT15("case 0: disable mouse\n");
4221 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4222 ret = send_to_mouse_ctrl(0xF5); // disable mouse command
4223 if (ret == 0) {
4224 ret = get_mouse_data(&mouse_data1);
4225 if ( (ret == 0) || (mouse_data1 == 0xFA) ) {
4226 CLEAR_CF();
4227 regs.u.r8.ah = 0;
4228 return;
4232 // error
4233 SET_CF();
4234 regs.u.r8.ah = ret;
4235 return;
4236 break;
4238 case 1: // Enable Mouse
4239 BX_DEBUG_INT15("case 1: enable mouse\n");
4240 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4241 if ( (mouse_flags_2 & 0x80) == 0 ) {
4242 BX_DEBUG_INT15("INT 15h C2 Enable Mouse, no far call handler\n");
4243 SET_CF(); // error
4244 regs.u.r8.ah = 5; // no far call installed
4245 return;
4247 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4248 ret = send_to_mouse_ctrl(0xF4); // enable mouse command
4249 if (ret == 0) {
4250 ret = get_mouse_data(&mouse_data1);
4251 if ( (ret == 0) && (mouse_data1 == 0xFA) ) {
4252 enable_mouse_int_and_events(); // turn IRQ12 and packet generation on
4253 CLEAR_CF();
4254 regs.u.r8.ah = 0;
4255 return;
4258 SET_CF();
4259 regs.u.r8.ah = ret;
4260 return;
4262 default: // invalid subfunction
4263 BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs.u.r8.bh);
4264 SET_CF(); // error
4265 regs.u.r8.ah = 1; // invalid subfunction
4266 return;
4268 break;
4270 case 1: // Reset Mouse
4271 case 5: // Initialize Mouse
4272 BX_DEBUG_INT15("case 1 or 5:\n");
4273 if (regs.u.r8.al == 5) {
4274 if (regs.u.r8.bh != 3) {
4275 SET_CF();
4276 regs.u.r8.ah = 0x02; // invalid input
4277 return;
4279 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4280 mouse_flags_2 = (mouse_flags_2 & 0x00) | regs.u.r8.bh;
4281 mouse_flags_1 = 0x00;
4282 write_byte(ebda_seg, 0x0026, mouse_flags_1);
4283 write_byte(ebda_seg, 0x0027, mouse_flags_2);
4286 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4287 ret = send_to_mouse_ctrl(0xFF); // reset mouse command
4288 if (ret == 0) {
4289 ret = get_mouse_data(&mouse_data3);
4290 // if no mouse attached, it will return RESEND
4291 if (mouse_data3 == 0xfe) {
4292 SET_CF();
4293 return;
4295 if (mouse_data3 != 0xfa)
4296 BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3);
4297 if ( ret == 0 ) {
4298 ret = get_mouse_data(&mouse_data1);
4299 if ( ret == 0 ) {
4300 ret = get_mouse_data(&mouse_data2);
4301 if ( ret == 0 ) {
4302 // turn IRQ12 and packet generation on
4303 enable_mouse_int_and_events();
4304 CLEAR_CF();
4305 regs.u.r8.ah = 0;
4306 regs.u.r8.bl = mouse_data1;
4307 regs.u.r8.bh = mouse_data2;
4308 return;
4314 // error
4315 SET_CF();
4316 regs.u.r8.ah = ret;
4317 return;
4319 case 2: // Set Sample Rate
4320 BX_DEBUG_INT15("case 2:\n");
4321 switch (regs.u.r8.bh) {
4322 case 0: mouse_data1 = 10; break; // 10 reports/sec
4323 case 1: mouse_data1 = 20; break; // 20 reports/sec
4324 case 2: mouse_data1 = 40; break; // 40 reports/sec
4325 case 3: mouse_data1 = 60; break; // 60 reports/sec
4326 case 4: mouse_data1 = 80; break; // 80 reports/sec
4327 case 5: mouse_data1 = 100; break; // 100 reports/sec (default)
4328 case 6: mouse_data1 = 200; break; // 200 reports/sec
4329 default: mouse_data1 = 0;
4331 if (mouse_data1 > 0) {
4332 ret = send_to_mouse_ctrl(0xF3); // set sample rate command
4333 if (ret == 0) {
4334 ret = get_mouse_data(&mouse_data2);
4335 ret = send_to_mouse_ctrl(mouse_data1);
4336 ret = get_mouse_data(&mouse_data2);
4337 CLEAR_CF();
4338 regs.u.r8.ah = 0;
4339 } else {
4340 // error
4341 SET_CF();
4342 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4344 } else {
4345 // error
4346 SET_CF();
4347 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4349 break;
4351 case 3: // Set Resolution
4352 BX_DEBUG_INT15("case 3:\n");
4353 // BX:
4354 // 0 = 25 dpi, 1 count per millimeter
4355 // 1 = 50 dpi, 2 counts per millimeter
4356 // 2 = 100 dpi, 4 counts per millimeter
4357 // 3 = 200 dpi, 8 counts per millimeter
4358 CLEAR_CF();
4359 regs.u.r8.ah = 0;
4360 break;
4362 case 4: // Get Device ID
4363 BX_DEBUG_INT15("case 4:\n");
4364 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4365 ret = send_to_mouse_ctrl(0xF2); // get mouse ID command
4366 if (ret == 0) {
4367 ret = get_mouse_data(&mouse_data1);
4368 ret = get_mouse_data(&mouse_data2);
4369 CLEAR_CF();
4370 regs.u.r8.ah = 0;
4371 regs.u.r8.bh = mouse_data2;
4372 } else {
4373 // error
4374 SET_CF();
4375 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4377 break;
4379 case 6: // Return Status & Set Scaling Factor...
4380 BX_DEBUG_INT15("case 6:\n");
4381 switch (regs.u.r8.bh) {
4382 case 0: // Return Status
4383 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4384 ret = send_to_mouse_ctrl(0xE9); // get mouse info command
4385 if (ret == 0) {
4386 ret = get_mouse_data(&mouse_data1);
4387 if (mouse_data1 != 0xfa)
4388 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4389 if (ret == 0) {
4390 ret = get_mouse_data(&mouse_data1);
4391 if ( ret == 0 ) {
4392 ret = get_mouse_data(&mouse_data2);
4393 if ( ret == 0 ) {
4394 ret = get_mouse_data(&mouse_data3);
4395 if ( ret == 0 ) {
4396 CLEAR_CF();
4397 regs.u.r8.ah = 0;
4398 regs.u.r8.bl = mouse_data1;
4399 regs.u.r8.cl = mouse_data2;
4400 regs.u.r8.dl = mouse_data3;
4401 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
4402 return;
4409 // error
4410 SET_CF();
4411 regs.u.r8.ah = ret;
4412 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
4413 return;
4415 case 1: // Set Scaling Factor to 1:1
4416 case 2: // Set Scaling Factor to 2:1
4417 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4418 if (regs.u.r8.bh == 1) {
4419 ret = send_to_mouse_ctrl(0xE6);
4420 } else {
4421 ret = send_to_mouse_ctrl(0xE7);
4423 if (ret == 0) {
4424 get_mouse_data(&mouse_data1);
4425 ret = (mouse_data1 != 0xFA);
4427 if (ret == 0) {
4428 CLEAR_CF();
4429 regs.u.r8.ah = 0;
4430 } else {
4431 // error
4432 SET_CF();
4433 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4435 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
4436 break;
4438 default:
4439 BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs.u.r8.bh);
4441 break;
4443 case 7: // Set Mouse Handler Address
4444 BX_DEBUG_INT15("case 7:\n");
4445 mouse_driver_seg = ES;
4446 mouse_driver_offset = regs.u.r16.bx;
4447 write_word(ebda_seg, 0x0022, mouse_driver_offset);
4448 write_word(ebda_seg, 0x0024, mouse_driver_seg);
4449 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4450 if (mouse_driver_offset == 0 && mouse_driver_seg == 0) {
4451 /* remove handler */
4452 if ( (mouse_flags_2 & 0x80) != 0 ) {
4453 mouse_flags_2 &= ~0x80;
4454 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4457 else {
4458 /* install handler */
4459 mouse_flags_2 |= 0x80;
4461 write_byte(ebda_seg, 0x0027, mouse_flags_2);
4462 CLEAR_CF();
4463 regs.u.r8.ah = 0;
4464 break;
4466 default:
4467 BX_DEBUG_INT15("case default:\n");
4468 regs.u.r8.ah = 1; // invalid function
4469 SET_CF();
4471 break;
4473 default:
4474 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4475 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4476 SET_CF();
4477 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4478 break;
4481 #endif
4483 void
4484 int15_function32(regs, ES, DS, FLAGS)
4485 pushad_regs_t regs; // REGS pushed via pushad
4486 Bit16u ES, DS, FLAGS;
4488 Bit32u extended_memory_size=0; // 64bits long
4489 Bit16u CX,DX;
4491 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4493 switch (regs.u.r8.ah) {
4494 case 0x86:
4495 // Wait for CX:DX microseconds. currently using the
4496 // refresh request port 0x61 bit4, toggling every 15usec
4498 CX = regs.u.r16.cx;
4499 DX = regs.u.r16.dx;
4501 ASM_START
4502 ;; Get the count in eax
4503 mov ax, .int15_function32.CX [bp]
4504 shl eax, #16
4505 mov ax, .int15_function32.DX [bp]
4507 ;; convert to numbers of 15usec ticks
4508 mov ebx, #15
4509 xor edx, edx
4510 div eax, ebx
4511 mov ecx, eax
4513 ;; wait for ecx number of refresh requests
4514 in al, #0x61
4515 and al,#0x10
4516 mov ah, al
4518 or ecx, ecx
4519 je int1586_tick_end
4520 int1586_tick:
4521 in al, #0x61
4522 and al,#0x10
4523 cmp al, ah
4524 je int1586_tick
4525 mov ah, al
4526 dec ecx
4527 jnz int1586_tick
4528 int1586_tick_end:
4529 ASM_END
4531 break;
4533 case 0xe8:
4534 switch(regs.u.r8.al)
4536 case 0x20: {
4537 Bit16u e820_table_size = read_word(0xe000, 0x8) * 0x14;
4539 if (regs.u.r32.edx != 0x534D4150) /* SMAP */
4540 goto int15_unimplemented;
4542 if ((regs.u.r16.bx / 0x14) * 0x14 == regs.u.r16.bx) {
4543 if (regs.u.r16.bx + 0x14 <= e820_table_size)
4544 memcpyb(ES, regs.u.r16.di,
4545 0xe000, 0x10 + regs.u.r16.bx, 0x14);
4546 regs.u.r32.ebx += 0x14;
4547 if ((regs.u.r32.ebx + 0x14 - 1) > e820_table_size)
4548 regs.u.r32.ebx = 0;
4549 } else if (regs.u.r16.bx == 1) {
4550 Bit32u base, type;
4551 Bit16u off;
4552 for (off = 0; off < e820_table_size; off += 0x14) {
4553 base = read_dword(0xe000, 0x10 + off);
4554 type = read_dword(0xe000, 0x20 + off);
4555 if ((base >= 0x100000) && (type == 1))
4556 break;
4558 if (off == e820_table_size) {
4559 SET_CF();
4560 break;
4562 memcpyb(ES, regs.u.r16.di, 0xe000, 0x10 + off, 0x14);
4563 regs.u.r32.ebx = 0;
4564 } else { /* AX=E820, DX=534D4150, BX unrecognized */
4565 goto int15_unimplemented;
4568 regs.u.r32.eax = 0x534D4150;
4569 regs.u.r32.ecx = 0x14;
4570 CLEAR_CF();
4571 break;
4574 case 0x01: {
4575 Bit16u off, e820_table_size = read_word(0xe000, 0x8) * 0x14;
4576 Bit32u base, type, size;
4578 // do we have any reason to fail here ?
4579 CLEAR_CF();
4581 // Get the amount of extended memory (above 1M)
4582 regs.u.r8.cl = inb_cmos(0x30);
4583 regs.u.r8.ch = inb_cmos(0x31);
4585 // limit to 15M
4586 if (regs.u.r16.cx > (15*1024))
4587 regs.u.r16.cx = 15*1024;
4589 // Find first RAM E820 entry >= 1MB.
4590 for (off = 0; off < e820_table_size; off += 0x14) {
4591 base = read_dword(0xe000, 0x10 + off);
4592 type = read_dword(0xe000, 0x20 + off);
4593 if ((base >= 0x100000) && (type == 1))
4594 break;
4597 // If there is RAM above 16MB, return amount in 64kB chunks.
4598 regs.u.r16.dx = 0;
4599 if (off != e820_table_size) {
4600 size = base + read_dword(0xe000, 0x18 + off);
4601 if (size > 0x1000000) {
4602 size -= 0x1000000;
4603 regs.u.r16.dx = (Bit16u)(size >> 16);
4607 // Set configured memory equal to extended memory
4608 regs.u.r16.ax = regs.u.r16.cx;
4609 regs.u.r16.bx = regs.u.r16.dx;
4610 break;
4612 default: /* AH=0xE8?? but not implemented */
4613 goto int15_unimplemented;
4615 break;
4616 int15_unimplemented:
4617 // fall into the default
4618 default:
4619 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4620 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4621 SET_CF();
4622 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4623 break;
4627 void
4628 int16_function(DI, SI, BP, SP, BX, DX, CX, AX, FLAGS)
4629 Bit16u DI, SI, BP, SP, BX, DX, CX, AX, FLAGS;
4631 Bit8u scan_code, ascii_code, shift_flags, count;
4632 Bit16u kbd_code, max;
4634 BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX, BX, CX, DX);
4636 switch (GET_AH()) {
4637 case 0x00: /* read keyboard input */
4639 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4640 BX_PANIC("KBD: int16h: out of keyboard input\n");
4642 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4643 else if (ascii_code == 0xE0) ascii_code = 0;
4644 AX = (scan_code << 8) | ascii_code;
4645 break;
4647 case 0x01: /* check keyboard status */
4648 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4649 SET_ZF();
4650 return;
4652 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4653 else if (ascii_code == 0xE0) ascii_code = 0;
4654 AX = (scan_code << 8) | ascii_code;
4655 CLEAR_ZF();
4656 break;
4658 case 0x02: /* get shift flag status */
4659 shift_flags = read_byte(0x0040, 0x17);
4660 SET_AL(shift_flags);
4661 break;
4663 case 0x05: /* store key-stroke into buffer */
4664 if ( !enqueue_key(GET_CH(), GET_CL()) ) {
4665 SET_AL(1);
4667 else {
4668 SET_AL(0);
4670 break;
4672 case 0x09: /* GET KEYBOARD FUNCTIONALITY */
4673 // bit Bochs Description
4674 // 7 0 reserved
4675 // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
4676 // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
4677 // 4 1 INT 16/AH=0Ah supported
4678 // 3 0 INT 16/AX=0306h supported
4679 // 2 0 INT 16/AX=0305h supported
4680 // 1 0 INT 16/AX=0304h supported
4681 // 0 0 INT 16/AX=0300h supported
4682 //
4683 SET_AL(0x30);
4684 break;
4686 case 0x0A: /* GET KEYBOARD ID */
4687 count = 2;
4688 kbd_code = 0x0;
4689 outb(0x60, 0xf2);
4690 /* Wait for data */
4691 max=0xffff;
4692 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4693 if (max>0x0) {
4694 if ((inb(0x60) == 0xfa)) {
4695 do {
4696 max=0xffff;
4697 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4698 if (max>0x0) {
4699 kbd_code >>= 8;
4700 kbd_code |= (inb(0x60) << 8);
4702 } while (--count>0);
4705 BX=kbd_code;
4706 break;
4708 case 0x10: /* read MF-II keyboard input */
4710 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4711 BX_PANIC("KBD: int16h: out of keyboard input\n");
4713 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4714 AX = (scan_code << 8) | ascii_code;
4715 break;
4717 case 0x11: /* check MF-II keyboard status */
4718 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4719 SET_ZF();
4720 return;
4722 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4723 AX = (scan_code << 8) | ascii_code;
4724 CLEAR_ZF();
4725 break;
4727 case 0x12: /* get extended keyboard status */
4728 shift_flags = read_byte(0x0040, 0x17);
4729 SET_AL(shift_flags);
4730 shift_flags = read_byte(0x0040, 0x18);
4731 SET_AH(shift_flags);
4732 BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX);
4733 break;
4735 case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
4736 SET_AH(0x80); // function int16 ah=0x10-0x12 supported
4737 break;
4739 case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
4740 // don't change AH : function int16 ah=0x20-0x22 NOT supported
4741 break;
4743 case 0x6F:
4744 if (GET_AL() == 0x08)
4745 SET_AH(0x02); // unsupported, aka normal keyboard
4747 default:
4748 BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
4752 unsigned int
4753 dequeue_key(scan_code, ascii_code, incr)
4754 Bit8u *scan_code;
4755 Bit8u *ascii_code;
4756 unsigned int incr;
4758 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail;
4759 Bit16u ss;
4760 Bit8u acode, scode;
4762 #if BX_CPU < 2
4763 buffer_start = 0x001E;
4764 buffer_end = 0x003E;
4765 #else
4766 buffer_start = read_word(0x0040, 0x0080);
4767 buffer_end = read_word(0x0040, 0x0082);
4768 #endif
4770 buffer_head = read_word(0x0040, 0x001a);
4771 buffer_tail = read_word(0x0040, 0x001c);
4773 if (buffer_head != buffer_tail) {
4774 ss = get_SS();
4775 acode = read_byte(0x0040, buffer_head);
4776 scode = read_byte(0x0040, buffer_head+1);
4777 write_byte(ss, ascii_code, acode);
4778 write_byte(ss, scan_code, scode);
4780 if (incr) {
4781 buffer_head += 2;
4782 if (buffer_head >= buffer_end)
4783 buffer_head = buffer_start;
4784 write_word(0x0040, 0x001a, buffer_head);
4786 return(1);
4788 else {
4789 return(0);
4793 static char panic_msg_keyb_buffer_full[] = "%s: keyboard input buffer full\n";
4795 Bit8u
4796 inhibit_mouse_int_and_events()
4798 Bit8u command_byte, prev_command_byte;
4800 // Turn off IRQ generation and aux data line
4801 if ( inb(0x64) & 0x02 )
4802 BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
4803 outb(0x64, 0x20); // get command byte
4804 while ( (inb(0x64) & 0x01) != 0x01 );
4805 prev_command_byte = inb(0x60);
4806 command_byte = prev_command_byte;
4807 //while ( (inb(0x64) & 0x02) );
4808 if ( inb(0x64) & 0x02 )
4809 BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
4810 command_byte &= 0xfd; // turn off IRQ 12 generation
4811 command_byte |= 0x20; // disable mouse serial clock line
4812 outb(0x64, 0x60); // write command byte
4813 outb(0x60, command_byte);
4814 return(prev_command_byte);
4817 void
4818 enable_mouse_int_and_events()
4820 Bit8u command_byte;
4822 // Turn on IRQ generation and aux data line
4823 if ( inb(0x64) & 0x02 )
4824 BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
4825 outb(0x64, 0x20); // get command byte
4826 while ( (inb(0x64) & 0x01) != 0x01 );
4827 command_byte = inb(0x60);
4828 //while ( (inb(0x64) & 0x02) );
4829 if ( inb(0x64) & 0x02 )
4830 BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
4831 command_byte |= 0x02; // turn on IRQ 12 generation
4832 command_byte &= 0xdf; // enable mouse serial clock line
4833 outb(0x64, 0x60); // write command byte
4834 outb(0x60, command_byte);
4837 Bit8u
4838 send_to_mouse_ctrl(sendbyte)
4839 Bit8u sendbyte;
4841 Bit8u response;
4843 // wait for chance to write to ctrl
4844 if ( inb(0x64) & 0x02 )
4845 BX_PANIC(panic_msg_keyb_buffer_full,"sendmouse");
4846 outb(0x64, 0xD4);
4847 outb(0x60, sendbyte);
4848 return(0);
4852 Bit8u
4853 get_mouse_data(data)
4854 Bit8u *data;
4856 Bit8u response;
4857 Bit16u ss;
4859 while ( (inb(0x64) & 0x21) != 0x21 ) {
4862 response = inb(0x60);
4864 ss = get_SS();
4865 write_byte(ss, data, response);
4866 return(0);
4869 void
4870 set_kbd_command_byte(command_byte)
4871 Bit8u command_byte;
4873 if ( inb(0x64) & 0x02 )
4874 BX_PANIC(panic_msg_keyb_buffer_full,"setkbdcomm");
4875 outb(0x64, 0xD4);
4877 outb(0x64, 0x60); // write command byte
4878 outb(0x60, command_byte);
4881 void
4882 int09_function(DI, SI, BP, SP, BX, DX, CX, AX)
4883 Bit16u DI, SI, BP, SP, BX, DX, CX, AX;
4885 Bit8u scancode, asciicode, shift_flags;
4886 Bit8u mf2_flags, mf2_state, led_flags;
4888 //
4889 // DS has been set to F000 before call
4890 //
4893 scancode = GET_AL();
4895 if (scancode == 0) {
4896 BX_INFO("KBD: int09 handler: AL=0\n");
4897 return;
4901 shift_flags = read_byte(0x0040, 0x17);
4902 mf2_flags = read_byte(0x0040, 0x18);
4903 mf2_state = read_byte(0x0040, 0x96);
4904 led_flags = read_byte(0x0040, 0x97);
4905 asciicode = 0;
4907 switch (scancode) {
4908 case 0x3a: /* Caps Lock press */
4909 shift_flags ^= 0x40;
4910 write_byte(0x0040, 0x17, shift_flags);
4911 mf2_flags |= 0x40;
4912 write_byte(0x0040, 0x18, mf2_flags);
4913 led_flags ^= 0x04;
4914 write_byte(0x0040, 0x97, led_flags);
4915 break;
4916 case 0xba: /* Caps Lock release */
4917 mf2_flags &= ~0x40;
4918 write_byte(0x0040, 0x18, mf2_flags);
4919 break;
4921 case 0x2a: /* L Shift press */
4922 /*shift_flags &= ~0x40;*/
4923 shift_flags |= 0x02;
4924 write_byte(0x0040, 0x17, shift_flags);
4925 led_flags &= ~0x04;
4926 write_byte(0x0040, 0x97, led_flags);
4927 break;
4928 case 0xaa: /* L Shift release */
4929 shift_flags &= ~0x02;
4930 write_byte(0x0040, 0x17, shift_flags);
4931 break;
4933 case 0x36: /* R Shift press */
4934 /*shift_flags &= ~0x40;*/
4935 shift_flags |= 0x01;
4936 write_byte(0x0040, 0x17, shift_flags);
4937 led_flags &= ~0x04;
4938 write_byte(0x0040, 0x97, led_flags);
4939 break;
4940 case 0xb6: /* R Shift release */
4941 shift_flags &= ~0x01;
4942 write_byte(0x0040, 0x17, shift_flags);
4943 break;
4945 case 0x1d: /* Ctrl press */
4946 shift_flags |= 0x04;
4947 write_byte(0x0040, 0x17, shift_flags);
4948 if (mf2_state & 0x01) {
4949 mf2_flags |= 0x04;
4950 } else {
4951 mf2_flags |= 0x01;
4953 write_byte(0x0040, 0x18, mf2_flags);
4954 break;
4955 case 0x9d: /* Ctrl release */
4956 shift_flags &= ~0x04;
4957 write_byte(0x0040, 0x17, shift_flags);
4958 if (mf2_state & 0x01) {
4959 mf2_flags &= ~0x04;
4960 } else {
4961 mf2_flags &= ~0x01;
4963 write_byte(0x0040, 0x18, mf2_flags);
4964 break;
4966 case 0x38: /* Alt press */
4967 shift_flags |= 0x08;
4968 write_byte(0x0040, 0x17, shift_flags);
4969 if (mf2_state & 0x01) {
4970 mf2_flags |= 0x08;
4971 } else {
4972 mf2_flags |= 0x02;
4974 write_byte(0x0040, 0x18, mf2_flags);
4975 break;
4976 case 0xb8: /* Alt release */
4977 shift_flags &= ~0x08;
4978 write_byte(0x0040, 0x17, shift_flags);
4979 if (mf2_state & 0x01) {
4980 mf2_flags &= ~0x08;
4981 } else {
4982 mf2_flags &= ~0x02;
4984 write_byte(0x0040, 0x18, mf2_flags);
4985 break;
4987 case 0x45: /* Num Lock press */
4988 if ((mf2_state & 0x01) == 0) {
4989 mf2_flags |= 0x20;
4990 write_byte(0x0040, 0x18, mf2_flags);
4991 shift_flags ^= 0x20;
4992 led_flags ^= 0x02;
4993 write_byte(0x0040, 0x17, shift_flags);
4994 write_byte(0x0040, 0x97, led_flags);
4996 break;
4997 case 0xc5: /* Num Lock release */
4998 if ((mf2_state & 0x01) == 0) {
4999 mf2_flags &= ~0x20;
5000 write_byte(0x0040, 0x18, mf2_flags);
5002 break;
5004 case 0x46: /* Scroll Lock press */
5005 mf2_flags |= 0x10;
5006 write_byte(0x0040, 0x18, mf2_flags);
5007 shift_flags ^= 0x10;
5008 led_flags ^= 0x01;
5009 write_byte(0x0040, 0x17, shift_flags);
5010 write_byte(0x0040, 0x97, led_flags);
5011 break;
5013 case 0xc6: /* Scroll Lock release */
5014 mf2_flags &= ~0x10;
5015 write_byte(0x0040, 0x18, mf2_flags);
5016 break;
5018 case 0x53: /* Del */
5019 if ((shift_flags & 0x0c) == 0x0c) /* Ctrl + Alt */
5020 machine_reset();
5021 /* Fall through */
5022 default:
5023 if (scancode & 0x80) return; /* toss key releases ... */
5024 if (scancode > MAX_SCAN_CODE) {
5025 BX_INFO("KBD: int09h_handler(): unknown scancode (%x) read!\n", scancode);
5026 return;
5028 if (shift_flags & 0x08) { /* ALT */
5029 asciicode = scan_to_scanascii[scancode].alt;
5030 scancode = scan_to_scanascii[scancode].alt >> 8;
5032 else if (shift_flags & 0x04) { /* CONTROL */
5033 asciicode = scan_to_scanascii[scancode].control;
5034 scancode = scan_to_scanascii[scancode].control >> 8;
5036 else if (shift_flags & 0x03) { /* LSHIFT + RSHIFT */
5037 /* check if lock state should be ignored
5038 * because a SHIFT key are pressed */
5040 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
5041 asciicode = scan_to_scanascii[scancode].normal;
5042 scancode = scan_to_scanascii[scancode].normal >> 8;
5044 else {
5045 asciicode = scan_to_scanascii[scancode].shift;
5046 scancode = scan_to_scanascii[scancode].shift >> 8;
5049 else {
5050 /* check if lock is on */
5051 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
5052 asciicode = scan_to_scanascii[scancode].shift;
5053 scancode = scan_to_scanascii[scancode].shift >> 8;
5055 else {
5056 asciicode = scan_to_scanascii[scancode].normal;
5057 scancode = scan_to_scanascii[scancode].normal >> 8;
5060 if (scancode==0 && asciicode==0) {
5061 BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
5063 enqueue_key(scancode, asciicode);
5064 break;
5066 mf2_state &= ~0x01;
5069 unsigned int
5070 enqueue_key(scan_code, ascii_code)
5071 Bit8u scan_code, ascii_code;
5073 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail, temp_tail;
5075 //BX_INFO("KBD: enqueue_key() called scan:%02x, ascii:%02x\n",
5076 // scan_code, ascii_code);
5078 #if BX_CPU < 2
5079 buffer_start = 0x001E;
5080 buffer_end = 0x003E;
5081 #else
5082 buffer_start = read_word(0x0040, 0x0080);
5083 buffer_end = read_word(0x0040, 0x0082);
5084 #endif
5086 buffer_head = read_word(0x0040, 0x001A);
5087 buffer_tail = read_word(0x0040, 0x001C);
5089 temp_tail = buffer_tail;
5090 buffer_tail += 2;
5091 if (buffer_tail >= buffer_end)
5092 buffer_tail = buffer_start;
5094 if (buffer_tail == buffer_head) {
5095 return(0);
5098 write_byte(0x0040, temp_tail, ascii_code);
5099 write_byte(0x0040, temp_tail+1, scan_code);
5100 write_word(0x0040, 0x001C, buffer_tail);
5101 return(1);
5105 void
5106 int74_function(make_farcall, Z, Y, X, status)
5107 Bit16u make_farcall, Z, Y, X, status;
5109 Bit16u ebda_seg=read_word(0x0040,0x000E);
5110 Bit8u in_byte, index, package_count;
5111 Bit8u mouse_flags_1, mouse_flags_2;
5113 BX_DEBUG_INT74("entering int74_function\n");
5114 make_farcall = 0;
5116 in_byte = inb(0x64);
5117 if ( (in_byte & 0x21) != 0x21 ) {
5118 return;
5120 in_byte = inb(0x60);
5121 BX_DEBUG_INT74("int74: read byte %02x\n", in_byte);
5123 mouse_flags_1 = read_byte(ebda_seg, 0x0026);
5124 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
5126 if ( (mouse_flags_2 & 0x80) != 0x80 ) {
5127 // BX_PANIC("int74_function:\n");
5128 return;
5131 package_count = mouse_flags_2 & 0x07;
5132 index = mouse_flags_1 & 0x07;
5133 write_byte(ebda_seg, 0x28 + index, in_byte);
5135 if ( (index+1) >= package_count ) {
5136 BX_DEBUG_INT74("int74_function: make_farcall=1\n");
5137 status = read_byte(ebda_seg, 0x0028 + 0);
5138 X = read_byte(ebda_seg, 0x0028 + 1);
5139 Y = read_byte(ebda_seg, 0x0028 + 2);
5140 Z = 0;
5141 mouse_flags_1 = 0;
5142 // check if far call handler installed
5143 if (mouse_flags_2 & 0x80)
5144 make_farcall = 1;
5146 else {
5147 mouse_flags_1++;
5149 write_byte(ebda_seg, 0x0026, mouse_flags_1);
5152 #define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
5154 #if BX_USE_ATADRV
5156 void
5157 int13_harddisk(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5158 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5160 Bit32u lba;
5161 Bit16u ebda_seg=read_word(0x0040,0x000E);
5162 Bit16u cylinder, head, sector;
5163 Bit16u segment, offset;
5164 Bit16u npc, nph, npspt, nlc, nlh, nlspt;
5165 Bit16u size, count;
5166 Bit8u device, status;
5168 BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5170 write_byte(0x0040, 0x008e, 0); // clear completion flag
5172 // basic check : device has to be defined
5173 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES) ) {
5174 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5175 goto int13_fail;
5178 // Get the ata channel
5179 device=read_byte(ebda_seg,&EbdaData->ata.hdidmap[GET_ELDL()-0x80]);
5181 // basic check : device has to be valid
5182 if (device >= BX_MAX_ATA_DEVICES) {
5183 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5184 goto int13_fail;
5187 switch (GET_AH()) {
5189 case 0x00: /* disk controller reset */
5190 ata_reset (device);
5191 goto int13_success;
5192 break;
5194 case 0x01: /* read disk status */
5195 status = read_byte(0x0040, 0x0074);
5196 SET_AH(status);
5197 SET_DISK_RET_STATUS(0);
5198 /* set CF if error status read */
5199 if (status) goto int13_fail_nostatus;
5200 else goto int13_success_noah;
5201 break;
5203 case 0x02: // read disk sectors
5204 case 0x03: // write disk sectors
5205 case 0x04: // verify disk sectors
5207 count = GET_AL();
5208 cylinder = GET_CH();
5209 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
5210 sector = (GET_CL() & 0x3f);
5211 head = GET_DH();
5213 segment = ES;
5214 offset = BX;
5216 if ( (count > 128) || (count == 0) ) {
5217 BX_INFO("int13_harddisk: function %02x, count out of range!\n",GET_AH());
5218 goto int13_fail;
5221 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
5222 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
5223 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
5225 // sanity check on cyl heads, sec
5226 if( (cylinder >= nlc) || (head >= nlh) || (sector > nlspt )) {
5227 BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder, head, sector);
5228 goto int13_fail;
5231 // FIXME verify
5232 if ( GET_AH() == 0x04 ) goto int13_success;
5234 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5235 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5237 // if needed, translate lchs to lba, and execute command
5238 if ( (nph != nlh) || (npspt != nlspt)) {
5239 lba = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
5240 sector = 0; // this forces the command to be lba
5243 if ( GET_AH() == 0x02 )
5244 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, cylinder, head, sector, lba, segment, offset);
5245 else
5246 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, cylinder, head, sector, lba, segment, offset);
5248 // Set nb of sector transferred
5249 SET_AL(read_word(ebda_seg, &EbdaData->ata.trsfsectors));
5251 if (status != 0) {
5252 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5253 SET_AH(0x0c);
5254 goto int13_fail_noah;
5257 goto int13_success;
5258 break;
5260 case 0x05: /* format disk track */
5261 BX_INFO("format disk track called\n");
5262 goto int13_success;
5263 return;
5264 break;
5266 case 0x08: /* read disk drive parameters */
5268 // Get logical geometry from table
5269 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
5270 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
5271 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
5272 count = read_byte(ebda_seg, &EbdaData->ata.hdcount);
5274 nlc = nlc - 2; /* 0 based , last sector not used */
5275 SET_AL(0);
5276 SET_CH(nlc & 0xff);
5277 SET_CL(((nlc >> 2) & 0xc0) | (nlspt & 0x3f));
5278 SET_DH(nlh - 1);
5279 SET_DL(count); /* FIXME returns 0, 1, or n hard drives */
5281 // FIXME should set ES & DI
5283 goto int13_success;
5284 break;
5286 case 0x10: /* check drive ready */
5287 // should look at 40:8E also???
5289 // Read the status from controller
5290 status = inb(read_word(ebda_seg, &EbdaData->ata.channels[device/2].iobase1) + ATA_CB_STAT);
5291 if ( (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY ) {
5292 goto int13_success;
5294 else {
5295 SET_AH(0xAA);
5296 goto int13_fail_noah;
5298 break;
5300 case 0x15: /* read disk drive size */
5302 // Get physical geometry from table
5303 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5304 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5305 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5307 // Compute sector count seen by int13
5308 lba = (Bit32u)(npc - 1) * (Bit32u)nph * (Bit32u)npspt;
5309 CX = lba >> 16;
5310 DX = lba & 0xffff;
5312 SET_AH(3); // hard disk accessible
5313 goto int13_success_noah;
5314 break;
5316 case 0x41: // IBM/MS installation check
5317 BX=0xaa55; // install check
5318 SET_AH(0x30); // EDD 3.0
5319 CX=0x0007; // ext disk access and edd, removable supported
5320 goto int13_success_noah;
5321 break;
5323 case 0x42: // IBM/MS extended read
5324 case 0x43: // IBM/MS extended write
5325 case 0x44: // IBM/MS verify
5326 case 0x47: // IBM/MS extended seek
5328 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5329 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5330 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5332 // Can't use 64 bits lba
5333 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5334 if (lba != 0L) {
5335 BX_PANIC("int13_harddisk: function %02x. Can't use 64bits lba\n",GET_AH());
5336 goto int13_fail;
5339 // Get 32 bits lba and check
5340 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5341 if (lba >= read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors) ) {
5342 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5343 goto int13_fail;
5346 // If verify or seek
5347 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5348 goto int13_success;
5350 // Execute the command
5351 if ( GET_AH() == 0x42 )
5352 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba, segment, offset);
5353 else
5354 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
5356 count=read_word(ebda_seg, &EbdaData->ata.trsfsectors);
5357 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5359 if (status != 0) {
5360 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5361 SET_AH(0x0c);
5362 goto int13_fail_noah;
5365 goto int13_success;
5366 break;
5368 case 0x45: // IBM/MS lock/unlock drive
5369 case 0x49: // IBM/MS extended media change
5370 goto int13_success; // Always success for HD
5371 break;
5373 case 0x46: // IBM/MS eject media
5374 SET_AH(0xb2); // Volume Not Removable
5375 goto int13_fail_noah; // Always fail for HD
5376 break;
5378 case 0x48: // IBM/MS get drive parameters
5379 size=read_word(DS,SI+(Bit16u)&Int13DPT->size);
5381 // Buffer is too small
5382 if(size < 0x1a)
5383 goto int13_fail;
5385 // EDD 1.x
5386 if(size >= 0x1a) {
5387 Bit16u blksize;
5389 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5390 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5391 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5392 lba = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors);
5393 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5395 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5396 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x02); // geometry is valid
5397 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, (Bit32u)npc);
5398 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, (Bit32u)nph);
5399 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, (Bit32u)npspt);
5400 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, lba); // FIXME should be Bit64
5401 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0L);
5402 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5405 // EDD 2.x
5406 if(size >= 0x1e) {
5407 Bit8u channel, dev, irq, mode, checksum, i, translation;
5408 Bit16u iobase1, iobase2, options;
5410 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5412 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5413 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5415 // Fill in dpte
5416 channel = device / 2;
5417 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5418 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5419 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5420 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5421 translation = read_byte(ebda_seg, &EbdaData->ata.devices[device].translation);
5423 options = (translation==ATA_TRANSLATION_NONE?0:1<<3); // chs translation
5424 options |= (1<<4); // lba translation
5425 options |= (mode==ATA_MODE_PIO32?1:0<<7);
5426 options |= (translation==ATA_TRANSLATION_LBA?1:0<<9);
5427 options |= (translation==ATA_TRANSLATION_RECHS?3:0<<9);
5429 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5430 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5431 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5432 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5433 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5434 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5435 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5436 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5437 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5438 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5439 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5441 checksum=0;
5442 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5443 checksum = ~checksum;
5444 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5447 // EDD 3.x
5448 if(size >= 0x42) {
5449 Bit8u channel, iface, checksum, i;
5450 Bit16u iobase1;
5452 channel = device / 2;
5453 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5454 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5456 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5457 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5458 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5459 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5460 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5462 if (iface==ATA_IFACE_ISA) {
5463 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5464 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5465 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5466 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5468 else {
5469 // FIXME PCI
5471 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5472 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5473 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5474 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5476 if (iface==ATA_IFACE_ISA) {
5477 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5478 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5479 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5481 else {
5482 // FIXME PCI
5484 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5485 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5486 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5487 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5489 checksum=0;
5490 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5491 checksum = ~checksum;
5492 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5495 goto int13_success;
5496 break;
5498 case 0x4e: // // IBM/MS set hardware configuration
5499 // DMA, prefetch, PIO maximum not supported
5500 switch (GET_AL()) {
5501 case 0x01:
5502 case 0x03:
5503 case 0x04:
5504 case 0x06:
5505 goto int13_success;
5506 break;
5507 default :
5508 goto int13_fail;
5510 break;
5512 case 0x09: /* initialize drive parameters */
5513 case 0x0c: /* seek to specified cylinder */
5514 case 0x0d: /* alternate disk reset */
5515 case 0x11: /* recalibrate */
5516 case 0x14: /* controller internal diagnostic */
5517 BX_INFO("int13h_harddisk function %02xh unimplemented, returns success\n", GET_AH());
5518 goto int13_success;
5519 break;
5521 case 0x0a: /* read disk sectors with ECC */
5522 case 0x0b: /* write disk sectors with ECC */
5523 case 0x18: // set media type for format
5524 case 0x50: // IBM/MS send packet command
5525 default:
5526 BX_INFO("int13_harddisk function %02xh unsupported, returns fail\n", GET_AH());
5527 goto int13_fail;
5528 break;
5531 int13_fail:
5532 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5533 int13_fail_noah:
5534 SET_DISK_RET_STATUS(GET_AH());
5535 int13_fail_nostatus:
5536 SET_CF(); // error occurred
5537 return;
5539 int13_success:
5540 SET_AH(0x00); // no error
5541 int13_success_noah:
5542 SET_DISK_RET_STATUS(0x00);
5543 CLEAR_CF(); // no error
5544 return;
5547 // ---------------------------------------------------------------------------
5548 // Start of int13 for cdrom
5549 // ---------------------------------------------------------------------------
5551 void
5552 int13_cdrom(EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5553 Bit16u EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5555 Bit16u ebda_seg=read_word(0x0040,0x000E);
5556 Bit8u device, status, locks;
5557 Bit8u atacmd[12];
5558 Bit32u lba;
5559 Bit16u count, segment, offset, i, size;
5561 BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5562 // BX_DEBUG_INT13_CD("int13_cdrom: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
5564 SET_DISK_RET_STATUS(0x00);
5566 /* basic check : device should be 0xE0+ */
5567 if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES) ) {
5568 BX_INFO("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5569 goto int13_fail;
5572 // Get the ata channel
5573 device=read_byte(ebda_seg,&EbdaData->ata.cdidmap[GET_ELDL()-0xE0]);
5575 /* basic check : device has to be valid */
5576 if (device >= BX_MAX_ATA_DEVICES) {
5577 BX_INFO("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5578 goto int13_fail;
5581 switch (GET_AH()) {
5583 // all those functions return SUCCESS
5584 case 0x00: /* disk controller reset */
5585 case 0x09: /* initialize drive parameters */
5586 case 0x0c: /* seek to specified cylinder */
5587 case 0x0d: /* alternate disk reset */
5588 case 0x10: /* check drive ready */
5589 case 0x11: /* recalibrate */
5590 case 0x14: /* controller internal diagnostic */
5591 case 0x16: /* detect disk change */
5592 goto int13_success;
5593 break;
5595 // all those functions return disk write-protected
5596 case 0x03: /* write disk sectors */
5597 case 0x05: /* format disk track */
5598 case 0x43: // IBM/MS extended write
5599 SET_AH(0x03);
5600 goto int13_fail_noah;
5601 break;
5603 case 0x01: /* read disk status */
5604 status = read_byte(0x0040, 0x0074);
5605 SET_AH(status);
5606 SET_DISK_RET_STATUS(0);
5608 /* set CF if error status read */
5609 if (status) goto int13_fail_nostatus;
5610 else goto int13_success_noah;
5611 break;
5613 case 0x15: /* read disk drive size */
5614 SET_AH(0x02);
5615 goto int13_fail_noah;
5616 break;
5618 case 0x41: // IBM/MS installation check
5619 BX=0xaa55; // install check
5620 SET_AH(0x30); // EDD 2.1
5621 CX=0x0007; // ext disk access, removable and edd
5622 goto int13_success_noah;
5623 break;
5625 case 0x42: // IBM/MS extended read
5626 case 0x44: // IBM/MS verify sectors
5627 case 0x47: // IBM/MS extended seek
5629 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5630 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5631 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5633 // Can't use 64 bits lba
5634 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5635 if (lba != 0L) {
5636 BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
5637 goto int13_fail;
5640 // Get 32 bits lba
5641 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5643 // If verify or seek
5644 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5645 goto int13_success;
5647 memsetb(get_SS(),atacmd,0,12);
5648 atacmd[0]=0x28; // READ command
5649 atacmd[7]=(count & 0xff00) >> 8; // Sectors
5650 atacmd[8]=(count & 0x00ff); // Sectors
5651 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
5652 atacmd[3]=(lba & 0x00ff0000) >> 16;
5653 atacmd[4]=(lba & 0x0000ff00) >> 8;
5654 atacmd[5]=(lba & 0x000000ff);
5655 status = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, count*2048L, ATA_DATA_IN, segment,offset);
5657 count = (Bit16u)(read_dword(ebda_seg, &EbdaData->ata.trsfbytes) >> 11);
5658 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5660 if (status != 0) {
5661 BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status);
5662 SET_AH(0x0c);
5663 goto int13_fail_noah;
5666 goto int13_success;
5667 break;
5669 case 0x45: // IBM/MS lock/unlock drive
5670 if (GET_AL() > 2) goto int13_fail;
5672 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
5674 switch (GET_AL()) {
5675 case 0 : // lock
5676 if (locks == 0xff) {
5677 SET_AH(0xb4);
5678 SET_AL(1);
5679 goto int13_fail_noah;
5681 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, ++locks);
5682 SET_AL(1);
5683 break;
5684 case 1 : // unlock
5685 if (locks == 0x00) {
5686 SET_AH(0xb0);
5687 SET_AL(0);
5688 goto int13_fail_noah;
5690 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, --locks);
5691 SET_AL(locks==0?0:1);
5692 break;
5693 case 2 : // status
5694 SET_AL(locks==0?0:1);
5695 break;
5697 goto int13_success;
5698 break;
5700 case 0x46: // IBM/MS eject media
5701 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
5703 if (locks != 0) {
5704 SET_AH(0xb1); // media locked
5705 goto int13_fail_noah;
5707 // FIXME should handle 0x31 no media in device
5708 // FIXME should handle 0xb5 valid request failed
5710 // Call removable media eject
5711 ASM_START
5712 push bp
5713 mov bp, sp
5715 mov ah, #0x52
5716 int 15
5717 mov _int13_cdrom.status + 2[bp], ah
5718 jnc int13_cdrom_rme_end
5719 mov _int13_cdrom.status, #1
5720 int13_cdrom_rme_end:
5721 pop bp
5722 ASM_END
5724 if (status != 0) {
5725 SET_AH(0xb1); // media locked
5726 goto int13_fail_noah;
5729 goto int13_success;
5730 break;
5732 case 0x48: // IBM/MS get drive parameters
5733 size = read_word(DS,SI+(Bit16u)&Int13Ext->size);
5735 // Buffer is too small
5736 if(size < 0x1a)
5737 goto int13_fail;
5739 // EDD 1.x
5740 if(size >= 0x1a) {
5741 Bit16u cylinders, heads, spt, blksize;
5743 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5745 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5746 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x74); // removable, media change, lockable, max values
5747 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, 0xffffffff);
5748 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, 0xffffffff);
5749 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, 0xffffffff);
5750 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, 0xffffffff); // FIXME should be Bit64
5751 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0xffffffff);
5752 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5755 // EDD 2.x
5756 if(size >= 0x1e) {
5757 Bit8u channel, dev, irq, mode, checksum, i;
5758 Bit16u iobase1, iobase2, options;
5760 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5762 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5763 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5765 // Fill in dpte
5766 channel = device / 2;
5767 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5768 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5769 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5770 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5772 // FIXME atapi device
5773 options = (1<<4); // lba translation
5774 options |= (1<<5); // removable device
5775 options |= (1<<6); // atapi device
5776 options |= (mode==ATA_MODE_PIO32?1:0<<7);
5778 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5779 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5780 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5781 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5782 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5783 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5784 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5785 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5786 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5787 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5788 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5790 checksum=0;
5791 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5792 checksum = ~checksum;
5793 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5796 // EDD 3.x
5797 if(size >= 0x42) {
5798 Bit8u channel, iface, checksum, i;
5799 Bit16u iobase1;
5801 channel = device / 2;
5802 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5803 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5805 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5806 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5807 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5808 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5809 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5811 if (iface==ATA_IFACE_ISA) {
5812 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5813 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5814 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5815 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5817 else {
5818 // FIXME PCI
5820 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5821 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5822 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5823 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5825 if (iface==ATA_IFACE_ISA) {
5826 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5827 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5828 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5830 else {
5831 // FIXME PCI
5833 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5834 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5835 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5836 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5838 checksum=0;
5839 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5840 checksum = ~checksum;
5841 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5844 goto int13_success;
5845 break;
5847 case 0x49: // IBM/MS extended media change
5848 // always send changed ??
5849 SET_AH(06);
5850 goto int13_fail_nostatus;
5851 break;
5853 case 0x4e: // // IBM/MS set hardware configuration
5854 // DMA, prefetch, PIO maximum not supported
5855 switch (GET_AL()) {
5856 case 0x01:
5857 case 0x03:
5858 case 0x04:
5859 case 0x06:
5860 goto int13_success;
5861 break;
5862 default :
5863 goto int13_fail;
5865 break;
5867 // all those functions return unimplemented
5868 case 0x02: /* read sectors */
5869 case 0x04: /* verify sectors */
5870 case 0x08: /* read disk drive parameters */
5871 case 0x0a: /* read disk sectors with ECC */
5872 case 0x0b: /* write disk sectors with ECC */
5873 case 0x18: /* set media type for format */
5874 case 0x50: // ? - send packet command
5875 default:
5876 BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
5877 goto int13_fail;
5878 break;
5881 int13_fail:
5882 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5883 int13_fail_noah:
5884 SET_DISK_RET_STATUS(GET_AH());
5885 int13_fail_nostatus:
5886 SET_CF(); // error occurred
5887 return;
5889 int13_success:
5890 SET_AH(0x00); // no error
5891 int13_success_noah:
5892 SET_DISK_RET_STATUS(0x00);
5893 CLEAR_CF(); // no error
5894 return;
5897 // ---------------------------------------------------------------------------
5898 // End of int13 for cdrom
5899 // ---------------------------------------------------------------------------
5901 #if BX_ELTORITO_BOOT
5902 // ---------------------------------------------------------------------------
5903 // Start of int13 for eltorito functions
5904 // ---------------------------------------------------------------------------
5906 void
5907 int13_eltorito(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
5908 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
5910 Bit16u ebda_seg=read_word(0x0040,0x000E);
5912 BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5913 // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
5915 switch (GET_AH()) {
5917 // FIXME ElTorito Various. Should be implemented
5918 case 0x4a: // ElTorito - Initiate disk emu
5919 case 0x4c: // ElTorito - Initiate disk emu and boot
5920 case 0x4d: // ElTorito - Return Boot catalog
5921 BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX);
5922 goto int13_fail;
5923 break;
5925 case 0x4b: // ElTorito - Terminate disk emu
5926 // FIXME ElTorito Hardcoded
5927 write_byte(DS,SI+0x00,0x13);
5928 write_byte(DS,SI+0x01,read_byte(ebda_seg,&EbdaData->cdemu.media));
5929 write_byte(DS,SI+0x02,read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
5930 write_byte(DS,SI+0x03,read_byte(ebda_seg,&EbdaData->cdemu.controller_index));
5931 write_dword(DS,SI+0x04,read_dword(ebda_seg,&EbdaData->cdemu.ilba));
5932 write_word(DS,SI+0x08,read_word(ebda_seg,&EbdaData->cdemu.device_spec));
5933 write_word(DS,SI+0x0a,read_word(ebda_seg,&EbdaData->cdemu.buffer_segment));
5934 write_word(DS,SI+0x0c,read_word(ebda_seg,&EbdaData->cdemu.load_segment));
5935 write_word(DS,SI+0x0e,read_word(ebda_seg,&EbdaData->cdemu.sector_count));
5936 write_byte(DS,SI+0x10,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.cylinders));
5937 write_byte(DS,SI+0x11,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.spt));
5938 write_byte(DS,SI+0x12,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.heads));
5940 // If we have to terminate emulation
5941 if(GET_AL() == 0x00) {
5942 // FIXME ElTorito Various. Should be handled accordingly to spec
5943 write_byte(ebda_seg,&EbdaData->cdemu.active, 0x00); // bye bye
5946 goto int13_success;
5947 break;
5949 default:
5950 BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
5951 goto int13_fail;
5952 break;
5955 int13_fail:
5956 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5957 SET_DISK_RET_STATUS(GET_AH());
5958 SET_CF(); // error occurred
5959 return;
5961 int13_success:
5962 SET_AH(0x00); // no error
5963 SET_DISK_RET_STATUS(0x00);
5964 CLEAR_CF(); // no error
5965 return;
5968 // ---------------------------------------------------------------------------
5969 // End of int13 for eltorito functions
5970 // ---------------------------------------------------------------------------
5972 // ---------------------------------------------------------------------------
5973 // Start of int13 when emulating a device from the cd
5974 // ---------------------------------------------------------------------------
5976 void
5977 int13_cdemu(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
5978 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
5980 Bit16u ebda_seg=read_word(0x0040,0x000E);
5981 Bit8u device, status;
5982 Bit16u vheads, vspt, vcylinders;
5983 Bit16u head, sector, cylinder, nbsectors;
5984 Bit32u vlba, ilba, slba, elba;
5985 Bit16u before, segment, offset;
5986 Bit8u atacmd[12];
5988 BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5989 //BX_DEBUG_INT13_ET("int13_cdemu: SS=%04x ES=%04x DI=%04x SI=%04x\n", get_SS(), ES, DI, SI);
5991 /* at this point, we are emulating a floppy/harddisk */
5993 // Recompute the device number
5994 device = read_byte(ebda_seg,&EbdaData->cdemu.controller_index) * 2;
5995 device += read_byte(ebda_seg,&EbdaData->cdemu.device_spec);
5997 SET_DISK_RET_STATUS(0x00);
5999 /* basic checks : emulation should be active, dl should equal the emulated drive */
6000 if( (read_byte(ebda_seg,&EbdaData->cdemu.active) ==0 )
6001 || (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive ) != GET_DL())) {
6002 BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
6003 goto int13_fail;
6007 switch (GET_AH()) {
6009 // all those functions return SUCCESS
6010 case 0x00: /* disk controller reset */
6011 case 0x09: /* initialize drive parameters */
6012 case 0x0c: /* seek to specified cylinder */
6013 case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
6014 case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
6015 case 0x11: /* recalibrate */
6016 case 0x14: /* controller internal diagnostic */
6017 case 0x16: /* detect disk change */
6018 goto int13_success;
6019 break;
6021 // all those functions return disk write-protected
6022 case 0x03: /* write disk sectors */
6023 case 0x05: /* format disk track */
6024 SET_AH(0x03);
6025 goto int13_fail_noah;
6026 break;
6028 case 0x01: /* read disk status */
6029 status=read_byte(0x0040, 0x0074);
6030 SET_AH(status);
6031 SET_DISK_RET_STATUS(0);
6033 /* set CF if error status read */
6034 if (status) goto int13_fail_nostatus;
6035 else goto int13_success_noah;
6036 break;
6038 case 0x02: // read disk sectors
6039 case 0x04: // verify disk sectors
6040 vspt = read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
6041 vcylinders = read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders);
6042 vheads = read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads);
6044 ilba = read_dword(ebda_seg,&EbdaData->cdemu.ilba);
6046 sector = GET_CL() & 0x003f;
6047 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
6048 head = GET_DH();
6049 nbsectors = GET_AL();
6050 segment = ES;
6051 offset = BX;
6053 // no sector to read ?
6054 if(nbsectors==0) goto int13_success;
6056 // sanity checks sco openserver needs this!
6057 if ((sector > vspt)
6058 || (cylinder >= vcylinders)
6059 || (head >= vheads)) {
6060 goto int13_fail;
6063 // After controls, verify do nothing
6064 if (GET_AH() == 0x04) goto int13_success;
6066 segment = ES+(BX / 16);
6067 offset = BX % 16;
6069 // calculate the virtual lba inside the image
6070 vlba=((((Bit32u)cylinder*(Bit32u)vheads)+(Bit32u)head)*(Bit32u)vspt)+((Bit32u)(sector-1));
6072 // In advance so we don't loose the count
6073 SET_AL(nbsectors);
6075 // start lba on cd
6076 slba = (Bit32u)vlba/4;
6077 before= (Bit16u)vlba%4;
6079 // end lba on cd
6080 elba = (Bit32u)(vlba+nbsectors-1)/4;
6082 memsetb(get_SS(),atacmd,0,12);
6083 atacmd[0]=0x28; // READ command
6084 atacmd[7]=((Bit16u)(elba-slba+1) & 0xff00) >> 8; // Sectors
6085 atacmd[8]=((Bit16u)(elba-slba+1) & 0x00ff); // Sectors
6086 atacmd[2]=(ilba+slba & 0xff000000) >> 24; // LBA
6087 atacmd[3]=(ilba+slba & 0x00ff0000) >> 16;
6088 atacmd[4]=(ilba+slba & 0x0000ff00) >> 8;
6089 atacmd[5]=(ilba+slba & 0x000000ff);
6090 if((status = ata_cmd_packet(device, 12, get_SS(), atacmd, before*512, nbsectors*512L, ATA_DATA_IN, segment,offset)) != 0) {
6091 BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status);
6092 SET_AH(0x02);
6093 SET_AL(0);
6094 goto int13_fail_noah;
6097 goto int13_success;
6098 break;
6100 case 0x08: /* read disk drive parameters */
6101 vspt=read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
6102 vcylinders=read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders) - 1;
6103 vheads=read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads) - 1;
6105 SET_AL( 0x00 );
6106 SET_BL( 0x00 );
6107 SET_CH( vcylinders & 0xff );
6108 SET_CL((( vcylinders >> 2) & 0xc0) | ( vspt & 0x3f ));
6109 SET_DH( vheads );
6110 SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2
6111 // FIXME ElTorito Harddisk. should send the HD count
6113 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
6114 case 0x01: SET_BL( 0x02 ); break;
6115 case 0x02: SET_BL( 0x04 ); break;
6116 case 0x03: SET_BL( 0x06 ); break;
6119 ASM_START
6120 push bp
6121 mov bp, sp
6122 mov ax, #diskette_param_table2
6123 mov _int13_cdemu.DI+2[bp], ax
6124 mov _int13_cdemu.ES+2[bp], cs
6125 pop bp
6126 ASM_END
6127 goto int13_success;
6128 break;
6130 case 0x15: /* read disk drive size */
6131 // FIXME ElTorito Harddisk. What geometry to send ?
6132 SET_AH(0x03);
6133 goto int13_success_noah;
6134 break;
6136 // all those functions return unimplemented
6137 case 0x0a: /* read disk sectors with ECC */
6138 case 0x0b: /* write disk sectors with ECC */
6139 case 0x18: /* set media type for format */
6140 case 0x41: // IBM/MS installation check
6141 // FIXME ElTorito Harddisk. Darwin would like to use EDD
6142 case 0x42: // IBM/MS extended read
6143 case 0x43: // IBM/MS extended write
6144 case 0x44: // IBM/MS verify sectors
6145 case 0x45: // IBM/MS lock/unlock drive
6146 case 0x46: // IBM/MS eject media
6147 case 0x47: // IBM/MS extended seek
6148 case 0x48: // IBM/MS get drive parameters
6149 case 0x49: // IBM/MS extended media change
6150 case 0x4e: // ? - set hardware configuration
6151 case 0x50: // ? - send packet command
6152 default:
6153 BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
6154 goto int13_fail;
6155 break;
6158 int13_fail:
6159 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
6160 int13_fail_noah:
6161 SET_DISK_RET_STATUS(GET_AH());
6162 int13_fail_nostatus:
6163 SET_CF(); // error occurred
6164 return;
6166 int13_success:
6167 SET_AH(0x00); // no error
6168 int13_success_noah:
6169 SET_DISK_RET_STATUS(0x00);
6170 CLEAR_CF(); // no error
6171 return;
6174 // ---------------------------------------------------------------------------
6175 // End of int13 when emulating a device from the cd
6176 // ---------------------------------------------------------------------------
6178 #endif // BX_ELTORITO_BOOT
6180 #else //BX_USE_ATADRV
6182 void
6183 outLBA(cylinder,hd_heads,head,hd_sectors,sector,dl)
6184 Bit16u cylinder;
6185 Bit16u hd_heads;
6186 Bit16u head;
6187 Bit16u hd_sectors;
6188 Bit16u sector;
6189 Bit16u dl;
6191 ASM_START
6192 push bp
6193 mov bp, sp
6194 push eax
6195 push ebx
6196 push edx
6197 xor eax,eax
6198 mov ax,4[bp] // cylinder
6199 xor ebx,ebx
6200 mov bl,6[bp] // hd_heads
6201 imul ebx
6203 mov bl,8[bp] // head
6204 add eax,ebx
6205 mov bl,10[bp] // hd_sectors
6206 imul ebx
6207 mov bl,12[bp] // sector
6208 add eax,ebx
6210 dec eax
6211 mov dx,#0x1f3
6212 out dx,al
6213 mov dx,#0x1f4
6214 mov al,ah
6215 out dx,al
6216 shr eax,#16
6217 mov dx,#0x1f5
6218 out dx,al
6219 and ah,#0xf
6220 mov bl,14[bp] // dl
6221 and bl,#1
6222 shl bl,#4
6223 or ah,bl
6224 or ah,#0xe0
6225 mov al,ah
6226 mov dx,#0x01f6
6227 out dx,al
6228 pop edx
6229 pop ebx
6230 pop eax
6231 pop bp
6232 ASM_END
6235 void
6236 int13_harddisk(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
6237 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
6239 Bit8u drive, num_sectors, sector, head, status, mod;
6240 Bit8u drive_map;
6241 Bit8u n_drives;
6242 Bit16u cyl_mod, ax;
6243 Bit16u max_cylinder, cylinder, total_sectors;
6244 Bit16u hd_cylinders;
6245 Bit8u hd_heads, hd_sectors;
6246 Bit16u val16;
6247 Bit8u sector_count;
6248 unsigned int i;
6249 Bit16u tempbx;
6250 Bit16u dpsize;
6252 Bit16u count, segment, offset;
6253 Bit32u lba;
6254 Bit16u error;
6256 BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6258 write_byte(0x0040, 0x008e, 0); // clear completion flag
6260 /* at this point, DL is >= 0x80 to be passed from the floppy int13h
6261 handler code */
6262 /* check how many disks first (cmos reg 0x12), return an error if
6263 drive not present */
6264 drive_map = inb_cmos(0x12);
6265 drive_map = (((drive_map & 0xf0)==0) ? 0 : 1) |
6266 (((drive_map & 0x0f)==0) ? 0 : 2);
6267 n_drives = (drive_map==0) ? 0 :
6268 ((drive_map==3) ? 2 : 1);
6270 if (!(drive_map & (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
6271 SET_AH(0x01);
6272 SET_DISK_RET_STATUS(0x01);
6273 SET_CF(); /* error occurred */
6274 return;
6277 switch (GET_AH()) {
6279 case 0x00: /* disk controller reset */
6280 BX_DEBUG_INT13_HD("int13_f00\n");
6282 SET_AH(0);
6283 SET_DISK_RET_STATUS(0);
6284 set_diskette_ret_status(0);
6285 set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
6286 set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
6287 CLEAR_CF(); /* successful */
6288 return;
6289 break;
6291 case 0x01: /* read disk status */
6292 BX_DEBUG_INT13_HD("int13_f01\n");
6293 status = read_byte(0x0040, 0x0074);
6294 SET_AH(status);
6295 SET_DISK_RET_STATUS(0);
6296 /* set CF if error status read */
6297 if (status) SET_CF();
6298 else CLEAR_CF();
6299 return;
6300 break;
6302 case 0x04: // verify disk sectors
6303 case 0x02: // read disk sectors
6304 drive = GET_ELDL();
6305 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6307 num_sectors = GET_AL();
6308 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
6309 sector = (GET_CL() & 0x3f);
6310 head = GET_DH();
6313 if (hd_cylinders > 1024) {
6314 if (hd_cylinders <= 2048) {
6315 cylinder <<= 1;
6317 else if (hd_cylinders <= 4096) {
6318 cylinder <<= 2;
6320 else if (hd_cylinders <= 8192) {
6321 cylinder <<= 3;
6323 else { // hd_cylinders <= 16384
6324 cylinder <<= 4;
6327 ax = head / hd_heads;
6328 cyl_mod = ax & 0xff;
6329 head = ax >> 8;
6330 cylinder |= cyl_mod;
6333 if ( (cylinder >= hd_cylinders) ||
6334 (sector > hd_sectors) ||
6335 (head >= hd_heads) ) {
6336 SET_AH(1);
6337 SET_DISK_RET_STATUS(1);
6338 SET_CF(); /* error occurred */
6339 return;
6342 if ( (num_sectors > 128) || (num_sectors == 0) )
6343 BX_PANIC("int13_harddisk(): num_sectors out of range!\n");
6345 if (head > 15)
6346 BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
6348 if ( GET_AH() == 0x04 ) {
6349 SET_AH(0);
6350 SET_DISK_RET_STATUS(0);
6351 CLEAR_CF();
6352 return;
6355 status = inb(0x1f7);
6356 if (status & 0x80) {
6357 BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
6359 outb(0x01f2, num_sectors);
6360 /* activate LBA? (tomv) */
6361 if (hd_heads > 16) {
6362 BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder, head, sector);
6363 outLBA(cylinder,hd_heads,head,hd_sectors,sector,drive);
6365 else {
6366 outb(0x01f3, sector);
6367 outb(0x01f4, cylinder & 0x00ff);
6368 outb(0x01f5, cylinder >> 8);
6369 outb(0x01f6, 0xa0 | ((drive & 0x01)<<4) | (head & 0x0f));
6371 outb(0x01f7, 0x20);
6373 while (1) {
6374 status = inb(0x1f7);
6375 if ( !(status & 0x80) ) break;
6378 if (status & 0x01) {
6379 BX_PANIC("hard drive BIOS:(read/verify) read error\n");
6380 } else if ( !(status & 0x08) ) {
6381 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6382 BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
6385 sector_count = 0;
6386 tempbx = BX;
6388 ASM_START
6389 sti ;; enable higher priority interrupts
6390 ASM_END
6392 while (1) {
6393 ASM_START
6394 ;; store temp bx in real DI register
6395 push bp
6396 mov bp, sp
6397 mov di, _int13_harddisk.tempbx + 2 [bp]
6398 pop bp
6400 ;; adjust if there will be an overrun
6401 cmp di, #0xfe00
6402 jbe i13_f02_no_adjust
6403 i13_f02_adjust:
6404 sub di, #0x0200 ; sub 512 bytes from offset
6405 mov ax, es
6406 add ax, #0x0020 ; add 512 to segment
6407 mov es, ax
6409 i13_f02_no_adjust:
6410 mov cx, #0x0100 ;; counter (256 words = 512b)
6411 mov dx, #0x01f0 ;; AT data read port
6413 rep
6414 insw ;; CX words transfered from port(DX) to ES:[DI]
6416 i13_f02_done:
6417 ;; store real DI register back to temp bx
6418 push bp
6419 mov bp, sp
6420 mov _int13_harddisk.tempbx + 2 [bp], di
6421 pop bp
6422 ASM_END
6424 sector_count++;
6425 num_sectors--;
6426 if (num_sectors == 0) {
6427 status = inb(0x1f7);
6428 if ( (status & 0xc9) != 0x40 )
6429 BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status);
6430 break;
6432 else {
6433 status = inb(0x1f7);
6434 if ( (status & 0xc9) != 0x48 )
6435 BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status);
6436 continue;
6440 SET_AH(0);
6441 SET_DISK_RET_STATUS(0);
6442 SET_AL(sector_count);
6443 CLEAR_CF(); /* successful */
6444 return;
6445 break;
6448 case 0x03: /* write disk sectors */
6449 BX_DEBUG_INT13_HD("int13_f03\n");
6450 drive = GET_ELDL ();
6451 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6453 num_sectors = GET_AL();
6454 cylinder = GET_CH();
6455 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
6456 sector = (GET_CL() & 0x3f);
6457 head = GET_DH();
6459 if (hd_cylinders > 1024) {
6460 if (hd_cylinders <= 2048) {
6461 cylinder <<= 1;
6463 else if (hd_cylinders <= 4096) {
6464 cylinder <<= 2;
6466 else if (hd_cylinders <= 8192) {
6467 cylinder <<= 3;
6469 else { // hd_cylinders <= 16384
6470 cylinder <<= 4;
6473 ax = head / hd_heads;
6474 cyl_mod = ax & 0xff;
6475 head = ax >> 8;
6476 cylinder |= cyl_mod;
6479 if ( (cylinder >= hd_cylinders) ||
6480 (sector > hd_sectors) ||
6481 (head >= hd_heads) ) {
6482 SET_AH( 1);
6483 SET_DISK_RET_STATUS(1);
6484 SET_CF(); /* error occurred */
6485 return;
6488 if ( (num_sectors > 128) || (num_sectors == 0) )
6489 BX_PANIC("int13_harddisk(): num_sectors out of range!\n");
6491 if (head > 15)
6492 BX_PANIC("hard drive BIOS:(read) head > 15\n");
6494 status = inb(0x1f7);
6495 if (status & 0x80) {
6496 BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
6498 // should check for Drive Ready Bit also in status reg
6499 outb(0x01f2, num_sectors);
6501 /* activate LBA? (tomv) */
6502 if (hd_heads > 16) {
6503 BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder, head, sector);
6504 outLBA(cylinder,hd_heads,head,hd_sectors,sector,GET_ELDL());
6506 else {
6507 outb(0x01f3, sector);
6508 outb(0x01f4, cylinder & 0x00ff);
6509 outb(0x01f5, cylinder >> 8);
6510 outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head & 0x0f));
6512 outb(0x01f7, 0x30);
6514 // wait for busy bit to turn off after seeking
6515 while (1) {
6516 status = inb(0x1f7);
6517 if ( !(status & 0x80) ) break;
6520 if ( !(status & 0x08) ) {
6521 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6522 BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
6525 sector_count = 0;
6526 tempbx = BX;
6528 ASM_START
6529 sti ;; enable higher priority interrupts
6530 ASM_END
6532 while (1) {
6533 ASM_START
6534 ;; store temp bx in real SI register
6535 push bp
6536 mov bp, sp
6537 mov si, _int13_harddisk.tempbx + 2 [bp]
6538 pop bp
6540 ;; adjust if there will be an overrun
6541 cmp si, #0xfe00
6542 jbe i13_f03_no_adjust
6543 i13_f03_adjust:
6544 sub si, #0x0200 ; sub 512 bytes from offset
6545 mov ax, es
6546 add ax, #0x0020 ; add 512 to segment
6547 mov es, ax
6549 i13_f03_no_adjust:
6550 mov cx, #0x0100 ;; counter (256 words = 512b)
6551 mov dx, #0x01f0 ;; AT data read port
6553 seg ES
6554 rep
6555 outsw ;; CX words tranfered from ES:[SI] to port(DX)
6557 ;; store real SI register back to temp bx
6558 push bp
6559 mov bp, sp
6560 mov _int13_harddisk.tempbx + 2 [bp], si
6561 pop bp
6562 ASM_END
6564 sector_count++;
6565 num_sectors--;
6566 if (num_sectors == 0) {
6567 status = inb(0x1f7);
6568 if ( (status & 0xe9) != 0x40 )
6569 BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status);
6570 break;
6572 else {
6573 status = inb(0x1f7);
6574 if ( (status & 0xc9) != 0x48 )
6575 BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status);
6576 continue;
6580 SET_AH(0);
6581 SET_DISK_RET_STATUS(0);
6582 SET_AL(sector_count);
6583 CLEAR_CF(); /* successful */
6584 return;
6585 break;
6587 case 0x05: /* format disk track */
6588 BX_DEBUG_INT13_HD("int13_f05\n");
6589 BX_PANIC("format disk track called\n");
6590 /* nop */
6591 SET_AH(0);
6592 SET_DISK_RET_STATUS(0);
6593 CLEAR_CF(); /* successful */
6594 return;
6595 break;
6597 case 0x08: /* read disk drive parameters */
6598 BX_DEBUG_INT13_HD("int13_f08\n");
6600 drive = GET_ELDL ();
6601 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6603 // translate CHS
6604 //
6605 if (hd_cylinders <= 1024) {
6606 // hd_cylinders >>= 0;
6607 // hd_heads <<= 0;
6609 else if (hd_cylinders <= 2048) {
6610 hd_cylinders >>= 1;
6611 hd_heads <<= 1;
6613 else if (hd_cylinders <= 4096) {
6614 hd_cylinders >>= 2;
6615 hd_heads <<= 2;
6617 else if (hd_cylinders <= 8192) {
6618 hd_cylinders >>= 3;
6619 hd_heads <<= 3;
6621 else { // hd_cylinders <= 16384
6622 hd_cylinders >>= 4;
6623 hd_heads <<= 4;
6626 max_cylinder = hd_cylinders - 2; /* 0 based */
6627 SET_AL(0);
6628 SET_CH(max_cylinder & 0xff);
6629 SET_CL(((max_cylinder >> 2) & 0xc0) | (hd_sectors & 0x3f));
6630 SET_DH(hd_heads - 1);
6631 SET_DL(n_drives); /* returns 0, 1, or 2 hard drives */
6632 SET_AH(0);
6633 SET_DISK_RET_STATUS(0);
6634 CLEAR_CF(); /* successful */
6636 return;
6637 break;
6639 case 0x09: /* initialize drive parameters */
6640 BX_DEBUG_INT13_HD("int13_f09\n");
6641 SET_AH(0);
6642 SET_DISK_RET_STATUS(0);
6643 CLEAR_CF(); /* successful */
6644 return;
6645 break;
6647 case 0x0a: /* read disk sectors with ECC */
6648 BX_DEBUG_INT13_HD("int13_f0a\n");
6649 case 0x0b: /* write disk sectors with ECC */
6650 BX_DEBUG_INT13_HD("int13_f0b\n");
6651 BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
6652 return;
6653 break;
6655 case 0x0c: /* seek to specified cylinder */
6656 BX_DEBUG_INT13_HD("int13_f0c\n");
6657 BX_INFO("int13h function 0ch (seek) not implemented!\n");
6658 SET_AH(0);
6659 SET_DISK_RET_STATUS(0);
6660 CLEAR_CF(); /* successful */
6661 return;
6662 break;
6664 case 0x0d: /* alternate disk reset */
6665 BX_DEBUG_INT13_HD("int13_f0d\n");
6666 SET_AH(0);
6667 SET_DISK_RET_STATUS(0);
6668 CLEAR_CF(); /* successful */
6669 return;
6670 break;
6672 case 0x10: /* check drive ready */
6673 BX_DEBUG_INT13_HD("int13_f10\n");
6674 //SET_AH(0);
6675 //SET_DISK_RET_STATUS(0);
6676 //CLEAR_CF(); /* successful */
6677 //return;
6678 //break;
6680 // should look at 40:8E also???
6681 status = inb(0x01f7);
6682 if ( (status & 0xc0) == 0x40 ) {
6683 SET_AH(0);
6684 SET_DISK_RET_STATUS(0);
6685 CLEAR_CF(); // drive ready
6686 return;
6688 else {
6689 SET_AH(0xAA);
6690 SET_DISK_RET_STATUS(0xAA);
6691 SET_CF(); // not ready
6692 return;
6694 break;
6696 case 0x11: /* recalibrate */
6697 BX_DEBUG_INT13_HD("int13_f11\n");
6698 SET_AH(0);
6699 SET_DISK_RET_STATUS(0);
6700 CLEAR_CF(); /* successful */
6701 return;
6702 break;
6704 case 0x14: /* controller internal diagnostic */
6705 BX_DEBUG_INT13_HD("int13_f14\n");
6706 SET_AH(0);
6707 SET_DISK_RET_STATUS(0);
6708 CLEAR_CF(); /* successful */
6709 SET_AL(0);
6710 return;
6711 break;
6713 case 0x15: /* read disk drive size */
6714 drive = GET_ELDL();
6715 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6716 ASM_START
6717 push bp
6718 mov bp, sp
6719 mov al, _int13_harddisk.hd_heads + 2 [bp]
6720 mov ah, _int13_harddisk.hd_sectors + 2 [bp]
6721 mul al, ah ;; ax = heads * sectors
6722 mov bx, _int13_harddisk.hd_cylinders + 2 [bp]
6723 dec bx ;; use (cylinders - 1) ???
6724 mul ax, bx ;; dx:ax = (cylinders -1) * (heads * sectors)
6725 ;; now we need to move the 32bit result dx:ax to what the
6726 ;; BIOS wants which is cx:dx.
6727 ;; and then into CX:DX on the stack
6728 mov _int13_harddisk.CX + 2 [bp], dx
6729 mov _int13_harddisk.DX + 2 [bp], ax
6730 pop bp
6731 ASM_END
6732 SET_AH(3); // hard disk accessible
6733 SET_DISK_RET_STATUS(0); // ??? should this be 0
6734 CLEAR_CF(); // successful
6735 return;
6736 break;
6738 case 0x18: // set media type for format
6739 case 0x41: // IBM/MS
6740 case 0x42: // IBM/MS
6741 case 0x43: // IBM/MS
6742 case 0x44: // IBM/MS
6743 case 0x45: // IBM/MS lock/unlock drive
6744 case 0x46: // IBM/MS eject media
6745 case 0x47: // IBM/MS extended seek
6746 case 0x49: // IBM/MS extended media change
6747 case 0x50: // IBM/MS send packet command
6748 default:
6749 BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
6751 SET_AH(1); // code=invalid function in AH or invalid parameter
6752 SET_DISK_RET_STATUS(1);
6753 SET_CF(); /* unsuccessful */
6754 return;
6755 break;
6759 static char panic_msg_reg12h[] = "HD%d cmos reg 12h not type F\n";
6760 static char panic_msg_reg19h[] = "HD%d cmos reg %02xh not user definable type 47\n";
6762 void
6763 get_hd_geometry(drive, hd_cylinders, hd_heads, hd_sectors)
6764 Bit8u drive;
6765 Bit16u *hd_cylinders;
6766 Bit8u *hd_heads;
6767 Bit8u *hd_sectors;
6769 Bit8u hd_type;
6770 Bit16u ss;
6771 Bit16u cylinders;
6772 Bit8u iobase;
6774 ss = get_SS();
6775 if (drive == 0x80) {
6776 hd_type = inb_cmos(0x12) & 0xf0;
6777 if (hd_type != 0xf0)
6778 BX_INFO(panic_msg_reg12h,0);
6779 hd_type = inb_cmos(0x19); // HD0: extended type
6780 if (hd_type != 47)
6781 BX_INFO(panic_msg_reg19h,0,0x19);
6782 iobase = 0x1b;
6783 } else {
6784 hd_type = inb_cmos(0x12) & 0x0f;
6785 if (hd_type != 0x0f)
6786 BX_INFO(panic_msg_reg12h,1);
6787 hd_type = inb_cmos(0x1a); // HD0: extended type
6788 if (hd_type != 47)
6789 BX_INFO(panic_msg_reg19h,0,0x1a);
6790 iobase = 0x24;
6793 // cylinders
6794 cylinders = inb_cmos(iobase) | (inb_cmos(iobase+1) << 8);
6795 write_word(ss, hd_cylinders, cylinders);
6797 // heads
6798 write_byte(ss, hd_heads, inb_cmos(iobase+2));
6800 // sectors per track
6801 write_byte(ss, hd_sectors, inb_cmos(iobase+8));
6804 #endif //else BX_USE_ATADRV
6807 //////////////////////
6808 // FLOPPY functions //
6809 //////////////////////
6811 bx_bool
6812 floppy_media_known(drive)
6813 Bit16u drive;
6815 Bit8u val8;
6816 Bit16u media_state_offset;
6818 val8 = read_byte(0x0040, 0x003e); // diskette recal status
6819 if (drive)
6820 val8 >>= 1;
6821 val8 &= 0x01;
6822 if (val8 == 0)
6823 return(0);
6825 media_state_offset = 0x0090;
6826 if (drive)
6827 media_state_offset += 1;
6829 val8 = read_byte(0x0040, media_state_offset);
6830 val8 = (val8 >> 4) & 0x01;
6831 if (val8 == 0)
6832 return(0);
6834 // check pass, return KNOWN
6835 return(1);
6838 bx_bool
6839 floppy_media_sense(drive)
6840 Bit16u drive;
6842 bx_bool retval;
6843 Bit16u media_state_offset;
6844 Bit8u drive_type, config_data, media_state;
6846 if (floppy_drive_recal(drive) == 0) {
6847 return(0);
6850 // for now cheat and get drive type from CMOS,
6851 // assume media is same as drive type
6853 // ** config_data **
6854 // Bitfields for diskette media control:
6855 // Bit(s) Description (Table M0028)
6856 // 7-6 last data rate set by controller
6857 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6858 // 5-4 last diskette drive step rate selected
6859 // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
6860 // 3-2 {data rate at start of operation}
6861 // 1-0 reserved
6863 // ** media_state **
6864 // Bitfields for diskette drive media state:
6865 // Bit(s) Description (Table M0030)
6866 // 7-6 data rate
6867 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6868 // 5 double stepping required (e.g. 360kB in 1.2MB)
6869 // 4 media type established
6870 // 3 drive capable of supporting 4MB media
6871 // 2-0 on exit from BIOS, contains
6872 // 000 trying 360kB in 360kB
6873 // 001 trying 360kB in 1.2MB
6874 // 010 trying 1.2MB in 1.2MB
6875 // 011 360kB in 360kB established
6876 // 100 360kB in 1.2MB established
6877 // 101 1.2MB in 1.2MB established
6878 // 110 reserved
6879 // 111 all other formats/drives
6881 drive_type = inb_cmos(0x10);
6882 if (drive == 0)
6883 drive_type >>= 4;
6884 else
6885 drive_type &= 0x0f;
6886 if ( drive_type == 1 ) {
6887 // 360K 5.25" drive
6888 config_data = 0x00; // 0000 0000
6889 media_state = 0x25; // 0010 0101
6890 retval = 1;
6892 else if ( drive_type == 2 ) {
6893 // 1.2 MB 5.25" drive
6894 config_data = 0x00; // 0000 0000
6895 media_state = 0x25; // 0010 0101 // need double stepping??? (bit 5)
6896 retval = 1;
6898 else if ( drive_type == 3 ) {
6899 // 720K 3.5" drive
6900 config_data = 0x00; // 0000 0000 ???
6901 media_state = 0x17; // 0001 0111
6902 retval = 1;
6904 else if ( drive_type == 4 ) {
6905 // 1.44 MB 3.5" drive
6906 config_data = 0x00; // 0000 0000
6907 media_state = 0x17; // 0001 0111
6908 retval = 1;
6910 else if ( drive_type == 5 ) {
6911 // 2.88 MB 3.5" drive
6912 config_data = 0xCC; // 1100 1100
6913 media_state = 0xD7; // 1101 0111
6914 retval = 1;
6916 //
6917 // Extended floppy size uses special cmos setting
6918 else if ( drive_type == 6 ) {
6919 // 160k 5.25" drive
6920 config_data = 0x00; // 0000 0000
6921 media_state = 0x27; // 0010 0111
6922 retval = 1;
6924 else if ( drive_type == 7 ) {
6925 // 180k 5.25" drive
6926 config_data = 0x00; // 0000 0000
6927 media_state = 0x27; // 0010 0111
6928 retval = 1;
6930 else if ( drive_type == 8 ) {
6931 // 320k 5.25" drive
6932 config_data = 0x00; // 0000 0000
6933 media_state = 0x27; // 0010 0111
6934 retval = 1;
6937 else {
6938 // not recognized
6939 config_data = 0x00; // 0000 0000
6940 media_state = 0x00; // 0000 0000
6941 retval = 0;
6944 if (drive == 0)
6945 media_state_offset = 0x90;
6946 else
6947 media_state_offset = 0x91;
6948 write_byte(0x0040, 0x008B, config_data);
6949 write_byte(0x0040, media_state_offset, media_state);
6951 return(retval);
6954 bx_bool
6955 floppy_drive_recal(drive)
6956 Bit16u drive;
6958 Bit8u val8, dor;
6959 Bit16u curr_cyl_offset;
6961 // set 40:3e bit 7 to 0
6962 val8 = read_byte(0x0000, 0x043e);
6963 val8 &= 0x7f;
6964 write_byte(0x0000, 0x043e, val8);
6966 // turn on motor of selected drive, DMA & int enabled, normal operation
6967 if (drive)
6968 dor = 0x20;
6969 else
6970 dor = 0x10;
6971 dor |= 0x0c;
6972 dor |= drive;
6973 outb(0x03f2, dor);
6975 // reset the disk motor timeout value of INT 08
6976 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
6978 // check port 3f4 for drive readiness
6979 val8 = inb(0x3f4);
6980 if ( (val8 & 0xf0) != 0x80 )
6981 BX_PANIC("floppy recal:f07: ctrl not ready\n");
6983 // send Recalibrate command (2 bytes) to controller
6984 outb(0x03f5, 0x07); // 07: Recalibrate
6985 outb(0x03f5, drive); // 0=drive0, 1=drive1
6987 // turn on interrupts
6988 ASM_START
6989 sti
6990 ASM_END
6992 // wait on 40:3e bit 7 to become 1
6993 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6994 while ( val8 == 0 ) {
6995 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6998 val8 = 0; // separate asm from while() loop
6999 // turn off interrupts
7000 ASM_START
7001 cli
7002 ASM_END
7004 // set 40:3e bit 7 to 0, and calibrated bit
7005 val8 = read_byte(0x0000, 0x043e);
7006 val8 &= 0x7f;
7007 if (drive) {
7008 val8 |= 0x02; // Drive 1 calibrated
7009 curr_cyl_offset = 0x0095;
7011 else {
7012 val8 |= 0x01; // Drive 0 calibrated
7013 curr_cyl_offset = 0x0094;
7015 write_byte(0x0040, 0x003e, val8);
7016 write_byte(0x0040, curr_cyl_offset, 0); // current cylinder is 0
7018 return(1);
7023 bx_bool
7024 floppy_drive_exists(drive)
7025 Bit16u drive;
7027 Bit8u drive_type;
7029 // check CMOS to see if drive exists
7030 drive_type = inb_cmos(0x10);
7031 if (drive == 0)
7032 drive_type >>= 4;
7033 else
7034 drive_type &= 0x0f;
7035 if ( drive_type == 0 )
7036 return(0);
7037 else
7038 return(1);
7041 #if BX_SUPPORT_FLOPPY
7042 void
7043 int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
7044 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
7046 Bit8u drive, num_sectors, track, sector, head, status;
7047 Bit16u base_address, base_count, base_es;
7048 Bit8u page, mode_register, val8, dor;
7049 Bit8u return_status[7];
7050 Bit8u drive_type, num_floppies, ah;
7051 Bit16u es, last_addr;
7053 BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
7054 // BX_DEBUG_INT13_FL("int13_diskette: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), get_DS(), ES, DI, SI);
7056 ah = GET_AH();
7058 switch ( ah ) {
7059 case 0x00: // diskette controller reset
7060 BX_DEBUG_INT13_FL("floppy f00\n");
7061 drive = GET_ELDL();
7062 if (drive > 1) {
7063 SET_AH(1); // invalid param
7064 set_diskette_ret_status(1);
7065 SET_CF();
7066 return;
7068 drive_type = inb_cmos(0x10);
7070 if (drive == 0)
7071 drive_type >>= 4;
7072 else
7073 drive_type &= 0x0f;
7074 if (drive_type == 0) {
7075 SET_AH(0x80); // drive not responding
7076 set_diskette_ret_status(0x80);
7077 SET_CF();
7078 return;
7080 SET_AH(0);
7081 set_diskette_ret_status(0);
7082 CLEAR_CF(); // successful
7083 set_diskette_current_cyl(drive, 0); // current cylinder
7084 return;
7086 case 0x01: // Read Diskette Status
7087 CLEAR_CF();
7088 val8 = read_byte(0x0000, 0x0441);
7089 SET_AH(val8);
7090 if (val8) {
7091 SET_CF();
7093 return;
7095 case 0x02: // Read Diskette Sectors
7096 case 0x03: // Write Diskette Sectors
7097 case 0x04: // Verify Diskette Sectors
7098 num_sectors = GET_AL();
7099 track = GET_CH();
7100 sector = GET_CL();
7101 head = GET_DH();
7102 drive = GET_ELDL();
7104 if ( (drive > 1) || (head > 1) ||
7105 (num_sectors == 0) || (num_sectors > 72) ) {
7106 BX_INFO("floppy: drive>1 || head>1 ...\n");
7107 SET_AH(1);
7108 set_diskette_ret_status(1);
7109 SET_AL(0); // no sectors read
7110 SET_CF(); // error occurred
7111 return;
7114 // see if drive exists
7115 if (floppy_drive_exists(drive) == 0) {
7116 SET_AH(0x80); // not responding
7117 set_diskette_ret_status(0x80);
7118 SET_AL(0); // no sectors read
7119 SET_CF(); // error occurred
7120 return;
7123 // see if media in drive, and type is known
7124 if (floppy_media_known(drive) == 0) {
7125 if (floppy_media_sense(drive) == 0) {
7126 SET_AH(0x0C); // Media type not found
7127 set_diskette_ret_status(0x0C);
7128 SET_AL(0); // no sectors read
7129 SET_CF(); // error occurred
7130 return;
7134 if (ah == 0x02) {
7135 // Read Diskette Sectors
7137 //-----------------------------------
7138 // set up DMA controller for transfer
7139 //-----------------------------------
7141 // es:bx = pointer to where to place information from diskette
7142 // port 04: DMA-1 base and current address, channel 2
7143 // port 05: DMA-1 base and current count, channel 2
7144 page = (ES >> 12); // upper 4 bits
7145 base_es = (ES << 4); // lower 16bits contributed by ES
7146 base_address = base_es + BX; // lower 16 bits of address
7147 // contributed by ES:BX
7148 if ( base_address < base_es ) {
7149 // in case of carry, adjust page by 1
7150 page++;
7152 base_count = (num_sectors * 512) - 1;
7154 // check for 64K boundary overrun
7155 last_addr = base_address + base_count;
7156 if (last_addr < base_address) {
7157 SET_AH(0x09);
7158 set_diskette_ret_status(0x09);
7159 SET_AL(0); // no sectors read
7160 SET_CF(); // error occurred
7161 return;
7164 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7165 outb(0x000a, 0x06);
7167 BX_DEBUG_INT13_FL("clear flip-flop\n");
7168 outb(0x000c, 0x00); // clear flip-flop
7169 outb(0x0004, base_address);
7170 outb(0x0004, base_address>>8);
7171 BX_DEBUG_INT13_FL("clear flip-flop\n");
7172 outb(0x000c, 0x00); // clear flip-flop
7173 outb(0x0005, base_count);
7174 outb(0x0005, base_count>>8);
7176 // port 0b: DMA-1 Mode Register
7177 mode_register = 0x46; // single mode, increment, autoinit disable,
7178 // transfer type=write, channel 2
7179 BX_DEBUG_INT13_FL("setting mode register\n");
7180 outb(0x000b, mode_register);
7182 BX_DEBUG_INT13_FL("setting page register\n");
7183 // port 81: DMA-1 Page Register, channel 2
7184 outb(0x0081, page);
7186 BX_DEBUG_INT13_FL("unmask chan 2\n");
7187 outb(0x000a, 0x02); // unmask channel 2
7189 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7190 outb(0x000a, 0x02);
7192 //--------------------------------------
7193 // set up floppy controller for transfer
7194 //--------------------------------------
7196 // set 40:3e bit 7 to 0
7197 val8 = read_byte(0x0000, 0x043e);
7198 val8 &= 0x7f;
7199 write_byte(0x0000, 0x043e, val8);
7201 // turn on motor of selected drive, DMA & int enabled, normal operation
7202 if (drive)
7203 dor = 0x20;
7204 else
7205 dor = 0x10;
7206 dor |= 0x0c;
7207 dor |= drive;
7208 outb(0x03f2, dor);
7210 // reset the disk motor timeout value of INT 08
7211 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
7213 // check port 3f4 for drive readiness
7214 val8 = inb(0x3f4);
7215 if ( (val8 & 0xf0) != 0x80 )
7216 BX_PANIC("int13_diskette:f02: ctrl not ready\n");
7218 // send read-normal-data command (9 bytes) to controller
7219 outb(0x03f5, 0xe6); // e6: read normal data
7220 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7221 outb(0x03f5, track);
7222 outb(0x03f5, head);
7223 outb(0x03f5, sector);
7224 outb(0x03f5, 2); // 512 byte sector size
7225 outb(0x03f5, 0); // last sector number possible on track
7226 outb(0x03f5, 0); // Gap length
7227 outb(0x03f5, 0xff); // Gap length
7229 // turn on interrupts
7230 ASM_START
7231 sti
7232 ASM_END
7234 // wait on 40:3e bit 7 to become 1
7235 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7236 while ( val8 == 0 ) {
7237 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7240 val8 = 0; // separate asm from while() loop
7241 // turn off interrupts
7242 ASM_START
7243 cli
7244 ASM_END
7246 // set 40:3e bit 7 to 0
7247 val8 = read_byte(0x0000, 0x043e);
7248 val8 &= 0x7f;
7249 write_byte(0x0000, 0x043e, val8);
7251 // check port 3f4 for accessibility to status bytes
7252 val8 = inb(0x3f4);
7253 if ( (val8 & 0xc0) != 0xc0 )
7254 BX_PANIC("int13_diskette: ctrl not ready\n");
7256 // read 7 return status bytes from controller
7257 // using loop index broken, have to unroll...
7258 return_status[0] = inb(0x3f5);
7259 return_status[1] = inb(0x3f5);
7260 return_status[2] = inb(0x3f5);
7261 return_status[3] = inb(0x3f5);
7262 return_status[4] = inb(0x3f5);
7263 return_status[5] = inb(0x3f5);
7264 return_status[6] = inb(0x3f5);
7265 // record in BIOS Data Area
7266 write_byte(0x0040, 0x0042, return_status[0]);
7267 write_byte(0x0040, 0x0043, return_status[1]);
7268 write_byte(0x0040, 0x0044, return_status[2]);
7269 write_byte(0x0040, 0x0045, return_status[3]);
7270 write_byte(0x0040, 0x0046, return_status[4]);
7271 write_byte(0x0040, 0x0047, return_status[5]);
7272 write_byte(0x0040, 0x0048, return_status[6]);
7274 if ( (return_status[0] & 0xc0) != 0 ) {
7275 SET_AH(0x20);
7276 set_diskette_ret_status(0x20);
7277 SET_AL(0); // no sectors read
7278 SET_CF(); // error occurred
7279 return;
7282 // ??? should track be new val from return_status[3] ?
7283 set_diskette_current_cyl(drive, track);
7284 // AL = number of sectors read (same value as passed)
7285 SET_AH(0x00); // success
7286 CLEAR_CF(); // success
7287 return;
7289 else if (ah == 0x03) {
7290 // Write Diskette Sectors
7292 //-----------------------------------
7293 // set up DMA controller for transfer
7294 //-----------------------------------
7296 // es:bx = pointer to where to place information from diskette
7297 // port 04: DMA-1 base and current address, channel 2
7298 // port 05: DMA-1 base and current count, channel 2
7299 page = (ES >> 12); // upper 4 bits
7300 base_es = (ES << 4); // lower 16bits contributed by ES
7301 base_address = base_es + BX; // lower 16 bits of address
7302 // contributed by ES:BX
7303 if ( base_address < base_es ) {
7304 // in case of carry, adjust page by 1
7305 page++;
7307 base_count = (num_sectors * 512) - 1;
7309 // check for 64K boundary overrun
7310 last_addr = base_address + base_count;
7311 if (last_addr < base_address) {
7312 SET_AH(0x09);
7313 set_diskette_ret_status(0x09);
7314 SET_AL(0); // no sectors read
7315 SET_CF(); // error occurred
7316 return;
7319 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7320 outb(0x000a, 0x06);
7322 outb(0x000c, 0x00); // clear flip-flop
7323 outb(0x0004, base_address);
7324 outb(0x0004, base_address>>8);
7325 outb(0x000c, 0x00); // clear flip-flop
7326 outb(0x0005, base_count);
7327 outb(0x0005, base_count>>8);
7329 // port 0b: DMA-1 Mode Register
7330 mode_register = 0x4a; // single mode, increment, autoinit disable,
7331 // transfer type=read, channel 2
7332 outb(0x000b, mode_register);
7334 // port 81: DMA-1 Page Register, channel 2
7335 outb(0x0081, page);
7337 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7338 outb(0x000a, 0x02);
7340 //--------------------------------------
7341 // set up floppy controller for transfer
7342 //--------------------------------------
7344 // set 40:3e bit 7 to 0
7345 val8 = read_byte(0x0000, 0x043e);
7346 val8 &= 0x7f;
7347 write_byte(0x0000, 0x043e, val8);
7349 // turn on motor of selected drive, DMA & int enabled, normal operation
7350 if (drive)
7351 dor = 0x20;
7352 else
7353 dor = 0x10;
7354 dor |= 0x0c;
7355 dor |= drive;
7356 outb(0x03f2, dor);
7358 // reset the disk motor timeout value of INT 08
7359 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
7361 // check port 3f4 for drive readiness
7362 val8 = inb(0x3f4);
7363 if ( (val8 & 0xf0) != 0x80 )
7364 BX_PANIC("int13_diskette:f03: ctrl not ready\n");
7366 // send read-normal-data command (9 bytes) to controller
7367 outb(0x03f5, 0xc5); // c5: write normal data
7368 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7369 outb(0x03f5, track);
7370 outb(0x03f5, head);
7371 outb(0x03f5, sector);
7372 outb(0x03f5, 2); // 512 byte sector size
7373 outb(0x03f5, 0); // last sector number possible on track
7374 outb(0x03f5, 0); // Gap length
7375 outb(0x03f5, 0xff); // Gap length
7377 // turn on interrupts
7378 ASM_START
7379 sti
7380 ASM_END
7382 // wait on 40:3e bit 7 to become 1
7383 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7384 while ( val8 == 0 ) {
7385 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7388 val8 = 0; // separate asm from while() loop
7389 // turn off interrupts
7390 ASM_START
7391 cli
7392 ASM_END
7394 // set 40:3e bit 7 to 0
7395 val8 = read_byte(0x0000, 0x043e);
7396 val8 &= 0x7f;
7397 write_byte(0x0000, 0x043e, val8);
7399 // check port 3f4 for accessibility to status bytes
7400 val8 = inb(0x3f4);
7401 if ( (val8 & 0xc0) != 0xc0 )
7402 BX_PANIC("int13_diskette: ctrl not ready\n");
7404 // read 7 return status bytes from controller
7405 // using loop index broken, have to unroll...
7406 return_status[0] = inb(0x3f5);
7407 return_status[1] = inb(0x3f5);
7408 return_status[2] = inb(0x3f5);
7409 return_status[3] = inb(0x3f5);
7410 return_status[4] = inb(0x3f5);
7411 return_status[5] = inb(0x3f5);
7412 return_status[6] = inb(0x3f5);
7413 // record in BIOS Data Area
7414 write_byte(0x0040, 0x0042, return_status[0]);
7415 write_byte(0x0040, 0x0043, return_status[1]);
7416 write_byte(0x0040, 0x0044, return_status[2]);
7417 write_byte(0x0040, 0x0045, return_status[3]);
7418 write_byte(0x0040, 0x0046, return_status[4]);
7419 write_byte(0x0040, 0x0047, return_status[5]);
7420 write_byte(0x0040, 0x0048, return_status[6]);
7422 if ( (return_status[0] & 0xc0) != 0 ) {
7423 if ( (return_status[1] & 0x02) != 0 ) {
7424 // diskette not writable.
7425 // AH=status code=0x03 (tried to write on write-protected disk)
7426 // AL=number of sectors written=0
7427 AX = 0x0300;
7428 SET_CF();
7429 return;
7430 } else {
7431 BX_PANIC("int13_diskette_function: read error\n");
7435 // ??? should track be new val from return_status[3] ?
7436 set_diskette_current_cyl(drive, track);
7437 // AL = number of sectors read (same value as passed)
7438 SET_AH(0x00); // success
7439 CLEAR_CF(); // success
7440 return;
7442 else { // if (ah == 0x04)
7443 // Verify Diskette Sectors
7445 // ??? should track be new val from return_status[3] ?
7446 set_diskette_current_cyl(drive, track);
7447 // AL = number of sectors verified (same value as passed)
7448 CLEAR_CF(); // success
7449 SET_AH(0x00); // success
7450 return;
7454 case 0x05: // format diskette track
7455 BX_DEBUG_INT13_FL("floppy f05\n");
7457 num_sectors = GET_AL();
7458 track = GET_CH();
7459 head = GET_DH();
7460 drive = GET_ELDL();
7462 if ((drive > 1) || (head > 1) || (track > 79) ||
7463 (num_sectors == 0) || (num_sectors > 18)) {
7464 SET_AH(1);
7465 set_diskette_ret_status(1);
7466 SET_CF(); // error occurred
7469 // see if drive exists
7470 if (floppy_drive_exists(drive) == 0) {
7471 SET_AH(0x80); // drive not responding
7472 set_diskette_ret_status(0x80);
7473 SET_CF(); // error occurred
7474 return;
7477 // see if media in drive, and type is known
7478 if (floppy_media_known(drive) == 0) {
7479 if (floppy_media_sense(drive) == 0) {
7480 SET_AH(0x0C); // Media type not found
7481 set_diskette_ret_status(0x0C);
7482 SET_AL(0); // no sectors read
7483 SET_CF(); // error occurred
7484 return;
7488 // set up DMA controller for transfer
7489 page = (ES >> 12); // upper 4 bits
7490 base_es = (ES << 4); // lower 16bits contributed by ES
7491 base_address = base_es + BX; // lower 16 bits of address
7492 // contributed by ES:BX
7493 if ( base_address < base_es ) {
7494 // in case of carry, adjust page by 1
7495 page++;
7497 base_count = (num_sectors * 4) - 1;
7499 // check for 64K boundary overrun
7500 last_addr = base_address + base_count;
7501 if (last_addr < base_address) {
7502 SET_AH(0x09);
7503 set_diskette_ret_status(0x09);
7504 SET_AL(0); // no sectors read
7505 SET_CF(); // error occurred
7506 return;
7509 outb(0x000a, 0x06);
7510 outb(0x000c, 0x00); // clear flip-flop
7511 outb(0x0004, base_address);
7512 outb(0x0004, base_address>>8);
7513 outb(0x000c, 0x00); // clear flip-flop
7514 outb(0x0005, base_count);
7515 outb(0x0005, base_count>>8);
7516 mode_register = 0x4a; // single mode, increment, autoinit disable,
7517 // transfer type=read, channel 2
7518 outb(0x000b, mode_register);
7519 // port 81: DMA-1 Page Register, channel 2
7520 outb(0x0081, page);
7521 outb(0x000a, 0x02);
7523 // set up floppy controller for transfer
7524 val8 = read_byte(0x0000, 0x043e);
7525 val8 &= 0x7f;
7526 write_byte(0x0000, 0x043e, val8);
7527 // turn on motor of selected drive, DMA & int enabled, normal operation
7528 if (drive)
7529 dor = 0x20;
7530 else
7531 dor = 0x10;
7532 dor |= 0x0c;
7533 dor |= drive;
7534 outb(0x03f2, dor);
7536 // reset the disk motor timeout value of INT 08
7537 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
7539 // check port 3f4 for drive readiness
7540 val8 = inb(0x3f4);
7541 if ( (val8 & 0xf0) != 0x80 )
7542 BX_PANIC("int13_diskette:f05: ctrl not ready\n");
7544 // send read-normal-data command (6 bytes) to controller
7545 outb(0x03f5, 0x4d); // 4d: format track
7546 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7547 outb(0x03f5, 2); // 512 byte sector size
7548 outb(0x03f5, num_sectors); // number of sectors per track
7549 outb(0x03f5, 0); // Gap length
7550 outb(0x03f5, 0xf6); // Fill byte
7551 // turn on interrupts
7552 ASM_START
7553 sti
7554 ASM_END
7555 // wait on 40:3e bit 7 to become 1
7556 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7557 while ( val8 == 0 ) {
7558 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7560 val8 = 0; // separate asm from while() loop
7561 // turn off interrupts
7562 ASM_START
7563 cli
7564 ASM_END
7565 // set 40:3e bit 7 to 0
7566 val8 = read_byte(0x0000, 0x043e);
7567 val8 &= 0x7f;
7568 write_byte(0x0000, 0x043e, val8);
7569 // check port 3f4 for accessibility to status bytes
7570 val8 = inb(0x3f4);
7571 if ( (val8 & 0xc0) != 0xc0 )
7572 BX_PANIC("int13_diskette: ctrl not ready\n");
7574 // read 7 return status bytes from controller
7575 // using loop index broken, have to unroll...
7576 return_status[0] = inb(0x3f5);
7577 return_status[1] = inb(0x3f5);
7578 return_status[2] = inb(0x3f5);
7579 return_status[3] = inb(0x3f5);
7580 return_status[4] = inb(0x3f5);
7581 return_status[5] = inb(0x3f5);
7582 return_status[6] = inb(0x3f5);
7583 // record in BIOS Data Area
7584 write_byte(0x0040, 0x0042, return_status[0]);
7585 write_byte(0x0040, 0x0043, return_status[1]);
7586 write_byte(0x0040, 0x0044, return_status[2]);
7587 write_byte(0x0040, 0x0045, return_status[3]);
7588 write_byte(0x0040, 0x0046, return_status[4]);
7589 write_byte(0x0040, 0x0047, return_status[5]);
7590 write_byte(0x0040, 0x0048, return_status[6]);
7592 if ( (return_status[0] & 0xc0) != 0 ) {
7593 if ( (return_status[1] & 0x02) != 0 ) {
7594 // diskette not writable.
7595 // AH=status code=0x03 (tried to write on write-protected disk)
7596 // AL=number of sectors written=0
7597 AX = 0x0300;
7598 SET_CF();
7599 return;
7600 } else {
7601 BX_PANIC("int13_diskette_function: write error\n");
7605 SET_AH(0);
7606 set_diskette_ret_status(0);
7607 set_diskette_current_cyl(drive, 0);
7608 CLEAR_CF(); // successful
7609 return;
7612 case 0x08: // read diskette drive parameters
7613 BX_DEBUG_INT13_FL("floppy f08\n");
7614 drive = GET_ELDL();
7616 if (drive > 1) {
7617 AX = 0;
7618 BX = 0;
7619 CX = 0;
7620 DX = 0;
7621 ES = 0;
7622 DI = 0;
7623 SET_DL(num_floppies);
7624 SET_CF();
7625 return;
7628 drive_type = inb_cmos(0x10);
7629 num_floppies = 0;
7630 if (drive_type & 0xf0)
7631 num_floppies++;
7632 if (drive_type & 0x0f)
7633 num_floppies++;
7635 if (drive == 0)
7636 drive_type >>= 4;
7637 else
7638 drive_type &= 0x0f;
7640 SET_BH(0);
7641 SET_BL(drive_type);
7642 SET_AH(0);
7643 SET_AL(0);
7644 SET_DL(num_floppies);
7646 switch (drive_type) {
7647 case 0: // none
7648 CX = 0;
7649 SET_DH(0); // max head #
7650 break;
7652 case 1: // 360KB, 5.25"
7653 CX = 0x2709; // 40 tracks, 9 sectors
7654 SET_DH(1); // max head #
7655 break;
7657 case 2: // 1.2MB, 5.25"
7658 CX = 0x4f0f; // 80 tracks, 15 sectors
7659 SET_DH(1); // max head #
7660 break;
7662 case 3: // 720KB, 3.5"
7663 CX = 0x4f09; // 80 tracks, 9 sectors
7664 SET_DH(1); // max head #
7665 break;
7667 case 4: // 1.44MB, 3.5"
7668 CX = 0x4f12; // 80 tracks, 18 sectors
7669 SET_DH(1); // max head #
7670 break;
7672 case 5: // 2.88MB, 3.5"
7673 CX = 0x4f24; // 80 tracks, 36 sectors
7674 SET_DH(1); // max head #
7675 break;
7677 case 6: // 160k, 5.25"
7678 CX = 0x2708; // 40 tracks, 8 sectors
7679 SET_DH(0); // max head #
7680 break;
7682 case 7: // 180k, 5.25"
7683 CX = 0x2709; // 40 tracks, 9 sectors
7684 SET_DH(0); // max head #
7685 break;
7687 case 8: // 320k, 5.25"
7688 CX = 0x2708; // 40 tracks, 8 sectors
7689 SET_DH(1); // max head #
7690 break;
7692 default: // ?
7693 BX_PANIC("floppy: int13: bad floppy type\n");
7696 /* set es & di to point to 11 byte diskette param table in ROM */
7697 ASM_START
7698 push bp
7699 mov bp, sp
7700 mov ax, #diskette_param_table2
7701 mov _int13_diskette_function.DI+2[bp], ax
7702 mov _int13_diskette_function.ES+2[bp], cs
7703 pop bp
7704 ASM_END
7705 CLEAR_CF(); // success
7706 /* disk status not changed upon success */
7707 return;
7710 case 0x15: // read diskette drive type
7711 BX_DEBUG_INT13_FL("floppy f15\n");
7712 drive = GET_ELDL();
7713 if (drive > 1) {
7714 SET_AH(0); // only 2 drives supported
7715 // set_diskette_ret_status here ???
7716 SET_CF();
7717 return;
7719 drive_type = inb_cmos(0x10);
7721 if (drive == 0)
7722 drive_type >>= 4;
7723 else
7724 drive_type &= 0x0f;
7725 CLEAR_CF(); // successful, not present
7726 if (drive_type==0) {
7727 SET_AH(0); // drive not present
7729 else {
7730 SET_AH(1); // drive present, does not support change line
7733 return;
7735 case 0x16: // get diskette change line status
7736 BX_DEBUG_INT13_FL("floppy f16\n");
7737 drive = GET_ELDL();
7738 if (drive > 1) {
7739 SET_AH(0x01); // invalid drive
7740 set_diskette_ret_status(0x01);
7741 SET_CF();
7742 return;
7745 SET_AH(0x06); // change line not supported
7746 set_diskette_ret_status(0x06);
7747 SET_CF();
7748 return;
7750 case 0x17: // set diskette type for format(old)
7751 BX_DEBUG_INT13_FL("floppy f17\n");
7752 /* not used for 1.44M floppies */
7753 SET_AH(0x01); // not supported
7754 set_diskette_ret_status(1); /* not supported */
7755 SET_CF();
7756 return;
7758 case 0x18: // set diskette type for format(new)
7759 BX_DEBUG_INT13_FL("floppy f18\n");
7760 SET_AH(0x01); // do later
7761 set_diskette_ret_status(1);
7762 SET_CF();
7763 return;
7765 default:
7766 BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
7768 // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
7769 SET_AH(0x01); // ???
7770 set_diskette_ret_status(1);
7771 SET_CF();
7772 return;
7773 // }
7776 #else // #if BX_SUPPORT_FLOPPY
7777 void
7778 int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
7779 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
7781 Bit8u val8;
7783 switch ( GET_AH() ) {
7785 case 0x01: // Read Diskette Status
7786 CLEAR_CF();
7787 val8 = read_byte(0x0000, 0x0441);
7788 SET_AH(val8);
7789 if (val8) {
7790 SET_CF();
7792 return;
7794 default:
7795 SET_CF();
7796 write_byte(0x0000, 0x0441, 0x01);
7797 SET_AH(0x01);
7800 #endif // #if BX_SUPPORT_FLOPPY
7802 void
7803 set_diskette_ret_status(value)
7804 Bit8u value;
7806 write_byte(0x0040, 0x0041, value);
7809 void
7810 set_diskette_current_cyl(drive, cyl)
7811 Bit8u drive;
7812 Bit8u cyl;
7814 if (drive > 1)
7815 BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
7816 write_byte(0x0040, 0x0094+drive, cyl);
7819 void
7820 determine_floppy_media(drive)
7821 Bit16u drive;
7823 #if 0
7824 Bit8u val8, DOR, ctrl_info;
7826 ctrl_info = read_byte(0x0040, 0x008F);
7827 if (drive==1)
7828 ctrl_info >>= 4;
7829 else
7830 ctrl_info &= 0x0f;
7832 #if 0
7833 if (drive == 0) {
7834 DOR = 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
7836 else {
7837 DOR = 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
7839 #endif
7841 if ( (ctrl_info & 0x04) != 0x04 ) {
7842 // Drive not determined means no drive exists, done.
7843 return;
7846 #if 0
7847 // check Main Status Register for readiness
7848 val8 = inb(0x03f4) & 0x80; // Main Status Register
7849 if (val8 != 0x80)
7850 BX_PANIC("d_f_m: MRQ bit not set\n");
7852 // change line
7854 // existing BDA values
7856 // turn on drive motor
7857 outb(0x03f2, DOR); // Digital Output Register
7858 //
7859 #endif
7860 BX_PANIC("d_f_m: OK so far\n");
7861 #endif
7864 void
7865 int17_function(regs, ds, iret_addr)
7866 pusha_regs_t regs; // regs pushed from PUSHA instruction
7867 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
7868 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
7870 Bit16u addr,timeout;
7871 Bit8u val8;
7873 ASM_START
7874 sti
7875 ASM_END
7877 addr = read_word(0x0040, (regs.u.r16.dx << 1) + 8);
7878 if ((regs.u.r8.ah < 3) && (regs.u.r16.dx < 3) && (addr > 0)) {
7879 timeout = read_byte(0x0040, 0x0078 + regs.u.r16.dx) << 8;
7880 if (regs.u.r8.ah == 0) {
7881 outb(addr, regs.u.r8.al);
7882 val8 = inb(addr+2);
7883 outb(addr+2, val8 | 0x01); // send strobe
7884 ASM_START
7885 nop
7886 ASM_END
7887 outb(addr+2, val8 & ~0x01);
7888 while (((inb(addr+1) & 0x40) == 0x40) && (timeout)) {
7889 timeout--;
7892 if (regs.u.r8.ah == 1) {
7893 val8 = inb(addr+2);
7894 outb(addr+2, val8 & ~0x04); // send init
7895 ASM_START
7896 nop
7897 ASM_END
7898 outb(addr+2, val8 | 0x04);
7900 val8 = inb(addr+1);
7901 regs.u.r8.ah = (val8 ^ 0x48);
7902 if (!timeout) regs.u.r8.ah |= 0x01;
7903 ClearCF(iret_addr.flags);
7904 } else {
7905 SetCF(iret_addr.flags); // Unsupported
7909 void
7910 int18_function(seq_nr)
7911 Bit16u seq_nr;
7913 Bit16u ebda_seg=read_word(0x0040,0x000E);
7914 Bit16u bootdev;
7915 Bit8u bootdrv;
7916 Bit8u bootchk;
7917 Bit16u bootseg;
7918 Bit16u bootip;
7919 Bit16u status;
7921 struct ipl_entry e;
7923 // if BX_ELTORITO_BOOT is not defined, old behavior
7924 // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
7925 // in preparation for the intial INT 13h (0=floppy A:, 0x80=C:)
7926 // 0: system boot sequence, first drive C: then A:
7927 // 1: system boot sequence, first drive A: then C:
7928 // else BX_ELTORITO_BOOT is defined
7929 // CMOS regs 0x3D and 0x38 contain the boot sequence:
7930 // CMOS reg 0x3D & 0x0f : 1st boot device
7931 // CMOS reg 0x3D & 0xf0 : 2nd boot device
7932 // CMOS reg 0x38 & 0xf0 : 3rd boot device
7933 // boot device codes:
7934 // 0x00 : not defined
7935 // 0x01 : first floppy
7936 // 0x02 : first harddrive
7937 // 0x03 : first cdrom
7938 // 0x04 - 0x0f : PnP expansion ROMs (e.g. Etherboot)
7939 // else : boot failure
7941 // Get the boot sequence
7942 #if BX_ELTORITO_BOOT
7943 bootdev = inb_cmos(0x3d);
7944 bootdev |= ((inb_cmos(0x38) & 0xf0) << 4);
7945 bootdev >>= 4 * seq_nr;
7946 bootdev &= 0xf;
7947 if (bootdev == 0) BX_PANIC("No bootable device.\n");
7949 /* Translate from CMOS runes to an IPL table offset by subtracting 1 */
7950 bootdev -= 1;
7951 #else
7952 if (seq_nr ==2) BX_PANIC("No more boot devices.");
7953 if (!!(inb_cmos(0x2d) & 0x20) ^ (seq_nr == 1))
7954 /* Boot from floppy if the bit is set or it's the second boot */
7955 bootdev = 0x00;
7956 else
7957 bootdev = 0x01;
7958 #endif
7960 /* Read the boot device from the IPL table */
7961 if (get_boot_vector(bootdev, &e) == 0) {
7962 BX_INFO("Invalid boot device (0x%x)\n", bootdev);
7963 return;
7966 /* Do the loading, and set up vector as a far pointer to the boot
7967 * address, and bootdrv as the boot drive */
7968 print_boot_device(e.type);
7970 switch(e.type) {
7971 case 0x01: /* FDD */
7972 case 0x02: /* HDD */
7974 bootdrv = (e.type == 0x02) ? 0x80 : 0x00;
7975 bootseg = 0x07c0;
7976 status = 0;
7978 ASM_START
7979 push bp
7980 mov bp, sp
7981 push ax
7982 push bx
7983 push cx
7984 push dx
7986 mov dl, _int18_function.bootdrv + 2[bp]
7987 mov ax, _int18_function.bootseg + 2[bp]
7988 mov es, ax ;; segment
7989 mov bx, #0x0000 ;; offset
7990 mov ah, #0x02 ;; function 2, read diskette sector
7991 mov al, #0x01 ;; read 1 sector
7992 mov ch, #0x00 ;; track 0
7993 mov cl, #0x01 ;; sector 1
7994 mov dh, #0x00 ;; head 0
7995 int #0x13 ;; read sector
7996 jnc int19_load_done
7997 mov ax, #0x0001
7998 mov _int18_function.status + 2[bp], ax
8000 int19_load_done:
8001 pop dx
8002 pop cx
8003 pop bx
8004 pop ax
8005 pop bp
8006 ASM_END
8008 if (status != 0) {
8009 print_boot_failure(e.type, 1);
8010 return;
8013 /* Always check the signature on a HDD boot sector; on FDD, only do
8014 * the check if the CMOS doesn't tell us to skip it */
8015 if (e.type != 0x00 || !((inb_cmos(0x38) & 0x01))) {
8016 if (read_word(bootseg,0x1fe) != 0xaa55) {
8017 print_boot_failure(e.type, 0);
8018 return;
8022 #if BX_TCGBIOS
8023 tcpa_add_bootdevice((Bit32u)0L, (Bit32u)bootdrv);
8024 tcpa_ipl((Bit32u)0L,(Bit32u)bootseg,(Bit32u)0L,(Bit32u)512L); /* specs: 8.2.3 steps 4 and 5 */
8025 #endif
8027 /* Canonicalize bootseg:bootip */
8028 bootip = (bootseg & 0x0fff) << 4;
8029 bootseg &= 0xf000;
8030 break;
8032 #if BX_ELTORITO_BOOT
8033 case 0x03: /* CD-ROM */
8034 status = cdrom_boot();
8036 // If failure
8037 if ( (status & 0x00ff) !=0 ) {
8038 print_cdromboot_failure(status);
8039 print_boot_failure(e.type, 1);
8040 return;
8043 bootdrv = (Bit8u)(status>>8);
8044 bootseg = read_word(ebda_seg,&EbdaData->cdemu.load_segment);
8046 /* Canonicalize bootseg:bootip */
8047 bootip = (bootseg & 0x0fff) << 4;
8048 bootseg &= 0xf000;
8049 break;
8050 #endif
8052 case 0x80: /* Expansion ROM with a Bootstrap Entry Vector (a far pointer) */
8053 bootseg = e.vector >> 16;
8054 bootip = e.vector & 0xffff;
8055 break;
8057 default: return;
8061 /* Jump to the boot vector */
8062 ASM_START
8063 mov bp, sp
8064 ;; Build an iret stack frame that will take us to the boot vector.
8065 ;; iret pops ip, then cs, then flags, so push them in the opposite order.
8066 pushf
8067 mov ax, _int18_function.bootseg + 0[bp]
8068 push ax
8069 mov ax, _int18_function.bootip + 0[bp]
8070 push ax
8071 ;; Set the magic number in ax and the boot drive in dl.
8072 mov ax, #0xaa55
8073 mov dl, _int18_function.bootdrv + 0[bp]
8074 ;; Zero some of the other registers.
8075 xor bx, bx
8076 mov ds, bx
8077 mov es, bx
8078 mov bp, bx
8079 ;; Go!
8080 iret
8081 ASM_END
8084 void
8085 int1a_function(regs, ds, iret_addr)
8086 pusha_regs_t regs; // regs pushed from PUSHA instruction
8087 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8088 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8090 Bit8u val8;
8092 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);
8094 ASM_START
8095 sti
8096 ASM_END
8098 switch (regs.u.r8.ah) {
8099 case 0: // get current clock count
8100 ASM_START
8101 cli
8102 ASM_END
8103 regs.u.r16.cx = BiosData->ticks_high;
8104 regs.u.r16.dx = BiosData->ticks_low;
8105 regs.u.r8.al = BiosData->midnight_flag;
8106 BiosData->midnight_flag = 0; // reset flag
8107 ASM_START
8108 sti
8109 ASM_END
8110 // AH already 0
8111 ClearCF(iret_addr.flags); // OK
8112 break;
8114 case 1: // Set Current Clock Count
8115 ASM_START
8116 cli
8117 ASM_END
8118 BiosData->ticks_high = regs.u.r16.cx;
8119 BiosData->ticks_low = regs.u.r16.dx;
8120 BiosData->midnight_flag = 0; // reset flag
8121 ASM_START
8122 sti
8123 ASM_END
8124 regs.u.r8.ah = 0;
8125 ClearCF(iret_addr.flags); // OK
8126 break;
8129 case 2: // Read CMOS Time
8130 if (rtc_updating()) {
8131 SetCF(iret_addr.flags);
8132 break;
8135 regs.u.r8.dh = inb_cmos(0x00); // Seconds
8136 regs.u.r8.cl = inb_cmos(0x02); // Minutes
8137 regs.u.r8.ch = inb_cmos(0x04); // Hours
8138 regs.u.r8.dl = inb_cmos(0x0b) & 0x01; // Stat Reg B
8139 regs.u.r8.ah = 0;
8140 regs.u.r8.al = regs.u.r8.ch;
8141 ClearCF(iret_addr.flags); // OK
8142 break;
8144 case 3: // Set CMOS Time
8145 // Using a debugger, I notice the following masking/setting
8146 // of bits in Status Register B, by setting Reg B to
8147 // a few values and getting its value after INT 1A was called.
8148 //
8149 // try#1 try#2 try#3
8150 // before 1111 1101 0111 1101 0000 0000
8151 // after 0110 0010 0110 0010 0000 0010
8152 //
8153 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8154 // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
8155 if (rtc_updating()) {
8156 init_rtc();
8157 // fall through as if an update were not in progress
8159 outb_cmos(0x00, regs.u.r8.dh); // Seconds
8160 outb_cmos(0x02, regs.u.r8.cl); // Minutes
8161 outb_cmos(0x04, regs.u.r8.ch); // Hours
8162 // Set Daylight Savings time enabled bit to requested value
8163 val8 = (inb_cmos(0x0b) & 0x60) | 0x02 | (regs.u.r8.dl & 0x01);
8164 // (reg B already selected)
8165 outb_cmos(0x0b, val8);
8166 regs.u.r8.ah = 0;
8167 regs.u.r8.al = val8; // val last written to Reg B
8168 ClearCF(iret_addr.flags); // OK
8169 break;
8171 case 4: // Read CMOS Date
8172 regs.u.r8.ah = 0;
8173 if (rtc_updating()) {
8174 SetCF(iret_addr.flags);
8175 break;
8177 regs.u.r8.cl = inb_cmos(0x09); // Year
8178 regs.u.r8.dh = inb_cmos(0x08); // Month
8179 regs.u.r8.dl = inb_cmos(0x07); // Day of Month
8180 regs.u.r8.ch = inb_cmos(0x32); // Century
8181 regs.u.r8.al = regs.u.r8.ch;
8182 ClearCF(iret_addr.flags); // OK
8183 break;
8185 case 5: // Set CMOS Date
8186 // Using a debugger, I notice the following masking/setting
8187 // of bits in Status Register B, by setting Reg B to
8188 // a few values and getting its value after INT 1A was called.
8189 //
8190 // try#1 try#2 try#3 try#4
8191 // before 1111 1101 0111 1101 0000 0010 0000 0000
8192 // after 0110 1101 0111 1101 0000 0010 0000 0000
8193 //
8194 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8195 // My assumption: RegB = (RegB & 01111111b)
8196 if (rtc_updating()) {
8197 init_rtc();
8198 SetCF(iret_addr.flags);
8199 break;
8201 outb_cmos(0x09, regs.u.r8.cl); // Year
8202 outb_cmos(0x08, regs.u.r8.dh); // Month
8203 outb_cmos(0x07, regs.u.r8.dl); // Day of Month
8204 outb_cmos(0x32, regs.u.r8.ch); // Century
8205 val8 = inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
8206 outb_cmos(0x0b, val8);
8207 regs.u.r8.ah = 0;
8208 regs.u.r8.al = val8; // AL = val last written to Reg B
8209 ClearCF(iret_addr.flags); // OK
8210 break;
8212 case 6: // Set Alarm Time in CMOS
8213 // Using a debugger, I notice the following masking/setting
8214 // of bits in Status Register B, by setting Reg B to
8215 // a few values and getting its value after INT 1A was called.
8216 //
8217 // try#1 try#2 try#3
8218 // before 1101 1111 0101 1111 0000 0000
8219 // after 0110 1111 0111 1111 0010 0000
8220 //
8221 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8222 // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
8223 val8 = inb_cmos(0x0b); // Get Status Reg B
8224 regs.u.r16.ax = 0;
8225 if (val8 & 0x20) {
8226 // Alarm interrupt enabled already
8227 SetCF(iret_addr.flags); // Error: alarm in use
8228 break;
8230 if (rtc_updating()) {
8231 init_rtc();
8232 // fall through as if an update were not in progress
8234 outb_cmos(0x01, regs.u.r8.dh); // Seconds alarm
8235 outb_cmos(0x03, regs.u.r8.cl); // Minutes alarm
8236 outb_cmos(0x05, regs.u.r8.ch); // Hours alarm
8237 outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
8238 // enable Status Reg B alarm bit, clear halt clock bit
8239 outb_cmos(0x0b, (val8 & 0x7f) | 0x20);
8240 ClearCF(iret_addr.flags); // OK
8241 break;
8243 case 7: // Turn off Alarm
8244 // Using a debugger, I notice the following masking/setting
8245 // of bits in Status Register B, by setting Reg B to
8246 // a few values and getting its value after INT 1A was called.
8247 //
8248 // try#1 try#2 try#3 try#4
8249 // before 1111 1101 0111 1101 0010 0000 0010 0010
8250 // after 0100 0101 0101 0101 0000 0000 0000 0010
8251 //
8252 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
8253 // My assumption: RegB = (RegB & 01010111b)
8254 val8 = inb_cmos(0x0b); // Get Status Reg B
8255 // clear clock-halt bit, disable alarm bit
8256 outb_cmos(0x0b, val8 & 0x57); // disable alarm bit
8257 regs.u.r8.ah = 0;
8258 regs.u.r8.al = val8; // val last written to Reg B
8259 ClearCF(iret_addr.flags); // OK
8260 break;
8261 #if BX_PCIBIOS
8262 case 0xb1:
8263 // real mode PCI BIOS functions now handled in assembler code
8264 // this C code handles the error code for information only
8265 if (regs.u.r8.bl == 0xff) {
8266 BX_INFO("PCI BIOS: PCI not present\n");
8267 } else if (regs.u.r8.bl == 0x81) {
8268 BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs.u.r8.al);
8269 } else if (regs.u.r8.bl == 0x83) {
8270 BX_INFO("bad PCI vendor ID %04x\n", regs.u.r16.dx);
8271 } else if (regs.u.r8.bl == 0x86) {
8272 BX_INFO("PCI device %04x:%04x not found\n", regs.u.r16.dx, regs.u.r16.cx);
8274 regs.u.r8.ah = regs.u.r8.bl;
8275 SetCF(iret_addr.flags);
8276 break;
8277 #endif
8279 default:
8280 SetCF(iret_addr.flags); // Unsupported
8284 void
8285 int70_function(regs, ds, iret_addr)
8286 pusha_regs_t regs; // regs pushed from PUSHA instruction
8287 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8288 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
8290 // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
8291 Bit8u registerB = 0, registerC = 0;
8293 // Check which modes are enabled and have occurred.
8294 registerB = inb_cmos( 0xB );
8295 registerC = inb_cmos( 0xC );
8297 if( ( registerB & 0x60 ) != 0 ) {
8298 if( ( registerC & 0x20 ) != 0 ) {
8299 // Handle Alarm Interrupt.
8300 ASM_START
8301 sti
8302 int #0x4a
8303 cli
8304 ASM_END
8306 if( ( registerC & 0x40 ) != 0 ) {
8307 // Handle Periodic Interrupt.
8309 if( read_byte( 0x40, 0xA0 ) != 0 ) {
8310 // Wait Interval (Int 15, AH=83) active.
8311 Bit32u time, toggle;
8313 time = read_dword( 0x40, 0x9C ); // Time left in microseconds.
8314 if( time < 0x3D1 ) {
8315 // Done waiting.
8316 Bit16u segment, offset;
8318 offset = read_word( 0x40, 0x98 );
8319 segment = read_word( 0x40, 0x9A );
8320 write_byte( 0x40, 0xA0, 0 ); // Turn of status byte.
8321 outb_cmos( 0xB, registerB & 0x37 ); // Clear the Periodic Interrupt.
8322 write_byte( segment, offset, 0x80 ); // Write to specified flag byte.
8323 } else {
8324 // Continue waiting.
8325 time -= 0x3D1;
8326 write_dword( 0x40, 0x9C, time );
8332 ASM_START
8333 call eoi_both_pics
8334 ASM_END
8338 ASM_START
8339 ;------------------------------------------
8340 ;- INT74h : PS/2 mouse hardware interrupt -
8341 ;------------------------------------------
8342 int74_handler:
8343 sti
8344 pusha
8345 push ds ;; save DS
8346 push #0x00 ;; placeholder for status
8347 push #0x00 ;; placeholder for X
8348 push #0x00 ;; placeholder for Y
8349 push #0x00 ;; placeholder for Z
8350 push #0x00 ;; placeholder for make_far_call boolean
8351 call _int74_function
8352 pop cx ;; remove make_far_call from stack
8353 jcxz int74_done
8355 ;; make far call to EBDA:0022
8356 push #0x00
8357 pop ds
8358 push 0x040E ;; push 0000:040E (opcodes 0xff, 0x36, 0x0E, 0x04)
8359 pop ds
8360 //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
8361 call far ptr[0x22]
8362 int74_done:
8363 cli
8364 call eoi_both_pics
8365 add sp, #8 ;; pop status, x, y, z
8367 pop ds ;; restore DS
8368 popa
8369 iret
8372 ;; This will perform an IRET, but will retain value of current CF
8373 ;; by altering flags on stack. Better than RETF #02.
8374 iret_modify_cf:
8375 jc carry_set
8376 push bp
8377 mov bp, sp
8378 and BYTE [bp + 0x06], #0xfe
8379 pop bp
8380 iret
8381 carry_set:
8382 push bp
8383 mov bp, sp
8384 or BYTE [bp + 0x06], #0x01
8385 pop bp
8386 iret
8389 ;----------------------
8390 ;- INT13h (relocated) -
8391 ;----------------------
8393 ; int13_relocated is a little bit messed up since I played with it
8394 ; I have to rewrite it:
8395 ; - call a function that detect which function to call
8396 ; - make all called C function get the same parameters list
8398 int13_relocated:
8400 #if BX_ELTORITO_BOOT
8401 ;; check for an eltorito function
8402 cmp ah,#0x4a
8403 jb int13_not_eltorito
8404 cmp ah,#0x4d
8405 ja int13_not_eltorito
8407 pusha
8408 push es
8409 push ds
8410 push ss
8411 pop ds
8413 push #int13_out
8414 jmp _int13_eltorito ;; ELDX not used
8416 int13_not_eltorito:
8417 push ax
8418 push bx
8419 push cx
8420 push dx
8422 ;; check if emulation active
8423 call _cdemu_isactive
8424 cmp al,#0x00
8425 je int13_cdemu_inactive
8427 ;; check if access to the emulated drive
8428 call _cdemu_emulated_drive
8429 pop dx
8430 push dx
8431 cmp al,dl ;; int13 on emulated drive
8432 jne int13_nocdemu
8434 pop dx
8435 pop cx
8436 pop bx
8437 pop ax
8439 pusha
8440 push es
8441 push ds
8442 push ss
8443 pop ds
8445 push #int13_out
8446 jmp _int13_cdemu ;; ELDX not used
8448 int13_nocdemu:
8449 and dl,#0xE0 ;; mask to get device class, including cdroms
8450 cmp al,dl ;; al is 0x00 or 0x80
8451 jne int13_cdemu_inactive ;; inactive for device class
8453 pop dx
8454 pop cx
8455 pop bx
8456 pop ax
8458 push ax
8459 push cx
8460 push dx
8461 push bx
8463 dec dl ;; real drive is dl - 1
8464 jmp int13_legacy
8466 int13_cdemu_inactive:
8467 pop dx
8468 pop cx
8469 pop bx
8470 pop ax
8472 #endif // BX_ELTORITO_BOOT
8474 int13_noeltorito:
8476 push ax
8477 push cx
8478 push dx
8479 push bx
8481 int13_legacy:
8483 push dx ;; push eltorito value of dx instead of sp
8485 push bp
8486 push si
8487 push di
8489 push es
8490 push ds
8491 push ss
8492 pop ds
8494 ;; now the 16-bit registers can be restored with:
8495 ;; pop ds; pop es; popa; iret
8496 ;; arguments passed to functions should be
8497 ;; DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS
8499 test dl, #0x80
8500 jnz int13_notfloppy
8502 push #int13_out
8503 jmp _int13_diskette_function
8505 int13_notfloppy:
8507 #if BX_USE_ATADRV
8509 cmp dl, #0xE0
8510 jb int13_notcdrom
8512 // ebx is modified: BSD 5.2.1 boot loader problem
8513 // someone should figure out which 32 bit register that actually are used
8515 shr ebx, #16
8516 push bx
8518 call _int13_cdrom
8520 pop bx
8521 shl ebx, #16
8523 jmp int13_out
8525 int13_notcdrom:
8527 #endif
8529 int13_disk:
8530 call _int13_harddisk
8532 int13_out:
8533 pop ds
8534 pop es
8535 popa
8536 iret
8538 ;----------
8539 ;- INT18h -
8540 ;----------
8541 int18_handler: ;; Boot Failure recovery: try the next device.
8543 ;; Reset SP and SS
8544 mov ax, #0xfffe
8545 mov sp, ax
8546 xor ax, ax
8547 mov ss, ax
8549 ;; Get the boot sequence number out of the IPL memory
8550 ;; The first time we do this it will have been set to -1 so
8551 ;; we will start from device 0.
8552 mov bx, #IPL_SEG
8553 mov ds, bx ;; Set segment
8554 mov bx, IPL_SEQUENCE_OFFSET ;; BX is now the sequence number
8555 inc bx ;; ++
8556 mov IPL_SEQUENCE_OFFSET, bx ;; Write it back
8557 mov ds, ax ;; and reset the segment to zero.
8559 ;; Call the C code for the next boot device
8560 push bx
8561 call _int18_function
8563 ;; Boot failed: invoke the boot recovery function...
8564 int #0x18
8566 ;----------
8567 ;- INT19h -
8568 ;----------
8569 int19_relocated: ;; Boot function, relocated
8570 ;;
8571 ;; *** Warning: INT 19h resets the whole machine ***
8572 ;;
8573 ;; Because PV drivers in HVM guests detach some of the emulated devices,
8574 ;; it is not safe to do a soft reboot by just dropping to real mode and
8575 ;; invoking INT 19h -- the boot drives might have disappeared!
8576 ;; If the user asks for a soft reboot, the only thing we can do is
8577 ;; reset the whole machine. When it comes back up, the normal BIOS
8578 ;; boot sequence will start, which is more or less the required behaviour.
8579 ;;
8580 ;; Reset SP and SS
8581 mov ax, #0xfffe
8582 mov sp, ax
8583 xor ax, ax
8584 mov ss, ax
8585 call _machine_reset
8587 ;----------
8588 ;- INT1Ch -
8589 ;----------
8590 int1c_handler: ;; User Timer Tick
8591 iret
8594 ;----------------------
8595 ;- POST: Floppy Drive -
8596 ;----------------------
8597 floppy_drive_post:
8598 mov ax, #0x0000
8599 mov ds, ax
8601 mov al, #0x00
8602 mov 0x043e, al ;; drive 0 & 1 uncalibrated, no interrupt has occurred
8604 mov 0x043f, al ;; diskette motor status: read op, drive0, motors off
8606 mov 0x0440, al ;; diskette motor timeout counter: not active
8607 mov 0x0441, al ;; diskette controller status return code
8609 mov 0x0442, al ;; disk & diskette controller status register 0
8610 mov 0x0443, al ;; diskette controller status register 1
8611 mov 0x0444, al ;; diskette controller status register 2
8612 mov 0x0445, al ;; diskette controller cylinder number
8613 mov 0x0446, al ;; diskette controller head number
8614 mov 0x0447, al ;; diskette controller sector number
8615 mov 0x0448, al ;; diskette controller bytes written
8617 mov 0x048b, al ;; diskette configuration data
8619 ;; -----------------------------------------------------------------
8620 ;; (048F) diskette controller information
8621 ;;
8622 mov al, #0x10 ;; get CMOS diskette drive type
8623 out 0x70, AL
8624 in AL, 0x71
8625 mov ah, al ;; save byte to AH
8627 look_drive0:
8628 shr al, #4 ;; look at top 4 bits for drive 0
8629 jz f0_missing ;; jump if no drive0
8630 mov bl, #0x07 ;; drive0 determined, multi-rate, has changed line
8631 jmp look_drive1
8632 f0_missing:
8633 mov bl, #0x00 ;; no drive0
8635 look_drive1:
8636 mov al, ah ;; restore from AH
8637 and al, #0x0f ;; look at bottom 4 bits for drive 1
8638 jz f1_missing ;; jump if no drive1
8639 or bl, #0x70 ;; drive1 determined, multi-rate, has changed line
8640 f1_missing:
8641 ;; leave high bits in BL zerod
8642 mov 0x048f, bl ;; put new val in BDA (diskette controller information)
8643 ;; -----------------------------------------------------------------
8645 mov al, #0x00
8646 mov 0x0490, al ;; diskette 0 media state
8647 mov 0x0491, al ;; diskette 1 media state
8649 ;; diskette 0,1 operational starting state
8650 ;; drive type has not been determined,
8651 ;; has no changed detection line
8652 mov 0x0492, al
8653 mov 0x0493, al
8655 mov 0x0494, al ;; diskette 0 current cylinder
8656 mov 0x0495, al ;; diskette 1 current cylinder
8658 mov al, #0x02
8659 out #0x0a, al ;; clear DMA-1 channel 2 mask bit
8661 SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
8662 SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
8663 SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
8665 ret
8668 ;--------------------
8669 ;- POST: HARD DRIVE -
8670 ;--------------------
8671 ; relocated here because the primary POST area isnt big enough.
8672 hard_drive_post:
8673 // IRQ 14 = INT 76h
8674 // INT 76h calls INT 15h function ax=9100
8676 mov al, #0x0a ; 0000 1010 = reserved, disable IRQ 14
8677 mov dx, #0x03f6
8678 out dx, al
8680 mov ax, #0x0000
8681 mov ds, ax
8682 mov 0x0474, al /* hard disk status of last operation */
8683 mov 0x0477, al /* hard disk port offset (XT only ???) */
8684 mov 0x048c, al /* hard disk status register */
8685 mov 0x048d, al /* hard disk error register */
8686 mov 0x048e, al /* hard disk task complete flag */
8687 mov al, #0x01
8688 mov 0x0475, al /* hard disk number attached */
8689 mov al, #0xc0
8690 mov 0x0476, al /* hard disk control byte */
8691 SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
8692 SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
8693 ;; INT 41h: hard disk 0 configuration pointer
8694 ;; INT 46h: hard disk 1 configuration pointer
8695 SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D)
8696 SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D)
8698 ;; move disk geometry data from CMOS to EBDA disk parameter table(s)
8699 mov al, #0x12
8700 out #0x70, al
8701 in al, #0x71
8702 and al, #0xf0
8703 cmp al, #0xf0
8704 je post_d0_extended
8705 jmp check_for_hd1
8706 post_d0_extended:
8707 mov al, #0x19
8708 out #0x70, al
8709 in al, #0x71
8710 cmp al, #47 ;; decimal 47 - user definable
8711 je post_d0_type47
8712 HALT(__LINE__)
8713 post_d0_type47:
8714 ;; CMOS purpose param table offset
8715 ;; 1b cylinders low 0
8716 ;; 1c cylinders high 1
8717 ;; 1d heads 2
8718 ;; 1e write pre-comp low 5
8719 ;; 1f write pre-comp high 6
8720 ;; 20 retries/bad map/heads>8 8
8721 ;; 21 landing zone low C
8722 ;; 22 landing zone high D
8723 ;; 23 sectors/track E
8725 mov ax, #EBDA_SEG
8726 mov ds, ax
8728 ;;; Filling EBDA table for hard disk 0.
8729 mov al, #0x1f
8730 out #0x70, al
8731 in al, #0x71
8732 mov ah, al
8733 mov al, #0x1e
8734 out #0x70, al
8735 in al, #0x71
8736 mov (0x003d + 0x05), ax ;; write precomp word
8738 mov al, #0x20
8739 out #0x70, al
8740 in al, #0x71
8741 mov (0x003d + 0x08), al ;; drive control byte
8743 mov al, #0x22
8744 out #0x70, al
8745 in al, #0x71
8746 mov ah, al
8747 mov al, #0x21
8748 out #0x70, al
8749 in al, #0x71
8750 mov (0x003d + 0x0C), ax ;; landing zone word
8752 mov al, #0x1c ;; get cylinders word in AX
8753 out #0x70, al
8754 in al, #0x71 ;; high byte
8755 mov ah, al
8756 mov al, #0x1b
8757 out #0x70, al
8758 in al, #0x71 ;; low byte
8759 mov bx, ax ;; BX = cylinders
8761 mov al, #0x1d
8762 out #0x70, al
8763 in al, #0x71
8764 mov cl, al ;; CL = heads
8766 mov al, #0x23
8767 out #0x70, al
8768 in al, #0x71
8769 mov dl, al ;; DL = sectors
8771 cmp bx, #1024
8772 jnbe hd0_post_logical_chs ;; if cylinders > 1024, use translated style CHS
8774 hd0_post_physical_chs:
8775 ;; no logical CHS mapping used, just physical CHS
8776 ;; use Standard Fixed Disk Parameter Table (FDPT)
8777 mov (0x003d + 0x00), bx ;; number of physical cylinders
8778 mov (0x003d + 0x02), cl ;; number of physical heads
8779 mov (0x003d + 0x0E), dl ;; number of physical sectors
8780 jmp check_for_hd1
8782 hd0_post_logical_chs:
8783 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
8784 mov (0x003d + 0x09), bx ;; number of physical cylinders
8785 mov (0x003d + 0x0b), cl ;; number of physical heads
8786 mov (0x003d + 0x04), dl ;; number of physical sectors
8787 mov (0x003d + 0x0e), dl ;; number of logical sectors (same)
8788 mov al, #0xa0
8789 mov (0x003d + 0x03), al ;; A0h signature, indicates translated table
8791 cmp bx, #2048
8792 jnbe hd0_post_above_2048
8793 ;; 1024 < c <= 2048 cylinders
8794 shr bx, #0x01
8795 shl cl, #0x01
8796 jmp hd0_post_store_logical
8798 hd0_post_above_2048:
8799 cmp bx, #4096
8800 jnbe hd0_post_above_4096
8801 ;; 2048 < c <= 4096 cylinders
8802 shr bx, #0x02
8803 shl cl, #0x02
8804 jmp hd0_post_store_logical
8806 hd0_post_above_4096:
8807 cmp bx, #8192
8808 jnbe hd0_post_above_8192
8809 ;; 4096 < c <= 8192 cylinders
8810 shr bx, #0x03
8811 shl cl, #0x03
8812 jmp hd0_post_store_logical
8814 hd0_post_above_8192:
8815 ;; 8192 < c <= 16384 cylinders
8816 shr bx, #0x04
8817 shl cl, #0x04
8819 hd0_post_store_logical:
8820 mov (0x003d + 0x00), bx ;; number of physical cylinders
8821 mov (0x003d + 0x02), cl ;; number of physical heads
8822 ;; checksum
8823 mov cl, #0x0f ;; repeat count
8824 mov si, #0x003d ;; offset to disk0 FDPT
8825 mov al, #0x00 ;; sum
8826 hd0_post_checksum_loop:
8827 add al, [si]
8828 inc si
8829 dec cl
8830 jnz hd0_post_checksum_loop
8831 not al ;; now take 2s complement
8832 inc al
8833 mov [si], al
8834 ;;; Done filling EBDA table for hard disk 0.
8837 check_for_hd1:
8838 ;; is there really a second hard disk? if not, return now
8839 mov al, #0x12
8840 out #0x70, al
8841 in al, #0x71
8842 and al, #0x0f
8843 jnz post_d1_exists
8844 ret
8845 post_d1_exists:
8846 ;; check that the hd type is really 0x0f.
8847 cmp al, #0x0f
8848 jz post_d1_extended
8849 HALT(__LINE__)
8850 post_d1_extended:
8851 ;; check that the extended type is 47 - user definable
8852 mov al, #0x1a
8853 out #0x70, al
8854 in al, #0x71
8855 cmp al, #47 ;; decimal 47 - user definable
8856 je post_d1_type47
8857 HALT(__LINE__)
8858 post_d1_type47:
8859 ;; Table for disk1.
8860 ;; CMOS purpose param table offset
8861 ;; 0x24 cylinders low 0
8862 ;; 0x25 cylinders high 1
8863 ;; 0x26 heads 2
8864 ;; 0x27 write pre-comp low 5
8865 ;; 0x28 write pre-comp high 6
8866 ;; 0x29 heads>8 8
8867 ;; 0x2a landing zone low C
8868 ;; 0x2b landing zone high D
8869 ;; 0x2c sectors/track E
8870 ;;; Fill EBDA table for hard disk 1.
8871 mov ax, #EBDA_SEG
8872 mov ds, ax
8873 mov al, #0x28
8874 out #0x70, al
8875 in al, #0x71
8876 mov ah, al
8877 mov al, #0x27
8878 out #0x70, al
8879 in al, #0x71
8880 mov (0x004d + 0x05), ax ;; write precomp word
8882 mov al, #0x29
8883 out #0x70, al
8884 in al, #0x71
8885 mov (0x004d + 0x08), al ;; drive control byte
8887 mov al, #0x2b
8888 out #0x70, al
8889 in al, #0x71
8890 mov ah, al
8891 mov al, #0x2a
8892 out #0x70, al
8893 in al, #0x71
8894 mov (0x004d + 0x0C), ax ;; landing zone word
8896 mov al, #0x25 ;; get cylinders word in AX
8897 out #0x70, al
8898 in al, #0x71 ;; high byte
8899 mov ah, al
8900 mov al, #0x24
8901 out #0x70, al
8902 in al, #0x71 ;; low byte
8903 mov bx, ax ;; BX = cylinders
8905 mov al, #0x26
8906 out #0x70, al
8907 in al, #0x71
8908 mov cl, al ;; CL = heads
8910 mov al, #0x2c
8911 out #0x70, al
8912 in al, #0x71
8913 mov dl, al ;; DL = sectors
8915 cmp bx, #1024
8916 jnbe hd1_post_logical_chs ;; if cylinders > 1024, use translated style CHS
8918 hd1_post_physical_chs:
8919 ;; no logical CHS mapping used, just physical CHS
8920 ;; use Standard Fixed Disk Parameter Table (FDPT)
8921 mov (0x004d + 0x00), bx ;; number of physical cylinders
8922 mov (0x004d + 0x02), cl ;; number of physical heads
8923 mov (0x004d + 0x0E), dl ;; number of physical sectors
8924 ret
8926 hd1_post_logical_chs:
8927 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
8928 mov (0x004d + 0x09), bx ;; number of physical cylinders
8929 mov (0x004d + 0x0b), cl ;; number of physical heads
8930 mov (0x004d + 0x04), dl ;; number of physical sectors
8931 mov (0x004d + 0x0e), dl ;; number of logical sectors (same)
8932 mov al, #0xa0
8933 mov (0x004d + 0x03), al ;; A0h signature, indicates translated table
8935 cmp bx, #2048
8936 jnbe hd1_post_above_2048
8937 ;; 1024 < c <= 2048 cylinders
8938 shr bx, #0x01
8939 shl cl, #0x01
8940 jmp hd1_post_store_logical
8942 hd1_post_above_2048:
8943 cmp bx, #4096
8944 jnbe hd1_post_above_4096
8945 ;; 2048 < c <= 4096 cylinders
8946 shr bx, #0x02
8947 shl cl, #0x02
8948 jmp hd1_post_store_logical
8950 hd1_post_above_4096:
8951 cmp bx, #8192
8952 jnbe hd1_post_above_8192
8953 ;; 4096 < c <= 8192 cylinders
8954 shr bx, #0x03
8955 shl cl, #0x03
8956 jmp hd1_post_store_logical
8958 hd1_post_above_8192:
8959 ;; 8192 < c <= 16384 cylinders
8960 shr bx, #0x04
8961 shl cl, #0x04
8963 hd1_post_store_logical:
8964 mov (0x004d + 0x00), bx ;; number of physical cylinders
8965 mov (0x004d + 0x02), cl ;; number of physical heads
8966 ;; checksum
8967 mov cl, #0x0f ;; repeat count
8968 mov si, #0x004d ;; offset to disk0 FDPT
8969 mov al, #0x00 ;; sum
8970 hd1_post_checksum_loop:
8971 add al, [si]
8972 inc si
8973 dec cl
8974 jnz hd1_post_checksum_loop
8975 not al ;; now take 2s complement
8976 inc al
8977 mov [si], al
8978 ;;; Done filling EBDA table for hard disk 1.
8980 ret
8982 ;--------------------
8983 ;- POST: EBDA segment
8984 ;--------------------
8985 ; relocated here because the primary POST area isnt big enough.
8986 ebda_post:
8987 #if BX_USE_EBDA
8988 mov ax, #EBDA_SEG
8989 mov ds, ax
8990 mov byte ptr [0x0], #EBDA_SIZE
8991 #endif
8992 xor ax, ax ; mov EBDA seg into 40E
8993 mov ds, ax
8994 mov word ptr [0x40E], #EBDA_SEG
8995 ret;;
8997 ;--------------------
8998 ;- POST: EOI + jmp via [0x40:67)
8999 ;--------------------
9000 ; relocated here because the primary POST area isnt big enough.
9001 eoi_jmp_post:
9002 call eoi_both_pics
9004 xor ax, ax
9005 mov ds, ax
9007 jmp far ptr [0x467]
9010 ;--------------------
9011 eoi_both_pics:
9012 mov al, #0x20
9013 out #0xA0, al ;; slave PIC EOI
9014 eoi_master_pic:
9015 mov al, #0x20
9016 out #0x20, al ;; master PIC EOI
9017 ret
9019 ;--------------------
9020 BcdToBin:
9021 ;; in: AL in BCD format
9022 ;; out: AL in binary format, AH will always be 0
9023 ;; trashes BX
9024 mov bl, al
9025 and bl, #0x0f ;; bl has low digit
9026 shr al, #4 ;; al has high digit
9027 mov bh, #10
9028 mul al, bh ;; multiply high digit by 10 (result in AX)
9029 add al, bl ;; then add low digit
9030 ret
9032 ;--------------------
9033 timer_tick_post:
9034 ;; Setup the Timer Ticks Count (0x46C:dword) and
9035 ;; Timer Ticks Roller Flag (0x470:byte)
9036 ;; The Timer Ticks Count needs to be set according to
9037 ;; the current CMOS time, as if ticks have been occurring
9038 ;; at 18.2hz since midnight up to this point. Calculating
9039 ;; this is a little complicated. Here are the factors I gather
9040 ;; regarding this. 14,318,180 hz was the original clock speed,
9041 ;; chosen so it could be divided by either 3 to drive the 5Mhz CPU
9042 ;; at the time, or 4 to drive the CGA video adapter. The div3
9043 ;; source was divided again by 4 to feed a 1.193Mhz signal to
9044 ;; the timer. With a maximum 16bit timer count, this is again
9045 ;; divided down by 65536 to 18.2hz.
9046 ;;
9047 ;; 14,318,180 Hz clock
9048 ;; /3 = 4,772,726 Hz fed to orginal 5Mhz CPU
9049 ;; /4 = 1,193,181 Hz fed to timer
9050 ;; /65536 (maximum timer count) = 18.20650736 ticks/second
9051 ;; 1 second = 18.20650736 ticks
9052 ;; 1 minute = 1092.390442 ticks
9053 ;; 1 hour = 65543.42651 ticks
9054 ;;
9055 ;; Given the values in the CMOS clock, one could calculate
9056 ;; the number of ticks by the following:
9057 ;; ticks = (BcdToBin(seconds) * 18.206507) +
9058 ;; (BcdToBin(minutes) * 1092.3904)
9059 ;; (BcdToBin(hours) * 65543.427)
9060 ;; To get a little more accuracy, since Im using integer
9061 ;; arithmatic, I use:
9062 ;; ticks = (BcdToBin(seconds) * 18206507) / 1000000 +
9063 ;; (BcdToBin(minutes) * 10923904) / 10000 +
9064 ;; (BcdToBin(hours) * 65543427) / 1000
9066 ;; assuming DS=0000
9068 ;; get CMOS seconds
9069 xor eax, eax ;; clear EAX
9070 mov al, #0x00
9071 out #0x70, al
9072 in al, #0x71 ;; AL has CMOS seconds in BCD
9073 call BcdToBin ;; EAX now has seconds in binary
9074 mov edx, #18206507
9075 mul eax, edx
9076 mov ebx, #1000000
9077 xor edx, edx
9078 div eax, ebx
9079 mov ecx, eax ;; ECX will accumulate total ticks
9081 ;; get CMOS minutes
9082 xor eax, eax ;; clear EAX
9083 mov al, #0x02
9084 out #0x70, al
9085 in al, #0x71 ;; AL has CMOS minutes in BCD
9086 call BcdToBin ;; EAX now has minutes in binary
9087 mov edx, #10923904
9088 mul eax, edx
9089 mov ebx, #10000
9090 xor edx, edx
9091 div eax, ebx
9092 add ecx, eax ;; add to total ticks
9094 ;; get CMOS hours
9095 xor eax, eax ;; clear EAX
9096 mov al, #0x04
9097 out #0x70, al
9098 in al, #0x71 ;; AL has CMOS hours in BCD
9099 call BcdToBin ;; EAX now has hours in binary
9100 mov edx, #65543427
9101 mul eax, edx
9102 mov ebx, #1000
9103 xor edx, edx
9104 div eax, ebx
9105 add ecx, eax ;; add to total ticks
9107 mov 0x46C, ecx ;; Timer Ticks Count
9108 xor al, al
9109 mov 0x470, al ;; Timer Ticks Rollover Flag
9110 ret
9112 ;--------------------
9113 int76_handler:
9114 ;; record completion in BIOS task complete flag
9115 push ax
9116 push ds
9117 mov ax, #0x0040
9118 mov ds, ax
9119 mov 0x008E, #0xff
9120 call eoi_both_pics
9121 pop ds
9122 pop ax
9123 iret
9126 ;--------------------
9127 #if BX_APM
9129 use32 386
9130 #define APM_PROT32
9131 #include "apmbios.S"
9133 use16 386
9134 #define APM_PROT16
9135 #include "apmbios.S"
9137 #define APM_REAL
9138 #include "apmbios.S"
9140 #endif
9142 ASM_END
9143 #include "32bitgateway.c"
9144 ASM_START
9146 ;--------------------
9147 #if BX_PCIBIOS
9148 use32 386
9149 .align 16
9150 bios32_structure:
9151 db 0x5f, 0x33, 0x32, 0x5f ;; "_32_" signature
9152 dw bios32_entry_point, 0xf ;; 32 bit physical address
9153 db 0 ;; revision level
9154 ;; length in paragraphs and checksum stored in a word to prevent errors
9155 dw (~(((bios32_entry_point >> 8) + (bios32_entry_point & 0xff) + 0x32) \
9156 & 0xff) << 8) + 0x01
9157 db 0,0,0,0,0 ;; reserved
9159 .align 16
9160 bios32_entry_point:
9161 pushf
9162 cmp eax, #0x49435024
9163 jne unknown_service
9164 mov eax, #0x80000000
9165 mov dx, #0x0cf8
9166 out dx, eax
9167 mov dx, #0x0cfc
9168 in eax, dx
9169 cmp eax, #0x12378086
9170 jne unknown_service
9171 mov ebx, #0x000f0000
9172 mov ecx, #0
9173 mov edx, #pcibios_protected
9174 xor al, al
9175 jmp bios32_end
9176 unknown_service:
9177 mov al, #0x80
9178 bios32_end:
9179 popf
9180 retf
9182 .align 16
9183 pcibios_protected:
9184 pushf
9185 cli
9186 push esi
9187 push edi
9188 cmp al, #0x01 ;; installation check
9189 jne pci_pro_f02
9190 mov bx, #0x0210
9191 mov cx, #0
9192 mov edx, #0x20494350
9193 mov al, #0x01
9194 jmp pci_pro_ok
9195 pci_pro_f02: ;; find pci device
9196 cmp al, #0x02
9197 jne pci_pro_f08
9198 shl ecx, #16
9199 mov cx, dx
9200 mov bx, #0x0000
9201 mov di, #0x00
9202 pci_pro_devloop:
9203 call pci_pro_select_reg
9204 mov dx, #0x0cfc
9205 in eax, dx
9206 cmp eax, ecx
9207 jne pci_pro_nextdev
9208 cmp si, #0
9209 je pci_pro_ok
9210 dec si
9211 pci_pro_nextdev:
9212 inc bx
9213 cmp bx, #0x0100
9214 jne pci_pro_devloop
9215 mov ah, #0x86
9216 jmp pci_pro_fail
9217 pci_pro_f08: ;; read configuration byte
9218 cmp al, #0x08
9219 jne pci_pro_f09
9220 call pci_pro_select_reg
9221 push edx
9222 mov dx, di
9223 and dx, #0x03
9224 add dx, #0x0cfc
9225 in al, dx
9226 pop edx
9227 mov cl, al
9228 jmp pci_pro_ok
9229 pci_pro_f09: ;; read configuration word
9230 cmp al, #0x09
9231 jne pci_pro_f0a
9232 call pci_pro_select_reg
9233 push edx
9234 mov dx, di
9235 and dx, #0x02
9236 add dx, #0x0cfc
9237 in ax, dx
9238 pop edx
9239 mov cx, ax
9240 jmp pci_pro_ok
9241 pci_pro_f0a: ;; read configuration dword
9242 cmp al, #0x0a
9243 jne pci_pro_f0b
9244 call pci_pro_select_reg
9245 push edx
9246 mov dx, #0x0cfc
9247 in eax, dx
9248 pop edx
9249 mov ecx, eax
9250 jmp pci_pro_ok
9251 pci_pro_f0b: ;; write configuration byte
9252 cmp al, #0x0b
9253 jne pci_pro_f0c
9254 call pci_pro_select_reg
9255 push edx
9256 mov dx, di
9257 and dx, #0x03
9258 add dx, #0x0cfc
9259 mov al, cl
9260 out dx, al
9261 pop edx
9262 jmp pci_pro_ok
9263 pci_pro_f0c: ;; write configuration word
9264 cmp al, #0x0c
9265 jne pci_pro_f0d
9266 call pci_pro_select_reg
9267 push edx
9268 mov dx, di
9269 and dx, #0x02
9270 add dx, #0x0cfc
9271 mov ax, cx
9272 out dx, ax
9273 pop edx
9274 jmp pci_pro_ok
9275 pci_pro_f0d: ;; write configuration dword
9276 cmp al, #0x0d
9277 jne pci_pro_unknown
9278 call pci_pro_select_reg
9279 push edx
9280 mov dx, #0x0cfc
9281 mov eax, ecx
9282 out dx, eax
9283 pop edx
9284 jmp pci_pro_ok
9285 pci_pro_unknown:
9286 mov ah, #0x81
9287 pci_pro_fail:
9288 pop edi
9289 pop esi
9290 sti
9291 popf
9292 stc
9293 retf
9294 pci_pro_ok:
9295 xor ah, ah
9296 pop edi
9297 pop esi
9298 sti
9299 popf
9300 clc
9301 retf
9303 pci_pro_select_reg:
9304 push edx
9305 mov eax, #0x800000
9306 mov ax, bx
9307 shl eax, #8
9308 and di, #0xff
9309 or ax, di
9310 and al, #0xfc
9311 mov dx, #0x0cf8
9312 out dx, eax
9313 pop edx
9314 ret
9316 use16 386
9318 pcibios_real:
9319 push eax
9320 push dx
9321 mov eax, #0x80000000
9322 mov dx, #0x0cf8
9323 out dx, eax
9324 mov dx, #0x0cfc
9325 in eax, dx
9326 cmp eax, #0x12378086
9327 je pci_present
9328 pop dx
9329 pop eax
9330 mov ah, #0xff
9331 stc
9332 ret
9333 pci_present:
9334 pop dx
9335 pop eax
9336 cmp al, #0x01 ;; installation check
9337 jne pci_real_f02
9338 mov ax, #0x0001
9339 mov bx, #0x0210
9340 mov cx, #0
9341 mov edx, #0x20494350
9342 mov edi, #0xf0000
9343 mov di, #pcibios_protected
9344 clc
9345 ret
9346 pci_real_f02: ;; find pci device
9347 push esi
9348 push edi
9349 cmp al, #0x02
9350 jne pci_real_f08
9351 shl ecx, #16
9352 mov cx, dx
9353 mov bx, #0x0000
9354 mov di, #0x00
9355 pci_real_devloop:
9356 call pci_real_select_reg
9357 mov dx, #0x0cfc
9358 in eax, dx
9359 cmp eax, ecx
9360 jne pci_real_nextdev
9361 cmp si, #0
9362 je pci_real_ok
9363 dec si
9364 pci_real_nextdev:
9365 inc bx
9366 cmp bx, #0x0100
9367 jne pci_real_devloop
9368 mov dx, cx
9369 shr ecx, #16
9370 mov ah, #0x86
9371 jmp pci_real_fail
9372 pci_real_f08: ;; read configuration byte
9373 cmp al, #0x08
9374 jne pci_real_f09
9375 call pci_real_select_reg
9376 push dx
9377 mov dx, di
9378 and dx, #0x03
9379 add dx, #0x0cfc
9380 in al, dx
9381 pop dx
9382 mov cl, al
9383 jmp pci_real_ok
9384 pci_real_f09: ;; read configuration word
9385 cmp al, #0x09
9386 jne pci_real_f0a
9387 call pci_real_select_reg
9388 push dx
9389 mov dx, di
9390 and dx, #0x02
9391 add dx, #0x0cfc
9392 in ax, dx
9393 pop dx
9394 mov cx, ax
9395 jmp pci_real_ok
9396 pci_real_f0a: ;; read configuration dword
9397 cmp al, #0x0a
9398 jne pci_real_f0b
9399 call pci_real_select_reg
9400 push dx
9401 mov dx, #0x0cfc
9402 in eax, dx
9403 pop dx
9404 mov ecx, eax
9405 jmp pci_real_ok
9406 pci_real_f0b: ;; write configuration byte
9407 cmp al, #0x0b
9408 jne pci_real_f0c
9409 call pci_real_select_reg
9410 push dx
9411 mov dx, di
9412 and dx, #0x03
9413 add dx, #0x0cfc
9414 mov al, cl
9415 out dx, al
9416 pop dx
9417 jmp pci_real_ok
9418 pci_real_f0c: ;; write configuration word
9419 cmp al, #0x0c
9420 jne pci_real_f0d
9421 call pci_real_select_reg
9422 push dx
9423 mov dx, di
9424 and dx, #0x02
9425 add dx, #0x0cfc
9426 mov ax, cx
9427 out dx, ax
9428 pop dx
9429 jmp pci_real_ok
9430 pci_real_f0d: ;; write configuration dword
9431 cmp al, #0x0d
9432 jne pci_real_unknown
9433 call pci_real_select_reg
9434 push dx
9435 mov dx, #0x0cfc
9436 mov eax, ecx
9437 out dx, eax
9438 pop dx
9439 jmp pci_real_ok
9440 pci_real_unknown:
9441 mov ah, #0x81
9442 pci_real_fail:
9443 pop edi
9444 pop esi
9445 stc
9446 ret
9447 pci_real_ok:
9448 xor ah, ah
9449 pop edi
9450 pop esi
9451 clc
9452 ret
9454 pci_real_select_reg:
9455 push dx
9456 mov eax, #0x800000
9457 mov ax, bx
9458 shl eax, #8
9459 and di, #0xff
9460 or ax, di
9461 and al, #0xfc
9462 mov dx, #0x0cf8
9463 out dx, eax
9464 pop dx
9465 ret
9467 .align 16
9468 pci_routing_table_structure:
9469 db 0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature
9470 db 0, 1 ;; version
9471 dw 32 + (6 * 16) ;; table size
9472 db 0 ;; PCI interrupt router bus
9473 db 0x08 ;; PCI interrupt router DevFunc
9474 dw 0x0000 ;; PCI exclusive IRQs
9475 dw 0x8086 ;; compatible PCI interrupt router vendor ID
9476 dw 0x7000 ;; compatible PCI interrupt router device ID
9477 dw 0,0 ;; Miniport data
9478 db 0,0,0,0,0,0,0,0,0,0,0 ;; reserved
9479 db 0x07 ;; checksum
9480 ;; first slot entry PCI-to-ISA (embedded)
9481 db 0 ;; pci bus number
9482 db 0x08 ;; pci device number (bit 7-3)
9483 db 0x61 ;; link value INTA#: pointer into PCI2ISA config space
9484 dw 0x0c20 ;; IRQ bitmap INTA#
9485 db 0x62 ;; link value INTB#
9486 dw 0x0c20 ;; IRQ bitmap INTB#
9487 db 0x63 ;; link value INTC#
9488 dw 0x0c20 ;; IRQ bitmap INTC#
9489 db 0x60 ;; link value INTD#
9490 dw 0x0c20 ;; IRQ bitmap INTD#
9491 db 0 ;; physical slot (0 = embedded)
9492 db 0 ;; reserved
9493 ;; second slot entry: 1st PCI slot
9494 db 0 ;; pci bus number
9495 db 0x10 ;; pci device number (bit 7-3)
9496 db 0x62 ;; link value INTA#
9497 dw 0x0c20 ;; IRQ bitmap INTA#
9498 db 0x63 ;; link value INTB#
9499 dw 0x0c20 ;; IRQ bitmap INTB#
9500 db 0x60 ;; link value INTC#
9501 dw 0x0c20 ;; IRQ bitmap INTC#
9502 db 0x61 ;; link value INTD#
9503 dw 0x0c20 ;; IRQ bitmap INTD#
9504 db 1 ;; physical slot (0 = embedded)
9505 db 0 ;; reserved
9506 ;; third slot entry: 2nd PCI slot
9507 db 0 ;; pci bus number
9508 db 0x18 ;; pci device number (bit 7-3)
9509 db 0x63 ;; link value INTA#
9510 dw 0x0c20 ;; IRQ bitmap INTA#
9511 db 0x60 ;; link value INTB#
9512 dw 0x0c20 ;; IRQ bitmap INTB#
9513 db 0x61 ;; link value INTC#
9514 dw 0x0c20 ;; IRQ bitmap INTC#
9515 db 0x62 ;; link value INTD#
9516 dw 0x0c20 ;; IRQ bitmap INTD#
9517 db 2 ;; physical slot (0 = embedded)
9518 db 0 ;; reserved
9519 ;; 4th slot entry: 3rd PCI slot
9520 db 0 ;; pci bus number
9521 db 0x20 ;; pci device number (bit 7-3)
9522 db 0x60 ;; link value INTA#
9523 dw 0x0c20 ;; IRQ bitmap INTA#
9524 db 0x61 ;; link value INTB#
9525 dw 0x0c20 ;; IRQ bitmap INTB#
9526 db 0x62 ;; link value INTC#
9527 dw 0x0c20 ;; IRQ bitmap INTC#
9528 db 0x63 ;; link value INTD#
9529 dw 0x0c20 ;; IRQ bitmap INTD#
9530 db 3 ;; physical slot (0 = embedded)
9531 db 0 ;; reserved
9532 ;; 5th slot entry: 4rd PCI slot
9533 db 0 ;; pci bus number
9534 db 0x28 ;; pci device number (bit 7-3)
9535 db 0x61 ;; link value INTA#
9536 dw 0x0c20 ;; IRQ bitmap INTA#
9537 db 0x62 ;; link value INTB#
9538 dw 0x0c20 ;; IRQ bitmap INTB#
9539 db 0x63 ;; link value INTC#
9540 dw 0x0c20 ;; IRQ bitmap INTC#
9541 db 0x60 ;; link value INTD#
9542 dw 0x0c20 ;; IRQ bitmap INTD#
9543 db 4 ;; physical slot (0 = embedded)
9544 db 0 ;; reserved
9545 ;; 6th slot entry: 5rd PCI slot
9546 db 0 ;; pci bus number
9547 db 0x30 ;; pci device number (bit 7-3)
9548 db 0x62 ;; link value INTA#
9549 dw 0x0c20 ;; IRQ bitmap INTA#
9550 db 0x63 ;; link value INTB#
9551 dw 0x0c20 ;; IRQ bitmap INTB#
9552 db 0x60 ;; link value INTC#
9553 dw 0x0c20 ;; IRQ bitmap INTC#
9554 db 0x61 ;; link value INTD#
9555 dw 0x0c20 ;; IRQ bitmap INTD#
9556 db 5 ;; physical slot (0 = embedded)
9557 db 0 ;; reserved
9558 #endif // BX_PCIBIOS
9560 ; parallel port detection: base address in DX, index in BX, timeout in CL
9561 detect_parport:
9562 push dx
9563 add dx, #2
9564 in al, dx
9565 and al, #0xdf ; clear input mode
9566 out dx, al
9567 pop dx
9568 mov al, #0xaa
9569 out dx, al
9570 in al, dx
9571 cmp al, #0xaa
9572 jne no_parport
9573 push bx
9574 shl bx, #1
9575 mov [bx+0x408], dx ; Parallel I/O address
9576 pop bx
9577 mov [bx+0x478], cl ; Parallel printer timeout
9578 inc bx
9579 no_parport:
9580 ret
9582 ; serial port detection: base address in DX, index in BX, timeout in CL
9583 detect_serial:
9584 push dx
9585 inc dx
9586 mov al, #0x02
9587 out dx, al
9588 in al, dx
9589 cmp al, #0x02
9590 jne no_serial
9591 inc dx
9592 in al, dx
9593 cmp al, #0x02
9594 jne no_serial
9595 dec dx
9596 xor al, al
9597 out dx, al
9598 pop dx
9599 push bx
9600 shl bx, #1
9601 mov [bx+0x400], dx ; Serial I/O address
9602 pop bx
9603 mov [bx+0x47c], cl ; Serial timeout
9604 inc bx
9605 ret
9606 no_serial:
9607 pop dx
9608 ret
9610 rom_checksum:
9611 push ax
9612 push bx
9613 push cx
9614 xor ax, ax
9615 xor bx, bx
9616 xor cx, cx
9617 mov ch, [2]
9618 shl cx, #1
9619 checksum_loop:
9620 add al, [bx]
9621 inc bx
9622 loop checksum_loop
9623 and al, #0xff
9624 pop cx
9625 pop bx
9626 pop ax
9627 ret
9630 ;; We need a copy of this string, but we are not actually a PnP BIOS,
9631 ;; so make sure it is *not* aligned, so OSes will not see it if they scan.
9632 .align 16
9633 db 0
9634 pnp_string:
9635 .ascii "$PnP"
9638 rom_scan:
9639 ;; Scan for existence of valid expansion ROMS.
9640 ;; Video ROM: from 0xC0000..0xC7FFF in 2k increments
9641 ;; General ROM: from 0xC8000..0xDFFFF in 2k increments
9642 ;; System ROM: only 0xE0000
9643 ;;
9644 ;; Header:
9645 ;; Offset Value
9646 ;; 0 0x55
9647 ;; 1 0xAA
9648 ;; 2 ROM length in 512-byte blocks
9649 ;; 3 ROM initialization entry point (FAR CALL)
9651 #if BX_TCGBIOS
9652 call _tcpa_start_option_rom_scan /* specs: 3.2.3.3 + 10.4.3 */
9653 #endif
9654 mov cx, #0xc000
9655 rom_scan_loop:
9656 mov ds, cx
9657 mov ax, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
9658 cmp [0], #0xAA55 ;; look for signature
9659 jne rom_scan_increment
9660 call rom_checksum
9661 jnz rom_scan_increment
9662 mov al, [2] ;; change increment to ROM length in 512-byte blocks
9664 ;; We want our increment in 512-byte quantities, rounded to
9665 ;; the nearest 2k quantity, since we only scan at 2k intervals.
9666 test al, #0x03
9667 jz block_count_rounded
9668 and al, #0xfc ;; needs rounding up
9669 add al, #0x04
9670 block_count_rounded:
9672 #if BX_TCGBIOS
9673 push ax
9674 push ds
9675 push ecx
9676 xor ax, ax
9677 mov ds, ax
9678 and ecx, #0xffff
9679 push ecx ;; segment where option rom is located at
9680 call _tcpa_option_rom /* specs: 3.2.3.3 */
9681 add sp, #4 ;; pop segment
9682 pop ecx ;; original ecx
9683 pop ds
9684 pop ax
9685 #endif
9686 xor bx, bx ;; Restore DS back to 0000:
9687 mov ds, bx
9688 push ax ;; Save AX
9689 push di ;; Save DI
9690 ;; Push addr of ROM entry point
9691 push cx ;; Push seg
9692 push #0x0003 ;; Push offset
9694 ;; Point ES:DI at "$PnP", which tells the ROM that we are a PnP BIOS.
9695 ;; That should stop it grabbing INT 19h; we will use its BEV instead.
9696 mov ax, #0xf000
9697 mov es, ax
9698 lea di, pnp_string
9700 mov bp, sp ;; Call ROM init routine using seg:off on stack
9701 db 0xff ;; call_far ss:[bp+0]
9702 db 0x5e
9703 db 0
9704 cli ;; In case expansion ROM BIOS turns IF on
9705 add sp, #2 ;; Pop offset value
9706 pop cx ;; Pop seg value (restore CX)
9708 ;; Look at the ROM's PnP Expansion header. Properly, we're supposed
9709 ;; to init all the ROMs and then go back and build an IPL table of
9710 ;; all the bootable devices, but we can get away with one pass.
9711 mov ds, cx ;; ROM base
9712 mov bx, 0x001a ;; 0x1A is the offset into ROM header that contains...
9713 mov ax, [bx] ;; the offset of PnP expansion header, where...
9714 cmp ax, #0x5024 ;; we look for signature "$PnP"
9715 jne no_bev
9716 mov ax, 2[bx]
9717 cmp ax, #0x506e
9718 jne no_bev
9719 mov ax, 0x1a[bx] ;; 0x1A is also the offset into the expansion header of...
9720 cmp ax, #0x0000 ;; the Bootstrap Entry Vector, or zero if there is none.
9721 je no_bev
9723 ;; Found a device that thinks it can boot the system. Record its BEV.
9724 mov bx, #IPL_SEG ;; Go to the segment where the IPL table lives
9725 mov ds, bx
9726 mov bx, IPL_COUNT_OFFSET ;; Read the number of entries so far
9727 cmp bx, #IPL_TABLE_ENTRIES
9728 je no_bev ;; Get out if the table is full
9729 shl bx, #0x4 ;; Turn count into offset (entries are 16 bytes)
9730 mov 0[bx], #0x80 ;; This entry is a BEV device
9731 mov 6[bx], cx ;; Build a far pointer from the segment...
9732 mov 4[bx], ax ;; and the offset
9733 shr bx, #0x4 ;; Turn the offset back into a count
9734 inc bx ;; We have one more entry now
9735 mov IPL_COUNT_OFFSET, bx ;; Remember that.
9737 no_bev:
9738 pop di ;; Restore DI
9739 pop ax ;; Restore AX
9740 rom_scan_increment:
9741 shl ax, #5 ;; convert 512-bytes blocks to 16-byte increments
9742 ;; because the segment selector is shifted left 4 bits.
9743 add cx, ax
9744 cmp cx, #0xe000
9745 jbe rom_scan_loop
9747 xor ax, ax ;; Restore DS back to 0000:
9748 mov ds, ax
9749 ret
9751 #ifdef HVMASSIST
9753 ; Copy the SMBIOS entry point from where hvmloader left it.
9754 ; The entry point must be somewhere in 0xf0000-0xfffff on a 16-byte boundary,
9755 ; but the tables themselves can be elsewhere.
9756 smbios_init:
9757 push ax
9758 push cx
9759 push es
9760 push ds
9761 push di
9762 push si
9764 mov cx, #0x001f ; 0x1f bytes to copy
9765 mov ax, #0xf000
9766 mov es, ax ; destination segment is 0xf0000
9767 mov di, #smbios_entry_point ; destination offset
9768 mov ax, #(SMBIOS_PHYSICAL_ADDRESS>>4)
9769 mov ds, ax
9770 mov si, #(SMBIOS_PHYSICAL_ADDRESS&15)
9771 cld
9772 rep
9773 movsb
9775 pop si
9776 pop di
9777 pop ds
9778 pop es
9779 pop cx
9780 pop ax
9782 ret
9784 #endif
9786 #if BX_TCGBIOS
9787 ; The section between the POST entry and the NMI entry is filling up
9788 ; and causes crashes if this code was directly there
9789 tcpa_post_part1:
9790 call _tcpa_acpi_init
9792 push dword #0
9793 call _tcpa_initialize_tpm
9794 add sp, #4
9796 call _tcpa_do_measure_POSTs
9797 call _tcpa_wake_event /* specs: 3.2.3.7 */
9798 ret
9800 tcpa_post_part2:
9801 call _tcpa_calling_int19h /* specs: 8.2.3 step 1 */
9802 call _tcpa_add_event_separators /* specs: 8.2.3 step 2 */
9803 /* we do not call int 19h handler but keep following eventlog */
9804 call _tcpa_returned_int19h /* specs: 8.2.3 step 3/7 */
9805 ret
9806 #endif
9809 ;; for 'C' strings and other data, insert them here with
9810 ;; a the following hack:
9811 ;; DATA_SEG_DEFS_HERE
9814 ;--------
9815 ;- POST -
9816 ;--------
9817 .org 0xe05b ; POST Entry Point
9818 post:
9820 xor ax, ax
9822 ;; first reset the DMA controllers
9823 out 0x0d,al
9824 out 0xda,al
9826 ;; then initialize the DMA controllers
9827 mov al, #0xC0
9828 out 0xD6, al ; cascade mode of channel 4 enabled
9829 mov al, #0x00
9830 out 0xD4, al ; unmask channel 4
9832 ;; Examine CMOS shutdown status.
9833 mov AL, #0x0f
9834 out 0x70, AL
9835 in AL, 0x71
9837 ;; backup status
9838 mov bl, al
9840 ;; Reset CMOS shutdown status.
9841 mov AL, #0x0f
9842 out 0x70, AL ; select CMOS register Fh
9843 mov AL, #0x00
9844 out 0x71, AL ; set shutdown action to normal
9846 ;; Examine CMOS shutdown status.
9847 mov al, bl
9849 ;; 0xFE S3 resume
9850 cmp AL, #0xFE
9851 jnz not_s3_resume
9853 ;; set S3 resume flag
9854 mov dx, #0xF000
9855 mov ds, dx
9856 mov [_s3_resume_flag], AL
9857 jmp normal_post
9859 not_s3_resume:
9861 ;; 0x00, 0x09, 0x0D+ = normal startup
9862 cmp AL, #0x00
9863 jz normal_post
9864 cmp AL, #0x0d
9865 jae normal_post
9866 cmp AL, #0x09
9867 je normal_post
9869 ;; 0x05 = eoi + jmp via [0x40:0x67] jump
9870 cmp al, #0x05
9871 je eoi_jmp_post
9873 ;; Examine CMOS shutdown status.
9874 ;; 0x01,0x02,0x03,0x04,0x06,0x07,0x08, 0x0a, 0x0b, 0x0c = Unimplemented shutdown status.
9875 push bx
9876 call _shutdown_status_panic
9878 #if 0
9879 HALT(__LINE__)
9881 ;#if 0
9882 ; 0xb0, 0x20, /* mov al, #0x20 */
9883 ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */
9884 ;#endif
9886 pop es
9887 pop ds
9888 popa
9889 iret
9890 #endif
9892 normal_post:
9893 ; case 0: normal startup
9895 cli
9896 mov ax, #0xfffe
9897 mov sp, ax
9898 mov ax, #0x0000
9899 mov ds, ax
9900 mov ss, ax
9902 ;; zero out BIOS data area (40:00..40:ff)
9903 mov es, ax
9904 mov cx, #0x0080 ;; 128 words
9905 mov di, #0x0400
9906 cld
9907 rep
9908 stosw
9910 call _log_bios_start
9912 call _clobber_entry_point
9914 ;; set all interrupts to default handler
9915 mov bx, #0x0000 ;; offset index
9916 mov cx, #0x0100 ;; counter (256 interrupts)
9917 mov ax, #dummy_iret_handler
9918 mov dx, #0xF000
9920 post_default_ints:
9921 mov [bx], ax
9922 inc bx
9923 inc bx
9924 mov [bx], dx
9925 inc bx
9926 inc bx
9927 loop post_default_ints
9929 ;; set vector 0x79 to zero
9930 ;; this is used by 'gardian angel' protection system
9931 SET_INT_VECTOR(0x79, #0, #0)
9933 ;; base memory in K 40:13 (word)
9934 mov ax, #BASE_MEM_IN_K
9935 mov 0x0413, ax
9938 ;; Manufacturing Test 40:12
9939 ;; zerod out above
9941 ;; Warm Boot Flag 0040:0072
9942 ;; value of 1234h = skip memory checks
9943 ;; zerod out above
9946 ;; Printer Services vector
9947 SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
9949 ;; Bootstrap failure vector
9950 SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
9952 ;; Bootstrap Loader vector
9953 SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
9955 ;; User Timer Tick vector
9956 SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
9958 ;; Memory Size Check vector
9959 SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
9961 ;; Equipment Configuration Check vector
9962 SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
9964 ;; System Services
9965 SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
9967 ;; EBDA setup
9968 call ebda_post
9970 ;; PIT setup
9971 SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
9972 ;; int 1C already points at dummy_iret_handler (above)
9973 mov al, #0x34 ; timer0: binary count, 16bit count, mode 2
9974 out 0x43, al
9975 #ifdef HVMASSIST
9976 mov al, #0x0b ; #0xe90b = 20 Hz (temporary, until we fix xen/vmx support)
9977 out 0x40, al ; lsb
9978 mov al, #0xe9
9979 out 0x40, al ; msb
9980 #else
9981 mov al, #0x00 ; maximum count of 0000H = 18.2Hz
9982 out 0x40, al
9983 out 0x40, al
9984 #endif
9986 ;; Keyboard
9987 SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
9988 SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
9990 xor ax, ax
9991 mov ds, ax
9992 mov 0x0417, al /* keyboard shift flags, set 1 */
9993 mov 0x0418, al /* keyboard shift flags, set 2 */
9994 mov 0x0419, al /* keyboard alt-numpad work area */
9995 mov 0x0471, al /* keyboard ctrl-break flag */
9996 mov 0x0497, al /* keyboard status flags 4 */
9997 mov al, #0x10
9998 mov 0x0496, al /* keyboard status flags 3 */
10001 /* keyboard head of buffer pointer */
10002 mov bx, #0x001E
10003 mov 0x041A, bx
10005 /* keyboard end of buffer pointer */
10006 mov 0x041C, bx
10008 /* keyboard pointer to start of buffer */
10009 mov bx, #0x001E
10010 mov 0x0480, bx
10012 /* keyboard pointer to end of buffer */
10013 mov bx, #0x003E
10014 mov 0x0482, bx
10016 /* init the keyboard */
10017 call _keyboard_init
10019 ;; mov CMOS Equipment Byte to BDA Equipment Word
10020 mov ax, 0x0410
10021 mov al, #0x14
10022 out 0x70, al
10023 in al, 0x71
10024 mov 0x0410, ax
10026 #if BX_TCGBIOS
10027 call tcpa_post_part1
10028 #endif
10030 ;; Parallel setup
10031 SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
10032 xor ax, ax
10033 mov ds, ax
10034 xor bx, bx
10035 mov cl, #0x14 ; timeout value
10036 mov dx, #0x378 ; Parallel I/O address, port 1
10037 call detect_parport
10038 mov dx, #0x278 ; Parallel I/O address, port 2
10039 call detect_parport
10040 shl bx, #0x0e
10041 mov ax, 0x410 ; Equipment word bits 14..15 determing # parallel ports
10042 and ax, #0x3fff
10043 or ax, bx ; set number of parallel ports
10044 mov 0x410, ax
10046 ;; Serial setup
10047 SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
10048 SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
10049 xor bx, bx
10050 mov cl, #0x0a ; timeout value
10051 mov dx, #0x03f8 ; Serial I/O address, port 1
10052 call detect_serial
10053 mov dx, #0x02f8 ; Serial I/O address, port 2
10054 call detect_serial
10055 mov dx, #0x03e8 ; Serial I/O address, port 3
10056 call detect_serial
10057 mov dx, #0x02e8 ; Serial I/O address, port 4
10058 call detect_serial
10059 shl bx, #0x09
10060 mov ax, 0x410 ; Equipment word bits 9..11 determing # serial ports
10061 and ax, #0xf1ff
10062 or ax, bx ; set number of serial port
10063 mov 0x410, ax
10065 ;; CMOS RTC
10066 SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
10067 SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
10068 SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
10069 ;; BIOS DATA AREA 0x4CE ???
10070 call timer_tick_post
10072 ;; PS/2 mouse setup
10073 SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
10075 ;; IRQ13 (FPU exception) setup
10076 SET_INT_VECTOR(0x75, #0xF000, #int75_handler)
10078 ;; Video setup
10079 SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
10081 ;; PIC
10082 mov al, #0x11 ; send initialisation commands
10083 out 0x20, al
10084 out 0xa0, al
10085 mov al, #0x08
10086 out 0x21, al
10087 mov al, #0x70
10088 out 0xa1, al
10089 mov al, #0x04
10090 out 0x21, al
10091 mov al, #0x02
10092 out 0xa1, al
10093 mov al, #0x01
10094 out 0x21, al
10095 out 0xa1, al
10096 mov al, #0xb8
10097 out 0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6
10098 #if BX_USE_PS2_MOUSE
10099 mov al, #0x8f
10100 #else
10101 mov al, #0x9f
10102 #endif
10103 out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14
10105 #ifdef HVMASSIST
10106 call _copy_e820_table
10107 call smbios_init
10108 #endif
10110 call _init_boot_vectors
10112 call rom_scan
10114 call _print_bios_banner
10116 ;;
10117 ;; Floppy setup
10118 ;;
10119 call floppy_drive_post
10121 #if BX_USE_ATADRV
10123 ;;
10124 ;; Hard Drive setup
10125 ;;
10126 call hard_drive_post
10128 ;;
10129 ;; ATA/ATAPI driver setup
10130 ;;
10131 call _ata_init
10132 call _ata_detect
10133 ;;
10134 #else // BX_USE_ATADRV
10136 ;;
10137 ;; Hard Drive setup
10138 ;;
10139 call hard_drive_post
10141 #endif // BX_USE_ATADRV
10143 #if BX_ELTORITO_BOOT
10144 ;;
10145 ;; eltorito floppy/harddisk emulation from cd
10146 ;;
10147 call _cdemu_init
10148 ;;
10149 #endif // BX_ELTORITO_BOOT
10151 call _s3_resume
10152 call _interactive_bootkey
10154 #if BX_TCGBIOS
10155 call tcpa_post_part2
10156 #endif
10158 ;; Start the boot sequence. See the comments in int19_relocated
10159 ;; for why we use INT 18h instead of INT 19h here.
10160 int #0x18
10162 .org 0xe2c3 ; NMI Handler Entry Point
10163 nmi:
10164 ;; FIXME the NMI handler should not panic
10165 ;; but iret when called from int75 (fpu exception)
10166 call _nmi_handler_msg
10167 iret
10169 int75_handler:
10170 out 0xf0, al // clear irq13
10171 call eoi_both_pics // clear interrupt
10172 int 2 // legacy nmi call
10173 iret
10175 ;-------------------------------------------
10176 ;- INT 13h Fixed Disk Services Entry Point -
10177 ;-------------------------------------------
10178 .org 0xe3fe ; INT 13h Fixed Disk Services Entry Point
10179 int13_handler:
10180 //JMPL(int13_relocated)
10181 jmp int13_relocated
10183 .org 0xe401 ; Fixed Disk Parameter Table
10185 ;----------
10186 ;- INT19h -
10187 ;----------
10188 .org 0xe6f2 ; INT 19h Boot Load Service Entry Point
10189 int19_handler:
10191 jmp int19_relocated
10192 ;-------------------------------------------
10193 ;- System BIOS Configuration Data Table
10194 ;-------------------------------------------
10195 .org BIOS_CONFIG_TABLE
10196 db 0x08 ; Table size (bytes) -Lo
10197 db 0x00 ; Table size (bytes) -Hi
10198 db SYS_MODEL_ID
10199 db SYS_SUBMODEL_ID