ia64/xen-unstable

view tools/firmware/rombios/rombios.c @ 5610:cd86df78b879

bitkeeper revision 1.1775 (42c3a866BfZr3l3NiVNwr6Z_1Uin_A)

[PATCH] Fix PCI BIOS double initialization.

Fix PCI BIOS double initialization.

Because the qemu device models are already doing the PCI BIOS initialization,
don't do it in rombios. With this change, the PCI network card becomes
functional.

Signed-off-by: Winston Wang <winston.l.wang@intel.com>
Signed-off-by: Arun Sharma <arun.sharma@intel.com>

diff -r e71f644f492e -r 5d58883fc7b8 tools/firmware/rombios/rombios.c
author arun.sharma@intel.com[kaf24]
date Thu Jun 30 08:08:06 2005 +0000 (2005-06-30)
parents 63c1bb85fcea
children 3acc0ae6a001 b53a65034532
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 #define VMXASSIST
30 #undef VMXTEST
32 // ROM BIOS compatability entry points:
33 // ===================================
34 // $e05b ; POST Entry Point
35 // $e2c3 ; NMI Handler Entry Point
36 // $e3fe ; INT 13h Fixed Disk Services Entry Point
37 // $e401 ; Fixed Disk Parameter Table
38 // $e6f2 ; INT 19h Boot Load Service Entry Point
39 // $e6f5 ; Configuration Data Table
40 // $e729 ; Baud Rate Generator Table
41 // $e739 ; INT 14h Serial Communications Service Entry Point
42 // $e82e ; INT 16h Keyboard Service Entry Point
43 // $e987 ; INT 09h Keyboard Service Entry Point
44 // $ec59 ; INT 13h Diskette Service Entry Point
45 // $ef57 ; INT 0Eh Diskette Hardware ISR Entry Point
46 // $efc7 ; Diskette Controller Parameter Table
47 // $efd2 ; INT 17h Printer Service Entry Point
48 // $f045 ; INT 10 Functions 0-Fh Entry Point
49 // $f065 ; INT 10h Video Support Service Entry Point
50 // $f0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
51 // $f841 ; INT 12h Memory Size Service Entry Point
52 // $f84d ; INT 11h Equipment List Service Entry Point
53 // $f859 ; INT 15h System Services Entry Point
54 // $fa6e ; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
55 // $fe6e ; INT 1Ah Time-of-day Service Entry Point
56 // $fea5 ; INT 08h System Timer ISR Entry Point
57 // $fef3 ; Initial Interrupt Vector Offsets Loaded by POST
58 // $ff53 ; IRET Instruction for Dummy Interrupt Handler
59 // $ff54 ; INT 05h Print Screen Service Entry Point
60 // $fff0 ; Power-up Entry Point
61 // $fff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
62 // $fffe ; System Model ID
64 // NOTES for ATA/ATAPI driver (cbbochs@free.fr)
65 // Features
66 // - supports up to 4 ATA interfaces
67 // - device/geometry detection
68 // - 16bits/32bits device access
69 // - pchs/lba access
70 // - datain/dataout/packet command support
71 //
72 // NOTES for El-Torito Boot (cbbochs@free.fr)
73 // - CD-ROM booting is only available if ATA/ATAPI Driver is available
74 // - Current code is only able to boot mono-session cds
75 // - Current code can not boot and emulate a hard-disk
76 // the bios will panic otherwise
77 // - Current code also use memory in EBDA segement.
78 // - I used cmos byte 0x3D to store extended information on boot-device
79 // - Code has to be modified modified to handle multiple cdrom drives
80 // - Here are the cdrom boot failure codes:
81 // 1 : no atapi device found
82 // 2 : no atapi cdrom found
83 // 3 : can not read cd - BRVD
84 // 4 : cd is not eltorito (BRVD)
85 // 5 : cd is not eltorito (ISO TAG)
86 // 6 : cd is not eltorito (ELTORITO TAG)
87 // 7 : can not read cd - boot catalog
88 // 8 : boot catalog : bad header
89 // 9 : boot catalog : bad platform
90 // 10 : boot catalog : bad signature
91 // 11 : boot catalog : bootable flag not set
92 // 12 : can not read cd - boot image
93 //
94 // ATA driver
95 // - EBDA segment.
96 // I used memory starting at 0x121 in the segment
97 // - the translation policy is defined in cmos regs 0x39 & 0x3a
98 //
99 // TODO :
100 //
101 // int74
102 // - needs to be reworked. Uses direct [bp] offsets. (?)
103 //
104 // int13:
105 // - f04 (verify sectors) isn't complete (?)
106 // - f02/03/04 should set current cyl,etc in BDA (?)
107 // - rewrite int13_relocated & clean up int13 entry code
108 //
109 // NOTES:
110 // - NMI access (bit7 of addr written to 70h)
111 //
112 // ATA driver
113 // - should handle the "don't detect" bit (cmos regs 0x3b & 0x3c)
114 // - could send the multiple-sector read/write commands
115 //
116 // El-Torito
117 // - Emulate a Hard-disk (currently only diskette can be emulated) see "FIXME ElTorito Harddisk"
118 // - Implement remaining int13_cdemu functions (as defined by El-Torito specs)
119 // - cdrom drive is hardcoded to ide 0 device 1 in several places. see "FIXME ElTorito Hardcoded"
120 // - int13 Fix DL when emulating a cd. In that case DL is decremented before calling real int13.
121 // This is ok. But DL should be reincremented afterwards.
122 // - Fix all "FIXME ElTorito Various"
123 // - should be able to boot any cdrom instead of the first one
124 //
125 // BCC Bug: find a generic way to handle the bug of #asm after an "if" (fixed in 0.16.7)
127 #define DEBUG_ROMBIOS 0
129 #define DEBUG_ATA 0
130 #define DEBUG_INT13_HD 0
131 #define DEBUG_INT13_CD 0
132 #define DEBUG_INT13_ET 0
133 #define DEBUG_INT13_FL 0
134 #define DEBUG_INT15 0
135 #define DEBUG_INT16 0
136 #define DEBUG_INT1A 0
137 #define DEBUG_INT74 0
138 #define DEBUG_APM 0
140 #define BX_CPU 3
141 #define BX_USE_PS2_MOUSE 1
142 #define BX_CALL_INT15_4F 1
143 #define BX_USE_EBDA 1
144 #define BX_SUPPORT_FLOPPY 1
145 #define BX_FLOPPY_ON_CNT 37 /* 2 seconds */
146 #define BX_PCIBIOS 1
147 #define BX_APM 1
149 #define BX_USE_ATADRV 1
150 #define BX_ELTORITO_BOOT 1
152 #define BX_MAX_ATA_INTERFACES 4
153 #define BX_MAX_ATA_DEVICES (BX_MAX_ATA_INTERFACES*2)
155 #define BX_VIRTUAL_PORTS 1 /* normal output to Bochs ports */
156 #define BX_DEBUG_SERIAL 0 /* output to COM1 */
158 /* model byte 0xFC = AT */
159 #define SYS_MODEL_ID 0xFC
160 #define SYS_SUBMODEL_ID 0x00
161 #define BIOS_REVISION 1
162 #define BIOS_CONFIG_TABLE 0xe6f5
164 #ifndef BIOS_BUILD_DATE
165 # define BIOS_BUILD_DATE "06/23/99"
166 #endif
168 // 1K of base memory used for Extended Bios Data Area (EBDA)
169 // EBDA is used for PS/2 mouse support, and IDE BIOS, etc.
170 #define EBDA_SEG 0x9FC0
171 #define EBDA_SIZE 1 // In KiB
172 #define BASE_MEM_IN_K (640 - EBDA_SIZE)
174 // Define the application NAME
175 #ifdef VMXASSIST
176 # define BX_APPNAME "VMXAssist"
177 #elif PLEX86
178 # define BX_APPNAME "Plex86"
179 #else
180 # define BX_APPNAME "Bochs"
181 #endif
183 // Sanity Checks
184 #if BX_USE_ATADRV && BX_CPU<3
185 # error The ATA/ATAPI Driver can only to be used with a 386+ cpu
186 #endif
187 #if BX_USE_ATADRV && !BX_USE_EBDA
188 # error ATA/ATAPI Driver can only be used if EBDA is available
189 #endif
190 #if BX_ELTORITO_BOOT && !BX_USE_ATADRV
191 # error El-Torito Boot can only be use if ATA/ATAPI Driver is available
192 #endif
193 #if BX_PCIBIOS && BX_CPU<3
194 # error PCI BIOS can only be used with 386+ cpu
195 #endif
196 #if BX_APM && BX_CPU<3
197 # error APM BIOS can only be used with 386+ cpu
198 #endif
200 #ifndef BX_SMP_PROCESSORS
201 #define BX_SMP_PROCESSORS 1
202 # warning BX_SMP_PROCESSORS not defined, defaulting to 1
203 #endif
205 #define PANIC_PORT 0x400
206 #define PANIC_PORT2 0x401
207 #define INFO_PORT 0x402
208 #define DEBUG_PORT 0x403
210 // #20 is dec 20
211 // #$20 is hex 20 = 32
212 // #0x20 is hex 20 = 32
213 // LDA #$20
214 // JSR $E820
215 // LDD .i,S
216 // JSR $C682
217 // mov al, #$20
219 // all hex literals should be prefixed with '0x'
220 // grep "#[0-9a-fA-F][0-9a-fA-F]" rombios.c
221 // no mov SEG-REG, #value, must mov register into seg-reg
222 // grep -i "mov[ ]*.s" rombios.c
224 // This is for compiling with gcc2 and gcc3
225 #define ASM_START #asm
226 #define ASM_END #endasm
228 ASM_START
229 .rom
231 .org 0x0000
233 #if BX_CPU >= 3
234 use16 386
235 #else
236 use16 286
237 #endif
239 MACRO HALT
240 ;; the HALT macro is called with the line number of the HALT call.
241 ;; The line number is then sent to the PANIC_PORT, causing Bochs/Plex
242 ;; to print a BX_PANIC message. This will normally halt the simulation
243 ;; with a message such as "BIOS panic at rombios.c, line 4091".
244 ;; However, users can choose to make panics non-fatal and continue.
245 #if BX_VIRTUAL_PORTS
246 mov dx,#PANIC_PORT
247 mov ax,#?1
248 out dx,ax
249 #else
250 mov dx,#0x80
251 mov ax,#?1
252 out dx,al
253 #endif
254 MEND
256 MACRO JMP_AP
257 db 0xea
258 dw ?2
259 dw ?1
260 MEND
262 MACRO SET_INT_VECTOR
263 mov ax, ?3
264 mov ?1*4, ax
265 mov ax, ?2
266 mov ?1*4+2, ax
267 MEND
269 ASM_END
271 typedef unsigned char Bit8u;
272 typedef unsigned short Bit16u;
273 typedef unsigned short bx_bool;
274 typedef unsigned long Bit32u;
276 #if BX_USE_ATADRV
278 void memsetb(seg,offset,value,count);
279 void memcpyb(dseg,doffset,sseg,soffset,count);
280 void memcpyd(dseg,doffset,sseg,soffset,count);
282 // memset of count bytes
283 void
284 memsetb(seg,offset,value,count)
285 Bit16u seg;
286 Bit16u offset;
287 Bit16u value;
288 Bit16u count;
289 {
290 ASM_START
291 push bp
292 mov bp, sp
294 push ax
295 push cx
296 push es
297 push di
299 mov cx, 10[bp] ; count
300 cmp cx, #0x00
301 je memsetb_end
302 mov ax, 4[bp] ; segment
303 mov es, ax
304 mov ax, 6[bp] ; offset
305 mov di, ax
306 mov al, 8[bp] ; value
307 cld
308 rep
309 stosb
311 memsetb_end:
312 pop di
313 pop es
314 pop cx
315 pop ax
317 pop bp
318 ASM_END
319 }
321 // memcpy of count bytes
322 void
323 memcpyb(dseg,doffset,sseg,soffset,count)
324 Bit16u dseg;
325 Bit16u doffset;
326 Bit16u sseg;
327 Bit16u soffset;
328 Bit16u count;
329 {
330 ASM_START
331 push bp
332 mov bp, sp
334 push ax
335 push cx
336 push es
337 push di
338 push ds
339 push si
341 mov cx, 12[bp] ; count
342 cmp cx, #0x0000
343 je memcpyb_end
344 mov ax, 4[bp] ; dsegment
345 mov es, ax
346 mov ax, 6[bp] ; doffset
347 mov di, ax
348 mov ax, 8[bp] ; ssegment
349 mov ds, ax
350 mov ax, 10[bp] ; soffset
351 mov si, ax
352 cld
353 rep
354 movsb
356 memcpyb_end:
357 pop si
358 pop ds
359 pop di
360 pop es
361 pop cx
362 pop ax
364 pop bp
365 ASM_END
366 }
368 #if 0
369 // memcpy of count dword
370 void
371 memcpyd(dseg,doffset,sseg,soffset,count)
372 Bit16u dseg;
373 Bit16u doffset;
374 Bit16u sseg;
375 Bit16u soffset;
376 Bit16u count;
377 {
378 ASM_START
379 push bp
380 mov bp, sp
382 push ax
383 push cx
384 push es
385 push di
386 push ds
387 push si
389 mov cx, 12[bp] ; count
390 cmp cx, #0x0000
391 je memcpyd_end
392 mov ax, 4[bp] ; dsegment
393 mov es, ax
394 mov ax, 6[bp] ; doffset
395 mov di, ax
396 mov ax, 8[bp] ; ssegment
397 mov ds, ax
398 mov ax, 10[bp] ; soffset
399 mov si, ax
400 cld
401 rep
402 movsd
404 memcpyd_end:
405 pop si
406 pop ds
407 pop di
408 pop es
409 pop cx
410 pop ax
412 pop bp
413 ASM_END
414 }
415 #endif
416 #endif //BX_USE_ATADRV
418 // read_dword and write_dword functions
419 static Bit32u read_dword();
420 static void write_dword();
422 Bit32u
423 read_dword(seg, offset)
424 Bit16u seg;
425 Bit16u offset;
426 {
427 ASM_START
428 push bp
429 mov bp, sp
431 push bx
432 push ds
433 mov ax, 4[bp] ; segment
434 mov ds, ax
435 mov bx, 6[bp] ; offset
436 mov ax, [bx]
437 inc bx
438 inc bx
439 mov dx, [bx]
440 ;; ax = return value (word)
441 ;; dx = return value (word)
442 pop ds
443 pop bx
445 pop bp
446 ASM_END
447 }
449 void
450 write_dword(seg, offset, data)
451 Bit16u seg;
452 Bit16u offset;
453 Bit32u data;
454 {
455 ASM_START
456 push bp
457 mov bp, sp
459 push ax
460 push bx
461 push ds
462 mov ax, 4[bp] ; segment
463 mov ds, ax
464 mov bx, 6[bp] ; offset
465 mov ax, 8[bp] ; data word
466 mov [bx], ax ; write data word
467 inc bx
468 inc bx
469 mov ax, 10[bp] ; data word
470 mov [bx], ax ; write data word
471 pop ds
472 pop bx
473 pop ax
475 pop bp
476 ASM_END
477 }
479 // Bit32u (unsigned long) and long helper functions
480 ASM_START
482 ;; and function
483 landl:
484 landul:
485 SEG SS
486 and ax,[di]
487 SEG SS
488 and bx,2[di]
489 ret
491 ;; add function
492 laddl:
493 laddul:
494 SEG SS
495 add ax,[di]
496 SEG SS
497 adc bx,2[di]
498 ret
500 ;; cmp function
501 lcmpl:
502 lcmpul:
503 and eax, #0x0000FFFF
504 shl ebx, #16
505 add eax, ebx
506 shr ebx, #16
507 SEG SS
508 cmp eax, dword ptr [di]
509 ret
511 ;; sub function
512 lsubl:
513 lsubul:
514 SEG SS
515 sub ax,[di]
516 SEG SS
517 sbb bx,2[di]
518 ret
520 ;; mul function
521 lmull:
522 lmulul:
523 and eax, #0x0000FFFF
524 shl ebx, #16
525 add eax, ebx
526 SEG SS
527 mul eax, dword ptr [di]
528 mov ebx, eax
529 shr ebx, #16
530 ret
532 ;; dec function
533 ldecl:
534 ldecul:
535 SEG SS
536 dec dword ptr [bx]
537 ret
539 ;; or function
540 lorl:
541 lorul:
542 SEG SS
543 or ax,[di]
544 SEG SS
545 or bx,2[di]
546 ret
548 ;; inc function
549 lincl:
550 lincul:
551 SEG SS
552 inc dword ptr [bx]
553 ret
555 ;; tst function
556 ltstl:
557 ltstul:
558 and eax, #0x0000FFFF
559 shl ebx, #16
560 add eax, ebx
561 shr ebx, #16
562 test eax, eax
563 ret
565 ;; sr function
566 lsrul:
567 mov cx,di
568 jcxz lsr_exit
569 and eax, #0x0000FFFF
570 shl ebx, #16
571 add eax, ebx
572 lsr_loop:
573 shr eax, #1
574 loop lsr_loop
575 mov ebx, eax
576 shr ebx, #16
577 lsr_exit:
578 ret
580 ;; sl function
581 lsll:
582 lslul:
583 mov cx,di
584 jcxz lsl_exit
585 and eax, #0x0000FFFF
586 shl ebx, #16
587 add eax, ebx
588 lsl_loop:
589 shl eax, #1
590 loop lsl_loop
591 mov ebx, eax
592 shr ebx, #16
593 lsl_exit:
594 ret
596 idiv_:
597 cwd
598 idiv bx
599 ret
601 idiv_u:
602 xor dx,dx
603 div bx
604 ret
606 ldivul:
607 and eax, #0x0000FFFF
608 shl ebx, #16
609 add eax, ebx
610 xor edx, edx
611 SEG SS
612 mov bx, 2[di]
613 shl ebx, #16
614 SEG SS
615 mov bx, [di]
616 div ebx
617 mov ebx, eax
618 shr ebx, #16
619 ret
621 ASM_END
623 // for access to RAM area which is used by interrupt vectors
624 // and BIOS Data Area
626 typedef struct {
627 unsigned char filler1[0x400];
628 unsigned char filler2[0x6c];
629 Bit16u ticks_low;
630 Bit16u ticks_high;
631 Bit8u midnight_flag;
632 } bios_data_t;
634 #define BiosData ((bios_data_t *) 0)
636 #if BX_USE_ATADRV
637 typedef struct {
638 Bit16u heads; // # heads
639 Bit16u cylinders; // # cylinders
640 Bit16u spt; // # sectors / track
641 } chs_t;
643 // DPTE definition
644 typedef struct {
645 Bit16u iobase1;
646 Bit16u iobase2;
647 Bit8u prefix;
648 Bit8u unused;
649 Bit8u irq;
650 Bit8u blkcount;
651 Bit8u dma;
652 Bit8u pio;
653 Bit16u options;
654 Bit16u reserved;
655 Bit8u revision;
656 Bit8u checksum;
657 } dpte_t;
659 typedef struct {
660 Bit8u iface; // ISA or PCI
661 Bit16u iobase1; // IO Base 1
662 Bit16u iobase2; // IO Base 2
663 Bit8u irq; // IRQ
664 } ata_channel_t;
666 typedef struct {
667 Bit8u type; // Detected type of ata (ata/atapi/none/unknown)
668 Bit8u device; // Detected type of attached devices (hd/cd/none)
669 Bit8u removable; // Removable device flag
670 Bit8u lock; // Locks for removable devices
671 // Bit8u lba_capable; // LBA capable flag - always yes for bochs devices
672 Bit8u mode; // transfert mode : PIO 16/32 bits - IRQ - ISADMA - PCIDMA
673 Bit16u blksize; // block size
675 Bit8u translation; // type of translation
676 chs_t lchs; // Logical CHS
677 chs_t pchs; // Physical CHS
679 Bit32u sectors; // Total sectors count
680 } ata_device_t;
682 typedef struct {
683 // ATA channels info
684 ata_channel_t channels[BX_MAX_ATA_INTERFACES];
686 // ATA devices info
687 ata_device_t devices[BX_MAX_ATA_DEVICES];
688 //
689 // map between (bios hd id - 0x80) and ata channels
690 Bit8u hdcount, hdidmap[BX_MAX_ATA_DEVICES];
692 // map between (bios cd id - 0xE0) and ata channels
693 Bit8u cdcount, cdidmap[BX_MAX_ATA_DEVICES];
695 // Buffer for DPTE table
696 dpte_t dpte;
698 // Count of transferred sectors and bytes
699 Bit16u trsfsectors;
700 Bit32u trsfbytes;
702 } ata_t;
704 #if BX_ELTORITO_BOOT
705 // ElTorito Device Emulation data
706 typedef struct {
707 Bit8u active;
708 Bit8u media;
709 Bit8u emulated_drive;
710 Bit8u controller_index;
711 Bit16u device_spec;
712 Bit32u ilba;
713 Bit16u buffer_segment;
714 Bit16u load_segment;
715 Bit16u sector_count;
717 // Virtual device
718 chs_t vdevice;
719 } cdemu_t;
720 #endif // BX_ELTORITO_BOOT
722 // for access to EBDA area
723 // The EBDA structure should conform to
724 // http://www.cybertrails.com/~fys/rombios.htm document
725 // I made the ata and cdemu structs begin at 0x121 in the EBDA seg
726 typedef struct {
727 unsigned char filler1[0x3D];
729 // FDPT - Can be splitted in data members if needed
730 unsigned char fdpt0[0x10];
731 unsigned char fdpt1[0x10];
733 unsigned char filler2[0xC4];
735 // ATA Driver data
736 ata_t ata;
738 #if BX_ELTORITO_BOOT
739 // El Torito Emulation data
740 cdemu_t cdemu;
741 #endif // BX_ELTORITO_BOOT
743 } ebda_data_t;
745 #define EbdaData ((ebda_data_t *) 0)
747 // for access to the int13ext structure
748 typedef struct {
749 Bit8u size;
750 Bit8u reserved;
751 Bit16u count;
752 Bit16u offset;
753 Bit16u segment;
754 Bit32u lba1;
755 Bit32u lba2;
756 } int13ext_t;
758 #define Int13Ext ((int13ext_t *) 0)
760 // Disk Physical Table definition
761 typedef struct {
762 Bit16u size;
763 Bit16u infos;
764 Bit32u cylinders;
765 Bit32u heads;
766 Bit32u spt;
767 Bit32u sector_count1;
768 Bit32u sector_count2;
769 Bit16u blksize;
770 Bit16u dpte_segment;
771 Bit16u dpte_offset;
772 Bit16u key;
773 Bit8u dpi_length;
774 Bit8u reserved1;
775 Bit16u reserved2;
776 Bit8u host_bus[4];
777 Bit8u iface_type[8];
778 Bit8u iface_path[8];
779 Bit8u device_path[8];
780 Bit8u reserved3;
781 Bit8u checksum;
782 } dpt_t;
784 #define Int13DPT ((dpt_t *) 0)
786 #endif // BX_USE_ATADRV
788 typedef struct {
789 union {
790 struct {
791 Bit16u di, si, bp, sp;
792 Bit16u bx, dx, cx, ax;
793 } r16;
794 struct {
795 Bit16u filler[4];
796 Bit8u bl, bh, dl, dh, cl, ch, al, ah;
797 } r8;
798 } u;
799 } pusha_regs_t;
801 typedef struct {
802 union {
803 struct {
804 Bit32u edi, esi, ebp, esp;
805 Bit32u ebx, edx, ecx, eax;
806 } r32;
807 struct {
808 Bit16u di, filler1, si, filler2, bp, filler3, sp, filler4;
809 Bit16u bx, filler5, dx, filler6, cx, filler7, ax, filler8;
810 } r16;
811 struct {
812 Bit32u filler[4];
813 Bit8u bl, bh;
814 Bit16u filler1;
815 Bit8u dl, dh;
816 Bit16u filler2;
817 Bit8u cl, ch;
818 Bit16u filler3;
819 Bit8u al, ah;
820 Bit16u filler4;
821 } r8;
822 } u;
823 } pushad_regs_t;
825 typedef struct {
826 union {
827 struct {
828 Bit16u flags;
829 } r16;
830 struct {
831 Bit8u flagsl;
832 Bit8u flagsh;
833 } r8;
834 } u;
835 } flags_t;
837 #define SetCF(x) x.u.r8.flagsl |= 0x01
838 #define SetZF(x) x.u.r8.flagsl |= 0x40
839 #define ClearCF(x) x.u.r8.flagsl &= 0xfe
840 #define ClearZF(x) x.u.r8.flagsl &= 0xbf
841 #define GetCF(x) (x.u.r8.flagsl & 0x01)
843 typedef struct {
844 Bit16u ip;
845 Bit16u cs;
846 flags_t flags;
847 } iret_addr_t;
851 static Bit8u inb();
852 static Bit8u inb_cmos();
853 static void outb();
854 static void outb_cmos();
855 static Bit16u inw();
856 static void outw();
857 static void init_rtc();
858 static bx_bool rtc_updating();
860 static Bit8u read_byte();
861 static Bit16u read_word();
862 static void write_byte();
863 static void write_word();
864 static void bios_printf();
865 static void copy_e820_table();
867 static Bit8u inhibit_mouse_int_and_events();
868 static void enable_mouse_int_and_events();
869 static Bit8u send_to_mouse_ctrl();
870 static Bit8u get_mouse_data();
871 static void set_kbd_command_byte();
873 static void int09_function();
874 static void int13_harddisk();
875 static void int13_cdrom();
876 static void int13_cdemu();
877 static void int13_eltorito();
878 static void int13_diskette_function();
879 static void int14_function();
880 static void int15_function();
881 static void int16_function();
882 static void int17_function();
883 static Bit32u int19_function();
884 static void int1a_function();
885 static void int70_function();
886 static void int74_function();
887 static Bit16u get_CS();
888 //static Bit16u get_DS();
889 //static void set_DS();
890 static Bit16u get_SS();
891 static unsigned int enqueue_key();
892 static unsigned int dequeue_key();
893 static void get_hd_geometry();
894 static void set_diskette_ret_status();
895 static void set_diskette_current_cyl();
896 static void determine_floppy_media();
897 static bx_bool floppy_drive_exists();
898 static bx_bool floppy_drive_recal();
899 static bx_bool floppy_media_known();
900 static bx_bool floppy_media_sense();
901 static bx_bool set_enable_a20();
902 static void debugger_on();
903 static void debugger_off();
904 static void keyboard_init();
905 static void keyboard_panic();
906 static void shutdown_status_panic();
907 static void nmi_handler_msg();
909 static void print_bios_banner();
910 static void print_boot_device();
911 static void print_boot_failure();
912 static void print_cdromboot_failure();
914 # if BX_USE_ATADRV
916 // ATA / ATAPI driver
917 void ata_init();
918 void ata_detect();
919 void ata_reset();
921 Bit16u ata_cmd_non_data();
922 Bit16u ata_cmd_data_in();
923 Bit16u ata_cmd_data_out();
924 Bit16u ata_cmd_packet();
926 Bit16u atapi_get_sense();
927 Bit16u atapi_is_ready();
928 Bit16u atapi_is_cdrom();
930 #endif // BX_USE_ATADRV
932 #if BX_ELTORITO_BOOT
934 void cdemu_init();
935 Bit8u cdemu_isactive();
936 Bit8u cdemu_emulated_drive();
938 Bit16u cdrom_boot();
940 #endif // BX_ELTORITO_BOOT
942 static char bios_cvs_version_string[] = "$Revision: 1.138 $";
943 static char bios_date_string[] = "$Date: 2005/05/07 15:55:26 $";
945 static char CVSID[] = "$Id: rombios.c,v 1.138 2005/05/07 15:55:26 vruppert Exp $";
947 /* Offset to skip the CVS $Id: prefix */
948 #define bios_version_string (CVSID + 4)
950 #define BIOS_PRINTF_HALT 1
951 #define BIOS_PRINTF_SCREEN 2
952 #define BIOS_PRINTF_INFO 4
953 #define BIOS_PRINTF_DEBUG 8
954 #define BIOS_PRINTF_ALL (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO)
955 #define BIOS_PRINTF_DEBHALT (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO | BIOS_PRINTF_HALT)
957 #define printf(format, p...) bios_printf(BIOS_PRINTF_SCREEN, format, ##p)
959 // Defines the output macros.
960 // BX_DEBUG goes to INFO port until we can easily choose debug info on a
961 // per-device basis. Debug info are sent only in debug mode
962 #if DEBUG_ROMBIOS
963 # define BX_DEBUG(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
964 #else
965 # define BX_DEBUG(format, p...)
966 #endif
967 #define BX_INFO(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
968 #define BX_PANIC(format, p...) bios_printf(BIOS_PRINTF_DEBHALT, format, ##p)
970 #if DEBUG_ATA
971 # define BX_DEBUG_ATA(a...) BX_DEBUG(a)
972 #else
973 # define BX_DEBUG_ATA(a...)
974 #endif
975 #if DEBUG_INT13_HD
976 # define BX_DEBUG_INT13_HD(a...) BX_DEBUG(a)
977 #else
978 # define BX_DEBUG_INT13_HD(a...)
979 #endif
980 #if DEBUG_INT13_CD
981 # define BX_DEBUG_INT13_CD(a...) BX_DEBUG(a)
982 #else
983 # define BX_DEBUG_INT13_CD(a...)
984 #endif
985 #if DEBUG_INT13_ET
986 # define BX_DEBUG_INT13_ET(a...) BX_DEBUG(a)
987 #else
988 # define BX_DEBUG_INT13_ET(a...)
989 #endif
990 #if DEBUG_INT13_FL
991 # define BX_DEBUG_INT13_FL(a...) BX_DEBUG(a)
992 #else
993 # define BX_DEBUG_INT13_FL(a...)
994 #endif
995 #if DEBUG_INT15
996 # define BX_DEBUG_INT15(a...) BX_DEBUG(a)
997 #else
998 # define BX_DEBUG_INT15(a...)
999 #endif
1000 #if DEBUG_INT16
1001 # define BX_DEBUG_INT16(a...) BX_DEBUG(a)
1002 #else
1003 # define BX_DEBUG_INT16(a...)
1004 #endif
1005 #if DEBUG_INT1A
1006 # define BX_DEBUG_INT1A(a...) BX_DEBUG(a)
1007 #else
1008 # define BX_DEBUG_INT1A(a...)
1009 #endif
1010 #if DEBUG_INT74
1011 # define BX_DEBUG_INT74(a...) BX_DEBUG(a)
1012 #else
1013 # define BX_DEBUG_INT74(a...)
1014 #endif
1016 #define SET_AL(val8) AX = ((AX & 0xff00) | (val8))
1017 #define SET_BL(val8) BX = ((BX & 0xff00) | (val8))
1018 #define SET_CL(val8) CX = ((CX & 0xff00) | (val8))
1019 #define SET_DL(val8) DX = ((DX & 0xff00) | (val8))
1020 #define SET_AH(val8) AX = ((AX & 0x00ff) | ((val8) << 8))
1021 #define SET_BH(val8) BX = ((BX & 0x00ff) | ((val8) << 8))
1022 #define SET_CH(val8) CX = ((CX & 0x00ff) | ((val8) << 8))
1023 #define SET_DH(val8) DX = ((DX & 0x00ff) | ((val8) << 8))
1025 #define GET_AL() ( AX & 0x00ff )
1026 #define GET_BL() ( BX & 0x00ff )
1027 #define GET_CL() ( CX & 0x00ff )
1028 #define GET_DL() ( DX & 0x00ff )
1029 #define GET_AH() ( AX >> 8 )
1030 #define GET_BH() ( BX >> 8 )
1031 #define GET_CH() ( CX >> 8 )
1032 #define GET_DH() ( DX >> 8 )
1034 #define GET_ELDL() ( ELDX & 0x00ff )
1035 #define GET_ELDH() ( ELDX >> 8 )
1037 #define SET_CF() FLAGS |= 0x0001
1038 #define CLEAR_CF() FLAGS &= 0xfffe
1039 #define GET_CF() (FLAGS & 0x0001)
1041 #define SET_ZF() FLAGS |= 0x0040
1042 #define CLEAR_ZF() FLAGS &= 0xffbf
1043 #define GET_ZF() (FLAGS & 0x0040)
1045 #define UNSUPPORTED_FUNCTION 0x86
1047 #define none 0
1048 #define MAX_SCAN_CODE 0x53
1050 static struct {
1051 Bit16u normal;
1052 Bit16u shift;
1053 Bit16u control;
1054 Bit16u alt;
1055 Bit8u lock_flags;
1056 } scan_to_scanascii[MAX_SCAN_CODE + 1] = {
1057 { none, none, none, none, none },
1058 { 0x011b, 0x011b, 0x011b, 0x0100, none }, /* escape */
1059 { 0x0231, 0x0221, none, 0x7800, none }, /* 1! */
1060 { 0x0332, 0x0340, 0x0300, 0x7900, none }, /* 2@ */
1061 { 0x0433, 0x0423, none, 0x7a00, none }, /* 3# */
1062 { 0x0534, 0x0524, none, 0x7b00, none }, /* 4$ */
1063 { 0x0635, 0x0625, none, 0x7c00, none }, /* 5% */
1064 { 0x0736, 0x075e, 0x071e, 0x7d00, none }, /* 6^ */
1065 { 0x0837, 0x0826, none, 0x7e00, none }, /* 7& */
1066 { 0x0938, 0x092a, none, 0x7f00, none }, /* 8* */
1067 { 0x0a39, 0x0a28, none, 0x8000, none }, /* 9( */
1068 { 0x0b30, 0x0b29, none, 0x8100, none }, /* 0) */
1069 { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200, none }, /* -_ */
1070 { 0x0d3d, 0x0d2b, none, 0x8300, none }, /* =+ */
1071 { 0x0e08, 0x0e08, 0x0e7f, none, none }, /* backspace */
1072 { 0x0f09, 0x0f00, none, none, none }, /* tab */
1073 { 0x1071, 0x1051, 0x1011, 0x1000, 0x40 }, /* Q */
1074 { 0x1177, 0x1157, 0x1117, 0x1100, 0x40 }, /* W */
1075 { 0x1265, 0x1245, 0x1205, 0x1200, 0x40 }, /* E */
1076 { 0x1372, 0x1352, 0x1312, 0x1300, 0x40 }, /* R */
1077 { 0x1474, 0x1454, 0x1414, 0x1400, 0x40 }, /* T */
1078 { 0x1579, 0x1559, 0x1519, 0x1500, 0x40 }, /* Y */
1079 { 0x1675, 0x1655, 0x1615, 0x1600, 0x40 }, /* U */
1080 { 0x1769, 0x1749, 0x1709, 0x1700, 0x40 }, /* I */
1081 { 0x186f, 0x184f, 0x180f, 0x1800, 0x40 }, /* O */
1082 { 0x1970, 0x1950, 0x1910, 0x1900, 0x40 }, /* P */
1083 { 0x1a5b, 0x1a7b, 0x1a1b, none, none }, /* [{ */
1084 { 0x1b5d, 0x1b7d, 0x1b1d, none, none }, /* ]} */
1085 { 0x1c0d, 0x1c0d, 0x1c0a, none, none }, /* Enter */
1086 { none, none, none, none, none }, /* L Ctrl */
1087 { 0x1e61, 0x1e41, 0x1e01, 0x1e00, 0x40 }, /* A */
1088 { 0x1f73, 0x1f53, 0x1f13, 0x1f00, 0x40 }, /* S */
1089 { 0x2064, 0x2044, 0x2004, 0x2000, 0x40 }, /* D */
1090 { 0x2166, 0x2146, 0x2106, 0x2100, 0x40 }, /* F */
1091 { 0x2267, 0x2247, 0x2207, 0x2200, 0x40 }, /* G */
1092 { 0x2368, 0x2348, 0x2308, 0x2300, 0x40 }, /* H */
1093 { 0x246a, 0x244a, 0x240a, 0x2400, 0x40 }, /* J */
1094 { 0x256b, 0x254b, 0x250b, 0x2500, 0x40 }, /* K */
1095 { 0x266c, 0x264c, 0x260c, 0x2600, 0x40 }, /* L */
1096 { 0x273b, 0x273a, none, none, none }, /* ;: */
1097 { 0x2827, 0x2822, none, none, none }, /* '" */
1098 { 0x2960, 0x297e, none, none, none }, /* `~ */
1099 { none, none, none, none, none }, /* L shift */
1100 { 0x2b5c, 0x2b7c, 0x2b1c, none, none }, /* |\ */
1101 { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, 0x40 }, /* Z */
1102 { 0x2d78, 0x2d58, 0x2d18, 0x2d00, 0x40 }, /* X */
1103 { 0x2e63, 0x2e43, 0x2e03, 0x2e00, 0x40 }, /* C */
1104 { 0x2f76, 0x2f56, 0x2f16, 0x2f00, 0x40 }, /* V */
1105 { 0x3062, 0x3042, 0x3002, 0x3000, 0x40 }, /* B */
1106 { 0x316e, 0x314e, 0x310e, 0x3100, 0x40 }, /* N */
1107 { 0x326d, 0x324d, 0x320d, 0x3200, 0x40 }, /* M */
1108 { 0x332c, 0x333c, none, none, none }, /* ,< */
1109 { 0x342e, 0x343e, none, none, none }, /* .> */
1110 { 0x352f, 0x353f, none, none, none }, /* /? */
1111 { none, none, none, none, none }, /* R Shift */
1112 { 0x372a, 0x372a, none, none, none }, /* * */
1113 { none, none, none, none, none }, /* L Alt */
1114 { 0x3920, 0x3920, 0x3920, 0x3920, none }, /* space */
1115 { none, none, none, none, none }, /* caps lock */
1116 { 0x3b00, 0x5400, 0x5e00, 0x6800, none }, /* F1 */
1117 { 0x3c00, 0x5500, 0x5f00, 0x6900, none }, /* F2 */
1118 { 0x3d00, 0x5600, 0x6000, 0x6a00, none }, /* F3 */
1119 { 0x3e00, 0x5700, 0x6100, 0x6b00, none }, /* F4 */
1120 { 0x3f00, 0x5800, 0x6200, 0x6c00, none }, /* F5 */
1121 { 0x4000, 0x5900, 0x6300, 0x6d00, none }, /* F6 */
1122 { 0x4100, 0x5a00, 0x6400, 0x6e00, none }, /* F7 */
1123 { 0x4200, 0x5b00, 0x6500, 0x6f00, none }, /* F8 */
1124 { 0x4300, 0x5c00, 0x6600, 0x7000, none }, /* F9 */
1125 { 0x4400, 0x5d00, 0x6700, 0x7100, none }, /* F10 */
1126 { none, none, none, none, none }, /* Num Lock */
1127 { none, none, none, none, none }, /* Scroll Lock */
1128 { 0x4700, 0x4737, 0x7700, none, 0x20 }, /* 7 Home */
1129 { 0x4800, 0x4838, none, none, 0x20 }, /* 8 UP */
1130 { 0x4900, 0x4939, 0x8400, none, 0x20 }, /* 9 PgUp */
1131 { 0x4a2d, 0x4a2d, none, none, none }, /* - */
1132 { 0x4b00, 0x4b34, 0x7300, none, 0x20 }, /* 4 Left */
1133 { 0x4c00, 0x4c35, none, none, 0x20 }, /* 5 */
1134 { 0x4d00, 0x4d36, 0x7400, none, 0x20 }, /* 6 Right */
1135 { 0x4e2b, 0x4e2b, none, none, none }, /* + */
1136 { 0x4f00, 0x4f31, 0x7500, none, 0x20 }, /* 1 End */
1137 { 0x5000, 0x5032, none, none, 0x20 }, /* 2 Down */
1138 { 0x5100, 0x5133, 0x7600, none, 0x20 }, /* 3 PgDn */
1139 { 0x5200, 0x5230, none, none, 0x20 }, /* 0 Ins */
1140 { 0x5300, 0x532e, none, none, 0x20 } /* Del */
1141 };
1143 Bit8u
1144 inb(port)
1145 Bit16u port;
1147 ASM_START
1148 push bp
1149 mov bp, sp
1151 push dx
1152 mov dx, 4[bp]
1153 in al, dx
1154 pop dx
1156 pop bp
1157 ASM_END
1160 #if BX_USE_ATADRV
1161 Bit16u
1162 inw(port)
1163 Bit16u port;
1165 ASM_START
1166 push bp
1167 mov bp, sp
1169 push dx
1170 mov dx, 4[bp]
1171 in ax, dx
1172 pop dx
1174 pop bp
1175 ASM_END
1177 #endif
1179 void
1180 outb(port, val)
1181 Bit16u port;
1182 Bit8u val;
1184 ASM_START
1185 push bp
1186 mov bp, sp
1188 push ax
1189 push dx
1190 mov dx, 4[bp]
1191 mov al, 6[bp]
1192 out dx, al
1193 pop dx
1194 pop ax
1196 pop bp
1197 ASM_END
1200 #if BX_USE_ATADRV
1201 void
1202 outw(port, val)
1203 Bit16u port;
1204 Bit16u val;
1206 ASM_START
1207 push bp
1208 mov bp, sp
1210 push ax
1211 push dx
1212 mov dx, 4[bp]
1213 mov ax, 6[bp]
1214 out dx, ax
1215 pop dx
1216 pop ax
1218 pop bp
1219 ASM_END
1221 #endif
1223 void
1224 outb_cmos(cmos_reg, val)
1225 Bit8u cmos_reg;
1226 Bit8u val;
1228 ASM_START
1229 push bp
1230 mov bp, sp
1232 mov al, 4[bp] ;; cmos_reg
1233 out 0x70, al
1234 mov al, 6[bp] ;; val
1235 out 0x71, al
1237 pop bp
1238 ASM_END
1241 Bit8u
1242 inb_cmos(cmos_reg)
1243 Bit8u cmos_reg;
1245 ASM_START
1246 push bp
1247 mov bp, sp
1249 mov al, 4[bp] ;; cmos_reg
1250 out 0x70, al
1251 in al, 0x71
1253 pop bp
1254 ASM_END
1257 void
1258 init_rtc()
1260 outb_cmos(0x0a, 0x26);
1261 outb_cmos(0x0b, 0x02);
1262 inb_cmos(0x0c);
1263 inb_cmos(0x0d);
1266 bx_bool
1267 rtc_updating()
1269 // This function checks to see if the update-in-progress bit
1270 // is set in CMOS Status Register A. If not, it returns 0.
1271 // If it is set, it tries to wait until there is a transition
1272 // to 0, and will return 0 if such a transition occurs. A 1
1273 // is returned only after timing out. The maximum period
1274 // that this bit should be set is constrained to 244useconds.
1275 // The count I use below guarantees coverage or more than
1276 // this time, with any reasonable IPS setting.
1278 Bit16u count;
1280 count = 25000;
1281 while (--count != 0) {
1282 if ( (inb_cmos(0x0a) & 0x80) == 0 )
1283 return(0);
1285 return(1); // update-in-progress never transitioned to 0
1289 Bit8u
1290 read_byte(seg, offset)
1291 Bit16u seg;
1292 Bit16u offset;
1294 ASM_START
1295 push bp
1296 mov bp, sp
1298 push bx
1299 push ds
1300 mov ax, 4[bp] ; segment
1301 mov ds, ax
1302 mov bx, 6[bp] ; offset
1303 mov al, [bx]
1304 ;; al = return value (byte)
1305 pop ds
1306 pop bx
1308 pop bp
1309 ASM_END
1312 Bit16u
1313 read_word(seg, offset)
1314 Bit16u seg;
1315 Bit16u offset;
1317 ASM_START
1318 push bp
1319 mov bp, sp
1321 push bx
1322 push ds
1323 mov ax, 4[bp] ; segment
1324 mov ds, ax
1325 mov bx, 6[bp] ; offset
1326 mov ax, [bx]
1327 ;; ax = return value (word)
1328 pop ds
1329 pop bx
1331 pop bp
1332 ASM_END
1335 void
1336 write_byte(seg, offset, data)
1337 Bit16u seg;
1338 Bit16u offset;
1339 Bit8u data;
1341 ASM_START
1342 push bp
1343 mov bp, sp
1345 push ax
1346 push bx
1347 push ds
1348 mov ax, 4[bp] ; segment
1349 mov ds, ax
1350 mov bx, 6[bp] ; offset
1351 mov al, 8[bp] ; data byte
1352 mov [bx], al ; write data byte
1353 pop ds
1354 pop bx
1355 pop ax
1357 pop bp
1358 ASM_END
1361 void
1362 write_word(seg, offset, data)
1363 Bit16u seg;
1364 Bit16u offset;
1365 Bit16u data;
1367 ASM_START
1368 push bp
1369 mov bp, sp
1371 push ax
1372 push bx
1373 push ds
1374 mov ax, 4[bp] ; segment
1375 mov ds, ax
1376 mov bx, 6[bp] ; offset
1377 mov ax, 8[bp] ; data word
1378 mov [bx], ax ; write data word
1379 pop ds
1380 pop bx
1381 pop ax
1383 pop bp
1384 ASM_END
1387 Bit16u
1388 get_CS()
1390 ASM_START
1391 mov ax, cs
1392 ASM_END
1395 // Bit16u
1396 //get_DS()
1397 //{
1398 //ASM_START
1399 // mov ax, ds
1400 //ASM_END
1401 //}
1402 //
1403 // void
1404 //set_DS(ds_selector)
1405 // Bit16u ds_selector;
1406 //{
1407 //ASM_START
1408 // push bp
1409 // mov bp, sp
1410 //
1411 // push ax
1412 // mov ax, 4[bp] ; ds_selector
1413 // mov ds, ax
1414 // pop ax
1415 //
1416 // pop bp
1417 //ASM_END
1418 //}
1420 Bit16u
1421 get_SS()
1423 ASM_START
1424 mov ax, ss
1425 ASM_END
1428 #ifdef VMXASSIST
1429 void
1430 copy_e820_table()
1432 Bit8u nr_entries = read_byte(0x9000, 0x1e8);
1433 if (nr_entries > 32)
1434 nr_entries = 32;
1435 write_word(0xe000, 0x8, nr_entries);
1436 memcpyb(0xe000, 0x10, 0x9000, 0x2d0, nr_entries * 0x14);
1438 #endif /* VMXASSIST */
1440 #if BX_DEBUG_SERIAL
1441 /* serial debug port*/
1442 #define BX_DEBUG_PORT 0x03f8
1444 /* data */
1445 #define UART_RBR 0x00
1446 #define UART_THR 0x00
1448 /* control */
1449 #define UART_IER 0x01
1450 #define UART_IIR 0x02
1451 #define UART_FCR 0x02
1452 #define UART_LCR 0x03
1453 #define UART_MCR 0x04
1454 #define UART_DLL 0x00
1455 #define UART_DLM 0x01
1457 /* status */
1458 #define UART_LSR 0x05
1459 #define UART_MSR 0x06
1460 #define UART_SCR 0x07
1462 int uart_can_tx_byte(base_port)
1463 Bit16u base_port;
1465 return inb(base_port + UART_LSR) & 0x20;
1468 void uart_wait_to_tx_byte(base_port)
1469 Bit16u base_port;
1471 while (!uart_can_tx_byte(base_port));
1474 void uart_wait_until_sent(base_port)
1475 Bit16u base_port;
1477 while (!(inb(base_port + UART_LSR) & 0x40));
1480 void uart_tx_byte(base_port, data)
1481 Bit16u base_port;
1482 Bit8u data;
1484 uart_wait_to_tx_byte(base_port);
1485 outb(base_port + UART_THR, data);
1486 uart_wait_until_sent(base_port);
1488 #endif
1490 void
1491 wrch(c)
1492 Bit8u c;
1494 ASM_START
1495 push bp
1496 mov bp, sp
1498 push bx
1499 mov ah, #0x0e
1500 mov al, 4[bp]
1501 xor bx,bx
1502 int #0x10
1503 pop bx
1505 pop bp
1506 ASM_END
1509 void
1510 send(action, c)
1511 Bit16u action;
1512 Bit8u c;
1514 #if BX_DEBUG_SERIAL
1515 if (c == '\n') uart_tx_byte(BX_DEBUG_PORT, '\r');
1516 uart_tx_byte(BX_DEBUG_PORT, c);
1517 #endif
1518 #ifdef VMXASSIST
1519 outb(0xE9, c);
1520 #endif
1521 #if BX_VIRTUAL_PORTS
1522 if (action & BIOS_PRINTF_DEBUG) outb(DEBUG_PORT, c);
1523 if (action & BIOS_PRINTF_INFO) outb(INFO_PORT, c);
1524 #endif
1525 if (action & BIOS_PRINTF_SCREEN) {
1526 if (c == '\n') wrch('\r');
1527 wrch(c);
1531 void
1532 put_int(action, val, width, neg)
1533 Bit16u action;
1534 short val, width;
1535 bx_bool neg;
1537 short nval = val / 10;
1538 if (nval)
1539 put_int(action, nval, width - 1, neg);
1540 else {
1541 while (--width > 0) send(action, ' ');
1542 if (neg) send(action, '-');
1544 send(action, val - (nval * 10) + '0');
1547 void
1548 put_uint(action, val, width, neg)
1549 Bit16u action;
1550 unsigned short val;
1551 short width;
1552 bx_bool neg;
1554 unsigned short nval = val / 10;
1555 if (nval)
1556 put_uint(action, nval, width - 1, neg);
1557 else {
1558 while (--width > 0) send(action, ' ');
1559 if (neg) send(action, '-');
1561 send(action, val - (nval * 10) + '0');
1564 //--------------------------------------------------------------------------
1565 // bios_printf()
1566 // A compact variable argument printf function which prints its output via
1567 // an I/O port so that it can be logged by Bochs/Plex.
1568 // Currently, only %x is supported (or %02x, %04x, etc).
1569 //
1570 // Supports %[format_width][format]
1571 // where format can be d,x,c,s
1572 //--------------------------------------------------------------------------
1573 void
1574 bios_printf(action, s)
1575 Bit16u action;
1576 Bit8u *s;
1578 Bit8u c, format_char;
1579 bx_bool in_format;
1580 short i;
1581 Bit16u *arg_ptr;
1582 Bit16u arg_seg, arg, nibble, shift_count, format_width;
1584 arg_ptr = &s;
1585 arg_seg = get_SS();
1587 in_format = 0;
1588 format_width = 0;
1590 if ((action & BIOS_PRINTF_DEBHALT) == BIOS_PRINTF_DEBHALT) {
1591 #if BX_VIRTUAL_PORTS
1592 outb(PANIC_PORT2, 0x00);
1593 #endif
1594 bios_printf (BIOS_PRINTF_SCREEN, "FATAL: ");
1597 while (c = read_byte(get_CS(), s)) {
1598 if ( c == '%' ) {
1599 in_format = 1;
1600 format_width = 0;
1602 else if (in_format) {
1603 if ( (c>='0') && (c<='9') ) {
1604 format_width = (format_width * 10) + (c - '0');
1606 else {
1607 arg_ptr++; // increment to next arg
1608 arg = read_word(arg_seg, arg_ptr);
1609 if (c == 'x') {
1610 if (format_width == 0)
1611 format_width = 4;
1612 for (i=format_width-1; i>=0; i--) {
1613 nibble = (arg >> (4 * i)) & 0x000f;
1614 send (action, (nibble<=9)? (nibble+'0') : (nibble-10+'A'));
1617 else if (c == 'u') {
1618 put_uint(action, arg, format_width, 0);
1620 else if (c == 'd') {
1621 if (arg & 0x8000)
1622 put_int(action, -arg, format_width - 1, 1);
1623 else
1624 put_int(action, arg, format_width, 0);
1626 else if (c == 's') {
1627 bios_printf(action & (~BIOS_PRINTF_HALT), arg);
1629 else if (c == 'c') {
1630 send(action, arg);
1632 else
1633 BX_PANIC("bios_printf: unknown format\n");
1634 in_format = 0;
1637 else {
1638 send(action, c);
1640 s ++;
1643 if (action & BIOS_PRINTF_HALT) {
1644 // freeze in a busy loop.
1645 ASM_START
1646 cli
1647 halt2_loop:
1648 hlt
1649 jmp halt2_loop
1650 ASM_END
1654 //--------------------------------------------------------------------------
1655 // keyboard_init
1656 //--------------------------------------------------------------------------
1657 // this file is based on LinuxBIOS implementation of keyboard.c
1658 // could convert to #asm to gain space
1659 void
1660 keyboard_init()
1662 Bit16u max;
1664 /* ------------------- Flush buffers ------------------------*/
1665 /* Wait until buffer is empty */
1666 max=0xffff;
1667 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
1669 /* flush incoming keys */
1670 max=0x2000;
1671 while (--max > 0) {
1672 outb(0x80, 0x00);
1673 if (inb(0x64) & 0x01) {
1674 inb(0x60);
1675 max = 0x2000;
1679 // Due to timer issues, and if the IPS setting is > 15000000,
1680 // the incoming keys might not be flushed here. That will
1681 // cause a panic a few lines below. See sourceforge bug report :
1682 // [ 642031 ] FATAL: Keyboard RESET error:993
1684 /* ------------------- controller side ----------------------*/
1685 /* send cmd = 0xAA, self test 8042 */
1686 outb(0x64, 0xaa);
1688 /* Wait until buffer is empty */
1689 max=0xffff;
1690 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
1691 if (max==0x0) keyboard_panic(00);
1693 /* Wait for data */
1694 max=0xffff;
1695 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x01);
1696 if (max==0x0) keyboard_panic(01);
1698 /* read self-test result, 0x55 should be returned from 0x60 */
1699 if ((inb(0x60) != 0x55)){
1700 keyboard_panic(991);
1703 /* send cmd = 0xAB, keyboard interface test */
1704 outb(0x64,0xab);
1706 /* Wait until buffer is empty */
1707 max=0xffff;
1708 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x10);
1709 if (max==0x0) keyboard_panic(10);
1711 /* Wait for data */
1712 max=0xffff;
1713 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x11);
1714 if (max==0x0) keyboard_panic(11);
1716 /* read keyboard interface test result, */
1717 /* 0x00 should be returned form 0x60 */
1718 if ((inb(0x60) != 0x00)) {
1719 keyboard_panic(992);
1722 /* Enable Keyboard clock */
1723 outb(0x64,0xae);
1724 outb(0x64,0xa8);
1726 /* ------------------- keyboard side ------------------------*/
1727 /* reset kerboard and self test (keyboard side) */
1728 outb(0x60, 0xff);
1730 /* Wait until buffer is empty */
1731 max=0xffff;
1732 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x20);
1733 if (max==0x0) keyboard_panic(20);
1735 /* Wait for data */
1736 max=0xffff;
1737 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x21);
1738 if (max==0x0) keyboard_panic(21);
1740 /* keyboard should return ACK */
1741 if ((inb(0x60) != 0xfa)) {
1742 keyboard_panic(993);
1745 /* Wait for data */
1746 max=0xffff;
1747 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x31);
1748 if (max==0x0) keyboard_panic(31);
1750 if ((inb(0x60) != 0xaa)) {
1751 keyboard_panic(994);
1754 /* Disable keyboard */
1755 outb(0x60, 0xf5);
1757 /* Wait until buffer is empty */
1758 max=0xffff;
1759 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x40);
1760 if (max==0x0) keyboard_panic(40);
1762 /* Wait for data */
1763 max=0xffff;
1764 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x41);
1765 if (max==0x0) keyboard_panic(41);
1767 /* keyboard should return ACK */
1768 if ((inb(0x60) != 0xfa)) {
1769 keyboard_panic(995);
1772 /* Write Keyboard Mode */
1773 outb(0x64, 0x60);
1775 /* Wait until buffer is empty */
1776 max=0xffff;
1777 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x50);
1778 if (max==0x0) keyboard_panic(50);
1780 /* send cmd: scan code convert, disable mouse, enable IRQ 1 */
1781 outb(0x60, 0x61);
1783 /* Wait until buffer is empty */
1784 max=0xffff;
1785 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x60);
1786 if (max==0x0) keyboard_panic(60);
1788 /* Enable keyboard */
1789 outb(0x60, 0xf4);
1791 /* Wait until buffer is empty */
1792 max=0xffff;
1793 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x70);
1794 if (max==0x0) keyboard_panic(70);
1796 /* Wait for data */
1797 max=0xffff;
1798 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x71);
1799 if (max==0x0) keyboard_panic(70);
1801 /* keyboard should return ACK */
1802 if ((inb(0x60) != 0xfa)) {
1803 keyboard_panic(996);
1806 outb(0x80, 0x77);
1809 //--------------------------------------------------------------------------
1810 // keyboard_panic
1811 //--------------------------------------------------------------------------
1812 void
1813 keyboard_panic(status)
1814 Bit16u status;
1816 // If you're getting a 993 keyboard panic here,
1817 // please see the comment in keyboard_init
1819 BX_PANIC("Keyboard error:%u\n",status);
1822 //--------------------------------------------------------------------------
1823 // shutdown_status_panic
1824 // called when the shutdown statsu is not implemented, displays the status
1825 //--------------------------------------------------------------------------
1826 void
1827 shutdown_status_panic(status)
1828 Bit16u status;
1830 BX_PANIC("Unimplemented shutdown status: %02x\n",(Bit8u)status);
1833 //--------------------------------------------------------------------------
1834 // print_bios_banner
1835 // displays a the bios version
1836 //--------------------------------------------------------------------------
1837 void
1838 print_bios_banner()
1840 printf(BX_APPNAME" BIOS, %d cpu%s, ", BX_SMP_PROCESSORS, BX_SMP_PROCESSORS>1?"s":"");
1841 printf("%s %s\n", bios_cvs_version_string, bios_date_string);
1842 printf("\n");
1845 //--------------------------------------------------------------------------
1846 // print_boot_device
1847 // displays the boot device
1848 //--------------------------------------------------------------------------
1850 static char drivetypes[][10]={"Floppy","Hard Disk","CD-Rom"};
1852 void
1853 print_boot_device(cdboot, drive)
1854 Bit8u cdboot; Bit16u drive;
1856 Bit8u i;
1858 // cdboot contains 0 if floppy/harddisk, 1 otherwise
1859 // drive contains real/emulated boot drive
1861 if(cdboot)i=2; // CD-Rom
1862 else if((drive&0x0080)==0x00)i=0; // Floppy
1863 else if((drive&0x0080)==0x80)i=1; // Hard drive
1864 else return;
1866 printf("Booting from %s...\n",drivetypes[i]);
1869 //--------------------------------------------------------------------------
1870 // print_boot_failure
1871 // displays the reason why boot failed
1872 //--------------------------------------------------------------------------
1873 void
1874 print_boot_failure(cdboot, drive, reason, lastdrive)
1875 Bit8u cdboot; Bit8u drive; Bit8u lastdrive;
1877 Bit16u drivenum = drive&0x7f;
1879 // cdboot: 1 if boot from cd, 0 otherwise
1880 // drive : drive number
1881 // reason: 0 signature check failed, 1 read error
1882 // lastdrive: 1 boot drive is the last one in boot sequence
1884 if (cdboot)
1885 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s failed\n",drivetypes[2]);
1886 else if (drive & 0x80)
1887 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[1],drivenum);
1888 else
1889 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[0],drivenum);
1891 if (lastdrive==1) {
1892 if (reason==0)
1893 BX_PANIC("Not a bootable disk\n");
1894 else
1895 BX_PANIC("Could not read the boot disk\n");
1899 //--------------------------------------------------------------------------
1900 // print_cdromboot_failure
1901 // displays the reason why boot failed
1902 //--------------------------------------------------------------------------
1903 void
1904 print_cdromboot_failure( code )
1905 Bit16u code;
1907 bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "CDROM boot failure code : %04x\n",code);
1909 return;
1912 void
1913 nmi_handler_msg()
1915 BX_PANIC("NMI Handler called\n");
1918 void
1919 int18_panic_msg()
1921 BX_PANIC("INT18: BOOT FAILURE\n");
1924 void
1925 log_bios_start()
1927 #if BX_DEBUG_SERIAL
1928 outb(BX_DEBUG_PORT+UART_LCR, 0x03); /* setup for serial logging: 8N1 */
1929 #endif
1930 BX_INFO("%s\n", bios_version_string);
1933 bx_bool
1934 set_enable_a20(val)
1935 bx_bool val;
1937 Bit8u oldval;
1939 // Use PS2 System Control port A to set A20 enable
1941 // get current setting first
1942 oldval = inb(0x92);
1944 // change A20 status
1945 if (val)
1946 outb(0x92, oldval | 0x02);
1947 else
1948 outb(0x92, oldval & 0xfd);
1950 return((oldval & 0x02) != 0);
1953 void
1954 debugger_on()
1956 outb(0xfedc, 0x01);
1959 void
1960 debugger_off()
1962 outb(0xfedc, 0x00);
1965 #if BX_USE_ATADRV
1967 // ---------------------------------------------------------------------------
1968 // Start of ATA/ATAPI Driver
1969 // ---------------------------------------------------------------------------
1971 // Global defines -- ATA register and register bits.
1972 // command block & control block regs
1973 #define ATA_CB_DATA 0 // data reg in/out pio_base_addr1+0
1974 #define ATA_CB_ERR 1 // error in pio_base_addr1+1
1975 #define ATA_CB_FR 1 // feature reg out pio_base_addr1+1
1976 #define ATA_CB_SC 2 // sector count in/out pio_base_addr1+2
1977 #define ATA_CB_SN 3 // sector number in/out pio_base_addr1+3
1978 #define ATA_CB_CL 4 // cylinder low in/out pio_base_addr1+4
1979 #define ATA_CB_CH 5 // cylinder high in/out pio_base_addr1+5
1980 #define ATA_CB_DH 6 // device head in/out pio_base_addr1+6
1981 #define ATA_CB_STAT 7 // primary status in pio_base_addr1+7
1982 #define ATA_CB_CMD 7 // command out pio_base_addr1+7
1983 #define ATA_CB_ASTAT 6 // alternate status in pio_base_addr2+6
1984 #define ATA_CB_DC 6 // device control out pio_base_addr2+6
1985 #define ATA_CB_DA 7 // device address in pio_base_addr2+7
1987 #define ATA_CB_ER_ICRC 0x80 // ATA Ultra DMA bad CRC
1988 #define ATA_CB_ER_BBK 0x80 // ATA bad block
1989 #define ATA_CB_ER_UNC 0x40 // ATA uncorrected error
1990 #define ATA_CB_ER_MC 0x20 // ATA media change
1991 #define ATA_CB_ER_IDNF 0x10 // ATA id not found
1992 #define ATA_CB_ER_MCR 0x08 // ATA media change request
1993 #define ATA_CB_ER_ABRT 0x04 // ATA command aborted
1994 #define ATA_CB_ER_NTK0 0x02 // ATA track 0 not found
1995 #define ATA_CB_ER_NDAM 0x01 // ATA address mark not found
1997 #define ATA_CB_ER_P_SNSKEY 0xf0 // ATAPI sense key (mask)
1998 #define ATA_CB_ER_P_MCR 0x08 // ATAPI Media Change Request
1999 #define ATA_CB_ER_P_ABRT 0x04 // ATAPI command abort
2000 #define ATA_CB_ER_P_EOM 0x02 // ATAPI End of Media
2001 #define ATA_CB_ER_P_ILI 0x01 // ATAPI Illegal Length Indication
2003 // ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC)
2004 #define ATA_CB_SC_P_TAG 0xf8 // ATAPI tag (mask)
2005 #define ATA_CB_SC_P_REL 0x04 // ATAPI release
2006 #define ATA_CB_SC_P_IO 0x02 // ATAPI I/O
2007 #define ATA_CB_SC_P_CD 0x01 // ATAPI C/D
2009 // bits 7-4 of the device/head (CB_DH) reg
2010 #define ATA_CB_DH_DEV0 0xa0 // select device 0
2011 #define ATA_CB_DH_DEV1 0xb0 // select device 1
2013 // status reg (CB_STAT and CB_ASTAT) bits
2014 #define ATA_CB_STAT_BSY 0x80 // busy
2015 #define ATA_CB_STAT_RDY 0x40 // ready
2016 #define ATA_CB_STAT_DF 0x20 // device fault
2017 #define ATA_CB_STAT_WFT 0x20 // write fault (old name)
2018 #define ATA_CB_STAT_SKC 0x10 // seek complete
2019 #define ATA_CB_STAT_SERV 0x10 // service
2020 #define ATA_CB_STAT_DRQ 0x08 // data request
2021 #define ATA_CB_STAT_CORR 0x04 // corrected
2022 #define ATA_CB_STAT_IDX 0x02 // index
2023 #define ATA_CB_STAT_ERR 0x01 // error (ATA)
2024 #define ATA_CB_STAT_CHK 0x01 // check (ATAPI)
2026 // device control reg (CB_DC) bits
2027 #define ATA_CB_DC_HD15 0x08 // bit should always be set to one
2028 #define ATA_CB_DC_SRST 0x04 // soft reset
2029 #define ATA_CB_DC_NIEN 0x02 // disable interrupts
2031 // Most mandtory and optional ATA commands (from ATA-3),
2032 #define ATA_CMD_CFA_ERASE_SECTORS 0xC0
2033 #define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03
2034 #define ATA_CMD_CFA_TRANSLATE_SECTOR 0x87
2035 #define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD
2036 #define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38
2037 #define ATA_CMD_CHECK_POWER_MODE1 0xE5
2038 #define ATA_CMD_CHECK_POWER_MODE2 0x98
2039 #define ATA_CMD_DEVICE_RESET 0x08
2040 #define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90
2041 #define ATA_CMD_FLUSH_CACHE 0xE7
2042 #define ATA_CMD_FORMAT_TRACK 0x50
2043 #define ATA_CMD_IDENTIFY_DEVICE 0xEC
2044 #define ATA_CMD_IDENTIFY_DEVICE_PACKET 0xA1
2045 #define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xA1
2046 #define ATA_CMD_IDLE1 0xE3
2047 #define ATA_CMD_IDLE2 0x97
2048 #define ATA_CMD_IDLE_IMMEDIATE1 0xE1
2049 #define ATA_CMD_IDLE_IMMEDIATE2 0x95
2050 #define ATA_CMD_INITIALIZE_DRIVE_PARAMETERS 0x91
2051 #define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
2052 #define ATA_CMD_NOP 0x00
2053 #define ATA_CMD_PACKET 0xA0
2054 #define ATA_CMD_READ_BUFFER 0xE4
2055 #define ATA_CMD_READ_DMA 0xC8
2056 #define ATA_CMD_READ_DMA_QUEUED 0xC7
2057 #define ATA_CMD_READ_MULTIPLE 0xC4
2058 #define ATA_CMD_READ_SECTORS 0x20
2059 #define ATA_CMD_READ_VERIFY_SECTORS 0x40
2060 #define ATA_CMD_RECALIBRATE 0x10
2061 #define ATA_CMD_SEEK 0x70
2062 #define ATA_CMD_SET_FEATURES 0xEF
2063 #define ATA_CMD_SET_MULTIPLE_MODE 0xC6
2064 #define ATA_CMD_SLEEP1 0xE6
2065 #define ATA_CMD_SLEEP2 0x99
2066 #define ATA_CMD_STANDBY1 0xE2
2067 #define ATA_CMD_STANDBY2 0x96
2068 #define ATA_CMD_STANDBY_IMMEDIATE1 0xE0
2069 #define ATA_CMD_STANDBY_IMMEDIATE2 0x94
2070 #define ATA_CMD_WRITE_BUFFER 0xE8
2071 #define ATA_CMD_WRITE_DMA 0xCA
2072 #define ATA_CMD_WRITE_DMA_QUEUED 0xCC
2073 #define ATA_CMD_WRITE_MULTIPLE 0xC5
2074 #define ATA_CMD_WRITE_SECTORS 0x30
2075 #define ATA_CMD_WRITE_VERIFY 0x3C
2077 #define ATA_IFACE_NONE 0x00
2078 #define ATA_IFACE_ISA 0x00
2079 #define ATA_IFACE_PCI 0x01
2081 #define ATA_TYPE_NONE 0x00
2082 #define ATA_TYPE_UNKNOWN 0x01
2083 #define ATA_TYPE_ATA 0x02
2084 #define ATA_TYPE_ATAPI 0x03
2086 #define ATA_DEVICE_NONE 0x00
2087 #define ATA_DEVICE_HD 0xFF
2088 #define ATA_DEVICE_CDROM 0x05
2090 #define ATA_MODE_NONE 0x00
2091 #define ATA_MODE_PIO16 0x00
2092 #define ATA_MODE_PIO32 0x01
2093 #define ATA_MODE_ISADMA 0x02
2094 #define ATA_MODE_PCIDMA 0x03
2095 #define ATA_MODE_USEIRQ 0x10
2097 #define ATA_TRANSLATION_NONE 0
2098 #define ATA_TRANSLATION_LBA 1
2099 #define ATA_TRANSLATION_LARGE 2
2100 #define ATA_TRANSLATION_RECHS 3
2102 #define ATA_DATA_NO 0x00
2103 #define ATA_DATA_IN 0x01
2104 #define ATA_DATA_OUT 0x02
2106 // ---------------------------------------------------------------------------
2107 // ATA/ATAPI driver : initialization
2108 // ---------------------------------------------------------------------------
2109 void ata_init( )
2111 Bit16u ebda_seg=read_word(0x0040,0x000E);
2112 Bit8u channel, device;
2114 // Channels info init.
2115 for (channel=0; channel<BX_MAX_ATA_INTERFACES; channel++) {
2116 write_byte(ebda_seg,&EbdaData->ata.channels[channel].iface,ATA_IFACE_NONE);
2117 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1,0x0);
2118 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2,0x0);
2119 write_byte(ebda_seg,&EbdaData->ata.channels[channel].irq,0);
2122 // Devices info init.
2123 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2124 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
2125 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_NONE);
2126 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable,0);
2127 write_byte(ebda_seg,&EbdaData->ata.devices[device].lock,0);
2128 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode,ATA_MODE_NONE);
2129 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,0);
2130 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation,ATA_TRANSLATION_NONE);
2131 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads,0);
2132 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders,0);
2133 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt,0);
2134 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads,0);
2135 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders,0);
2136 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt,0);
2138 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors,0L);
2141 // hdidmap and cdidmap init.
2142 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2143 write_byte(ebda_seg,&EbdaData->ata.hdidmap[device],BX_MAX_ATA_DEVICES);
2144 write_byte(ebda_seg,&EbdaData->ata.cdidmap[device],BX_MAX_ATA_DEVICES);
2147 write_byte(ebda_seg,&EbdaData->ata.hdcount,0);
2148 write_byte(ebda_seg,&EbdaData->ata.cdcount,0);
2151 // ---------------------------------------------------------------------------
2152 // ATA/ATAPI driver : device detection
2153 // ---------------------------------------------------------------------------
2155 void ata_detect( )
2157 Bit16u ebda_seg=read_word(0x0040,0x000E);
2158 Bit8u hdcount, cdcount, device, type;
2159 Bit8u buffer[0x0200];
2161 #if BX_MAX_ATA_INTERFACES > 0
2162 write_byte(ebda_seg,&EbdaData->ata.channels[0].iface,ATA_IFACE_ISA);
2163 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase1,0x1f0);
2164 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase2,0x3f0);
2165 write_byte(ebda_seg,&EbdaData->ata.channels[0].irq,14);
2166 #endif
2167 #if BX_MAX_ATA_INTERFACES > 1
2168 write_byte(ebda_seg,&EbdaData->ata.channels[1].iface,ATA_IFACE_ISA);
2169 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase1,0x170);
2170 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase2,0x370);
2171 write_byte(ebda_seg,&EbdaData->ata.channels[1].irq,15);
2172 #endif
2173 #if BX_MAX_ATA_INTERFACES > 2
2174 write_byte(ebda_seg,&EbdaData->ata.channels[2].iface,ATA_IFACE_ISA);
2175 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase1,0x1e8);
2176 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase2,0x3e0);
2177 write_byte(ebda_seg,&EbdaData->ata.channels[2].irq,12);
2178 #endif
2179 #if BX_MAX_ATA_INTERFACES > 3
2180 write_byte(ebda_seg,&EbdaData->ata.channels[3].iface,ATA_IFACE_ISA);
2181 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase1,0x168);
2182 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase2,0x360);
2183 write_byte(ebda_seg,&EbdaData->ata.channels[3].irq,11);
2184 #endif
2185 #if BX_MAX_ATA_INTERFACES > 4
2186 #error Please fill the ATA interface informations
2187 #endif
2189 // Device detection
2190 hdcount=cdcount=0;
2192 for(device=0; device<BX_MAX_ATA_DEVICES; device++) {
2193 Bit16u iobase1, iobase2;
2194 Bit8u channel, slave, shift;
2195 Bit8u sc, sn, cl, ch, st;
2197 channel = device / 2;
2198 slave = device % 2;
2200 iobase1 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1);
2201 iobase2 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2);
2203 // Disable interrupts
2204 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2206 // Look for device
2207 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2208 outb(iobase1+ATA_CB_SC, 0x55);
2209 outb(iobase1+ATA_CB_SN, 0xaa);
2210 outb(iobase1+ATA_CB_SC, 0xaa);
2211 outb(iobase1+ATA_CB_SN, 0x55);
2212 outb(iobase1+ATA_CB_SC, 0x55);
2213 outb(iobase1+ATA_CB_SN, 0xaa);
2215 // If we found something
2216 sc = inb(iobase1+ATA_CB_SC);
2217 sn = inb(iobase1+ATA_CB_SN);
2219 if ( (sc == 0x55) && (sn == 0xaa) ) {
2220 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_UNKNOWN);
2222 // reset the channel
2223 ata_reset (device);
2225 // check for ATA or ATAPI
2226 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2227 sc = inb(iobase1+ATA_CB_SC);
2228 sn = inb(iobase1+ATA_CB_SN);
2229 if ( (sc==0x01) && (sn==0x01) ) {
2230 cl = inb(iobase1+ATA_CB_CL);
2231 ch = inb(iobase1+ATA_CB_CH);
2232 st = inb(iobase1+ATA_CB_STAT);
2234 if ( (cl==0x14) && (ch==0xeb) ) {
2235 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATAPI);
2237 else if ( (cl==0x00) && (ch==0x00) && (st!=0x00) ) {
2238 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATA);
2243 type=read_byte(ebda_seg,&EbdaData->ata.devices[device].type);
2245 // Now we send a IDENTIFY command to ATA device
2246 if(type == ATA_TYPE_ATA) {
2247 Bit32u sectors;
2248 Bit16u cylinders, heads, spt, blksize;
2249 Bit8u translation, removable, mode;
2251 //Temporary values to do the transfer
2252 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2253 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2255 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE, 1, 0, 0, 0, 0L, get_SS(),buffer) !=0 )
2256 BX_PANIC("ata-detect: Failed to detect ATA device\n");
2258 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2259 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2260 blksize = read_word(get_SS(),buffer+10);
2262 cylinders = read_word(get_SS(),buffer+(1*2)); // word 1
2263 heads = read_word(get_SS(),buffer+(3*2)); // word 3
2264 spt = read_word(get_SS(),buffer+(6*2)); // word 6
2266 sectors = read_dword(get_SS(),buffer+(60*2)); // word 60 and word 61
2268 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2269 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2270 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2271 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2272 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads, heads);
2273 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders, cylinders);
2274 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt, spt);
2275 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors, sectors);
2276 BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel, slave,cylinders, heads, spt);
2278 translation = inb_cmos(0x39 + channel/2);
2279 for (shift=device%4; shift>0; shift--) translation >>= 2;
2280 translation &= 0x03;
2282 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation, translation);
2284 switch (translation) {
2285 case ATA_TRANSLATION_NONE:
2286 BX_INFO("none");
2287 break;
2288 case ATA_TRANSLATION_LBA:
2289 BX_INFO("lba");
2290 break;
2291 case ATA_TRANSLATION_LARGE:
2292 BX_INFO("large");
2293 break;
2294 case ATA_TRANSLATION_RECHS:
2295 BX_INFO("r-echs");
2296 break;
2298 switch (translation) {
2299 case ATA_TRANSLATION_NONE:
2300 break;
2301 case ATA_TRANSLATION_LBA:
2302 spt = 63;
2303 sectors /= 63;
2304 heads = sectors / 1024;
2305 if (heads>128) heads = 255;
2306 else if (heads>64) heads = 128;
2307 else if (heads>32) heads = 64;
2308 else if (heads>16) heads = 32;
2309 else heads=16;
2310 cylinders = sectors / heads;
2311 break;
2312 case ATA_TRANSLATION_RECHS:
2313 // Take care not to overflow
2314 if (heads==16) {
2315 if(cylinders>61439) cylinders=61439;
2316 heads=15;
2317 cylinders = (Bit16u)((Bit32u)(cylinders)*16/15);
2319 // then go through the large bitshift process
2320 case ATA_TRANSLATION_LARGE:
2321 while(cylinders > 1024) {
2322 cylinders >>= 1;
2323 heads <<= 1;
2325 // If we max out the head count
2326 if (heads > 127) break;
2328 break;
2330 // clip to 1024 cylinders in lchs
2331 if (cylinders > 1024) cylinders=1024;
2332 BX_INFO(" LCHS=%d/%d/%d\n", cylinders, heads, spt);
2334 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, heads);
2335 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, cylinders);
2336 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, spt);
2338 // fill hdidmap
2339 write_byte(ebda_seg,&EbdaData->ata.hdidmap[hdcount], device);
2340 hdcount++;
2343 // Now we send a IDENTIFY command to ATAPI device
2344 if(type == ATA_TYPE_ATAPI) {
2346 Bit8u type, removable, mode;
2347 Bit16u blksize;
2349 //Temporary values to do the transfer
2350 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_CDROM);
2351 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2353 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE_PACKET, 1, 0, 0, 0, 0L, get_SS(),buffer) != 0)
2354 BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
2356 type = read_byte(get_SS(),buffer+1) & 0x1f;
2357 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2358 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2359 blksize = 2048;
2361 write_byte(ebda_seg,&EbdaData->ata.devices[device].device, type);
2362 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2363 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2364 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2366 // fill cdidmap
2367 write_byte(ebda_seg,&EbdaData->ata.cdidmap[cdcount], device);
2368 cdcount++;
2372 Bit32u sizeinmb;
2373 Bit16u ataversion;
2374 Bit8u c, i, version, model[41];
2376 switch (type) {
2377 case ATA_TYPE_ATA:
2378 sizeinmb = read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors);
2379 sizeinmb >>= 11;
2380 case ATA_TYPE_ATAPI:
2381 // Read ATA/ATAPI version
2382 ataversion=((Bit16u)(read_byte(get_SS(),buffer+161))<<8)|read_byte(get_SS(),buffer+160);
2383 for(version=15;version>0;version--) {
2384 if((ataversion&(1<<version))!=0)
2385 break;
2388 // Read model name
2389 for(i=0;i<20;i++){
2390 write_byte(get_SS(),model+(i*2),read_byte(get_SS(),buffer+(i*2)+54+1));
2391 write_byte(get_SS(),model+(i*2)+1,read_byte(get_SS(),buffer+(i*2)+54));
2394 // Reformat
2395 write_byte(get_SS(),model+40,0x00);
2396 for(i=39;i>0;i--){
2397 if(read_byte(get_SS(),model+i)==0x20)
2398 write_byte(get_SS(),model+i,0x00);
2399 else break;
2401 break;
2404 switch (type) {
2405 case ATA_TYPE_ATA:
2406 printf("ata%d %s: ",channel,slave?" slave":"master");
2407 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2408 printf(" ATA-%d Hard-Disk (%d MBytes)\n",version,(Bit16u)sizeinmb);
2409 break;
2410 case ATA_TYPE_ATAPI:
2411 printf("ata%d %s: ",channel,slave?" slave":"master");
2412 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2413 if(read_byte(ebda_seg,&EbdaData->ata.devices[device].device)==ATA_DEVICE_CDROM)
2414 printf(" ATAPI-%d CD-Rom/DVD-Rom\n",version);
2415 else
2416 printf(" ATAPI-%d Device\n",version);
2417 break;
2418 case ATA_TYPE_UNKNOWN:
2419 printf("ata%d %s: Unknown device\n",channel,slave?" slave":"master");
2420 break;
2425 // Store the devices counts
2426 write_byte(ebda_seg,&EbdaData->ata.hdcount, hdcount);
2427 write_byte(ebda_seg,&EbdaData->ata.cdcount, cdcount);
2428 write_byte(0x40,0x75, hdcount);
2430 printf("\n");
2432 // FIXME : should use bios=cmos|auto|disable bits
2433 // FIXME : should know about translation bits
2434 // FIXME : move hard_drive_post here
2438 // ---------------------------------------------------------------------------
2439 // ATA/ATAPI driver : software reset
2440 // ---------------------------------------------------------------------------
2441 // ATA-3
2442 // 8.2.1 Software reset - Device 0
2444 void ata_reset(device)
2445 Bit16u device;
2447 Bit16u ebda_seg=read_word(0x0040,0x000E);
2448 Bit16u iobase1, iobase2;
2449 Bit8u channel, slave, sn, sc;
2450 Bit16u max;
2452 channel = device / 2;
2453 slave = device % 2;
2455 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2456 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2458 // Reset
2460 // 8.2.1 (a) -- set SRST in DC
2461 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN | ATA_CB_DC_SRST);
2463 // 8.2.1 (b) -- wait for BSY
2464 max=0xff;
2465 while(--max>0) {
2466 Bit8u status = inb(iobase1+ATA_CB_STAT);
2467 if ((status & ATA_CB_STAT_BSY) != 0) break;
2470 // 8.2.1 (f) -- clear SRST
2471 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2473 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_NONE) {
2475 // 8.2.1 (g) -- check for sc==sn==0x01
2476 // select device
2477 outb(iobase1+ATA_CB_DH, slave?ATA_CB_DH_DEV1:ATA_CB_DH_DEV0);
2478 sc = inb(iobase1+ATA_CB_SC);
2479 sn = inb(iobase1+ATA_CB_SN);
2481 if ( (sc==0x01) && (sn==0x01) ) {
2483 // 8.2.1 (h) -- wait for not BSY
2484 max=0xff;
2485 while(--max>0) {
2486 Bit8u status = inb(iobase1+ATA_CB_STAT);
2487 if ((status & ATA_CB_STAT_BSY) == 0) break;
2492 // 8.2.1 (i) -- wait for DRDY
2493 max=0xfff;
2494 while(--max>0) {
2495 Bit8u status = inb(iobase1+ATA_CB_STAT);
2496 if ((status & ATA_CB_STAT_RDY) != 0) break;
2499 // Enable interrupts
2500 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2503 // ---------------------------------------------------------------------------
2504 // ATA/ATAPI driver : execute a non data command
2505 // ---------------------------------------------------------------------------
2507 Bit16u ata_cmd_non_data()
2508 {return 0;}
2510 // ---------------------------------------------------------------------------
2511 // ATA/ATAPI driver : execute a data-in command
2512 // ---------------------------------------------------------------------------
2513 // returns
2514 // 0 : no error
2515 // 1 : BUSY bit set
2516 // 2 : read error
2517 // 3 : expected DRQ=1
2518 // 4 : no sectors left to read/verify
2519 // 5 : more sectors to read/verify
2520 // 6 : no sectors left to write
2521 // 7 : more sectors to write
2522 Bit16u ata_cmd_data_in(device, command, count, cylinder, head, sector, lba, segment, offset)
2523 Bit16u device, command, count, cylinder, head, sector, segment, offset;
2524 Bit32u lba;
2526 Bit16u ebda_seg=read_word(0x0040,0x000E);
2527 Bit16u iobase1, iobase2, blksize;
2528 Bit8u channel, slave;
2529 Bit8u status, current, mode;
2531 channel = device / 2;
2532 slave = device % 2;
2534 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2535 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2536 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2537 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2538 if (mode == ATA_MODE_PIO32) blksize>>=2;
2539 else blksize>>=1;
2541 // sector will be 0 only on lba access. Convert to lba-chs
2542 if (sector == 0) {
2543 sector = (Bit16u) (lba & 0x000000ffL);
2544 lba >>= 8;
2545 cylinder = (Bit16u) (lba & 0x0000ffffL);
2546 lba >>= 16;
2547 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
2550 // Reset count of transferred data
2551 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2552 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2553 current = 0;
2555 status = inb(iobase1 + ATA_CB_STAT);
2556 if (status & ATA_CB_STAT_BSY) return 1;
2558 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2559 outb(iobase1 + ATA_CB_FR, 0x00);
2560 outb(iobase1 + ATA_CB_SC, count);
2561 outb(iobase1 + ATA_CB_SN, sector);
2562 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2563 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2564 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
2565 outb(iobase1 + ATA_CB_CMD, command);
2567 while (1) {
2568 status = inb(iobase1 + ATA_CB_STAT);
2569 if ( !(status & ATA_CB_STAT_BSY) ) break;
2572 if (status & ATA_CB_STAT_ERR) {
2573 BX_DEBUG_ATA("ata_cmd_data_in : read error\n");
2574 return 2;
2575 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2576 BX_DEBUG_ATA("ata_cmd_data_in : DRQ not set (status %02x)\n", (unsigned) status);
2577 return 3;
2580 // FIXME : move seg/off translation here
2582 ASM_START
2583 sti ;; enable higher priority interrupts
2584 ASM_END
2586 while (1) {
2588 ASM_START
2589 push bp
2590 mov bp, sp
2591 mov di, _ata_cmd_data_in.offset + 2[bp]
2592 mov ax, _ata_cmd_data_in.segment + 2[bp]
2593 mov cx, _ata_cmd_data_in.blksize + 2[bp]
2595 ;; adjust if there will be an overrun. 2K max sector size
2596 cmp di, #0xf800 ;;
2597 jbe ata_in_no_adjust
2599 ata_in_adjust:
2600 sub di, #0x0800 ;; sub 2 kbytes from offset
2601 add ax, #0x0080 ;; add 2 Kbytes to segment
2603 ata_in_no_adjust:
2604 mov es, ax ;; segment in es
2606 mov dx, _ata_cmd_data_in.iobase1 + 2[bp] ;; ATA data read port
2608 mov ah, _ata_cmd_data_in.mode + 2[bp]
2609 cmp ah, #ATA_MODE_PIO32
2610 je ata_in_32
2612 ata_in_16:
2613 rep
2614 insw ;; CX words transfered from port(DX) to ES:[DI]
2615 jmp ata_in_done
2617 ata_in_32:
2618 rep
2619 insd ;; CX dwords transfered from port(DX) to ES:[DI]
2621 ata_in_done:
2622 mov _ata_cmd_data_in.offset + 2[bp], di
2623 mov _ata_cmd_data_in.segment + 2[bp], es
2624 pop bp
2625 ASM_END
2627 current++;
2628 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
2629 count--;
2630 status = inb(iobase1 + ATA_CB_STAT);
2631 if (count == 0) {
2632 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2633 != ATA_CB_STAT_RDY ) {
2634 BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n", (unsigned) status);
2635 return 4;
2637 break;
2639 else {
2640 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2641 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
2642 BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n", (unsigned) status);
2643 return 5;
2645 continue;
2648 // Enable interrupts
2649 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2650 return 0;
2653 // ---------------------------------------------------------------------------
2654 // ATA/ATAPI driver : execute a data-out command
2655 // ---------------------------------------------------------------------------
2656 // returns
2657 // 0 : no error
2658 // 1 : BUSY bit set
2659 // 2 : read error
2660 // 3 : expected DRQ=1
2661 // 4 : no sectors left to read/verify
2662 // 5 : more sectors to read/verify
2663 // 6 : no sectors left to write
2664 // 7 : more sectors to write
2665 Bit16u ata_cmd_data_out(device, command, count, cylinder, head, sector, lba, segment, offset)
2666 Bit16u device, command, count, cylinder, head, sector, segment, offset;
2667 Bit32u lba;
2669 Bit16u ebda_seg=read_word(0x0040,0x000E);
2670 Bit16u iobase1, iobase2, blksize;
2671 Bit8u channel, slave;
2672 Bit8u status, current, mode;
2674 channel = device / 2;
2675 slave = device % 2;
2677 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2678 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2679 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2680 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2681 if (mode == ATA_MODE_PIO32) blksize>>=2;
2682 else blksize>>=1;
2684 // sector will be 0 only on lba access. Convert to lba-chs
2685 if (sector == 0) {
2686 sector = (Bit16u) (lba & 0x000000ffL);
2687 lba >>= 8;
2688 cylinder = (Bit16u) (lba & 0x0000ffffL);
2689 lba >>= 16;
2690 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
2693 // Reset count of transferred data
2694 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2695 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2696 current = 0;
2698 status = inb(iobase1 + ATA_CB_STAT);
2699 if (status & ATA_CB_STAT_BSY) return 1;
2701 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2702 outb(iobase1 + ATA_CB_FR, 0x00);
2703 outb(iobase1 + ATA_CB_SC, count);
2704 outb(iobase1 + ATA_CB_SN, sector);
2705 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2706 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2707 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
2708 outb(iobase1 + ATA_CB_CMD, command);
2710 while (1) {
2711 status = inb(iobase1 + ATA_CB_STAT);
2712 if ( !(status & ATA_CB_STAT_BSY) ) break;
2715 if (status & ATA_CB_STAT_ERR) {
2716 BX_DEBUG_ATA("ata_cmd_data_out : read error\n");
2717 return 2;
2718 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2719 BX_DEBUG_ATA("ata_cmd_data_out : DRQ not set (status %02x)\n", (unsigned) status);
2720 return 3;
2723 // FIXME : move seg/off translation here
2725 ASM_START
2726 sti ;; enable higher priority interrupts
2727 ASM_END
2729 while (1) {
2731 ASM_START
2732 push bp
2733 mov bp, sp
2734 mov si, _ata_cmd_data_out.offset + 2[bp]
2735 mov ax, _ata_cmd_data_out.segment + 2[bp]
2736 mov cx, _ata_cmd_data_out.blksize + 2[bp]
2738 ;; adjust if there will be an overrun. 2K max sector size
2739 cmp si, #0xf800 ;;
2740 jbe ata_out_no_adjust
2742 ata_out_adjust:
2743 sub si, #0x0800 ;; sub 2 kbytes from offset
2744 add ax, #0x0080 ;; add 2 Kbytes to segment
2746 ata_out_no_adjust:
2747 mov es, ax ;; segment in es
2749 mov dx, _ata_cmd_data_out.iobase1 + 2[bp] ;; ATA data write port
2751 mov ah, _ata_cmd_data_out.mode + 2[bp]
2752 cmp ah, #ATA_MODE_PIO32
2753 je ata_out_32
2755 ata_out_16:
2756 seg ES
2757 rep
2758 outsw ;; CX words transfered from port(DX) to ES:[SI]
2759 jmp ata_out_done
2761 ata_out_32:
2762 seg ES
2763 rep
2764 outsd ;; CX dwords transfered from port(DX) to ES:[SI]
2766 ata_out_done:
2767 mov _ata_cmd_data_out.offset + 2[bp], si
2768 mov _ata_cmd_data_out.segment + 2[bp], es
2769 pop bp
2770 ASM_END
2772 current++;
2773 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
2774 count--;
2775 status = inb(iobase1 + ATA_CB_STAT);
2776 if (count == 0) {
2777 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2778 != ATA_CB_STAT_RDY ) {
2779 BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n", (unsigned) status);
2780 return 6;
2782 break;
2784 else {
2785 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2786 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
2787 BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n", (unsigned) status);
2788 return 7;
2790 continue;
2793 // Enable interrupts
2794 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2795 return 0;
2798 // ---------------------------------------------------------------------------
2799 // ATA/ATAPI driver : execute a packet command
2800 // ---------------------------------------------------------------------------
2801 // returns
2802 // 0 : no error
2803 // 1 : error in parameters
2804 // 2 : BUSY bit set
2805 // 3 : error
2806 // 4 : not ready
2807 Bit16u ata_cmd_packet(device, cmdlen, cmdseg, cmdoff, header, length, inout, bufseg, bufoff)
2808 Bit8u cmdlen,inout;
2809 Bit16u device,cmdseg, cmdoff, bufseg, bufoff;
2810 Bit16u header;
2811 Bit32u length;
2813 Bit16u ebda_seg=read_word(0x0040,0x000E);
2814 Bit16u iobase1, iobase2;
2815 Bit16u lcount, lbefore, lafter, count;
2816 Bit8u channel, slave;
2817 Bit8u status, mode, lmode;
2818 Bit32u total, transfer;
2820 channel = device / 2;
2821 slave = device % 2;
2823 // Data out is not supported yet
2824 if (inout == ATA_DATA_OUT) {
2825 BX_INFO("ata_cmd_packet: DATA_OUT not supported yet\n");
2826 return 1;
2829 // The header length must be even
2830 if (header & 1) {
2831 BX_DEBUG_ATA("ata_cmd_packet : header must be even (%04x)\n",header);
2832 return 1;
2835 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2836 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2837 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2838 transfer= 0L;
2840 if (cmdlen < 12) cmdlen=12;
2841 if (cmdlen > 12) cmdlen=16;
2842 cmdlen>>=1;
2844 // Reset count of transferred data
2845 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2846 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2848 status = inb(iobase1 + ATA_CB_STAT);
2849 if (status & ATA_CB_STAT_BSY) return 2;
2851 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2852 // outb(iobase1 + ATA_CB_FR, 0x00);
2853 // outb(iobase1 + ATA_CB_SC, 0x00);
2854 // outb(iobase1 + ATA_CB_SN, 0x00);
2855 outb(iobase1 + ATA_CB_CL, 0xfff0 & 0x00ff);
2856 outb(iobase1 + ATA_CB_CH, 0xfff0 >> 8);
2857 outb(iobase1 + ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2858 outb(iobase1 + ATA_CB_CMD, ATA_CMD_PACKET);
2860 // Device should ok to receive command
2861 while (1) {
2862 status = inb(iobase1 + ATA_CB_STAT);
2863 if ( !(status & ATA_CB_STAT_BSY) ) break;
2866 if (status & ATA_CB_STAT_ERR) {
2867 BX_DEBUG_ATA("ata_cmd_packet : error, status is %02x\n",status);
2868 return 3;
2869 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2870 BX_DEBUG_ATA("ata_cmd_packet : DRQ not set (status %02x)\n", (unsigned) status);
2871 return 4;
2874 // Normalize address
2875 cmdseg += (cmdoff / 16);
2876 cmdoff %= 16;
2878 // Send command to device
2879 ASM_START
2880 sti ;; enable higher priority interrupts
2882 push bp
2883 mov bp, sp
2885 mov si, _ata_cmd_packet.cmdoff + 2[bp]
2886 mov ax, _ata_cmd_packet.cmdseg + 2[bp]
2887 mov cx, _ata_cmd_packet.cmdlen + 2[bp]
2888 mov es, ax ;; segment in es
2890 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data write port
2892 seg ES
2893 rep
2894 outsw ;; CX words transfered from port(DX) to ES:[SI]
2896 pop bp
2897 ASM_END
2899 if (inout == ATA_DATA_NO) {
2900 status = inb(iobase1 + ATA_CB_STAT);
2902 else {
2903 while (1) {
2905 status = inb(iobase1 + ATA_CB_STAT);
2907 // Check if command completed
2908 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_DRQ) ) ==0 ) break;
2910 if (status & ATA_CB_STAT_ERR) {
2911 BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status);
2912 return 3;
2915 // Device must be ready to send data
2916 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2917 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
2918 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", status);
2919 return 4;
2922 // Normalize address
2923 bufseg += (bufoff / 16);
2924 bufoff %= 16;
2926 // Get the byte count
2927 lcount = ((Bit16u)(inb(iobase1 + ATA_CB_CH))<<8)+inb(iobase1 + ATA_CB_CL);
2929 // adjust to read what we want
2930 if(header>lcount) {
2931 lbefore=lcount;
2932 header-=lcount;
2933 lcount=0;
2935 else {
2936 lbefore=header;
2937 header=0;
2938 lcount-=lbefore;
2941 if(lcount>length) {
2942 lafter=lcount-length;
2943 lcount=length;
2944 length=0;
2946 else {
2947 lafter=0;
2948 length-=lcount;
2951 // Save byte count
2952 count = lcount;
2954 BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore+lcount+lafter,lbefore,lcount,lafter);
2955 BX_DEBUG_ATA("to 0x%04x:0x%04x\n",bufseg,bufoff);
2957 // If counts not dividable by 4, use 16bits mode
2958 lmode = mode;
2959 if (lbefore & 0x03) lmode=ATA_MODE_PIO16;
2960 if (lcount & 0x03) lmode=ATA_MODE_PIO16;
2961 if (lafter & 0x03) lmode=ATA_MODE_PIO16;
2963 // adds an extra byte if count are odd. before is always even
2964 if (lcount & 0x01) {
2965 lcount+=1;
2966 if ((lafter > 0) && (lafter & 0x01)) {
2967 lafter-=1;
2971 if (lmode == ATA_MODE_PIO32) {
2972 lcount>>=2; lbefore>>=2; lafter>>=2;
2974 else {
2975 lcount>>=1; lbefore>>=1; lafter>>=1;
2978 ; // FIXME bcc bug
2980 ASM_START
2981 push bp
2982 mov bp, sp
2984 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data read port
2986 mov cx, _ata_cmd_packet.lbefore + 2[bp]
2987 jcxz ata_packet_no_before
2989 mov ah, _ata_cmd_packet.lmode + 2[bp]
2990 cmp ah, #ATA_MODE_PIO32
2991 je ata_packet_in_before_32
2993 ata_packet_in_before_16:
2994 in ax, dx
2995 loop ata_packet_in_before_16
2996 jmp ata_packet_no_before
2998 ata_packet_in_before_32:
2999 push eax
3000 ata_packet_in_before_32_loop:
3001 in eax, dx
3002 loop ata_packet_in_before_32_loop
3003 pop eax
3005 ata_packet_no_before:
3006 mov cx, _ata_cmd_packet.lcount + 2[bp]
3007 jcxz ata_packet_after
3009 mov di, _ata_cmd_packet.bufoff + 2[bp]
3010 mov ax, _ata_cmd_packet.bufseg + 2[bp]
3011 mov es, ax
3013 mov ah, _ata_cmd_packet.lmode + 2[bp]
3014 cmp ah, #ATA_MODE_PIO32
3015 je ata_packet_in_32
3017 ata_packet_in_16:
3018 rep
3019 insw ;; CX words transfered tp port(DX) to ES:[DI]
3020 jmp ata_packet_after
3022 ata_packet_in_32:
3023 rep
3024 insd ;; CX dwords transfered to port(DX) to ES:[DI]
3026 ata_packet_after:
3027 mov cx, _ata_cmd_packet.lafter + 2[bp]
3028 jcxz ata_packet_done
3030 mov ah, _ata_cmd_packet.lmode + 2[bp]
3031 cmp ah, #ATA_MODE_PIO32
3032 je ata_packet_in_after_32
3034 ata_packet_in_after_16:
3035 in ax, dx
3036 loop ata_packet_in_after_16
3037 jmp ata_packet_done
3039 ata_packet_in_after_32:
3040 push eax
3041 ata_packet_in_after_32_loop:
3042 in eax, dx
3043 loop ata_packet_in_after_32_loop
3044 pop eax
3046 ata_packet_done:
3047 pop bp
3048 ASM_END
3050 // Compute new buffer address
3051 bufoff += count;
3053 // Save transferred bytes count
3054 transfer += count;
3055 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,transfer);
3059 // Final check, device must be ready
3060 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3061 != ATA_CB_STAT_RDY ) {
3062 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", (unsigned) status);
3063 return 4;
3066 // Enable interrupts
3067 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3068 return 0;
3071 // ---------------------------------------------------------------------------
3072 // End of ATA/ATAPI Driver
3073 // ---------------------------------------------------------------------------
3075 // ---------------------------------------------------------------------------
3076 // Start of ATA/ATAPI generic functions
3077 // ---------------------------------------------------------------------------
3079 Bit16u
3080 atapi_get_sense(device)
3081 Bit16u device;
3083 Bit8u atacmd[12];
3084 Bit8u buffer[16];
3085 Bit8u i;
3087 memsetb(get_SS(),atacmd,0,12);
3089 // Request SENSE
3090 atacmd[0]=0x03;
3091 atacmd[4]=0x20;
3092 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 16L, ATA_DATA_IN, get_SS(), buffer) != 0)
3093 return 0x0002;
3095 if ((buffer[0] & 0x7e) == 0x70) {
3096 return (((Bit16u)buffer[2]&0x0f)*0x100)+buffer[12];
3099 return 0;
3102 Bit16u
3103 atapi_is_ready(device)
3104 Bit16u device;
3106 Bit8u atacmd[12];
3107 Bit8u buffer[];
3109 memsetb(get_SS(),atacmd,0,12);
3111 // Test Unit Ready
3112 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3113 return 0x000f;
3115 if (atapi_get_sense(device) !=0 ) {
3116 memsetb(get_SS(),atacmd,0,12);
3118 // try to send Test Unit Ready again
3119 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3120 return 0x000f;
3122 return atapi_get_sense(device);
3124 return 0;
3127 Bit16u
3128 atapi_is_cdrom(device)
3129 Bit8u device;
3131 Bit16u ebda_seg=read_word(0x0040,0x000E);
3133 if (device >= BX_MAX_ATA_DEVICES)
3134 return 0;
3136 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_ATAPI)
3137 return 0;
3139 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].device) != ATA_DEVICE_CDROM)
3140 return 0;
3142 return 1;
3145 // ---------------------------------------------------------------------------
3146 // End of ATA/ATAPI generic functions
3147 // ---------------------------------------------------------------------------
3149 #endif // BX_USE_ATADRV
3151 #if BX_ELTORITO_BOOT
3153 // ---------------------------------------------------------------------------
3154 // Start of El-Torito boot functions
3155 // ---------------------------------------------------------------------------
3157 void
3158 cdemu_init()
3160 Bit16u ebda_seg=read_word(0x0040,0x000E);
3162 // the only important data is this one for now
3163 write_byte(ebda_seg,&EbdaData->cdemu.active,0x00);
3166 Bit8u
3167 cdemu_isactive()
3169 Bit16u ebda_seg=read_word(0x0040,0x000E);
3171 return(read_byte(ebda_seg,&EbdaData->cdemu.active));
3174 Bit8u
3175 cdemu_emulated_drive()
3177 Bit16u ebda_seg=read_word(0x0040,0x000E);
3179 return(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
3182 static char isotag[6]="CD001";
3183 static char eltorito[24]="EL TORITO SPECIFICATION";
3184 //
3185 // Returns ah: emulated drive, al: error code
3186 //
3187 Bit16u
3188 cdrom_boot()
3190 Bit16u ebda_seg=read_word(0x0040,0x000E);
3191 Bit8u atacmd[12], buffer[2048];
3192 Bit32u lba;
3193 Bit16u boot_segment, nbsectors, i, error;
3194 Bit8u device;
3196 // Find out the first cdrom
3197 for (device=0; device<BX_MAX_ATA_DEVICES;device++) {
3198 if (atapi_is_cdrom(device)) break;
3201 // if not found
3202 if(device >= BX_MAX_ATA_DEVICES) return 2;
3204 // Read the Boot Record Volume Descriptor
3205 memsetb(get_SS(),atacmd,0,12);
3206 atacmd[0]=0x28; // READ command
3207 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3208 atacmd[8]=(0x01 & 0x00ff); // Sectors
3209 atacmd[2]=(0x11 & 0xff000000) >> 24; // LBA
3210 atacmd[3]=(0x11 & 0x00ff0000) >> 16;
3211 atacmd[4]=(0x11 & 0x0000ff00) >> 8;
3212 atacmd[5]=(0x11 & 0x000000ff);
3213 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3214 return 3;
3216 // Validity checks
3217 if(buffer[0]!=0)return 4;
3218 for(i=0;i<5;i++){
3219 if(buffer[1+i]!=read_byte(0xf000,&isotag[i]))return 5;
3221 for(i=0;i<23;i++)
3222 if(buffer[7+i]!=read_byte(0xf000,&eltorito[i]))return 6;
3224 // ok, now we calculate the Boot catalog address
3225 lba=buffer[0x4A]*0x1000000+buffer[0x49]*0x10000+buffer[0x48]*0x100+buffer[0x47];
3227 // And we read the Boot Catalog
3228 memsetb(get_SS(),atacmd,0,12);
3229 atacmd[0]=0x28; // READ command
3230 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3231 atacmd[8]=(0x01 & 0x00ff); // Sectors
3232 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3233 atacmd[3]=(lba & 0x00ff0000) >> 16;
3234 atacmd[4]=(lba & 0x0000ff00) >> 8;
3235 atacmd[5]=(lba & 0x000000ff);
3236 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3237 return 7;
3239 // Validation entry
3240 if(buffer[0x00]!=0x01)return 8; // Header
3241 if(buffer[0x01]!=0x00)return 9; // Platform
3242 if(buffer[0x1E]!=0x55)return 10; // key 1
3243 if(buffer[0x1F]!=0xAA)return 10; // key 2
3245 // Initial/Default Entry
3246 if(buffer[0x20]!=0x88)return 11; // Bootable
3248 write_byte(ebda_seg,&EbdaData->cdemu.media,buffer[0x21]);
3249 if(buffer[0x21]==0){
3250 // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
3251 // Win2000 cd boot needs to know it booted from cd
3252 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0xE0);
3254 else if(buffer[0x21]<4)
3255 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x00);
3256 else
3257 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x80);
3259 write_byte(ebda_seg,&EbdaData->cdemu.controller_index,device/2);
3260 write_byte(ebda_seg,&EbdaData->cdemu.device_spec,device%2);
3262 boot_segment=buffer[0x23]*0x100+buffer[0x22];
3263 if(boot_segment==0x0000)boot_segment=0x07C0;
3265 write_word(ebda_seg,&EbdaData->cdemu.load_segment,boot_segment);
3266 write_word(ebda_seg,&EbdaData->cdemu.buffer_segment,0x0000);
3268 nbsectors=buffer[0x27]*0x100+buffer[0x26];
3269 write_word(ebda_seg,&EbdaData->cdemu.sector_count,nbsectors);
3271 lba=buffer[0x2B]*0x1000000+buffer[0x2A]*0x10000+buffer[0x29]*0x100+buffer[0x28];
3272 write_dword(ebda_seg,&EbdaData->cdemu.ilba,lba);
3274 // And we read the image in memory
3275 memsetb(get_SS(),atacmd,0,12);
3276 atacmd[0]=0x28; // READ command
3277 atacmd[7]=((1+(nbsectors-1)/4) & 0xff00) >> 8; // Sectors
3278 atacmd[8]=((1+(nbsectors-1)/4) & 0x00ff); // Sectors
3279 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3280 atacmd[3]=(lba & 0x00ff0000) >> 16;
3281 atacmd[4]=(lba & 0x0000ff00) >> 8;
3282 atacmd[5]=(lba & 0x000000ff);
3283 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, nbsectors*512L, ATA_DATA_IN, boot_segment,0)) != 0)
3284 return 12;
3286 // Remember the media type
3287 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
3288 case 0x01: // 1.2M floppy
3289 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,15);
3290 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3291 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3292 break;
3293 case 0x02: // 1.44M floppy
3294 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,18);
3295 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3296 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3297 break;
3298 case 0x03: // 2.88M floppy
3299 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,36);
3300 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3301 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3302 break;
3303 case 0x04: // Harddrive
3304 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,read_byte(boot_segment,446+6)&0x3f);
3305 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,
3306 (read_byte(boot_segment,446+6)<<2) + read_byte(boot_segment,446+7) + 1);
3307 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,read_byte(boot_segment,446+5) + 1);
3308 break;
3311 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0) {
3312 // Increase bios installed hardware number of devices
3313 if(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)==0x00)
3314 write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
3315 else
3316 write_byte(ebda_seg, &EbdaData->ata.hdcount, read_byte(ebda_seg, &EbdaData->ata.hdcount) + 1);
3320 // everything is ok, so from now on, the emulation is active
3321 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0)
3322 write_byte(ebda_seg,&EbdaData->cdemu.active,0x01);
3324 // return the boot drive + no error
3325 return (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)*0x100)+0;
3328 // ---------------------------------------------------------------------------
3329 // End of El-Torito boot functions
3330 // ---------------------------------------------------------------------------
3331 #endif // BX_ELTORITO_BOOT
3333 void
3334 int14_function(regs, ds, iret_addr)
3335 pusha_regs_t regs; // regs pushed from PUSHA instruction
3336 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
3337 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
3339 Bit16u addr,timer,val16;
3340 Bit8u timeout;
3342 ASM_START
3343 sti
3344 ASM_END
3346 addr = read_word(0x0040, (regs.u.r16.dx << 1));
3347 timeout = read_byte(0x0040, 0x007C + regs.u.r16.dx);
3348 if ((regs.u.r16.dx < 4) && (addr > 0)) {
3349 switch (regs.u.r8.ah) {
3350 case 0:
3351 outb(addr+3, inb(addr+3) | 0x80);
3352 if (regs.u.r8.al & 0xE0 == 0) {
3353 outb(addr, 0x17);
3354 outb(addr+1, 0x04);
3355 } else {
3356 val16 = 0x600 >> ((regs.u.r8.al & 0xE0) >> 5);
3357 outb(addr, val16 & 0xFF);
3358 outb(addr+1, val16 >> 8);
3360 outb(addr+3, regs.u.r8.al & 0x1F);
3361 regs.u.r8.ah = inb(addr+5);
3362 regs.u.r8.al = inb(addr+6);
3363 ClearCF(iret_addr.flags);
3364 break;
3365 case 1:
3366 timer = read_word(0x0040, 0x006C);
3367 while (((inb(addr+5) & 0x60) != 0x60) && (timeout)) {
3368 val16 = read_word(0x0040, 0x006C);
3369 if (val16 != timer) {
3370 timer = val16;
3371 timeout--;
3374 if (timeout) outb(addr, regs.u.r8.al);
3375 regs.u.r8.ah = inb(addr+5);
3376 if (!timeout) regs.u.r8.ah |= 0x80;
3377 ClearCF(iret_addr.flags);
3378 break;
3379 case 2:
3380 timer = read_word(0x0040, 0x006C);
3381 while (((inb(addr+5) & 0x01) == 0) && (timeout)) {
3382 val16 = read_word(0x0040, 0x006C);
3383 if (val16 != timer) {
3384 timer = val16;
3385 timeout--;
3388 if (timeout) {
3389 regs.u.r8.ah = 0;
3390 regs.u.r8.al = inb(addr);
3391 } else {
3392 regs.u.r8.ah = inb(addr+5);
3394 ClearCF(iret_addr.flags);
3395 break;
3396 case 3:
3397 regs.u.r8.ah = inb(addr+5);
3398 regs.u.r8.al = inb(addr+6);
3399 ClearCF(iret_addr.flags);
3400 break;
3401 default:
3402 SetCF(iret_addr.flags); // Unsupported
3404 } else {
3405 SetCF(iret_addr.flags); // Unsupported
3409 void
3410 int15_function(regs, ES, DS, FLAGS)
3411 pusha_regs_t regs; // REGS pushed via pusha
3412 Bit16u ES, DS, FLAGS;
3414 Bit16u ebda_seg=read_word(0x0040,0x000E);
3415 bx_bool prev_a20_enable;
3416 Bit16u base15_00;
3417 Bit8u base23_16;
3418 Bit16u ss;
3419 Bit16u CX,DX;
3421 Bit16u bRegister;
3422 Bit8u irqDisable;
3424 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
3426 switch (regs.u.r8.ah) {
3427 case 0x24: /* A20 Control */
3428 switch (regs.u.r8.al) {
3429 case 0x00:
3430 set_enable_a20(0);
3431 CLEAR_CF();
3432 regs.u.r8.ah = 0;
3433 break;
3434 case 0x01:
3435 set_enable_a20(1);
3436 CLEAR_CF();
3437 regs.u.r8.ah = 0;
3438 break;
3439 case 0x02:
3440 regs.u.r8.al = (inb(0x92) >> 1) & 0x01;
3441 CLEAR_CF();
3442 regs.u.r8.ah = 0;
3443 break;
3444 case 0x03:
3445 CLEAR_CF();
3446 regs.u.r8.ah = 0;
3447 regs.u.r16.bx = 3;
3448 break;
3449 default:
3450 BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs.u.r8.al);
3451 SET_CF();
3452 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3454 break;
3456 case 0x41:
3457 SET_CF();
3458 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3459 break;
3461 case 0x4f:
3462 /* keyboard intercept */
3463 #if BX_CPU < 2
3464 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3465 #else
3466 // nop
3467 #endif
3468 SET_CF();
3469 break;
3471 case 0x52: // removable media eject
3472 CLEAR_CF();
3473 regs.u.r8.ah = 0; // "ok ejection may proceed"
3474 break;
3476 case 0x83: {
3477 if( regs.u.r8.al == 0 ) {
3478 // Set Interval requested.
3479 if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
3480 // Interval not already set.
3481 write_byte( 0x40, 0xA0, 1 ); // Set status byte.
3482 write_word( 0x40, 0x98, ES ); // Byte location, segment
3483 write_word( 0x40, 0x9A, regs.u.r16.bx ); // Byte location, offset
3484 write_word( 0x40, 0x9C, regs.u.r16.dx ); // Low word, delay
3485 write_word( 0x40, 0x9E, regs.u.r16.cx ); // High word, delay.
3486 CLEAR_CF( );
3487 irqDisable = inb( 0xA1 );
3488 outb( 0xA1, irqDisable & 0xFE );
3489 bRegister = inb_cmos( 0xB ); // Unmask IRQ8 so INT70 will get through.
3490 outb_cmos( 0xB, bRegister | 0x40 ); // Turn on the Periodic Interrupt timer
3491 } else {
3492 // Interval already set.
3493 BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
3494 SET_CF();
3495 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3497 } else if( regs.u.r8.al == 1 ) {
3498 // Clear Interval requested
3499 write_byte( 0x40, 0xA0, 0 ); // Clear status byte
3500 CLEAR_CF( );
3501 bRegister = inb_cmos( 0xB );
3502 outb_cmos( 0xB, bRegister & ~0x40 ); // Turn off the Periodic Interrupt timer
3503 } else {
3504 BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
3505 SET_CF();
3506 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3507 regs.u.r8.al--;
3510 break;
3513 case 0x87:
3514 #if BX_CPU < 3
3515 # error "Int15 function 87h not supported on < 80386"
3516 #endif
3517 // +++ should probably have descriptor checks
3518 // +++ should have exception handlers
3520 // turn off interrupts
3521 ASM_START
3522 cli
3523 ASM_END
3525 prev_a20_enable = set_enable_a20(1); // enable A20 line
3527 // 128K max of transfer on 386+ ???
3528 // source == destination ???
3530 // ES:SI points to descriptor table
3531 // offset use initially comments
3532 // ==============================================
3533 // 00..07 Unused zeros Null descriptor
3534 // 08..0f GDT zeros filled in by BIOS
3535 // 10..17 source ssssssss source of data
3536 // 18..1f dest dddddddd destination of data
3537 // 20..27 CS zeros filled in by BIOS
3538 // 28..2f SS zeros filled in by BIOS
3540 //es:si
3541 //eeee0
3542 //0ssss
3543 //-----
3545 // check for access rights of source & dest here
3547 // Initialize GDT descriptor
3548 base15_00 = (ES << 4) + regs.u.r16.si;
3549 base23_16 = ES >> 12;
3550 if (base15_00 < (ES<<4))
3551 base23_16++;
3552 write_word(ES, regs.u.r16.si+0x08+0, 47); // limit 15:00 = 6 * 8bytes/descriptor
3553 write_word(ES, regs.u.r16.si+0x08+2, base15_00);// base 15:00
3554 write_byte(ES, regs.u.r16.si+0x08+4, base23_16);// base 23:16
3555 write_byte(ES, regs.u.r16.si+0x08+5, 0x93); // access
3556 write_word(ES, regs.u.r16.si+0x08+6, 0x0000); // base 31:24/reserved/limit 19:16
3558 // Initialize CS descriptor
3559 write_word(ES, regs.u.r16.si+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
3560 write_word(ES, regs.u.r16.si+0x20+2, 0x0000);// base 15:00
3561 write_byte(ES, regs.u.r16.si+0x20+4, 0x000f);// base 23:16
3562 write_byte(ES, regs.u.r16.si+0x20+5, 0x9b); // access
3563 write_word(ES, regs.u.r16.si+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
3565 // Initialize SS descriptor
3566 ss = get_SS();
3567 base15_00 = ss << 4;
3568 base23_16 = ss >> 12;
3569 write_word(ES, regs.u.r16.si+0x28+0, 0xffff); // limit 15:00 = normal 64K limit
3570 write_word(ES, regs.u.r16.si+0x28+2, base15_00);// base 15:00
3571 write_byte(ES, regs.u.r16.si+0x28+4, base23_16);// base 23:16
3572 write_byte(ES, regs.u.r16.si+0x28+5, 0x93); // access
3573 write_word(ES, regs.u.r16.si+0x28+6, 0x0000); // base 31:24/reserved/limit 19:16
3575 CX = regs.u.r16.cx;
3576 ASM_START
3577 // Compile generates locals offset info relative to SP.
3578 // Get CX (word count) from stack.
3579 mov bx, sp
3580 SEG SS
3581 mov cx, _int15_function.CX [bx]
3583 // since we need to set SS:SP, save them to the BDA
3584 // for future restore
3585 push eax
3586 xor eax, eax
3587 mov ds, ax
3588 mov 0x0469, ss
3589 mov 0x0467, sp
3591 SEG ES
3592 lgdt [si + 0x08]
3593 SEG CS
3594 lidt [pmode_IDT_info]
3595 ;; perhaps do something with IDT here
3597 ;; set PE bit in CR0
3598 mov eax, cr0
3599 or al, #0x01
3600 mov cr0, eax
3601 ;; far jump to flush CPU queue after transition to protected mode
3602 JMP_AP(0x0020, protected_mode)
3604 protected_mode:
3605 ;; GDT points to valid descriptor table, now load SS, DS, ES
3606 mov ax, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
3607 mov ss, ax
3608 mov ax, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
3609 mov ds, ax
3610 mov ax, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
3611 mov es, ax
3612 xor si, si
3613 xor di, di
3614 cld
3615 rep
3616 movsw ;; move CX words from DS:SI to ES:DI
3618 ;; make sure DS and ES limits are 64KB
3619 mov ax, #0x28
3620 mov ds, ax
3621 mov es, ax
3623 ;; reset PG bit in CR0 ???
3624 mov eax, cr0
3625 and al, #0xFE
3626 mov cr0, eax
3628 ;; far jump to flush CPU queue after transition to real mode
3629 JMP_AP(0xf000, real_mode)
3631 real_mode:
3632 ;; restore IDT to normal real-mode defaults
3633 SEG CS
3634 lidt [rmode_IDT_info]
3636 // restore SS:SP from the BDA
3637 xor ax, ax
3638 mov ds, ax
3639 mov ss, 0x0469
3640 mov sp, 0x0467
3641 pop eax
3642 ASM_END
3644 set_enable_a20(prev_a20_enable);
3646 // turn back on interrupts
3647 ASM_START
3648 sti
3649 ASM_END
3651 regs.u.r8.ah = 0;
3652 CLEAR_CF();
3653 break;
3656 case 0x88:
3657 // Get the amount of extended memory (above 1M)
3658 #if BX_CPU < 2
3659 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3660 SET_CF();
3661 #else
3662 regs.u.r8.al = inb_cmos(0x30);
3663 regs.u.r8.ah = inb_cmos(0x31);
3665 // limit to 15M
3666 if(regs.u.r16.ax > 0x3c00)
3667 regs.u.r16.ax = 0x3c00;
3669 CLEAR_CF();
3670 #endif
3671 break;
3673 case 0x90:
3674 /* Device busy interrupt. Called by Int 16h when no key available */
3675 break;
3677 case 0x91:
3678 /* Interrupt complete. Called by Int 16h when key becomes available */
3679 break;
3681 case 0xbf:
3682 BX_INFO("*** int 15h function AH=bf not yet supported!\n");
3683 SET_CF();
3684 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3685 break;
3687 case 0xC0:
3688 #if 0
3689 SET_CF();
3690 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3691 break;
3692 #endif
3693 CLEAR_CF();
3694 regs.u.r8.ah = 0;
3695 regs.u.r16.bx = BIOS_CONFIG_TABLE;
3696 ES = 0xF000;
3697 break;
3699 case 0xc1:
3700 ES = ebda_seg;
3701 CLEAR_CF();
3702 break;
3704 case 0xd8:
3705 bios_printf(BIOS_PRINTF_DEBUG, "EISA BIOS not present\n");
3706 SET_CF();
3707 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3708 break;
3710 default:
3711 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
3712 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
3713 SET_CF();
3714 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3715 break;
3719 #if BX_USE_PS2_MOUSE
3720 void
3721 int15_function_mouse(regs, ES, DS, FLAGS)
3722 pusha_regs_t regs; // REGS pushed via pusha
3723 Bit16u ES, DS, FLAGS;
3725 Bit16u ebda_seg=read_word(0x0040,0x000E);
3726 Bit8u mouse_flags_1, mouse_flags_2;
3727 Bit16u mouse_driver_seg;
3728 Bit16u mouse_driver_offset;
3729 Bit8u comm_byte, prev_command_byte;
3730 Bit8u ret, mouse_data1, mouse_data2, mouse_data3;
3732 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
3734 switch (regs.u.r8.ah) {
3735 case 0xC2:
3736 // Return Codes status in AH
3737 // =========================
3738 // 00: success
3739 // 01: invalid subfunction (AL > 7)
3740 // 02: invalid input value (out of allowable range)
3741 // 03: interface error
3742 // 04: resend command received from mouse controller,
3743 // device driver should attempt command again
3744 // 05: cannot enable mouse, since no far call has been installed
3745 // 80/86: mouse service not implemented
3747 switch (regs.u.r8.al) {
3748 case 0: // Disable/Enable Mouse
3749 BX_DEBUG_INT15("case 0:\n");
3750 switch (regs.u.r8.bh) {
3751 case 0: // Disable Mouse
3752 BX_DEBUG_INT15("case 0: disable mouse\n");
3753 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3754 ret = send_to_mouse_ctrl(0xF5); // disable mouse command
3755 if (ret == 0) {
3756 ret = get_mouse_data(&mouse_data1);
3757 if ( (ret == 0) || (mouse_data1 == 0xFA) ) {
3758 CLEAR_CF();
3759 regs.u.r8.ah = 0;
3760 return;
3764 // error
3765 SET_CF();
3766 regs.u.r8.ah = ret;
3767 return;
3768 break;
3770 case 1: // Enable Mouse
3771 BX_DEBUG_INT15("case 1: enable mouse\n");
3772 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
3773 if ( (mouse_flags_2 & 0x80) == 0 ) {
3774 BX_DEBUG_INT15("INT 15h C2 Enable Mouse, no far call handler\n");
3775 SET_CF(); // error
3776 regs.u.r8.ah = 5; // no far call installed
3777 return;
3779 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3780 ret = send_to_mouse_ctrl(0xF4); // enable mouse command
3781 if (ret == 0) {
3782 ret = get_mouse_data(&mouse_data1);
3783 if ( (ret == 0) && (mouse_data1 == 0xFA) ) {
3784 enable_mouse_int_and_events(); // turn IRQ12 and packet generation on
3785 CLEAR_CF();
3786 regs.u.r8.ah = 0;
3787 return;
3790 SET_CF();
3791 regs.u.r8.ah = ret;
3792 return;
3794 default: // invalid subfunction
3795 BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs.u.r8.bh);
3796 SET_CF(); // error
3797 regs.u.r8.ah = 1; // invalid subfunction
3798 return;
3800 break;
3802 case 1: // Reset Mouse
3803 case 5: // Initialize Mouse
3804 BX_DEBUG_INT15("case 1 or 5:\n");
3805 if (regs.u.r8.al == 5) {
3806 if (regs.u.r8.bh != 3) {
3807 SET_CF();
3808 regs.u.r8.ah = 0x02; // invalid input
3809 return;
3811 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
3812 mouse_flags_2 = (mouse_flags_2 & 0x00) | regs.u.r8.bh;
3813 mouse_flags_1 = 0x00;
3814 write_byte(ebda_seg, 0x0026, mouse_flags_1);
3815 write_byte(ebda_seg, 0x0027, mouse_flags_2);
3818 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3819 ret = send_to_mouse_ctrl(0xFF); // reset mouse command
3820 if (ret == 0) {
3821 ret = get_mouse_data(&mouse_data3);
3822 // if no mouse attached, it will return RESEND
3823 if (mouse_data3 == 0xfe) {
3824 SET_CF();
3825 return;
3827 if (mouse_data3 != 0xfa)
3828 BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3);
3829 if ( ret == 0 ) {
3830 ret = get_mouse_data(&mouse_data1);
3831 if ( ret == 0 ) {
3832 ret = get_mouse_data(&mouse_data2);
3833 if ( ret == 0 ) {
3834 // turn IRQ12 and packet generation on
3835 enable_mouse_int_and_events();
3836 CLEAR_CF();
3837 regs.u.r8.ah = 0;
3838 regs.u.r8.bl = mouse_data1;
3839 regs.u.r8.bh = mouse_data2;
3840 return;
3846 // error
3847 SET_CF();
3848 regs.u.r8.ah = ret;
3849 return;
3851 case 2: // Set Sample Rate
3852 BX_DEBUG_INT15("case 2:\n");
3853 switch (regs.u.r8.bh) {
3854 case 0: mouse_data1 = 10; break; // 10 reports/sec
3855 case 1: mouse_data1 = 20; break; // 20 reports/sec
3856 case 2: mouse_data1 = 40; break; // 40 reports/sec
3857 case 3: mouse_data1 = 60; break; // 60 reports/sec
3858 case 4: mouse_data1 = 80; break; // 80 reports/sec
3859 case 5: mouse_data1 = 100; break; // 100 reports/sec (default)
3860 case 6: mouse_data1 = 200; break; // 200 reports/sec
3861 default: mouse_data1 = 0;
3863 if (mouse_data1 > 0) {
3864 ret = send_to_mouse_ctrl(0xF3); // set sample rate command
3865 if (ret == 0) {
3866 ret = get_mouse_data(&mouse_data2);
3867 ret = send_to_mouse_ctrl(mouse_data1);
3868 ret = get_mouse_data(&mouse_data2);
3869 CLEAR_CF();
3870 regs.u.r8.ah = 0;
3871 } else {
3872 // error
3873 SET_CF();
3874 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3876 } else {
3877 // error
3878 SET_CF();
3879 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3881 break;
3883 case 3: // Set Resolution
3884 BX_DEBUG_INT15("case 3:\n");
3885 // BX:
3886 // 0 = 25 dpi, 1 count per millimeter
3887 // 1 = 50 dpi, 2 counts per millimeter
3888 // 2 = 100 dpi, 4 counts per millimeter
3889 // 3 = 200 dpi, 8 counts per millimeter
3890 CLEAR_CF();
3891 regs.u.r8.ah = 0;
3892 break;
3894 case 4: // Get Device ID
3895 BX_DEBUG_INT15("case 4:\n");
3896 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3897 ret = send_to_mouse_ctrl(0xF2); // get mouse ID command
3898 if (ret == 0) {
3899 ret = get_mouse_data(&mouse_data1);
3900 ret = get_mouse_data(&mouse_data2);
3901 CLEAR_CF();
3902 regs.u.r8.ah = 0;
3903 regs.u.r8.bh = mouse_data2;
3904 } else {
3905 // error
3906 SET_CF();
3907 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3909 break;
3911 case 6: // Return Status & Set Scaling Factor...
3912 BX_DEBUG_INT15("case 6:\n");
3913 switch (regs.u.r8.bh) {
3914 case 0: // Return Status
3915 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3916 ret = send_to_mouse_ctrl(0xE9); // get mouse info command
3917 if (ret == 0) {
3918 ret = get_mouse_data(&mouse_data1);
3919 if (mouse_data1 != 0xfa)
3920 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
3921 if (ret == 0) {
3922 ret = get_mouse_data(&mouse_data1);
3923 if ( ret == 0 ) {
3924 ret = get_mouse_data(&mouse_data2);
3925 if ( ret == 0 ) {
3926 ret = get_mouse_data(&mouse_data3);
3927 if ( ret == 0 ) {
3928 CLEAR_CF();
3929 regs.u.r8.ah = 0;
3930 regs.u.r8.bl = mouse_data1;
3931 regs.u.r8.cl = mouse_data2;
3932 regs.u.r8.dl = mouse_data3;
3933 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
3934 return;
3941 // error
3942 SET_CF();
3943 regs.u.r8.ah = ret;
3944 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
3945 return;
3947 case 1: // Set Scaling Factor to 1:1
3948 case 2: // Set Scaling Factor to 2:1
3949 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3950 if (regs.u.r8.bh == 1) {
3951 ret = send_to_mouse_ctrl(0xE6);
3952 } else {
3953 ret = send_to_mouse_ctrl(0xE7);
3955 if (ret == 0) {
3956 get_mouse_data(&mouse_data1);
3957 ret = (mouse_data1 != 0xFA);
3959 if (ret == 0) {
3960 CLEAR_CF();
3961 regs.u.r8.ah = 0;
3962 } else {
3963 // error
3964 SET_CF();
3965 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3967 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
3968 break;
3970 default:
3971 BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs.u.r8.bh);
3973 break;
3975 case 7: // Set Mouse Handler Address
3976 BX_DEBUG_INT15("case 7:\n");
3977 mouse_driver_seg = ES;
3978 mouse_driver_offset = regs.u.r16.bx;
3979 write_word(ebda_seg, 0x0022, mouse_driver_offset);
3980 write_word(ebda_seg, 0x0024, mouse_driver_seg);
3981 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
3982 if (mouse_driver_offset == 0 && mouse_driver_seg == 0) {
3983 /* remove handler */
3984 if ( (mouse_flags_2 & 0x80) != 0 ) {
3985 mouse_flags_2 &= ~0x80;
3986 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3989 else {
3990 /* install handler */
3991 mouse_flags_2 |= 0x80;
3993 write_byte(ebda_seg, 0x0027, mouse_flags_2);
3994 CLEAR_CF();
3995 regs.u.r8.ah = 0;
3996 break;
3998 default:
3999 BX_DEBUG_INT15("case default:\n");
4000 regs.u.r8.ah = 1; // invalid function
4001 SET_CF();
4003 break;
4005 default:
4006 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4007 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4008 SET_CF();
4009 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4010 break;
4013 #endif
4015 void
4016 int15_function32(regs, ES, DS, FLAGS)
4017 pushad_regs_t regs; // REGS pushed via pushad
4018 Bit16u ES, DS, FLAGS;
4020 Bit32u extended_memory_size=0; // 64bits long
4021 Bit16u CX,DX;
4023 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4025 switch (regs.u.r8.ah) {
4026 case 0x86:
4027 // Wait for CX:DX microseconds. currently using the
4028 // refresh request port 0x61 bit4, toggling every 15usec
4030 CX = regs.u.r16.cx;
4031 DX = regs.u.r16.dx;
4033 ASM_START
4034 sti
4036 ;; Get the count in eax
4037 mov bx, sp
4038 SEG SS
4039 mov ax, _int15_function.CX [bx]
4040 shl eax, #16
4041 SEG SS
4042 mov ax, _int15_function.DX [bx]
4044 ;; convert to numbers of 15usec ticks
4045 mov ebx, #15
4046 xor edx, edx
4047 div eax, ebx
4048 mov ecx, eax
4050 ;; wait for ecx number of refresh requests
4051 in al, #0x61
4052 and al,#0x10
4053 mov ah, al
4055 or ecx, ecx
4056 je int1586_tick_end
4057 int1586_tick:
4058 in al, #0x61
4059 and al,#0x10
4060 cmp al, ah
4061 je int1586_tick
4062 mov ah, al
4063 dec ecx
4064 jnz int1586_tick
4065 int1586_tick_end:
4066 ASM_END
4068 break;
4070 case 0xe8:
4071 switch(regs.u.r8.al)
4073 case 0x20: // coded by osmaker aka K.J.
4074 if(regs.u.r32.edx == 0x534D4150) /* SMAP */
4076 #ifdef VMXASSIST
4077 if ((regs.u.r16.bx / 0x14) * 0x14 == regs.u.r16.bx) {
4078 Bit16u e820_table_size = read_word(0xe000, 0x8) * 0x14;
4080 if (regs.u.r16.bx + 0x14 <= e820_table_size) {
4081 memcpyb(ES, regs.u.r16.di,
4082 0xe000, 0x10 + regs.u.r16.bx, 0x14);
4084 regs.u.r32.ebx += 0x14;
4085 if ((regs.u.r32.ebx + 0x14 - 1) > e820_table_size)
4086 regs.u.r32.ebx = 0;
4087 regs.u.r32.eax = 0x534D4150;
4088 regs.u.r32.ecx = 0x14;
4089 CLEAR_CF();
4090 return;
4091 } else if (regs.u.r16.bx == 1) {
4092 extended_memory_size = inb_cmos(0x35);
4093 extended_memory_size <<= 8;
4094 extended_memory_size |= inb_cmos(0x34);
4095 extended_memory_size *= 64;
4096 if (extended_memory_size > 0x3bc000) // greater than EFF00000???
4098 extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4100 extended_memory_size *= 1024;
4101 extended_memory_size += 15728640; // make up for the 16mb of memory that is chopped off
4103 if (extended_memory_size <= 15728640)
4105 extended_memory_size = inb_cmos(0x31);
4106 extended_memory_size <<= 8;
4107 extended_memory_size |= inb_cmos(0x30);
4108 extended_memory_size *= 1024;
4111 write_word(ES, regs.u.r16.di, 0x0000);
4112 write_word(ES, regs.u.r16.di+2, 0x0010);
4113 write_word(ES, regs.u.r16.di+4, 0x0000);
4114 write_word(ES, regs.u.r16.di+6, 0x0000);
4116 write_word(ES, regs.u.r16.di+8, extended_memory_size);
4117 extended_memory_size >>= 16;
4118 write_word(ES, regs.u.r16.di+10, extended_memory_size);
4119 extended_memory_size >>= 16;
4120 write_word(ES, regs.u.r16.di+12, extended_memory_size);
4121 extended_memory_size >>= 16;
4122 write_word(ES, regs.u.r16.di+14, extended_memory_size);
4124 write_word(ES, regs.u.r16.di+16, 0x1);
4125 write_word(ES, regs.u.r16.di+18, 0x0);
4127 regs.u.r32.ebx = 0;
4128 regs.u.r32.eax = 0x534D4150;
4129 regs.u.r32.ecx = 0x14;
4130 CLEAR_CF();
4131 return;
4132 } else { /* AX=E820, DX=534D4150, BX unrecognized */
4133 goto int15_unimplemented;
4135 #else
4136 switch(regs.u.r16.bx)
4138 case 0:
4139 write_word(ES, regs.u.r16.di, 0x00);
4140 write_word(ES, regs.u.r16.di+2, 0x00);
4141 write_word(ES, regs.u.r16.di+4, 0x00);
4142 write_word(ES, regs.u.r16.di+6, 0x00);
4144 write_word(ES, regs.u.r16.di+8, 0xFC00);
4145 write_word(ES, regs.u.r16.di+10, 0x0009);
4146 write_word(ES, regs.u.r16.di+12, 0x0000);
4147 write_word(ES, regs.u.r16.di+14, 0x0000);
4149 write_word(ES, regs.u.r16.di+16, 0x1);
4150 write_word(ES, regs.u.r16.di+18, 0x0);
4152 regs.u.r32.ebx = 1;
4154 regs.u.r32.eax = 0x534D4150;
4155 regs.u.r32.ecx = 0x14;
4156 CLEAR_CF();
4157 return;
4158 break;
4159 case 1:
4160 extended_memory_size = inb_cmos(0x35);
4161 extended_memory_size <<= 8;
4162 extended_memory_size |= inb_cmos(0x34);
4163 extended_memory_size *= 64;
4164 if(extended_memory_size > 0x3bc000) // greater than EFF00000???
4166 extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4168 extended_memory_size *= 1024;
4169 extended_memory_size += 15728640; // make up for the 16mb of memory that is chopped off
4171 if(extended_memory_size <= 15728640)
4173 extended_memory_size = inb_cmos(0x31);
4174 extended_memory_size <<= 8;
4175 extended_memory_size |= inb_cmos(0x30);
4176 extended_memory_size *= 1024;
4179 write_word(ES, regs.u.r16.di, 0x0000);
4180 write_word(ES, regs.u.r16.di+2, 0x0010);
4181 write_word(ES, regs.u.r16.di+4, 0x0000);
4182 write_word(ES, regs.u.r16.di+6, 0x0000);
4184 write_word(ES, regs.u.r16.di+8, extended_memory_size);
4185 extended_memory_size >>= 16;
4186 write_word(ES, regs.u.r16.di+10, extended_memory_size);
4187 extended_memory_size >>= 16;
4188 write_word(ES, regs.u.r16.di+12, extended_memory_size);
4189 extended_memory_size >>= 16;
4190 write_word(ES, regs.u.r16.di+14, extended_memory_size);
4192 write_word(ES, regs.u.r16.di+16, 0x1);
4193 write_word(ES, regs.u.r16.di+18, 0x0);
4195 regs.u.r32.ebx = 0;
4196 regs.u.r32.eax = 0x534D4150;
4197 regs.u.r32.ecx = 0x14;
4198 CLEAR_CF();
4199 return;
4200 break;
4201 default: /* AX=E820, DX=534D4150, BX unrecognized */
4202 goto int15_unimplemented;
4203 break;
4205 #endif
4206 } else {
4207 // if DX != 0x534D4150)
4208 goto int15_unimplemented;
4210 break;
4212 case 0x01:
4213 // do we have any reason to fail here ?
4214 CLEAR_CF();
4216 // my real system sets ax and bx to 0
4217 // this is confirmed by Ralph Brown list
4218 // but syslinux v1.48 is known to behave
4219 // strangely if ax is set to 0
4220 // regs.u.r16.ax = 0;
4221 // regs.u.r16.bx = 0;
4223 // Get the amount of extended memory (above 1M)
4224 regs.u.r8.cl = inb_cmos(0x30);
4225 regs.u.r8.ch = inb_cmos(0x31);
4227 // limit to 15M
4228 if(regs.u.r16.cx > 0x3c00)
4230 regs.u.r16.cx = 0x3c00;
4233 // Get the amount of extended memory above 16M in 64k blocs
4234 regs.u.r8.dl = inb_cmos(0x34);
4235 regs.u.r8.dh = inb_cmos(0x35);
4237 // Set configured memory equal to extended memory
4238 regs.u.r16.ax = regs.u.r16.cx;
4239 regs.u.r16.bx = regs.u.r16.dx;
4240 break;
4241 default: /* AH=0xE8?? but not implemented */
4242 goto int15_unimplemented;
4244 break;
4245 int15_unimplemented:
4246 // fall into the default
4247 default:
4248 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4249 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4250 SET_CF();
4251 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4252 break;
4256 void
4257 int16_function(DI, SI, BP, SP, BX, DX, CX, AX, FLAGS)
4258 Bit16u DI, SI, BP, SP, BX, DX, CX, AX, FLAGS;
4260 Bit8u scan_code, ascii_code, shift_flags, count;
4261 Bit16u kbd_code, max;
4263 BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX, BX, CX, DX);
4265 switch (GET_AH()) {
4266 case 0x00: /* read keyboard input */
4268 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4269 BX_PANIC("KBD: int16h: out of keyboard input\n");
4271 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4272 else if (ascii_code == 0xE0) ascii_code = 0;
4273 AX = (scan_code << 8) | ascii_code;
4274 break;
4276 case 0x01: /* check keyboard status */
4277 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4278 SET_ZF();
4279 return;
4281 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4282 else if (ascii_code == 0xE0) ascii_code = 0;
4283 AX = (scan_code << 8) | ascii_code;
4284 CLEAR_ZF();
4285 break;
4287 case 0x02: /* get shift flag status */
4288 shift_flags = read_byte(0x0040, 0x17);
4289 SET_AL(shift_flags);
4290 break;
4292 case 0x05: /* store key-stroke into buffer */
4293 if ( !enqueue_key(GET_CH(), GET_CL()) ) {
4294 SET_AL(1);
4296 else {
4297 SET_AL(0);
4299 break;
4301 case 0x09: /* GET KEYBOARD FUNCTIONALITY */
4302 // bit Bochs Description
4303 // 7 0 reserved
4304 // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
4305 // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
4306 // 4 1 INT 16/AH=0Ah supported
4307 // 3 0 INT 16/AX=0306h supported
4308 // 2 0 INT 16/AX=0305h supported
4309 // 1 0 INT 16/AX=0304h supported
4310 // 0 0 INT 16/AX=0300h supported
4311 //
4312 SET_AL(0x30);
4313 break;
4315 case 0x0A: /* GET KEYBOARD ID */
4316 count = 2;
4317 kbd_code = 0x0;
4318 outb(0x60, 0xf2);
4319 /* Wait for data */
4320 max=0xffff;
4321 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4322 if (max>0x0) {
4323 if ((inb(0x60) == 0xfa)) {
4324 do {
4325 max=0xffff;
4326 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4327 if (max>0x0) {
4328 kbd_code >>= 8;
4329 kbd_code |= (inb(0x60) << 8);
4331 } while (--count>0);
4334 BX=kbd_code;
4335 break;
4337 case 0x10: /* read MF-II keyboard input */
4339 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4340 BX_PANIC("KBD: int16h: out of keyboard input\n");
4342 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4343 AX = (scan_code << 8) | ascii_code;
4344 break;
4346 case 0x11: /* check MF-II keyboard status */
4347 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4348 SET_ZF();
4349 return;
4351 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4352 AX = (scan_code << 8) | ascii_code;
4353 CLEAR_ZF();
4354 break;
4356 case 0x12: /* get extended keyboard status */
4357 shift_flags = read_byte(0x0040, 0x17);
4358 SET_AL(shift_flags);
4359 shift_flags = read_byte(0x0040, 0x18);
4360 SET_AH(shift_flags);
4361 BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX);
4362 break;
4364 case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
4365 SET_AH(0x80); // function int16 ah=0x10-0x12 supported
4366 break;
4368 case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
4369 // don't change AH : function int16 ah=0x20-0x22 NOT supported
4370 break;
4372 case 0x6F:
4373 if (GET_AL() == 0x08)
4374 SET_AH(0x02); // unsupported, aka normal keyboard
4376 default:
4377 BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
4381 unsigned int
4382 dequeue_key(scan_code, ascii_code, incr)
4383 Bit8u *scan_code;
4384 Bit8u *ascii_code;
4385 unsigned int incr;
4387 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail;
4388 Bit16u ss;
4389 Bit8u acode, scode;
4391 #if BX_CPU < 2
4392 buffer_start = 0x001E;
4393 buffer_end = 0x003E;
4394 #else
4395 buffer_start = read_word(0x0040, 0x0080);
4396 buffer_end = read_word(0x0040, 0x0082);
4397 #endif
4399 buffer_head = read_word(0x0040, 0x001a);
4400 buffer_tail = read_word(0x0040, 0x001c);
4402 if (buffer_head != buffer_tail) {
4403 ss = get_SS();
4404 acode = read_byte(0x0040, buffer_head);
4405 scode = read_byte(0x0040, buffer_head+1);
4406 write_byte(ss, ascii_code, acode);
4407 write_byte(ss, scan_code, scode);
4409 if (incr) {
4410 buffer_head += 2;
4411 if (buffer_head >= buffer_end)
4412 buffer_head = buffer_start;
4413 write_word(0x0040, 0x001a, buffer_head);
4415 return(1);
4417 else {
4418 return(0);
4422 static char panic_msg_keyb_buffer_full[] = "%s: keyboard input buffer full\n";
4424 Bit8u
4425 inhibit_mouse_int_and_events()
4427 Bit8u command_byte, prev_command_byte;
4429 // Turn off IRQ generation and aux data line
4430 if ( inb(0x64) & 0x02 )
4431 BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
4432 outb(0x64, 0x20); // get command byte
4433 while ( (inb(0x64) & 0x01) != 0x01 );
4434 prev_command_byte = inb(0x60);
4435 command_byte = prev_command_byte;
4436 //while ( (inb(0x64) & 0x02) );
4437 if ( inb(0x64) & 0x02 )
4438 BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
4439 command_byte &= 0xfd; // turn off IRQ 12 generation
4440 command_byte |= 0x20; // disable mouse serial clock line
4441 outb(0x64, 0x60); // write command byte
4442 outb(0x60, command_byte);
4443 return(prev_command_byte);
4446 void
4447 enable_mouse_int_and_events()
4449 Bit8u command_byte;
4451 // Turn on IRQ generation and aux data line
4452 if ( inb(0x64) & 0x02 )
4453 BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
4454 outb(0x64, 0x20); // get command byte
4455 while ( (inb(0x64) & 0x01) != 0x01 );
4456 command_byte = inb(0x60);
4457 //while ( (inb(0x64) & 0x02) );
4458 if ( inb(0x64) & 0x02 )
4459 BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
4460 command_byte |= 0x02; // turn on IRQ 12 generation
4461 command_byte &= 0xdf; // enable mouse serial clock line
4462 outb(0x64, 0x60); // write command byte
4463 outb(0x60, command_byte);
4466 Bit8u
4467 send_to_mouse_ctrl(sendbyte)
4468 Bit8u sendbyte;
4470 Bit8u response;
4472 // wait for chance to write to ctrl
4473 if ( inb(0x64) & 0x02 )
4474 BX_PANIC(panic_msg_keyb_buffer_full,"sendmouse");
4475 outb(0x64, 0xD4);
4476 outb(0x60, sendbyte);
4477 return(0);
4481 Bit8u
4482 get_mouse_data(data)
4483 Bit8u *data;
4485 Bit8u response;
4486 Bit16u ss;
4488 while ( (inb(0x64) & 0x21) != 0x21 ) {
4491 response = inb(0x60);
4493 ss = get_SS();
4494 write_byte(ss, data, response);
4495 return(0);
4498 void
4499 set_kbd_command_byte(command_byte)
4500 Bit8u command_byte;
4502 if ( inb(0x64) & 0x02 )
4503 BX_PANIC(panic_msg_keyb_buffer_full,"setkbdcomm");
4504 outb(0x64, 0xD4);
4506 outb(0x64, 0x60); // write command byte
4507 outb(0x60, command_byte);
4510 void
4511 int09_function(DI, SI, BP, SP, BX, DX, CX, AX)
4512 Bit16u DI, SI, BP, SP, BX, DX, CX, AX;
4514 Bit8u scancode, asciicode, shift_flags;
4515 Bit8u mf2_flags, mf2_state, led_flags;
4517 //
4518 // DS has been set to F000 before call
4519 //
4522 scancode = GET_AL();
4524 if (scancode == 0) {
4525 BX_INFO("KBD: int09 handler: AL=0\n");
4526 return;
4530 shift_flags = read_byte(0x0040, 0x17);
4531 mf2_flags = read_byte(0x0040, 0x18);
4532 mf2_state = read_byte(0x0040, 0x96);
4533 led_flags = read_byte(0x0040, 0x97);
4534 asciicode = 0;
4536 switch (scancode) {
4537 case 0x3a: /* Caps Lock press */
4538 shift_flags ^= 0x40;
4539 write_byte(0x0040, 0x17, shift_flags);
4540 mf2_flags |= 0x40;
4541 write_byte(0x0040, 0x18, mf2_flags);
4542 led_flags ^= 0x04;
4543 write_byte(0x0040, 0x97, led_flags);
4544 break;
4545 case 0xba: /* Caps Lock release */
4546 mf2_flags &= ~0x40;
4547 write_byte(0x0040, 0x18, mf2_flags);
4548 break;
4550 case 0x2a: /* L Shift press */
4551 /*shift_flags &= ~0x40;*/
4552 shift_flags |= 0x02;
4553 write_byte(0x0040, 0x17, shift_flags);
4554 led_flags &= ~0x04;
4555 write_byte(0x0040, 0x97, led_flags);
4556 break;
4557 case 0xaa: /* L Shift release */
4558 shift_flags &= ~0x02;
4559 write_byte(0x0040, 0x17, shift_flags);
4560 break;
4562 case 0x36: /* R Shift press */
4563 /*shift_flags &= ~0x40;*/
4564 shift_flags |= 0x01;
4565 write_byte(0x0040, 0x17, shift_flags);
4566 led_flags &= ~0x04;
4567 write_byte(0x0040, 0x97, led_flags);
4568 break;
4569 case 0xb6: /* R Shift release */
4570 shift_flags &= ~0x01;
4571 write_byte(0x0040, 0x17, shift_flags);
4572 break;
4574 case 0x1d: /* Ctrl press */
4575 shift_flags |= 0x04;
4576 write_byte(0x0040, 0x17, shift_flags);
4577 if (mf2_state & 0x01) {
4578 mf2_flags |= 0x04;
4579 } else {
4580 mf2_flags |= 0x01;
4582 write_byte(0x0040, 0x18, mf2_flags);
4583 break;
4584 case 0x9d: /* Ctrl release */
4585 shift_flags &= ~0x04;
4586 write_byte(0x0040, 0x17, shift_flags);
4587 if (mf2_state & 0x01) {
4588 mf2_flags &= ~0x04;
4589 } else {
4590 mf2_flags &= ~0x01;
4592 write_byte(0x0040, 0x18, mf2_flags);
4593 break;
4595 case 0x38: /* Alt press */
4596 shift_flags |= 0x08;
4597 write_byte(0x0040, 0x17, shift_flags);
4598 if (mf2_state & 0x01) {
4599 mf2_flags |= 0x08;
4600 } else {
4601 mf2_flags |= 0x02;
4603 write_byte(0x0040, 0x18, mf2_flags);
4604 break;
4605 case 0xb8: /* Alt release */
4606 shift_flags &= ~0x08;
4607 write_byte(0x0040, 0x17, shift_flags);
4608 if (mf2_state & 0x01) {
4609 mf2_flags &= ~0x08;
4610 } else {
4611 mf2_flags &= ~0x02;
4613 write_byte(0x0040, 0x18, mf2_flags);
4614 break;
4616 case 0x45: /* Num Lock press */
4617 if ((mf2_state & 0x01) == 0) {
4618 mf2_flags |= 0x20;
4619 write_byte(0x0040, 0x18, mf2_flags);
4620 shift_flags ^= 0x20;
4621 led_flags ^= 0x02;
4622 write_byte(0x0040, 0x17, shift_flags);
4623 write_byte(0x0040, 0x97, led_flags);
4625 break;
4626 case 0xc5: /* Num Lock release */
4627 if ((mf2_state & 0x01) == 0) {
4628 mf2_flags &= ~0x20;
4629 write_byte(0x0040, 0x18, mf2_flags);
4631 break;
4633 case 0x46: /* Scroll Lock press */
4634 mf2_flags |= 0x10;
4635 write_byte(0x0040, 0x18, mf2_flags);
4636 shift_flags ^= 0x10;
4637 led_flags ^= 0x01;
4638 write_byte(0x0040, 0x17, shift_flags);
4639 write_byte(0x0040, 0x97, led_flags);
4640 break;
4642 case 0xc6: /* Scroll Lock release */
4643 mf2_flags &= ~0x10;
4644 write_byte(0x0040, 0x18, mf2_flags);
4645 break;
4647 default:
4648 if (scancode & 0x80) return; /* toss key releases ... */
4649 if (scancode > MAX_SCAN_CODE) {
4650 BX_INFO("KBD: int09h_handler(): unknown scancode read!\n");
4651 return;
4653 if (shift_flags & 0x08) { /* ALT */
4654 asciicode = scan_to_scanascii[scancode].alt;
4655 scancode = scan_to_scanascii[scancode].alt >> 8;
4657 else if (shift_flags & 0x04) { /* CONTROL */
4658 asciicode = scan_to_scanascii[scancode].control;
4659 scancode = scan_to_scanascii[scancode].control >> 8;
4661 else if (shift_flags & 0x03) { /* LSHIFT + RSHIFT */
4662 /* check if lock state should be ignored
4663 * because a SHIFT key are pressed */
4665 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
4666 asciicode = scan_to_scanascii[scancode].normal;
4667 scancode = scan_to_scanascii[scancode].normal >> 8;
4669 else {
4670 asciicode = scan_to_scanascii[scancode].shift;
4671 scancode = scan_to_scanascii[scancode].shift >> 8;
4674 else {
4675 /* check if lock is on */
4676 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
4677 asciicode = scan_to_scanascii[scancode].shift;
4678 scancode = scan_to_scanascii[scancode].shift >> 8;
4680 else {
4681 asciicode = scan_to_scanascii[scancode].normal;
4682 scancode = scan_to_scanascii[scancode].normal >> 8;
4685 if (scancode==0 && asciicode==0) {
4686 BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
4688 enqueue_key(scancode, asciicode);
4689 break;
4691 mf2_state &= ~0x01;
4694 unsigned int
4695 enqueue_key(scan_code, ascii_code)
4696 Bit8u scan_code, ascii_code;
4698 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail, temp_tail;
4700 //BX_INFO("KBD: enqueue_key() called scan:%02x, ascii:%02x\n",
4701 // scan_code, ascii_code);
4703 #if BX_CPU < 2
4704 buffer_start = 0x001E;
4705 buffer_end = 0x003E;
4706 #else
4707 buffer_start = read_word(0x0040, 0x0080);
4708 buffer_end = read_word(0x0040, 0x0082);
4709 #endif
4711 buffer_head = read_word(0x0040, 0x001A);
4712 buffer_tail = read_word(0x0040, 0x001C);
4714 temp_tail = buffer_tail;
4715 buffer_tail += 2;
4716 if (buffer_tail >= buffer_end)
4717 buffer_tail = buffer_start;
4719 if (buffer_tail == buffer_head) {
4720 return(0);
4723 write_byte(0x0040, temp_tail, ascii_code);
4724 write_byte(0x0040, temp_tail+1, scan_code);
4725 write_word(0x0040, 0x001C, buffer_tail);
4726 return(1);
4730 void
4731 int74_function(make_farcall, Z, Y, X, status)
4732 Bit16u make_farcall, Z, Y, X, status;
4734 Bit16u ebda_seg=read_word(0x0040,0x000E);
4735 Bit8u in_byte, index, package_count;
4736 Bit8u mouse_flags_1, mouse_flags_2;
4738 BX_DEBUG_INT74("entering int74_function\n");
4739 make_farcall = 0;
4741 in_byte = inb(0x64);
4742 if ( (in_byte & 0x21) != 0x21 ) {
4743 return;
4745 in_byte = inb(0x60);
4746 BX_DEBUG_INT74("int74: read byte %02x\n", in_byte);
4748 mouse_flags_1 = read_byte(ebda_seg, 0x0026);
4749 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4751 if ( (mouse_flags_2 & 0x80) != 0x80 ) {
4752 // BX_PANIC("int74_function:\n");
4753 return;
4756 package_count = mouse_flags_2 & 0x07;
4757 index = mouse_flags_1 & 0x07;
4758 write_byte(ebda_seg, 0x28 + index, in_byte);
4760 if ( (index+1) >= package_count ) {
4761 BX_DEBUG_INT74("int74_function: make_farcall=1\n");
4762 status = read_byte(ebda_seg, 0x0028 + 0);
4763 X = read_byte(ebda_seg, 0x0028 + 1);
4764 Y = read_byte(ebda_seg, 0x0028 + 2);
4765 Z = 0;
4766 mouse_flags_1 = 0;
4767 // check if far call handler installed
4768 if (mouse_flags_2 & 0x80)
4769 make_farcall = 1;
4771 else {
4772 mouse_flags_1++;
4774 write_byte(ebda_seg, 0x0026, mouse_flags_1);
4777 #define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
4779 #if BX_USE_ATADRV
4781 void
4782 int13_harddisk(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
4783 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
4785 Bit32u lba;
4786 Bit16u ebda_seg=read_word(0x0040,0x000E);
4787 Bit16u cylinder, head, sector;
4788 Bit16u segment, offset;
4789 Bit16u npc, nph, npspt, nlc, nlh, nlspt;
4790 Bit16u size, count;
4791 Bit8u device, status;
4793 BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
4795 write_byte(0x0040, 0x008e, 0); // clear completion flag
4797 // basic check : device has to be defined
4798 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES) ) {
4799 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
4800 goto int13_fail;
4803 // Get the ata channel
4804 device=read_byte(ebda_seg,&EbdaData->ata.hdidmap[GET_ELDL()-0x80]);
4806 // basic check : device has to be valid
4807 if (device >= BX_MAX_ATA_DEVICES) {
4808 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
4809 goto int13_fail;
4812 switch (GET_AH()) {
4814 case 0x00: /* disk controller reset */
4815 ata_reset (device);
4816 goto int13_success;
4817 break;
4819 case 0x01: /* read disk status */
4820 status = read_byte(0x0040, 0x0074);
4821 SET_AH(status);
4822 SET_DISK_RET_STATUS(0);
4823 /* set CF if error status read */
4824 if (status) goto int13_fail_nostatus;
4825 else goto int13_success_noah;
4826 break;
4828 case 0x02: // read disk sectors
4829 case 0x03: // write disk sectors
4830 case 0x04: // verify disk sectors
4832 count = GET_AL();
4833 cylinder = GET_CH();
4834 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
4835 sector = (GET_CL() & 0x3f);
4836 head = GET_DH();
4838 segment = ES;
4839 offset = BX;
4841 if ( (count > 128) || (count == 0) ) {
4842 BX_INFO("int13_harddisk: function %02x, count out of range!\n",GET_AH());
4843 goto int13_fail;
4846 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
4847 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
4848 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
4850 // sanity check on cyl heads, sec
4851 if( (cylinder >= nlc) || (head >= nlh) || (sector > nlspt )) {
4852 BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder, head, sector);
4853 goto int13_fail;
4856 // FIXME verify
4857 if ( GET_AH() == 0x04 ) goto int13_success;
4859 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
4860 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
4862 // if needed, translate lchs to lba, and execute command
4863 if ( (nph != nlh) || (npspt != nlspt)) {
4864 lba = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
4865 sector = 0; // this forces the command to be lba
4868 if ( GET_AH() == 0x02 )
4869 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, cylinder, head, sector, lba, segment, offset);
4870 else
4871 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, cylinder, head, sector, lba, segment, offset);
4873 // Set nb of sector transferred
4874 SET_AL(read_word(ebda_seg, &EbdaData->ata.trsfsectors));
4876 if (status != 0) {
4877 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
4878 SET_AH(0x0c);
4879 goto int13_fail_noah;
4882 goto int13_success;
4883 break;
4885 case 0x05: /* format disk track */
4886 BX_INFO("format disk track called\n");
4887 goto int13_success;
4888 return;
4889 break;
4891 case 0x08: /* read disk drive parameters */
4893 // Get logical geometry from table
4894 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
4895 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
4896 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
4897 count = read_byte(ebda_seg, &EbdaData->ata.hdcount);
4899 nlc = nlc - 2; /* 0 based , last sector not used */
4900 SET_AL(0);
4901 SET_CH(nlc & 0xff);
4902 SET_CL(((nlc >> 2) & 0xc0) | (nlspt & 0x3f));
4903 SET_DH(nlh - 1);
4904 SET_DL(count); /* FIXME returns 0, 1, or n hard drives */
4906 // FIXME should set ES & DI
4908 goto int13_success;
4909 break;
4911 case 0x10: /* check drive ready */
4912 // should look at 40:8E also???
4914 // Read the status from controller
4915 status = inb(read_word(ebda_seg, &EbdaData->ata.channels[device/2].iobase1) + ATA_CB_STAT);
4916 if ( (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY ) {
4917 goto int13_success;
4919 else {
4920 SET_AH(0xAA);
4921 goto int13_fail_noah;
4923 break;
4925 case 0x15: /* read disk drive size */
4927 // Get physical geometry from table
4928 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
4929 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
4930 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
4932 // Compute sector count seen by int13
4933 lba = (Bit32u)(npc - 1) * (Bit32u)nph * (Bit32u)npspt;
4934 CX = lba >> 16;
4935 DX = lba & 0xffff;
4937 SET_AH(3); // hard disk accessible
4938 goto int13_success_noah;
4939 break;
4941 case 0x41: // IBM/MS installation check
4942 BX=0xaa55; // install check
4943 SET_AH(0x30); // EDD 3.0
4944 CX=0x0007; // ext disk access and edd, removable supported
4945 goto int13_success_noah;
4946 break;
4948 case 0x42: // IBM/MS extended read
4949 case 0x43: // IBM/MS extended write
4950 case 0x44: // IBM/MS verify
4951 case 0x47: // IBM/MS extended seek
4953 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
4954 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
4955 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
4957 // Can't use 64 bits lba
4958 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
4959 if (lba != 0L) {
4960 BX_PANIC("int13_harddisk: function %02x. Can't use 64bits lba\n",GET_AH());
4961 goto int13_fail;
4964 // Get 32 bits lba and check
4965 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
4966 if (lba >= read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors) ) {
4967 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
4968 goto int13_fail;
4971 // If verify or seek
4972 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
4973 goto int13_success;
4975 // Execute the command
4976 if ( GET_AH() == 0x42 )
4977 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba, segment, offset);
4978 else
4979 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
4981 count=read_word(ebda_seg, &EbdaData->ata.trsfsectors);
4982 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
4984 if (status != 0) {
4985 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
4986 SET_AH(0x0c);
4987 goto int13_fail_noah;
4990 goto int13_success;
4991 break;
4993 case 0x45: // IBM/MS lock/unlock drive
4994 case 0x49: // IBM/MS extended media change
4995 goto int13_success; // Always success for HD
4996 break;
4998 case 0x46: // IBM/MS eject media
4999 SET_AH(0xb2); // Volume Not Removable
5000 goto int13_fail_noah; // Always fail for HD
5001 break;
5003 case 0x48: // IBM/MS get drive parameters
5004 size=read_word(DS,SI+(Bit16u)&Int13DPT->size);
5006 // Buffer is too small
5007 if(size < 0x1a)
5008 goto int13_fail;
5010 // EDD 1.x
5011 if(size >= 0x1a) {
5012 Bit16u blksize;
5014 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5015 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5016 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5017 lba = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors);
5018 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5020 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5021 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x02); // geometry is valid
5022 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, (Bit32u)npc);
5023 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, (Bit32u)nph);
5024 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, (Bit32u)npspt);
5025 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, lba); // FIXME should be Bit64
5026 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0L);
5027 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5030 // EDD 2.x
5031 if(size >= 0x1e) {
5032 Bit8u channel, dev, irq, mode, checksum, i, translation;
5033 Bit16u iobase1, iobase2, options;
5035 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5037 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5038 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5040 // Fill in dpte
5041 channel = device / 2;
5042 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5043 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5044 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5045 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5046 translation = read_byte(ebda_seg, &EbdaData->ata.devices[device].translation);
5048 options = (translation==ATA_TRANSLATION_NONE?0:1<<3); // chs translation
5049 options |= (1<<4); // lba translation
5050 options |= (mode==ATA_MODE_PIO32?1:0<<7);
5051 options |= (translation==ATA_TRANSLATION_LBA?1:0<<9);
5052 options |= (translation==ATA_TRANSLATION_RECHS?3:0<<9);
5054 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5055 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5056 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5057 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5058 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5059 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5060 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5061 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5062 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5063 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5064 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5066 checksum=0;
5067 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5068 checksum = ~checksum;
5069 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5072 // EDD 3.x
5073 if(size >= 0x42) {
5074 Bit8u channel, iface, checksum, i;
5075 Bit16u iobase1;
5077 channel = device / 2;
5078 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5079 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5081 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5082 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5083 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5084 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5085 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5087 if (iface==ATA_IFACE_ISA) {
5088 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5089 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5090 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5091 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5093 else {
5094 // FIXME PCI
5096 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5097 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5098 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5099 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5101 if (iface==ATA_IFACE_ISA) {
5102 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5103 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5104 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5106 else {
5107 // FIXME PCI
5109 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5110 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5111 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5112 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5114 checksum=0;
5115 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5116 checksum = ~checksum;
5117 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5120 goto int13_success;
5121 break;
5123 case 0x4e: // // IBM/MS set hardware configuration
5124 // DMA, prefetch, PIO maximum not supported
5125 switch (GET_AL()) {
5126 case 0x01:
5127 case 0x03:
5128 case 0x04:
5129 case 0x06:
5130 goto int13_success;
5131 break;
5132 default :
5133 goto int13_fail;
5135 break;
5137 case 0x09: /* initialize drive parameters */
5138 case 0x0c: /* seek to specified cylinder */
5139 case 0x0d: /* alternate disk reset */
5140 case 0x11: /* recalibrate */
5141 case 0x14: /* controller internal diagnostic */
5142 BX_INFO("int13h_harddisk function %02xh unimplemented, returns success\n", GET_AH());
5143 goto int13_success;
5144 break;
5146 case 0x0a: /* read disk sectors with ECC */
5147 case 0x0b: /* write disk sectors with ECC */
5148 case 0x18: // set media type for format
5149 case 0x50: // IBM/MS send packet command
5150 default:
5151 BX_INFO("int13_harddisk function %02xh unsupported, returns fail\n", GET_AH());
5152 goto int13_fail;
5153 break;
5156 int13_fail:
5157 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5158 int13_fail_noah:
5159 SET_DISK_RET_STATUS(GET_AH());
5160 int13_fail_nostatus:
5161 SET_CF(); // error occurred
5162 return;
5164 int13_success:
5165 SET_AH(0x00); // no error
5166 int13_success_noah:
5167 SET_DISK_RET_STATUS(0x00);
5168 CLEAR_CF(); // no error
5169 return;
5172 // ---------------------------------------------------------------------------
5173 // Start of int13 for cdrom
5174 // ---------------------------------------------------------------------------
5176 void
5177 int13_cdrom(EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5178 Bit16u EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5180 Bit16u ebda_seg=read_word(0x0040,0x000E);
5181 Bit8u device, status, locks;
5182 Bit8u atacmd[12];
5183 Bit32u lba;
5184 Bit16u count, segment, offset, i, size;
5186 BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5187 // BX_DEBUG_INT13_CD("int13_cdrom: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
5189 SET_DISK_RET_STATUS(0x00);
5191 /* basic check : device should be 0xE0+ */
5192 if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES) ) {
5193 BX_INFO("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5194 goto int13_fail;
5197 // Get the ata channel
5198 device=read_byte(ebda_seg,&EbdaData->ata.cdidmap[GET_ELDL()-0xE0]);
5200 /* basic check : device has to be valid */
5201 if (device >= BX_MAX_ATA_DEVICES) {
5202 BX_INFO("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5203 goto int13_fail;
5206 switch (GET_AH()) {
5208 // all those functions return SUCCESS
5209 case 0x00: /* disk controller reset */
5210 case 0x09: /* initialize drive parameters */
5211 case 0x0c: /* seek to specified cylinder */
5212 case 0x0d: /* alternate disk reset */
5213 case 0x10: /* check drive ready */
5214 case 0x11: /* recalibrate */
5215 case 0x14: /* controller internal diagnostic */
5216 case 0x16: /* detect disk change */
5217 goto int13_success;
5218 break;
5220 // all those functions return disk write-protected
5221 case 0x03: /* write disk sectors */
5222 case 0x05: /* format disk track */
5223 case 0x43: // IBM/MS extended write
5224 SET_AH(0x03);
5225 goto int13_fail_noah;
5226 break;
5228 case 0x01: /* read disk status */
5229 status = read_byte(0x0040, 0x0074);
5230 SET_AH(status);
5231 SET_DISK_RET_STATUS(0);
5233 /* set CF if error status read */
5234 if (status) goto int13_fail_nostatus;
5235 else goto int13_success_noah;
5236 break;
5238 case 0x15: /* read disk drive size */
5239 SET_AH(0x02);
5240 goto int13_fail_noah;
5241 break;
5243 case 0x41: // IBM/MS installation check
5244 BX=0xaa55; // install check
5245 SET_AH(0x30); // EDD 2.1
5246 CX=0x0007; // ext disk access, removable and edd
5247 goto int13_success_noah;
5248 break;
5250 case 0x42: // IBM/MS extended read
5251 case 0x44: // IBM/MS verify sectors
5252 case 0x47: // IBM/MS extended seek
5254 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5255 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5256 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5258 // Can't use 64 bits lba
5259 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5260 if (lba != 0L) {
5261 BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
5262 goto int13_fail;
5265 // Get 32 bits lba
5266 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5268 // If verify or seek
5269 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5270 goto int13_success;
5272 memsetb(get_SS(),atacmd,0,12);
5273 atacmd[0]=0x28; // READ command
5274 atacmd[7]=(count & 0xff00) >> 8; // Sectors
5275 atacmd[8]=(count & 0x00ff); // Sectors
5276 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
5277 atacmd[3]=(lba & 0x00ff0000) >> 16;
5278 atacmd[4]=(lba & 0x0000ff00) >> 8;
5279 atacmd[5]=(lba & 0x000000ff);
5280 status = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, count*2048L, ATA_DATA_IN, segment,offset);
5282 count = (Bit16u)(read_dword(ebda_seg, &EbdaData->ata.trsfbytes) >> 11);
5283 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5285 if (status != 0) {
5286 BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status);
5287 SET_AH(0x0c);
5288 goto int13_fail_noah;
5291 goto int13_success;
5292 break;
5294 case 0x45: // IBM/MS lock/unlock drive
5295 if (GET_AL() > 2) goto int13_fail;
5297 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
5299 switch (GET_AL()) {
5300 case 0 : // lock
5301 if (locks == 0xff) {
5302 SET_AH(0xb4);
5303 SET_AL(1);
5304 goto int13_fail_noah;
5306 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, ++locks);
5307 SET_AL(1);
5308 break;
5309 case 1 : // unlock
5310 if (locks == 0x00) {
5311 SET_AH(0xb0);
5312 SET_AL(0);
5313 goto int13_fail_noah;
5315 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, --locks);
5316 SET_AL(locks==0?0:1);
5317 break;
5318 case 2 : // status
5319 SET_AL(locks==0?0:1);
5320 break;
5322 goto int13_success;
5323 break;
5325 case 0x46: // IBM/MS eject media
5326 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
5328 if (locks != 0) {
5329 SET_AH(0xb1); // media locked
5330 goto int13_fail_noah;
5332 // FIXME should handle 0x31 no media in device
5333 // FIXME should handle 0xb5 valid request failed
5335 // Call removable media eject
5336 ASM_START
5337 push bp
5338 mov bp, sp
5340 mov ah, #0x52
5341 int 15
5342 mov _int13_cdrom.status + 2[bp], ah
5343 jnc int13_cdrom_rme_end
5344 mov _int13_cdrom.status, #1
5345 int13_cdrom_rme_end:
5346 pop bp
5347 ASM_END
5349 if (status != 0) {
5350 SET_AH(0xb1); // media locked
5351 goto int13_fail_noah;
5354 goto int13_success;
5355 break;
5357 case 0x48: // IBM/MS get drive parameters
5358 size = read_word(DS,SI+(Bit16u)&Int13Ext->size);
5360 // Buffer is too small
5361 if(size < 0x1a)
5362 goto int13_fail;
5364 // EDD 1.x
5365 if(size >= 0x1a) {
5366 Bit16u cylinders, heads, spt, blksize;
5368 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5370 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5371 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x74); // removable, media change, lockable, max values
5372 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, 0xffffffff);
5373 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, 0xffffffff);
5374 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, 0xffffffff);
5375 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, 0xffffffff); // FIXME should be Bit64
5376 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0xffffffff);
5377 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5380 // EDD 2.x
5381 if(size >= 0x1e) {
5382 Bit8u channel, dev, irq, mode, checksum, i;
5383 Bit16u iobase1, iobase2, options;
5385 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5387 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5388 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5390 // Fill in dpte
5391 channel = device / 2;
5392 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5393 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5394 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5395 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5397 // FIXME atapi device
5398 options = (1<<4); // lba translation
5399 options |= (1<<5); // removable device
5400 options |= (1<<6); // atapi device
5401 options |= (mode==ATA_MODE_PIO32?1:0<<7);
5403 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5404 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5405 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5406 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5407 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5408 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5409 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5410 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5411 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5412 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5413 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5415 checksum=0;
5416 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5417 checksum = ~checksum;
5418 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5421 // EDD 3.x
5422 if(size >= 0x42) {
5423 Bit8u channel, iface, checksum, i;
5424 Bit16u iobase1;
5426 channel = device / 2;
5427 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5428 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5430 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5431 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5432 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5433 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5434 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5436 if (iface==ATA_IFACE_ISA) {
5437 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5438 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5439 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5440 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5442 else {
5443 // FIXME PCI
5445 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5446 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5447 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5448 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5450 if (iface==ATA_IFACE_ISA) {
5451 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5452 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5453 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5455 else {
5456 // FIXME PCI
5458 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5459 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5460 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5461 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5463 checksum=0;
5464 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5465 checksum = ~checksum;
5466 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5469 goto int13_success;
5470 break;
5472 case 0x49: // IBM/MS extended media change
5473 // always send changed ??
5474 SET_AH(06);
5475 goto int13_fail_nostatus;
5476 break;
5478 case 0x4e: // // IBM/MS set hardware configuration
5479 // DMA, prefetch, PIO maximum not supported
5480 switch (GET_AL()) {
5481 case 0x01:
5482 case 0x03:
5483 case 0x04:
5484 case 0x06:
5485 goto int13_success;
5486 break;
5487 default :
5488 goto int13_fail;
5490 break;
5492 // all those functions return unimplemented
5493 case 0x02: /* read sectors */
5494 case 0x04: /* verify sectors */
5495 case 0x08: /* read disk drive parameters */
5496 case 0x0a: /* read disk sectors with ECC */
5497 case 0x0b: /* write disk sectors with ECC */
5498 case 0x18: /* set media type for format */
5499 case 0x50: // ? - send packet command
5500 default:
5501 BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
5502 goto int13_fail;
5503 break;
5506 int13_fail:
5507 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5508 int13_fail_noah:
5509 SET_DISK_RET_STATUS(GET_AH());
5510 int13_fail_nostatus:
5511 SET_CF(); // error occurred
5512 return;
5514 int13_success:
5515 SET_AH(0x00); // no error
5516 int13_success_noah:
5517 SET_DISK_RET_STATUS(0x00);
5518 CLEAR_CF(); // no error
5519 return;
5522 // ---------------------------------------------------------------------------
5523 // End of int13 for cdrom
5524 // ---------------------------------------------------------------------------
5526 #if BX_ELTORITO_BOOT
5527 // ---------------------------------------------------------------------------
5528 // Start of int13 for eltorito functions
5529 // ---------------------------------------------------------------------------
5531 void
5532 int13_eltorito(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
5533 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
5535 Bit16u ebda_seg=read_word(0x0040,0x000E);
5537 BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5538 // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
5540 switch (GET_AH()) {
5542 // FIXME ElTorito Various. Should be implemented
5543 case 0x4a: // ElTorito - Initiate disk emu
5544 case 0x4c: // ElTorito - Initiate disk emu and boot
5545 case 0x4d: // ElTorito - Return Boot catalog
5546 BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX);
5547 goto int13_fail;
5548 break;
5550 case 0x4b: // ElTorito - Terminate disk emu
5551 // FIXME ElTorito Hardcoded
5552 write_byte(DS,SI+0x00,0x13);
5553 write_byte(DS,SI+0x01,read_byte(ebda_seg,&EbdaData->cdemu.media));
5554 write_byte(DS,SI+0x02,read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
5555 write_byte(DS,SI+0x03,read_byte(ebda_seg,&EbdaData->cdemu.controller_index));
5556 write_dword(DS,SI+0x04,read_dword(ebda_seg,&EbdaData->cdemu.ilba));
5557 write_word(DS,SI+0x08,read_word(ebda_seg,&EbdaData->cdemu.device_spec));
5558 write_word(DS,SI+0x0a,read_word(ebda_seg,&EbdaData->cdemu.buffer_segment));
5559 write_word(DS,SI+0x0c,read_word(ebda_seg,&EbdaData->cdemu.load_segment));
5560 write_word(DS,SI+0x0e,read_word(ebda_seg,&EbdaData->cdemu.sector_count));
5561 write_byte(DS,SI+0x10,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.cylinders));
5562 write_byte(DS,SI+0x11,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.spt));
5563 write_byte(DS,SI+0x12,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.heads));
5565 // If we have to terminate emulation
5566 if(GET_AL() == 0x00) {
5567 // FIXME ElTorito Various. Should be handled accordingly to spec
5568 write_byte(ebda_seg,&EbdaData->cdemu.active, 0x00); // bye bye
5571 goto int13_success;
5572 break;
5574 default:
5575 BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
5576 goto int13_fail;
5577 break;
5580 int13_fail:
5581 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5582 SET_DISK_RET_STATUS(GET_AH());
5583 SET_CF(); // error occurred
5584 return;
5586 int13_success:
5587 SET_AH(0x00); // no error
5588 SET_DISK_RET_STATUS(0x00);
5589 CLEAR_CF(); // no error
5590 return;
5593 // ---------------------------------------------------------------------------
5594 // End of int13 for eltorito functions
5595 // ---------------------------------------------------------------------------
5597 // ---------------------------------------------------------------------------
5598 // Start of int13 when emulating a device from the cd
5599 // ---------------------------------------------------------------------------
5601 void
5602 int13_cdemu(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
5603 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
5605 Bit16u ebda_seg=read_word(0x0040,0x000E);
5606 Bit8u device, status;
5607 Bit16u vheads, vspt, vcylinders;
5608 Bit16u head, sector, cylinder, nbsectors;
5609 Bit32u vlba, ilba, slba, elba;
5610 Bit16u before, segment, offset;
5611 Bit8u atacmd[12];
5613 BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5614 //BX_DEBUG_INT13_ET("int13_cdemu: SS=%04x ES=%04x DI=%04x SI=%04x\n", get_SS(), ES, DI, SI);
5616 /* at this point, we are emulating a floppy/harddisk */
5618 // Recompute the device number
5619 device = read_byte(ebda_seg,&EbdaData->cdemu.controller_index) * 2;
5620 device += read_byte(ebda_seg,&EbdaData->cdemu.device_spec);
5622 SET_DISK_RET_STATUS(0x00);
5624 /* basic checks : emulation should be active, dl should equal the emulated drive */
5625 if( (read_byte(ebda_seg,&EbdaData->cdemu.active) ==0 )
5626 || (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive ) != GET_DL())) {
5627 BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
5628 goto int13_fail;
5631 switch (GET_AH()) {
5633 // all those functions return SUCCESS
5634 case 0x00: /* disk controller reset */
5635 case 0x09: /* initialize drive parameters */
5636 case 0x0c: /* seek to specified cylinder */
5637 case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
5638 case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
5639 case 0x11: /* recalibrate */
5640 case 0x14: /* controller internal diagnostic */
5641 case 0x16: /* detect disk change */
5642 goto int13_success;
5643 break;
5645 // all those functions return disk write-protected
5646 case 0x03: /* write disk sectors */
5647 case 0x05: /* format disk track */
5648 SET_AH(0x03);
5649 goto int13_fail_noah;
5650 break;
5652 case 0x01: /* read disk status */
5653 status=read_byte(0x0040, 0x0074);
5654 SET_AH(status);
5655 SET_DISK_RET_STATUS(0);
5657 /* set CF if error status read */
5658 if (status) goto int13_fail_nostatus;
5659 else goto int13_success_noah;
5660 break;
5662 case 0x02: // read disk sectors
5663 case 0x04: // verify disk sectors
5664 vspt = read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
5665 vcylinders = read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders);
5666 vheads = read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads);
5668 ilba = read_dword(ebda_seg,&EbdaData->cdemu.ilba);
5670 sector = GET_CL() & 0x003f;
5671 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
5672 head = GET_DH();
5673 nbsectors = GET_AL();
5674 segment = ES;
5675 offset = BX;
5677 // no sector to read ?
5678 if(nbsectors==0) goto int13_success;
5680 // sanity checks sco openserver needs this!
5681 if ((sector > vspt)
5682 || (cylinder >= vcylinders)
5683 || (head >= vheads)) {
5684 goto int13_fail;
5687 // After controls, verify do nothing
5688 if (GET_AH() == 0x04) goto int13_success;
5690 segment = ES+(BX / 16);
5691 offset = BX % 16;
5693 // calculate the virtual lba inside the image
5694 vlba=((((Bit32u)cylinder*(Bit32u)vheads)+(Bit32u)head)*(Bit32u)vspt)+((Bit32u)(sector-1));
5696 // In advance so we don't loose the count
5697 SET_AL(nbsectors);
5699 // start lba on cd
5700 slba = (Bit32u)vlba/4;
5701 before= (Bit16u)vlba%4;
5703 // end lba on cd
5704 elba = (Bit32u)(vlba+nbsectors-1)/4;
5706 memsetb(get_SS(),atacmd,0,12);
5707 atacmd[0]=0x28; // READ command
5708 atacmd[7]=((Bit16u)(elba-slba+1) & 0xff00) >> 8; // Sectors
5709 atacmd[8]=((Bit16u)(elba-slba+1) & 0x00ff); // Sectors
5710 atacmd[2]=(ilba+slba & 0xff000000) >> 24; // LBA
5711 atacmd[3]=(ilba+slba & 0x00ff0000) >> 16;
5712 atacmd[4]=(ilba+slba & 0x0000ff00) >> 8;
5713 atacmd[5]=(ilba+slba & 0x000000ff);
5714 if((status = ata_cmd_packet(device, 12, get_SS(), atacmd, before*512, nbsectors*512L, ATA_DATA_IN, segment,offset)) != 0) {
5715 BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status);
5716 SET_AH(0x02);
5717 SET_AL(0);
5718 goto int13_fail_noah;
5721 goto int13_success;
5722 break;
5724 case 0x08: /* read disk drive parameters */
5725 vspt=read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
5726 vcylinders=read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders) - 1;
5727 vheads=read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads) - 1;
5729 SET_AL( 0x00 );
5730 SET_BL( 0x00 );
5731 SET_CH( vcylinders & 0xff );
5732 SET_CL((( vcylinders >> 2) & 0xc0) | ( vspt & 0x3f ));
5733 SET_DH( vheads );
5734 SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2
5735 // FIXME ElTorito Harddisk. should send the HD count
5737 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
5738 case 0x01: SET_BL( 0x02 ); break;
5739 case 0x02: SET_BL( 0x04 ); break;
5740 case 0x03: SET_BL( 0x06 ); break;
5743 ASM_START
5744 push bp
5745 mov bp, sp
5746 mov ax, #diskette_param_table2
5747 mov _int13_cdemu.DI+2[bp], ax
5748 mov _int13_cdemu.ES+2[bp], cs
5749 pop bp
5750 ASM_END
5751 goto int13_success;
5752 break;
5754 case 0x15: /* read disk drive size */
5755 // FIXME ElTorito Harddisk. What geometry to send ?
5756 SET_AH(0x03);
5757 goto int13_success_noah;
5758 break;
5760 // all those functions return unimplemented
5761 case 0x0a: /* read disk sectors with ECC */
5762 case 0x0b: /* write disk sectors with ECC */
5763 case 0x18: /* set media type for format */
5764 case 0x41: // IBM/MS installation check
5765 // FIXME ElTorito Harddisk. Darwin would like to use EDD
5766 case 0x42: // IBM/MS extended read
5767 case 0x43: // IBM/MS extended write
5768 case 0x44: // IBM/MS verify sectors
5769 case 0x45: // IBM/MS lock/unlock drive
5770 case 0x46: // IBM/MS eject media
5771 case 0x47: // IBM/MS extended seek
5772 case 0x48: // IBM/MS get drive parameters
5773 case 0x49: // IBM/MS extended media change
5774 case 0x4e: // ? - set hardware configuration
5775 case 0x50: // ? - send packet command
5776 default:
5777 BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
5778 goto int13_fail;
5779 break;
5782 int13_fail:
5783 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5784 int13_fail_noah:
5785 SET_DISK_RET_STATUS(GET_AH());
5786 int13_fail_nostatus:
5787 SET_CF(); // error occurred
5788 return;
5790 int13_success:
5791 SET_AH(0x00); // no error
5792 int13_success_noah:
5793 SET_DISK_RET_STATUS(0x00);
5794 CLEAR_CF(); // no error
5795 return;
5798 // ---------------------------------------------------------------------------
5799 // End of int13 when emulating a device from the cd
5800 // ---------------------------------------------------------------------------
5802 #endif // BX_ELTORITO_BOOT
5804 #else //BX_USE_ATADRV
5806 void
5807 outLBA(cylinder,hd_heads,head,hd_sectors,sector,dl)
5808 Bit16u cylinder;
5809 Bit16u hd_heads;
5810 Bit16u head;
5811 Bit16u hd_sectors;
5812 Bit16u sector;
5813 Bit16u dl;
5815 ASM_START
5816 push bp
5817 mov bp, sp
5818 push eax
5819 push ebx
5820 push edx
5821 xor eax,eax
5822 mov ax,4[bp] // cylinder
5823 xor ebx,ebx
5824 mov bl,6[bp] // hd_heads
5825 imul ebx
5827 mov bl,8[bp] // head
5828 add eax,ebx
5829 mov bl,10[bp] // hd_sectors
5830 imul ebx
5831 mov bl,12[bp] // sector
5832 add eax,ebx
5834 dec eax
5835 mov dx,#0x1f3
5836 out dx,al
5837 mov dx,#0x1f4
5838 mov al,ah
5839 out dx,al
5840 shr eax,#16
5841 mov dx,#0x1f5
5842 out dx,al
5843 and ah,#0xf
5844 mov bl,14[bp] // dl
5845 and bl,#1
5846 shl bl,#4
5847 or ah,bl
5848 or ah,#0xe0
5849 mov al,ah
5850 mov dx,#0x01f6
5851 out dx,al
5852 pop edx
5853 pop ebx
5854 pop eax
5855 pop bp
5856 ASM_END
5859 void
5860 int13_harddisk(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5861 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5863 Bit8u drive, num_sectors, sector, head, status, mod;
5864 Bit8u drive_map;
5865 Bit8u n_drives;
5866 Bit16u cyl_mod, ax;
5867 Bit16u max_cylinder, cylinder, total_sectors;
5868 Bit16u hd_cylinders;
5869 Bit8u hd_heads, hd_sectors;
5870 Bit16u val16;
5871 Bit8u sector_count;
5872 unsigned int i;
5873 Bit16u tempbx;
5874 Bit16u dpsize;
5876 Bit16u count, segment, offset;
5877 Bit32u lba;
5878 Bit16u error;
5880 BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5882 write_byte(0x0040, 0x008e, 0); // clear completion flag
5884 /* at this point, DL is >= 0x80 to be passed from the floppy int13h
5885 handler code */
5886 /* check how many disks first (cmos reg 0x12), return an error if
5887 drive not present */
5888 drive_map = inb_cmos(0x12);
5889 drive_map = (((drive_map & 0xf0)==0) ? 0 : 1) |
5890 (((drive_map & 0x0f)==0) ? 0 : 2);
5891 n_drives = (drive_map==0) ? 0 :
5892 ((drive_map==3) ? 2 : 1);
5894 if (!(drive_map & (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
5895 SET_AH(0x01);
5896 SET_DISK_RET_STATUS(0x01);
5897 SET_CF(); /* error occurred */
5898 return;
5901 switch (GET_AH()) {
5903 case 0x00: /* disk controller reset */
5904 BX_DEBUG_INT13_HD("int13_f00\n");
5906 SET_AH(0);
5907 SET_DISK_RET_STATUS(0);
5908 set_diskette_ret_status(0);
5909 set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
5910 set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
5911 CLEAR_CF(); /* successful */
5912 return;
5913 break;
5915 case 0x01: /* read disk status */
5916 BX_DEBUG_INT13_HD("int13_f01\n");
5917 status = read_byte(0x0040, 0x0074);
5918 SET_AH(status);
5919 SET_DISK_RET_STATUS(0);
5920 /* set CF if error status read */
5921 if (status) SET_CF();
5922 else CLEAR_CF();
5923 return;
5924 break;
5926 case 0x04: // verify disk sectors
5927 case 0x02: // read disk sectors
5928 drive = GET_ELDL();
5929 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
5931 num_sectors = GET_AL();
5932 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
5933 sector = (GET_CL() & 0x3f);
5934 head = GET_DH();
5937 if (hd_cylinders > 1024) {
5938 if (hd_cylinders <= 2048) {
5939 cylinder <<= 1;
5941 else if (hd_cylinders <= 4096) {
5942 cylinder <<= 2;
5944 else if (hd_cylinders <= 8192) {
5945 cylinder <<= 3;
5947 else { // hd_cylinders <= 16384
5948 cylinder <<= 4;
5951 ax = head / hd_heads;
5952 cyl_mod = ax & 0xff;
5953 head = ax >> 8;
5954 cylinder |= cyl_mod;
5957 if ( (cylinder >= hd_cylinders) ||
5958 (sector > hd_sectors) ||
5959 (head >= hd_heads) ) {
5960 SET_AH(1);
5961 SET_DISK_RET_STATUS(1);
5962 SET_CF(); /* error occurred */
5963 return;
5966 if ( (num_sectors > 128) || (num_sectors == 0) )
5967 BX_PANIC("int13_harddisk(): num_sectors out of range!\n");
5969 if (head > 15)
5970 BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
5972 if ( GET_AH() == 0x04 ) {
5973 SET_AH(0);
5974 SET_DISK_RET_STATUS(0);
5975 CLEAR_CF();
5976 return;
5979 status = inb(0x1f7);
5980 if (status & 0x80) {
5981 BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
5983 outb(0x01f2, num_sectors);
5984 /* activate LBA? (tomv) */
5985 if (hd_heads > 16) {
5986 BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder, head, sector);
5987 outLBA(cylinder,hd_heads,head,hd_sectors,sector,drive);
5989 else {
5990 outb(0x01f3, sector);
5991 outb(0x01f4, cylinder & 0x00ff);
5992 outb(0x01f5, cylinder >> 8);
5993 outb(0x01f6, 0xa0 | ((drive & 0x01)<<4) | (head & 0x0f));
5995 outb(0x01f7, 0x20);
5997 while (1) {
5998 status = inb(0x1f7);
5999 if ( !(status & 0x80) ) break;
6002 if (status & 0x01) {
6003 BX_PANIC("hard drive BIOS:(read/verify) read error\n");
6004 } else if ( !(status & 0x08) ) {
6005 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6006 BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
6009 sector_count = 0;
6010 tempbx = BX;
6012 ASM_START
6013 sti ;; enable higher priority interrupts
6014 ASM_END
6016 while (1) {
6017 ASM_START
6018 ;; store temp bx in real DI register
6019 push bp
6020 mov bp, sp
6021 mov di, _int13_harddisk.tempbx + 2 [bp]
6022 pop bp
6024 ;; adjust if there will be an overrun
6025 cmp di, #0xfe00
6026 jbe i13_f02_no_adjust
6027 i13_f02_adjust:
6028 sub di, #0x0200 ; sub 512 bytes from offset
6029 mov ax, es
6030 add ax, #0x0020 ; add 512 to segment
6031 mov es, ax
6033 i13_f02_no_adjust:
6034 mov cx, #0x0100 ;; counter (256 words = 512b)
6035 mov dx, #0x01f0 ;; AT data read port
6037 rep
6038 insw ;; CX words transfered from port(DX) to ES:[DI]
6040 i13_f02_done:
6041 ;; store real DI register back to temp bx
6042 push bp
6043 mov bp, sp
6044 mov _int13_harddisk.tempbx + 2 [bp], di
6045 pop bp
6046 ASM_END
6048 sector_count++;
6049 num_sectors--;
6050 if (num_sectors == 0) {
6051 status = inb(0x1f7);
6052 if ( (status & 0xc9) != 0x40 )
6053 BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status);
6054 break;
6056 else {
6057 status = inb(0x1f7);
6058 if ( (status & 0xc9) != 0x48 )
6059 BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status);
6060 continue;
6064 SET_AH(0);
6065 SET_DISK_RET_STATUS(0);
6066 SET_AL(sector_count);
6067 CLEAR_CF(); /* successful */
6068 return;
6069 break;
6072 case 0x03: /* write disk sectors */
6073 BX_DEBUG_INT13_HD("int13_f03\n");
6074 drive = GET_ELDL ();
6075 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6077 num_sectors = GET_AL();
6078 cylinder = GET_CH();
6079 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
6080 sector = (GET_CL() & 0x3f);
6081 head = GET_DH();
6083 if (hd_cylinders > 1024) {
6084 if (hd_cylinders <= 2048) {
6085 cylinder <<= 1;
6087 else if (hd_cylinders <= 4096) {
6088 cylinder <<= 2;
6090 else if (hd_cylinders <= 8192) {
6091 cylinder <<= 3;
6093 else { // hd_cylinders <= 16384
6094 cylinder <<= 4;
6097 ax = head / hd_heads;
6098 cyl_mod = ax & 0xff;
6099 head = ax >> 8;
6100 cylinder |= cyl_mod;
6103 if ( (cylinder >= hd_cylinders) ||
6104 (sector > hd_sectors) ||
6105 (head >= hd_heads) ) {
6106 SET_AH( 1);
6107 SET_DISK_RET_STATUS(1);
6108 SET_CF(); /* error occurred */
6109 return;
6112 if ( (num_sectors > 128) || (num_sectors == 0) )
6113 BX_PANIC("int13_harddisk(): num_sectors out of range!\n");
6115 if (head > 15)
6116 BX_PANIC("hard drive BIOS:(read) head > 15\n");
6118 status = inb(0x1f7);
6119 if (status & 0x80) {
6120 BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
6122 // should check for Drive Ready Bit also in status reg
6123 outb(0x01f2, num_sectors);
6125 /* activate LBA? (tomv) */
6126 if (hd_heads > 16) {
6127 BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder, head, sector);
6128 outLBA(cylinder,hd_heads,head,hd_sectors,sector,GET_ELDL());
6130 else {
6131 outb(0x01f3, sector);
6132 outb(0x01f4, cylinder & 0x00ff);
6133 outb(0x01f5, cylinder >> 8);
6134 outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head & 0x0f));
6136 outb(0x01f7, 0x30);
6138 // wait for busy bit to turn off after seeking
6139 while (1) {
6140 status = inb(0x1f7);
6141 if ( !(status & 0x80) ) break;
6144 if ( !(status & 0x08) ) {
6145 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6146 BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
6149 sector_count = 0;
6150 tempbx = BX;
6152 ASM_START
6153 sti ;; enable higher priority interrupts
6154 ASM_END
6156 while (1) {
6157 ASM_START
6158 ;; store temp bx in real SI register
6159 push bp
6160 mov bp, sp
6161 mov si, _int13_harddisk.tempbx + 2 [bp]
6162 pop bp
6164 ;; adjust if there will be an overrun
6165 cmp si, #0xfe00
6166 jbe i13_f03_no_adjust
6167 i13_f03_adjust:
6168 sub si, #0x0200 ; sub 512 bytes from offset
6169 mov ax, es
6170 add ax, #0x0020 ; add 512 to segment
6171 mov es, ax
6173 i13_f03_no_adjust:
6174 mov cx, #0x0100 ;; counter (256 words = 512b)
6175 mov dx, #0x01f0 ;; AT data read port
6177 seg ES
6178 rep
6179 outsw ;; CX words tranfered from ES:[SI] to port(DX)
6181 ;; store real SI register back to temp bx
6182 push bp
6183 mov bp, sp
6184 mov _int13_harddisk.tempbx + 2 [bp], si
6185 pop bp
6186 ASM_END
6188 sector_count++;
6189 num_sectors--;
6190 if (num_sectors == 0) {
6191 status = inb(0x1f7);
6192 if ( (status & 0xe9) != 0x40 )
6193 BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status);
6194 break;
6196 else {
6197 status = inb(0x1f7);
6198 if ( (status & 0xc9) != 0x48 )
6199 BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status);
6200 continue;
6204 SET_AH(0);
6205 SET_DISK_RET_STATUS(0);
6206 SET_AL(sector_count);
6207 CLEAR_CF(); /* successful */
6208 return;
6209 break;
6211 case 0x05: /* format disk track */
6212 BX_DEBUG_INT13_HD("int13_f05\n");
6213 BX_PANIC("format disk track called\n");
6214 /* nop */
6215 SET_AH(0);
6216 SET_DISK_RET_STATUS(0);
6217 CLEAR_CF(); /* successful */
6218 return;
6219 break;
6221 case 0x08: /* read disk drive parameters */
6222 BX_DEBUG_INT13_HD("int13_f08\n");
6224 drive = GET_ELDL ();
6225 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6227 // translate CHS
6228 //
6229 if (hd_cylinders <= 1024) {
6230 // hd_cylinders >>= 0;
6231 // hd_heads <<= 0;
6233 else if (hd_cylinders <= 2048) {
6234 hd_cylinders >>= 1;
6235 hd_heads <<= 1;
6237 else if (hd_cylinders <= 4096) {
6238 hd_cylinders >>= 2;
6239 hd_heads <<= 2;
6241 else if (hd_cylinders <= 8192) {
6242 hd_cylinders >>= 3;
6243 hd_heads <<= 3;
6245 else { // hd_cylinders <= 16384
6246 hd_cylinders >>= 4;
6247 hd_heads <<= 4;
6250 max_cylinder = hd_cylinders - 2; /* 0 based */
6251 SET_AL(0);
6252 SET_CH(max_cylinder & 0xff);
6253 SET_CL(((max_cylinder >> 2) & 0xc0) | (hd_sectors & 0x3f));
6254 SET_DH(hd_heads - 1);
6255 SET_DL(n_drives); /* returns 0, 1, or 2 hard drives */
6256 SET_AH(0);
6257 SET_DISK_RET_STATUS(0);
6258 CLEAR_CF(); /* successful */
6260 return;
6261 break;
6263 case 0x09: /* initialize drive parameters */
6264 BX_DEBUG_INT13_HD("int13_f09\n");
6265 SET_AH(0);
6266 SET_DISK_RET_STATUS(0);
6267 CLEAR_CF(); /* successful */
6268 return;
6269 break;
6271 case 0x0a: /* read disk sectors with ECC */
6272 BX_DEBUG_INT13_HD("int13_f0a\n");
6273 case 0x0b: /* write disk sectors with ECC */
6274 BX_DEBUG_INT13_HD("int13_f0b\n");
6275 BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
6276 return;
6277 break;
6279 case 0x0c: /* seek to specified cylinder */
6280 BX_DEBUG_INT13_HD("int13_f0c\n");
6281 BX_INFO("int13h function 0ch (seek) not implemented!\n");
6282 SET_AH(0);
6283 SET_DISK_RET_STATUS(0);
6284 CLEAR_CF(); /* successful */
6285 return;
6286 break;
6288 case 0x0d: /* alternate disk reset */
6289 BX_DEBUG_INT13_HD("int13_f0d\n");
6290 SET_AH(0);
6291 SET_DISK_RET_STATUS(0);
6292 CLEAR_CF(); /* successful */
6293 return;
6294 break;
6296 case 0x10: /* check drive ready */
6297 BX_DEBUG_INT13_HD("int13_f10\n");
6298 //SET_AH(0);
6299 //SET_DISK_RET_STATUS(0);
6300 //CLEAR_CF(); /* successful */
6301 //return;
6302 //break;
6304 // should look at 40:8E also???
6305 status = inb(0x01f7);
6306 if ( (status & 0xc0) == 0x40 ) {
6307 SET_AH(0);
6308 SET_DISK_RET_STATUS(0);
6309 CLEAR_CF(); // drive ready
6310 return;
6312 else {
6313 SET_AH(0xAA);
6314 SET_DISK_RET_STATUS(0xAA);
6315 SET_CF(); // not ready
6316 return;
6318 break;
6320 case 0x11: /* recalibrate */
6321 BX_DEBUG_INT13_HD("int13_f11\n");
6322 SET_AH(0);
6323 SET_DISK_RET_STATUS(0);
6324 CLEAR_CF(); /* successful */
6325 return;
6326 break;
6328 case 0x14: /* controller internal diagnostic */
6329 BX_DEBUG_INT13_HD("int13_f14\n");
6330 SET_AH(0);
6331 SET_DISK_RET_STATUS(0);
6332 CLEAR_CF(); /* successful */
6333 SET_AL(0);
6334 return;
6335 break;
6337 case 0x15: /* read disk drive size */
6338 drive = GET_ELDL();
6339 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6340 ASM_START
6341 push bp
6342 mov bp, sp
6343 mov al, _int13_harddisk.hd_heads + 2 [bp]
6344 mov ah, _int13_harddisk.hd_sectors + 2 [bp]
6345 mul al, ah ;; ax = heads * sectors
6346 mov bx, _int13_harddisk.hd_cylinders + 2 [bp]
6347 dec bx ;; use (cylinders - 1) ???
6348 mul ax, bx ;; dx:ax = (cylinders -1) * (heads * sectors)
6349 ;; now we need to move the 32bit result dx:ax to what the
6350 ;; BIOS wants which is cx:dx.
6351 ;; and then into CX:DX on the stack
6352 mov _int13_harddisk.CX + 2 [bp], dx
6353 mov _int13_harddisk.DX + 2 [bp], ax
6354 pop bp
6355 ASM_END
6356 SET_AH(3); // hard disk accessible
6357 SET_DISK_RET_STATUS(0); // ??? should this be 0
6358 CLEAR_CF(); // successful
6359 return;
6360 break;
6362 case 0x18: // set media type for format
6363 case 0x41: // IBM/MS
6364 case 0x42: // IBM/MS
6365 case 0x43: // IBM/MS
6366 case 0x44: // IBM/MS
6367 case 0x45: // IBM/MS lock/unlock drive
6368 case 0x46: // IBM/MS eject media
6369 case 0x47: // IBM/MS extended seek
6370 case 0x49: // IBM/MS extended media change
6371 case 0x50: // IBM/MS send packet command
6372 default:
6373 BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
6375 SET_AH(1); // code=invalid function in AH or invalid parameter
6376 SET_DISK_RET_STATUS(1);
6377 SET_CF(); /* unsuccessful */
6378 return;
6379 break;
6383 static char panic_msg_reg12h[] = "HD%d cmos reg 12h not type F\n";
6384 static char panic_msg_reg19h[] = "HD%d cmos reg %02xh not user definable type 47\n";
6386 void
6387 get_hd_geometry(drive, hd_cylinders, hd_heads, hd_sectors)
6388 Bit8u drive;
6389 Bit16u *hd_cylinders;
6390 Bit8u *hd_heads;
6391 Bit8u *hd_sectors;
6393 Bit8u hd_type;
6394 Bit16u ss;
6395 Bit16u cylinders;
6396 Bit8u iobase;
6398 ss = get_SS();
6399 if (drive == 0x80) {
6400 hd_type = inb_cmos(0x12) & 0xf0;
6401 if (hd_type != 0xf0)
6402 BX_INFO(panic_msg_reg12h,0);
6403 hd_type = inb_cmos(0x19); // HD0: extended type
6404 if (hd_type != 47)
6405 BX_INFO(panic_msg_reg19h,0,0x19);
6406 iobase = 0x1b;
6407 } else {
6408 hd_type = inb_cmos(0x12) & 0x0f;
6409 if (hd_type != 0x0f)
6410 BX_INFO(panic_msg_reg12h,1);
6411 hd_type = inb_cmos(0x1a); // HD0: extended type
6412 if (hd_type != 47)
6413 BX_INFO(panic_msg_reg19h,0,0x1a);
6414 iobase = 0x24;
6417 // cylinders
6418 cylinders = inb_cmos(iobase) | (inb_cmos(iobase+1) << 8);
6419 write_word(ss, hd_cylinders, cylinders);
6421 // heads
6422 write_byte(ss, hd_heads, inb_cmos(iobase+2));
6424 // sectors per track
6425 write_byte(ss, hd_sectors, inb_cmos(iobase+8));
6428 #endif //else BX_USE_ATADRV
6431 //////////////////////
6432 // FLOPPY functions //
6433 //////////////////////
6435 bx_bool
6436 floppy_media_known(drive)
6437 Bit16u drive;
6439 Bit8u val8;
6440 Bit16u media_state_offset;
6442 val8 = read_byte(0x0040, 0x003e); // diskette recal status
6443 if (drive)
6444 val8 >>= 1;
6445 val8 &= 0x01;
6446 if (val8 == 0)
6447 return(0);
6449 media_state_offset = 0x0090;
6450 if (drive)
6451 media_state_offset += 1;
6453 val8 = read_byte(0x0040, media_state_offset);
6454 val8 = (val8 >> 4) & 0x01;
6455 if (val8 == 0)
6456 return(0);
6458 // check pass, return KNOWN
6459 return(1);
6462 bx_bool
6463 floppy_media_sense(drive)
6464 Bit16u drive;
6466 bx_bool retval;
6467 Bit16u media_state_offset;
6468 Bit8u drive_type, config_data, media_state;
6470 if (floppy_drive_recal(drive) == 0) {
6471 return(0);
6474 // for now cheat and get drive type from CMOS,
6475 // assume media is same as drive type
6477 // ** config_data **
6478 // Bitfields for diskette media control:
6479 // Bit(s) Description (Table M0028)
6480 // 7-6 last data rate set by controller
6481 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6482 // 5-4 last diskette drive step rate selected
6483 // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
6484 // 3-2 {data rate at start of operation}
6485 // 1-0 reserved
6487 // ** media_state **
6488 // Bitfields for diskette drive media state:
6489 // Bit(s) Description (Table M0030)
6490 // 7-6 data rate
6491 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6492 // 5 double stepping required (e.g. 360kB in 1.2MB)
6493 // 4 media type established
6494 // 3 drive capable of supporting 4MB media
6495 // 2-0 on exit from BIOS, contains
6496 // 000 trying 360kB in 360kB
6497 // 001 trying 360kB in 1.2MB
6498 // 010 trying 1.2MB in 1.2MB
6499 // 011 360kB in 360kB established
6500 // 100 360kB in 1.2MB established
6501 // 101 1.2MB in 1.2MB established
6502 // 110 reserved
6503 // 111 all other formats/drives
6505 drive_type = inb_cmos(0x10);
6506 if (drive == 0)
6507 drive_type >>= 4;
6508 else
6509 drive_type &= 0x0f;
6510 if ( drive_type == 1 ) {
6511 // 360K 5.25" drive
6512 config_data = 0x00; // 0000 0000
6513 media_state = 0x25; // 0010 0101
6514 retval = 1;
6516 else if ( drive_type == 2 ) {
6517 // 1.2 MB 5.25" drive
6518 config_data = 0x00; // 0000 0000
6519 media_state = 0x25; // 0010 0101 // need double stepping??? (bit 5)
6520 retval = 1;
6522 else if ( drive_type == 3 ) {
6523 // 720K 3.5" drive
6524 config_data = 0x00; // 0000 0000 ???
6525 media_state = 0x17; // 0001 0111
6526 retval = 1;
6528 else if ( drive_type == 4 ) {
6529 // 1.44 MB 3.5" drive
6530 config_data = 0x00; // 0000 0000
6531 media_state = 0x17; // 0001 0111
6532 retval = 1;
6534 else if ( drive_type == 5 ) {
6535 // 2.88 MB 3.5" drive
6536 config_data = 0xCC; // 1100 1100
6537 media_state = 0xD7; // 1101 0111
6538 retval = 1;
6540 //
6541 // Extended floppy size uses special cmos setting
6542 else if ( drive_type == 6 ) {
6543 // 160k 5.25" drive
6544 config_data = 0x00; // 0000 0000
6545 media_state = 0x27; // 0010 0111
6546 retval = 1;
6548 else if ( drive_type == 7 ) {
6549 // 180k 5.25" drive
6550 config_data = 0x00; // 0000 0000
6551 media_state = 0x27; // 0010 0111
6552 retval = 1;
6554 else if ( drive_type == 8 ) {
6555 // 320k 5.25" drive
6556 config_data = 0x00; // 0000 0000
6557 media_state = 0x27; // 0010 0111
6558 retval = 1;
6561 else {
6562 // not recognized
6563 config_data = 0x00; // 0000 0000
6564 media_state = 0x00; // 0000 0000
6565 retval = 0;
6568 if (drive == 0)
6569 media_state_offset = 0x90;
6570 else
6571 media_state_offset = 0x91;
6572 write_byte(0x0040, 0x008B, config_data);
6573 write_byte(0x0040, media_state_offset, media_state);
6575 return(retval);
6578 bx_bool
6579 floppy_drive_recal(drive)
6580 Bit16u drive;
6582 Bit8u val8, dor;
6583 Bit16u curr_cyl_offset;
6585 // set 40:3e bit 7 to 0
6586 val8 = read_byte(0x0000, 0x043e);
6587 val8 &= 0x7f;
6588 write_byte(0x0000, 0x043e, val8);
6590 // turn on motor of selected drive, DMA & int enabled, normal operation
6591 if (drive)
6592 dor = 0x20;
6593 else
6594 dor = 0x10;
6595 dor |= 0x0c;
6596 dor |= drive;
6597 outb(0x03f2, dor);
6599 // reset the disk motor timeout value of INT 08
6600 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
6602 // check port 3f4 for drive readiness
6603 val8 = inb(0x3f4);
6604 if ( (val8 & 0xf0) != 0x80 )
6605 BX_PANIC("floppy recal:f07: ctrl not ready\n");
6607 // send Recalibrate command (2 bytes) to controller
6608 outb(0x03f5, 0x07); // 07: Recalibrate
6609 outb(0x03f5, drive); // 0=drive0, 1=drive1
6611 // turn on interrupts
6612 ASM_START
6613 sti
6614 ASM_END
6616 // wait on 40:3e bit 7 to become 1
6617 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6618 while ( val8 == 0 ) {
6619 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6622 val8 = 0; // separate asm from while() loop
6623 // turn off interrupts
6624 ASM_START
6625 cli
6626 ASM_END
6628 // set 40:3e bit 7 to 0, and calibrated bit
6629 val8 = read_byte(0x0000, 0x043e);
6630 val8 &= 0x7f;
6631 if (drive) {
6632 val8 |= 0x02; // Drive 1 calibrated
6633 curr_cyl_offset = 0x0095;
6635 else {
6636 val8 |= 0x01; // Drive 0 calibrated
6637 curr_cyl_offset = 0x0094;
6639 write_byte(0x0040, 0x003e, val8);
6640 write_byte(0x0040, curr_cyl_offset, 0); // current cylinder is 0
6642 return(1);
6647 bx_bool
6648 floppy_drive_exists(drive)
6649 Bit16u drive;
6651 Bit8u drive_type;
6653 // check CMOS to see if drive exists
6654 drive_type = inb_cmos(0x10);
6655 if (drive == 0)
6656 drive_type >>= 4;
6657 else
6658 drive_type &= 0x0f;
6659 if ( drive_type == 0 )
6660 return(0);
6661 else
6662 return(1);
6665 #if BX_SUPPORT_FLOPPY
6666 void
6667 int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
6668 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
6670 Bit8u drive, num_sectors, track, sector, head, status;
6671 Bit16u base_address, base_count, base_es;
6672 Bit8u page, mode_register, val8, dor;
6673 Bit8u return_status[7];
6674 Bit8u drive_type, num_floppies, ah;
6675 Bit16u es, last_addr;
6677 BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6678 // BX_DEBUG_INT13_FL("int13_diskette: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), get_DS(), ES, DI, SI);
6680 ah = GET_AH();
6682 switch ( ah ) {
6683 case 0x00: // diskette controller reset
6684 BX_DEBUG_INT13_FL("floppy f00\n");
6685 drive = GET_ELDL();
6686 if (drive > 1) {
6687 SET_AH(1); // invalid param
6688 set_diskette_ret_status(1);
6689 SET_CF();
6690 return;
6692 drive_type = inb_cmos(0x10);
6694 if (drive == 0)
6695 drive_type >>= 4;
6696 else
6697 drive_type &= 0x0f;
6698 if (drive_type == 0) {
6699 SET_AH(0x80); // drive not responding
6700 set_diskette_ret_status(0x80);
6701 SET_CF();
6702 return;
6704 SET_AH(0);
6705 set_diskette_ret_status(0);
6706 CLEAR_CF(); // successful
6707 set_diskette_current_cyl(drive, 0); // current cylinder
6708 return;
6710 case 0x01: // Read Diskette Status
6711 CLEAR_CF();
6712 val8 = read_byte(0x0000, 0x0441);
6713 SET_AH(val8);
6714 if (val8) {
6715 SET_CF();
6717 return;
6719 case 0x02: // Read Diskette Sectors
6720 case 0x03: // Write Diskette Sectors
6721 case 0x04: // Verify Diskette Sectors
6722 num_sectors = GET_AL();
6723 track = GET_CH();
6724 sector = GET_CL();
6725 head = GET_DH();
6726 drive = GET_ELDL();
6728 if ( (drive > 1) || (head > 1) ||
6729 (num_sectors == 0) || (num_sectors > 72) ) {
6730 BX_INFO("floppy: drive>1 || head>1 ...\n");
6731 SET_AH(1);
6732 set_diskette_ret_status(1);
6733 SET_AL(0); // no sectors read
6734 SET_CF(); // error occurred
6735 return;
6738 // see if drive exists
6739 if (floppy_drive_exists(drive) == 0) {
6740 SET_AH(0x80); // not responding
6741 set_diskette_ret_status(0x80);
6742 SET_AL(0); // no sectors read
6743 SET_CF(); // error occurred
6744 return;
6747 // see if media in drive, and type is known
6748 if (floppy_media_known(drive) == 0) {
6749 if (floppy_media_sense(drive) == 0) {
6750 SET_AH(0x0C); // Media type not found
6751 set_diskette_ret_status(0x0C);
6752 SET_AL(0); // no sectors read
6753 SET_CF(); // error occurred
6754 return;
6758 if (ah == 0x02) {
6759 // Read Diskette Sectors
6761 //-----------------------------------
6762 // set up DMA controller for transfer
6763 //-----------------------------------
6765 // es:bx = pointer to where to place information from diskette
6766 // port 04: DMA-1 base and current address, channel 2
6767 // port 05: DMA-1 base and current count, channel 2
6768 page = (ES >> 12); // upper 4 bits
6769 base_es = (ES << 4); // lower 16bits contributed by ES
6770 base_address = base_es + BX; // lower 16 bits of address
6771 // contributed by ES:BX
6772 if ( base_address < base_es ) {
6773 // in case of carry, adjust page by 1
6774 page++;
6776 base_count = (num_sectors * 512) - 1;
6778 // check for 64K boundary overrun
6779 last_addr = base_address + base_count;
6780 if (last_addr < base_address) {
6781 SET_AH(0x09);
6782 set_diskette_ret_status(0x09);
6783 SET_AL(0); // no sectors read
6784 SET_CF(); // error occurred
6785 return;
6788 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
6789 outb(0x000a, 0x06);
6791 BX_DEBUG_INT13_FL("clear flip-flop\n");
6792 outb(0x000c, 0x00); // clear flip-flop
6793 outb(0x0004, base_address);
6794 outb(0x0004, base_address>>8);
6795 BX_DEBUG_INT13_FL("clear flip-flop\n");
6796 outb(0x000c, 0x00); // clear flip-flop
6797 outb(0x0005, base_count);
6798 outb(0x0005, base_count>>8);
6800 // port 0b: DMA-1 Mode Register
6801 mode_register = 0x46; // single mode, increment, autoinit disable,
6802 // transfer type=write, channel 2
6803 BX_DEBUG_INT13_FL("setting mode register\n");
6804 outb(0x000b, mode_register);
6806 BX_DEBUG_INT13_FL("setting page register\n");
6807 // port 81: DMA-1 Page Register, channel 2
6808 outb(0x0081, page);
6810 BX_DEBUG_INT13_FL("unmask chan 2\n");
6811 outb(0x000a, 0x02); // unmask channel 2
6813 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
6814 outb(0x000a, 0x02);
6816 //--------------------------------------
6817 // set up floppy controller for transfer
6818 //--------------------------------------
6820 // set 40:3e bit 7 to 0
6821 val8 = read_byte(0x0000, 0x043e);
6822 val8 &= 0x7f;
6823 write_byte(0x0000, 0x043e, val8);
6825 // turn on motor of selected drive, DMA & int enabled, normal operation
6826 if (drive)
6827 dor = 0x20;
6828 else
6829 dor = 0x10;
6830 dor |= 0x0c;
6831 dor |= drive;
6832 outb(0x03f2, dor);
6834 // reset the disk motor timeout value of INT 08
6835 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
6837 // check port 3f4 for drive readiness
6838 val8 = inb(0x3f4);
6839 if ( (val8 & 0xf0) != 0x80 )
6840 BX_PANIC("int13_diskette:f02: ctrl not ready\n");
6842 // send read-normal-data command (9 bytes) to controller
6843 outb(0x03f5, 0xe6); // e6: read normal data
6844 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
6845 outb(0x03f5, track);
6846 outb(0x03f5, head);
6847 outb(0x03f5, sector);
6848 outb(0x03f5, 2); // 512 byte sector size
6849 outb(0x03f5, 0); // last sector number possible on track
6850 outb(0x03f5, 0); // Gap length
6851 outb(0x03f5, 0xff); // Gap length
6853 // turn on interrupts
6854 ASM_START
6855 sti
6856 ASM_END
6858 // wait on 40:3e bit 7 to become 1
6859 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6860 while ( val8 == 0 ) {
6861 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6864 val8 = 0; // separate asm from while() loop
6865 // turn off interrupts
6866 ASM_START
6867 cli
6868 ASM_END
6870 // set 40:3e bit 7 to 0
6871 val8 = read_byte(0x0000, 0x043e);
6872 val8 &= 0x7f;
6873 write_byte(0x0000, 0x043e, val8);
6875 // check port 3f4 for accessibility to status bytes
6876 val8 = inb(0x3f4);
6877 if ( (val8 & 0xc0) != 0xc0 )
6878 BX_PANIC("int13_diskette: ctrl not ready\n");
6880 // read 7 return status bytes from controller
6881 // using loop index broken, have to unroll...
6882 return_status[0] = inb(0x3f5);
6883 return_status[1] = inb(0x3f5);
6884 return_status[2] = inb(0x3f5);
6885 return_status[3] = inb(0x3f5);
6886 return_status[4] = inb(0x3f5);
6887 return_status[5] = inb(0x3f5);
6888 return_status[6] = inb(0x3f5);
6889 // record in BIOS Data Area
6890 write_byte(0x0040, 0x0042, return_status[0]);
6891 write_byte(0x0040, 0x0043, return_status[1]);
6892 write_byte(0x0040, 0x0044, return_status[2]);
6893 write_byte(0x0040, 0x0045, return_status[3]);
6894 write_byte(0x0040, 0x0046, return_status[4]);
6895 write_byte(0x0040, 0x0047, return_status[5]);
6896 write_byte(0x0040, 0x0048, return_status[6]);
6898 if ( (return_status[0] & 0xc0) != 0 ) {
6899 SET_AH(0x20);
6900 set_diskette_ret_status(0x20);
6901 SET_AL(0); // no sectors read
6902 SET_CF(); // error occurred
6903 return;
6906 // ??? should track be new val from return_status[3] ?
6907 set_diskette_current_cyl(drive, track);
6908 // AL = number of sectors read (same value as passed)
6909 SET_AH(0x00); // success
6910 CLEAR_CF(); // success
6911 return;
6913 else if (ah == 0x03) {
6914 // Write Diskette Sectors
6916 //-----------------------------------
6917 // set up DMA controller for transfer
6918 //-----------------------------------
6920 // es:bx = pointer to where to place information from diskette
6921 // port 04: DMA-1 base and current address, channel 2
6922 // port 05: DMA-1 base and current count, channel 2
6923 page = (ES >> 12); // upper 4 bits
6924 base_es = (ES << 4); // lower 16bits contributed by ES
6925 base_address = base_es + BX; // lower 16 bits of address
6926 // contributed by ES:BX
6927 if ( base_address < base_es ) {
6928 // in case of carry, adjust page by 1
6929 page++;
6931 base_count = (num_sectors * 512) - 1;
6933 // check for 64K boundary overrun
6934 last_addr = base_address + base_count;
6935 if (last_addr < base_address) {
6936 SET_AH(0x09);
6937 set_diskette_ret_status(0x09);
6938 SET_AL(0); // no sectors read
6939 SET_CF(); // error occurred
6940 return;
6943 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
6944 outb(0x000a, 0x06);
6946 outb(0x000c, 0x00); // clear flip-flop
6947 outb(0x0004, base_address);
6948 outb(0x0004, base_address>>8);
6949 outb(0x000c, 0x00); // clear flip-flop
6950 outb(0x0005, base_count);
6951 outb(0x0005, base_count>>8);
6953 // port 0b: DMA-1 Mode Register
6954 mode_register = 0x4a; // single mode, increment, autoinit disable,
6955 // transfer type=read, channel 2
6956 outb(0x000b, mode_register);
6958 // port 81: DMA-1 Page Register, channel 2
6959 outb(0x0081, page);
6961 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
6962 outb(0x000a, 0x02);
6964 //--------------------------------------
6965 // set up floppy controller for transfer
6966 //--------------------------------------
6968 // set 40:3e bit 7 to 0
6969 val8 = read_byte(0x0000, 0x043e);
6970 val8 &= 0x7f;
6971 write_byte(0x0000, 0x043e, val8);
6973 // turn on motor of selected drive, DMA & int enabled, normal operation
6974 if (drive)
6975 dor = 0x20;
6976 else
6977 dor = 0x10;
6978 dor |= 0x0c;
6979 dor |= drive;
6980 outb(0x03f2, dor);
6982 // reset the disk motor timeout value of INT 08
6983 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
6985 // check port 3f4 for drive readiness
6986 val8 = inb(0x3f4);
6987 if ( (val8 & 0xf0) != 0x80 )
6988 BX_PANIC("int13_diskette:f03: ctrl not ready\n");
6990 // send read-normal-data command (9 bytes) to controller
6991 outb(0x03f5, 0xc5); // c5: write normal data
6992 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
6993 outb(0x03f5, track);
6994 outb(0x03f5, head);
6995 outb(0x03f5, sector);
6996 outb(0x03f5, 2); // 512 byte sector size
6997 outb(0x03f5, 0); // last sector number possible on track
6998 outb(0x03f5, 0); // Gap length
6999 outb(0x03f5, 0xff); // Gap length
7001 // turn on interrupts
7002 ASM_START
7003 sti
7004 ASM_END
7006 // wait on 40:3e bit 7 to become 1
7007 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7008 while ( val8 == 0 ) {
7009 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7012 val8 = 0; // separate asm from while() loop
7013 // turn off interrupts
7014 ASM_START
7015 cli
7016 ASM_END
7018 // set 40:3e bit 7 to 0
7019 val8 = read_byte(0x0000, 0x043e);
7020 val8 &= 0x7f;
7021 write_byte(0x0000, 0x043e, val8);
7023 // check port 3f4 for accessibility to status bytes
7024 val8 = inb(0x3f4);
7025 if ( (val8 & 0xc0) != 0xc0 )
7026 BX_PANIC("int13_diskette: ctrl not ready\n");
7028 // read 7 return status bytes from controller
7029 // using loop index broken, have to unroll...
7030 return_status[0] = inb(0x3f5);
7031 return_status[1] = inb(0x3f5);
7032 return_status[2] = inb(0x3f5);
7033 return_status[3] = inb(0x3f5);
7034 return_status[4] = inb(0x3f5);
7035 return_status[5] = inb(0x3f5);
7036 return_status[6] = inb(0x3f5);
7037 // record in BIOS Data Area
7038 write_byte(0x0040, 0x0042, return_status[0]);
7039 write_byte(0x0040, 0x0043, return_status[1]);
7040 write_byte(0x0040, 0x0044, return_status[2]);
7041 write_byte(0x0040, 0x0045, return_status[3]);
7042 write_byte(0x0040, 0x0046, return_status[4]);
7043 write_byte(0x0040, 0x0047, return_status[5]);
7044 write_byte(0x0040, 0x0048, return_status[6]);
7046 if ( (return_status[0] & 0xc0) != 0 ) {
7047 if ( (return_status[1] & 0x02) != 0 ) {
7048 // diskette not writable.
7049 // AH=status code=0x03 (tried to write on write-protected disk)
7050 // AL=number of sectors written=0
7051 AX = 0x0300;
7052 SET_CF();
7053 return;
7054 } else {
7055 BX_PANIC("int13_diskette_function: read error\n");
7059 // ??? should track be new val from return_status[3] ?
7060 set_diskette_current_cyl(drive, track);
7061 // AL = number of sectors read (same value as passed)
7062 SET_AH(0x00); // success
7063 CLEAR_CF(); // success
7064 return;
7066 else { // if (ah == 0x04)
7067 // Verify Diskette Sectors
7069 // ??? should track be new val from return_status[3] ?
7070 set_diskette_current_cyl(drive, track);
7071 // AL = number of sectors verified (same value as passed)
7072 CLEAR_CF(); // success
7073 SET_AH(0x00); // success
7074 return;
7078 case 0x05: // format diskette track
7079 BX_DEBUG_INT13_FL("floppy f05\n");
7081 num_sectors = GET_AL();
7082 track = GET_CH();
7083 head = GET_DH();
7084 drive = GET_ELDL();
7086 if ((drive > 1) || (head > 1) || (track > 79) ||
7087 (num_sectors == 0) || (num_sectors > 18)) {
7088 SET_AH(1);
7089 set_diskette_ret_status(1);
7090 SET_CF(); // error occurred
7093 // see if drive exists
7094 if (floppy_drive_exists(drive) == 0) {
7095 SET_AH(0x80); // drive not responding
7096 set_diskette_ret_status(0x80);
7097 SET_CF(); // error occurred
7098 return;
7101 // see if media in drive, and type is known
7102 if (floppy_media_known(drive) == 0) {
7103 if (floppy_media_sense(drive) == 0) {
7104 SET_AH(0x0C); // Media type not found
7105 set_diskette_ret_status(0x0C);
7106 SET_AL(0); // no sectors read
7107 SET_CF(); // error occurred
7108 return;
7112 // set up DMA controller for transfer
7113 page = (ES >> 12); // upper 4 bits
7114 base_es = (ES << 4); // lower 16bits contributed by ES
7115 base_address = base_es + BX; // lower 16 bits of address
7116 // contributed by ES:BX
7117 if ( base_address < base_es ) {
7118 // in case of carry, adjust page by 1
7119 page++;
7121 base_count = (num_sectors * 4) - 1;
7123 // check for 64K boundary overrun
7124 last_addr = base_address + base_count;
7125 if (last_addr < base_address) {
7126 SET_AH(0x09);
7127 set_diskette_ret_status(0x09);
7128 SET_AL(0); // no sectors read
7129 SET_CF(); // error occurred
7130 return;
7133 outb(0x000a, 0x06);
7134 outb(0x000c, 0x00); // clear flip-flop
7135 outb(0x0004, base_address);
7136 outb(0x0004, base_address>>8);
7137 outb(0x000c, 0x00); // clear flip-flop
7138 outb(0x0005, base_count);
7139 outb(0x0005, base_count>>8);
7140 mode_register = 0x4a; // single mode, increment, autoinit disable,
7141 // transfer type=read, channel 2
7142 outb(0x000b, mode_register);
7143 // port 81: DMA-1 Page Register, channel 2
7144 outb(0x0081, page);
7145 outb(0x000a, 0x02);
7147 // set up floppy controller for transfer
7148 val8 = read_byte(0x0000, 0x043e);
7149 val8 &= 0x7f;
7150 write_byte(0x0000, 0x043e, val8);
7151 // turn on motor of selected drive, DMA & int enabled, normal operation
7152 if (drive)
7153 dor = 0x20;
7154 else
7155 dor = 0x10;
7156 dor |= 0x0c;
7157 dor |= drive;
7158 outb(0x03f2, dor);
7160 // reset the disk motor timeout value of INT 08
7161 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
7163 // check port 3f4 for drive readiness
7164 val8 = inb(0x3f4);
7165 if ( (val8 & 0xf0) != 0x80 )
7166 BX_PANIC("int13_diskette:f05: ctrl not ready\n");
7168 // send read-normal-data command (6 bytes) to controller
7169 outb(0x03f5, 0x4d); // 4d: format track
7170 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7171 outb(0x03f5, 2); // 512 byte sector size
7172 outb(0x03f5, num_sectors); // number of sectors per track
7173 outb(0x03f5, 0); // Gap length
7174 outb(0x03f5, 0xf6); // Fill byte
7175 // turn on interrupts
7176 ASM_START
7177 sti
7178 ASM_END
7179 // wait on 40:3e bit 7 to become 1
7180 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7181 while ( val8 == 0 ) {
7182 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7184 val8 = 0; // separate asm from while() loop
7185 // turn off interrupts
7186 ASM_START
7187 cli
7188 ASM_END
7189 // set 40:3e bit 7 to 0
7190 val8 = read_byte(0x0000, 0x043e);
7191 val8 &= 0x7f;
7192 write_byte(0x0000, 0x043e, val8);
7193 // check port 3f4 for accessibility to status bytes
7194 val8 = inb(0x3f4);
7195 if ( (val8 & 0xc0) != 0xc0 )
7196 BX_PANIC("int13_diskette: ctrl not ready\n");
7198 // read 7 return status bytes from controller
7199 // using loop index broken, have to unroll...
7200 return_status[0] = inb(0x3f5);
7201 return_status[1] = inb(0x3f5);
7202 return_status[2] = inb(0x3f5);
7203 return_status[3] = inb(0x3f5);
7204 return_status[4] = inb(0x3f5);
7205 return_status[5] = inb(0x3f5);
7206 return_status[6] = inb(0x3f5);
7207 // record in BIOS Data Area
7208 write_byte(0x0040, 0x0042, return_status[0]);
7209 write_byte(0x0040, 0x0043, return_status[1]);
7210 write_byte(0x0040, 0x0044, return_status[2]);
7211 write_byte(0x0040, 0x0045, return_status[3]);
7212 write_byte(0x0040, 0x0046, return_status[4]);
7213 write_byte(0x0040, 0x0047, return_status[5]);
7214 write_byte(0x0040, 0x0048, return_status[6]);
7216 if ( (return_status[0] & 0xc0) != 0 ) {
7217 if ( (return_status[1] & 0x02) != 0 ) {
7218 // diskette not writable.
7219 // AH=status code=0x03 (tried to write on write-protected disk)
7220 // AL=number of sectors written=0
7221 AX = 0x0300;
7222 SET_CF();
7223 return;
7224 } else {
7225 BX_PANIC("int13_diskette_function: write error\n");
7229 SET_AH(0);
7230 set_diskette_ret_status(0);
7231 set_diskette_current_cyl(drive, 0);
7232 CLEAR_CF(); // successful
7233 return;
7236 case 0x08: // read diskette drive parameters
7237 BX_DEBUG_INT13_FL("floppy f08\n");
7238 drive = GET_ELDL();
7240 if (drive > 1) {
7241 AX = 0;
7242 BX = 0;
7243 CX = 0;
7244 DX = 0;
7245 ES = 0;
7246 DI = 0;
7247 SET_DL(num_floppies);
7248 SET_CF();
7249 return;
7252 drive_type = inb_cmos(0x10);
7253 num_floppies = 0;
7254 if (drive_type & 0xf0)
7255 num_floppies++;
7256 if (drive_type & 0x0f)
7257 num_floppies++;
7259 if (drive == 0)
7260 drive_type >>= 4;
7261 else
7262 drive_type &= 0x0f;
7264 SET_BH(0);
7265 SET_BL(drive_type);
7266 SET_AH(0);
7267 SET_AL(0);
7268 SET_DL(num_floppies);
7270 switch (drive_type) {
7271 case 0: // none
7272 CX = 0;
7273 SET_DH(0); // max head #
7274 break;
7276 case 1: // 360KB, 5.25"
7277 CX = 0x2709; // 40 tracks, 9 sectors
7278 SET_DH(1); // max head #
7279 break;
7281 case 2: // 1.2MB, 5.25"
7282 CX = 0x4f0f; // 80 tracks, 15 sectors
7283 SET_DH(1); // max head #
7284 break;
7286 case 3: // 720KB, 3.5"
7287 CX = 0x4f09; // 80 tracks, 9 sectors
7288 SET_DH(1); // max head #
7289 break;
7291 case 4: // 1.44MB, 3.5"
7292 CX = 0x4f12; // 80 tracks, 18 sectors
7293 SET_DH(1); // max head #
7294 break;
7296 case 5: // 2.88MB, 3.5"
7297 CX = 0x4f24; // 80 tracks, 36 sectors
7298 SET_DH(1); // max head #
7299 break;
7301 case 6: // 160k, 5.25"
7302 CX = 0x2708; // 40 tracks, 8 sectors
7303 SET_DH(0); // max head #
7304 break;
7306 case 7: // 180k, 5.25"
7307 CX = 0x2709; // 40 tracks, 9 sectors
7308 SET_DH(0); // max head #
7309 break;
7311 case 8: // 320k, 5.25"
7312 CX = 0x2708; // 40 tracks, 8 sectors
7313 SET_DH(1); // max head #
7314 break;
7316 default: // ?
7317 BX_PANIC("floppy: int13: bad floppy type\n");
7320 /* set es & di to point to 11 byte diskette param table in ROM */
7321 ASM_START
7322 push bp
7323 mov bp, sp
7324 mov ax, #diskette_param_table2
7325 mov _int13_diskette_function.DI+2[bp], ax
7326 mov _int13_diskette_function.ES+2[bp], cs
7327 pop bp
7328 ASM_END
7329 CLEAR_CF(); // success
7330 /* disk status not changed upon success */
7331 return;
7334 case 0x15: // read diskette drive type
7335 BX_DEBUG_INT13_FL("floppy f15\n");
7336 drive = GET_ELDL();
7337 if (drive > 1) {
7338 SET_AH(0); // only 2 drives supported
7339 // set_diskette_ret_status here ???
7340 SET_CF();
7341 return;
7343 drive_type = inb_cmos(0x10);
7345 if (drive == 0)
7346 drive_type >>= 4;
7347 else
7348 drive_type &= 0x0f;
7349 CLEAR_CF(); // successful, not present
7350 if (drive_type==0) {
7351 SET_AH(0); // drive not present
7353 else {
7354 SET_AH(1); // drive present, does not support change line
7357 return;
7359 case 0x16: // get diskette change line status
7360 BX_DEBUG_INT13_FL("floppy f16\n");
7361 drive = GET_ELDL();
7362 if (drive > 1) {
7363 SET_AH(0x01); // invalid drive
7364 set_diskette_ret_status(0x01);
7365 SET_CF();
7366 return;
7369 SET_AH(0x06); // change line not supported
7370 set_diskette_ret_status(0x06);
7371 SET_CF();
7372 return;
7374 case 0x17: // set diskette type for format(old)
7375 BX_DEBUG_INT13_FL("floppy f17\n");
7376 /* not used for 1.44M floppies */
7377 SET_AH(0x01); // not supported
7378 set_diskette_ret_status(1); /* not supported */
7379 SET_CF();
7380 return;
7382 case 0x18: // set diskette type for format(new)
7383 BX_DEBUG_INT13_FL("floppy f18\n");
7384 SET_AH(0x01); // do later
7385 set_diskette_ret_status(1);
7386 SET_CF();
7387 return;
7389 default:
7390 BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
7392 // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
7393 SET_AH(0x01); // ???
7394 set_diskette_ret_status(1);
7395 SET_CF();
7396 return;
7397 // }
7400 #else // #if BX_SUPPORT_FLOPPY
7401 void
7402 int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
7403 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
7405 Bit8u val8;
7407 switch ( GET_AH() ) {
7409 case 0x01: // Read Diskette Status
7410 CLEAR_CF();
7411 val8 = read_byte(0x0000, 0x0441);
7412 SET_AH(val8);
7413 if (val8) {
7414 SET_CF();
7416 return;
7418 default:
7419 SET_CF();
7420 write_byte(0x0000, 0x0441, 0x01);
7421 SET_AH(0x01);
7424 #endif // #if BX_SUPPORT_FLOPPY
7426 void
7427 set_diskette_ret_status(value)
7428 Bit8u value;
7430 write_byte(0x0040, 0x0041, value);
7433 void
7434 set_diskette_current_cyl(drive, cyl)
7435 Bit8u drive;
7436 Bit8u cyl;
7438 if (drive > 1)
7439 BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
7440 write_byte(0x0040, 0x0094+drive, cyl);
7443 void
7444 determine_floppy_media(drive)
7445 Bit16u drive;
7447 #if 0
7448 Bit8u val8, DOR, ctrl_info;
7450 ctrl_info = read_byte(0x0040, 0x008F);
7451 if (drive==1)
7452 ctrl_info >>= 4;
7453 else
7454 ctrl_info &= 0x0f;
7456 #if 0
7457 if (drive == 0) {
7458 DOR = 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
7460 else {
7461 DOR = 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
7463 #endif
7465 if ( (ctrl_info & 0x04) != 0x04 ) {
7466 // Drive not determined means no drive exists, done.
7467 return;
7470 #if 0
7471 // check Main Status Register for readiness
7472 val8 = inb(0x03f4) & 0x80; // Main Status Register
7473 if (val8 != 0x80)
7474 BX_PANIC("d_f_m: MRQ bit not set\n");
7476 // change line
7478 // existing BDA values
7480 // turn on drive motor
7481 outb(0x03f2, DOR); // Digital Output Register
7482 //
7483 #endif
7484 BX_PANIC("d_f_m: OK so far\n");
7485 #endif
7488 void
7489 int17_function(regs, ds, iret_addr)
7490 pusha_regs_t regs; // regs pushed from PUSHA instruction
7491 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
7492 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
7494 Bit16u addr,timeout;
7495 Bit8u val8;
7497 ASM_START
7498 sti
7499 ASM_END
7501 addr = read_word(0x0040, (regs.u.r16.dx << 1) + 8);
7502 if ((regs.u.r8.ah < 3) && (regs.u.r16.dx < 3) && (addr > 0)) {
7503 timeout = read_byte(0x0040, 0x0078 + regs.u.r16.dx) << 8;
7504 if (regs.u.r8.ah == 0) {
7505 outb(addr, regs.u.r8.al);
7506 val8 = inb(addr+2);
7507 outb(addr+2, val8 | 0x01); // send strobe
7508 ASM_START
7509 nop
7510 ASM_END
7511 outb(addr+2, val8 & ~0x01);
7512 while (((inb(addr+1) & 0x40) == 0x40) && (timeout)) {
7513 timeout--;
7516 if (regs.u.r8.ah == 1) {
7517 val8 = inb(addr+2);
7518 outb(addr+2, val8 & ~0x04); // send init
7519 ASM_START
7520 nop
7521 ASM_END
7522 outb(addr+2, val8 | 0x04);
7524 val8 = inb(addr+1);
7525 regs.u.r8.ah = (val8 ^ 0x48);
7526 if (!timeout) regs.u.r8.ah |= 0x01;
7527 ClearCF(iret_addr.flags);
7528 } else {
7529 SetCF(iret_addr.flags); // Unsupported
7533 // returns bootsegment in ax, drive in bl
7534 Bit32u
7535 int19_function(bseqnr)
7536 Bit8u bseqnr;
7538 Bit16u ebda_seg=read_word(0x0040,0x000E);
7539 Bit16u bootseq;
7540 Bit8u bootdrv;
7541 Bit8u bootcd;
7542 Bit8u bootchk;
7543 Bit16u bootseg;
7544 Bit16u status;
7545 Bit8u lastdrive=0;
7547 // if BX_ELTORITO_BOOT is not defined, old behavior
7548 // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
7549 // in preparation for the intial INT 13h (0=floppy A:, 0x80=C:)
7550 // 0: system boot sequence, first drive C: then A:
7551 // 1: system boot sequence, first drive A: then C:
7552 // else BX_ELTORITO_BOOT is defined
7553 // CMOS regs 0x3D and 0x38 contain the boot sequence:
7554 // CMOS reg 0x3D & 0x0f : 1st boot device
7555 // CMOS reg 0x3D & 0xf0 : 2nd boot device
7556 // CMOS reg 0x38 & 0xf0 : 3rd boot device
7557 // boot device codes:
7558 // 0x00 : not defined
7559 // 0x01 : first floppy
7560 // 0x02 : first harddrive
7561 // 0x03 : first cdrom
7562 // else : boot failure
7564 // Get the boot sequence
7565 #if BX_ELTORITO_BOOT
7566 bootseq=inb_cmos(0x3d);
7567 bootseq|=((inb_cmos(0x38) & 0xf0) << 4);
7569 if (bseqnr==2) bootseq >>= 4;
7570 if (bseqnr==3) bootseq >>= 8;
7571 if (bootseq<0x10) lastdrive = 1;
7572 bootdrv=0x00; bootcd=0;
7573 switch(bootseq & 0x0f) {
7574 case 0x01: bootdrv=0x00; bootcd=0; break;
7575 case 0x02: bootdrv=0x80; bootcd=0; break;
7576 case 0x03: bootdrv=0x00; bootcd=1; break;
7577 default: return 0x00000000;
7579 #else
7580 bootseq=inb_cmos(0x2d);
7582 if (bseqnr==2) {
7583 bootseq ^= 0x20;
7584 lastdrive = 1;
7586 bootdrv=0x00; bootcd=0;
7587 if((bootseq&0x20)==0) bootdrv=0x80;
7588 #endif // BX_ELTORITO_BOOT
7590 #if BX_ELTORITO_BOOT
7591 // We have to boot from cd
7592 if (bootcd != 0) {
7593 status = cdrom_boot();
7595 // If failure
7596 if ( (status & 0x00ff) !=0 ) {
7597 print_cdromboot_failure(status);
7598 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
7599 return 0x00000000;
7602 bootseg = read_word(ebda_seg,&EbdaData->cdemu.load_segment);
7603 bootdrv = (Bit8u)(status>>8);
7606 #endif // BX_ELTORITO_BOOT
7608 // We have to boot from harddisk or floppy
7609 if (bootcd == 0) {
7610 bootseg=0x07c0;
7612 ASM_START
7613 push bp
7614 mov bp, sp
7616 mov ax, #0x0000
7617 mov _int19_function.status + 2[bp], ax
7618 mov dl, _int19_function.bootdrv + 2[bp]
7619 mov ax, _int19_function.bootseg + 2[bp]
7620 mov es, ax ;; segment
7621 mov bx, #0x0000 ;; offset
7622 mov ah, #0x02 ;; function 2, read diskette sector
7623 mov al, #0x01 ;; read 1 sector
7624 mov ch, #0x00 ;; track 0
7625 mov cl, #0x01 ;; sector 1
7626 mov dh, #0x00 ;; head 0
7627 int #0x13 ;; read sector
7628 jnc int19_load_done
7629 mov ax, #0x0001
7630 mov _int19_function.status + 2[bp], ax
7632 int19_load_done:
7633 pop bp
7634 ASM_END
7636 if (status != 0) {
7637 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
7638 return 0x00000000;
7642 // check signature if instructed by cmos reg 0x38, only for floppy
7643 // bootchk = 1 : signature check disabled
7644 // bootchk = 0 : signature check enabled
7645 if (bootdrv != 0) bootchk = 0;
7646 else bootchk = inb_cmos(0x38) & 0x01;
7648 #if BX_ELTORITO_BOOT
7649 // if boot from cd, no signature check
7650 if (bootcd != 0)
7651 bootchk = 1;
7652 #endif // BX_ELTORITO_BOOT
7654 if (bootchk == 0) {
7655 if (read_word(bootseg,0x1fe) != 0xaa55) {
7656 print_boot_failure(bootcd, bootdrv, 0, lastdrive);
7657 return 0x00000000;
7661 #if BX_ELTORITO_BOOT
7662 // Print out the boot string
7663 print_boot_device(bootcd, bootdrv);
7664 #else // BX_ELTORITO_BOOT
7665 print_boot_device(0, bootdrv);
7666 #endif // BX_ELTORITO_BOOT
7668 // return the boot segment
7669 return (((Bit32u)bootdrv) << 16) + bootseg;
7672 void
7673 int1a_function(regs, ds, iret_addr)
7674 pusha_regs_t regs; // regs pushed from PUSHA instruction
7675 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
7676 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
7678 Bit8u val8;
7680 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);
7682 ASM_START
7683 sti
7684 ASM_END
7686 switch (regs.u.r8.ah) {
7687 case 0: // get current clock count
7688 ASM_START
7689 cli
7690 ASM_END
7691 regs.u.r16.cx = BiosData->ticks_high;
7692 regs.u.r16.dx = BiosData->ticks_low;
7693 regs.u.r8.al = BiosData->midnight_flag;
7694 BiosData->midnight_flag = 0; // reset flag
7695 ASM_START
7696 sti
7697 ASM_END
7698 // AH already 0
7699 ClearCF(iret_addr.flags); // OK
7700 break;
7702 case 1: // Set Current Clock Count
7703 ASM_START
7704 cli
7705 ASM_END
7706 BiosData->ticks_high = regs.u.r16.cx;
7707 BiosData->ticks_low = regs.u.r16.dx;
7708 BiosData->midnight_flag = 0; // reset flag
7709 ASM_START
7710 sti
7711 ASM_END
7712 regs.u.r8.ah = 0;
7713 ClearCF(iret_addr.flags); // OK
7714 break;
7717 case 2: // Read CMOS Time
7718 if (rtc_updating()) {
7719 SetCF(iret_addr.flags);
7720 break;
7723 regs.u.r8.dh = inb_cmos(0x00); // Seconds
7724 regs.u.r8.cl = inb_cmos(0x02); // Minutes
7725 regs.u.r8.ch = inb_cmos(0x04); // Hours
7726 regs.u.r8.dl = inb_cmos(0x0b) & 0x01; // Stat Reg B
7727 regs.u.r8.ah = 0;
7728 regs.u.r8.al = regs.u.r8.ch;
7729 ClearCF(iret_addr.flags); // OK
7730 break;
7732 case 3: // Set CMOS Time
7733 // Using a debugger, I notice the following masking/setting
7734 // of bits in Status Register B, by setting Reg B to
7735 // a few values and getting its value after INT 1A was called.
7736 //
7737 // try#1 try#2 try#3
7738 // before 1111 1101 0111 1101 0000 0000
7739 // after 0110 0010 0110 0010 0000 0010
7740 //
7741 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7742 // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
7743 if (rtc_updating()) {
7744 init_rtc();
7745 // fall through as if an update were not in progress
7747 outb_cmos(0x00, regs.u.r8.dh); // Seconds
7748 outb_cmos(0x02, regs.u.r8.cl); // Minutes
7749 outb_cmos(0x04, regs.u.r8.ch); // Hours
7750 // Set Daylight Savings time enabled bit to requested value
7751 val8 = (inb_cmos(0x0b) & 0x60) | 0x02 | (regs.u.r8.dl & 0x01);
7752 // (reg B already selected)
7753 outb_cmos(0x0b, val8);
7754 regs.u.r8.ah = 0;
7755 regs.u.r8.al = val8; // val last written to Reg B
7756 ClearCF(iret_addr.flags); // OK
7757 break;
7759 case 4: // Read CMOS Date
7760 regs.u.r8.ah = 0;
7761 if (rtc_updating()) {
7762 SetCF(iret_addr.flags);
7763 break;
7765 regs.u.r8.cl = inb_cmos(0x09); // Year
7766 regs.u.r8.dh = inb_cmos(0x08); // Month
7767 regs.u.r8.dl = inb_cmos(0x07); // Day of Month
7768 regs.u.r8.ch = inb_cmos(0x32); // Century
7769 regs.u.r8.al = regs.u.r8.ch;
7770 ClearCF(iret_addr.flags); // OK
7771 break;
7773 case 5: // Set CMOS Date
7774 // Using a debugger, I notice the following masking/setting
7775 // of bits in Status Register B, by setting Reg B to
7776 // a few values and getting its value after INT 1A was called.
7777 //
7778 // try#1 try#2 try#3 try#4
7779 // before 1111 1101 0111 1101 0000 0010 0000 0000
7780 // after 0110 1101 0111 1101 0000 0010 0000 0000
7781 //
7782 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7783 // My assumption: RegB = (RegB & 01111111b)
7784 if (rtc_updating()) {
7785 init_rtc();
7786 SetCF(iret_addr.flags);
7787 break;
7789 outb_cmos(0x09, regs.u.r8.cl); // Year
7790 outb_cmos(0x08, regs.u.r8.dh); // Month
7791 outb_cmos(0x07, regs.u.r8.dl); // Day of Month
7792 outb_cmos(0x32, regs.u.r8.ch); // Century
7793 val8 = inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
7794 outb_cmos(0x0b, val8);
7795 regs.u.r8.ah = 0;
7796 regs.u.r8.al = val8; // AL = val last written to Reg B
7797 ClearCF(iret_addr.flags); // OK
7798 break;
7800 case 6: // Set Alarm Time in CMOS
7801 // Using a debugger, I notice the following masking/setting
7802 // of bits in Status Register B, by setting Reg B to
7803 // a few values and getting its value after INT 1A was called.
7804 //
7805 // try#1 try#2 try#3
7806 // before 1101 1111 0101 1111 0000 0000
7807 // after 0110 1111 0111 1111 0010 0000
7808 //
7809 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7810 // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
7811 val8 = inb_cmos(0x0b); // Get Status Reg B
7812 regs.u.r16.ax = 0;
7813 if (val8 & 0x20) {
7814 // Alarm interrupt enabled already
7815 SetCF(iret_addr.flags); // Error: alarm in use
7816 break;
7818 if (rtc_updating()) {
7819 init_rtc();
7820 // fall through as if an update were not in progress
7822 outb_cmos(0x01, regs.u.r8.dh); // Seconds alarm
7823 outb_cmos(0x03, regs.u.r8.cl); // Minutes alarm
7824 outb_cmos(0x05, regs.u.r8.ch); // Hours alarm
7825 outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
7826 // enable Status Reg B alarm bit, clear halt clock bit
7827 outb_cmos(0x0b, (val8 & 0x7f) | 0x20);
7828 ClearCF(iret_addr.flags); // OK
7829 break;
7831 case 7: // Turn off Alarm
7832 // Using a debugger, I notice the following masking/setting
7833 // of bits in Status Register B, by setting Reg B to
7834 // a few values and getting its value after INT 1A was called.
7835 //
7836 // try#1 try#2 try#3 try#4
7837 // before 1111 1101 0111 1101 0010 0000 0010 0010
7838 // after 0100 0101 0101 0101 0000 0000 0000 0010
7839 //
7840 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7841 // My assumption: RegB = (RegB & 01010111b)
7842 val8 = inb_cmos(0x0b); // Get Status Reg B
7843 // clear clock-halt bit, disable alarm bit
7844 outb_cmos(0x0b, val8 & 0x57); // disable alarm bit
7845 regs.u.r8.ah = 0;
7846 regs.u.r8.al = val8; // val last written to Reg B
7847 ClearCF(iret_addr.flags); // OK
7848 break;
7849 #if BX_PCIBIOS
7850 case 0xb1:
7851 // real mode PCI BIOS functions now handled in assembler code
7852 // this C code handles the error code for information only
7853 if (regs.u.r8.bl == 0xff) {
7854 BX_INFO("PCI BIOS: PCI not present\n");
7855 } else if (regs.u.r8.bl == 0x81) {
7856 BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs.u.r8.al);
7857 } else if (regs.u.r8.bl == 0x83) {
7858 BX_INFO("bad PCI vendor ID %04x\n", regs.u.r16.dx);
7859 } else if (regs.u.r8.bl == 0x86) {
7860 BX_INFO("PCI device %04x:%04x not found\n", regs.u.r16.dx, regs.u.r16.cx);
7862 regs.u.r8.ah = regs.u.r8.bl;
7863 SetCF(iret_addr.flags);
7864 break;
7865 #endif
7867 default:
7868 SetCF(iret_addr.flags); // Unsupported
7872 void
7873 int70_function(regs, ds, iret_addr)
7874 pusha_regs_t regs; // regs pushed from PUSHA instruction
7875 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
7876 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
7878 // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
7879 Bit8u registerB = 0, registerC = 0;
7881 // Check which modes are enabled and have occurred.
7882 registerB = inb_cmos( 0xB );
7883 registerC = inb_cmos( 0xC );
7885 if( ( registerB & 0x60 ) != 0 ) {
7886 if( ( registerC & 0x20 ) != 0 ) {
7887 // Handle Alarm Interrupt.
7888 ASM_START
7889 sti
7890 int #0x4a
7891 cli
7892 ASM_END
7894 if( ( registerC & 0x40 ) != 0 ) {
7895 // Handle Periodic Interrupt.
7897 if( read_byte( 0x40, 0xA0 ) != 0 ) {
7898 // Wait Interval (Int 15, AH=83) active.
7899 Bit32u time, toggle;
7901 time = read_dword( 0x40, 0x9C ); // Time left in microseconds.
7902 if( time < 0x3D1 ) {
7903 // Done waiting.
7904 Bit16u segment, offset;
7906 offset = read_word( 0x40, 0x98 );
7907 segment = read_word( 0x40, 0x9A );
7908 write_byte( 0x40, 0xA0, 0 ); // Turn of status byte.
7909 outb_cmos( 0xB, registerB & 0x37 ); // Clear the Periodic Interrupt.
7910 write_byte( segment, offset, 0x80 ); // Write to specified flag byte.
7911 } else {
7912 // Continue waiting.
7913 time -= 0x3D1;
7914 write_dword( 0x40, 0x9C, time );
7920 ASM_START
7921 call eoi_both_pics
7922 ASM_END
7926 ASM_START
7927 ;------------------------------------------
7928 ;- INT74h : PS/2 mouse hardware interrupt -
7929 ;------------------------------------------
7930 int74_handler:
7931 sti
7932 pusha
7933 push ds ;; save DS
7934 push #0x00 ;; placeholder for status
7935 push #0x00 ;; placeholder for X
7936 push #0x00 ;; placeholder for Y
7937 push #0x00 ;; placeholder for Z
7938 push #0x00 ;; placeholder for make_far_call boolean
7939 call _int74_function
7940 pop cx ;; remove make_far_call from stack
7941 jcxz int74_done
7943 ;; make far call to EBDA:0022
7944 push #0x00
7945 pop ds
7946 push 0x040E ;; push 0000:040E (opcodes 0xff, 0x36, 0x0E, 0x04)
7947 pop ds
7948 //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
7949 call far ptr[0x22]
7950 int74_done:
7951 cli
7952 call eoi_both_pics
7953 add sp, #8 ;; pop status, x, y, z
7955 pop ds ;; restore DS
7956 popa
7957 iret
7960 ;; This will perform an IRET, but will retain value of current CF
7961 ;; by altering flags on stack. Better than RETF #02.
7962 iret_modify_cf:
7963 jc carry_set
7964 push bp
7965 mov bp, sp
7966 and BYTE [bp + 0x06], #0xfe
7967 pop bp
7968 iret
7969 carry_set:
7970 push bp
7971 mov bp, sp
7972 or BYTE [bp + 0x06], #0x01
7973 pop bp
7974 iret
7977 ;----------------------
7978 ;- INT13h (relocated) -
7979 ;----------------------
7981 ; int13_relocated is a little bit messed up since I played with it
7982 ; I have to rewrite it:
7983 ; - call a function that detect which function to call
7984 ; - make all called C function get the same parameters list
7986 int13_relocated:
7988 #if BX_ELTORITO_BOOT
7989 ;; check for an eltorito function
7990 cmp ah,#0x4a
7991 jb int13_not_eltorito
7992 cmp ah,#0x4d
7993 ja int13_not_eltorito
7995 pusha
7996 push es
7997 push ds
7998 push ss
7999 pop ds
8001 push #int13_out
8002 jmp _int13_eltorito ;; ELDX not used
8004 int13_not_eltorito:
8005 push ax
8006 push bx
8007 push cx
8008 push dx
8010 ;; check if emulation active
8011 call _cdemu_isactive
8012 cmp al,#0x00
8013 je int13_cdemu_inactive
8015 ;; check if access to the emulated drive
8016 call _cdemu_emulated_drive
8017 pop dx
8018 push dx
8019 cmp al,dl ;; int13 on emulated drive
8020 jne int13_nocdemu
8022 pop dx
8023 pop cx
8024 pop bx
8025 pop ax
8027 pusha
8028 push es
8029 push ds
8030 push ss
8031 pop ds
8033 push #int13_out
8034 jmp _int13_cdemu ;; ELDX not used
8036 int13_nocdemu:
8037 and dl,#0xE0 ;; mask to get device class, including cdroms
8038 cmp al,dl ;; al is 0x00 or 0x80
8039 jne int13_cdemu_inactive ;; inactive for device class
8041 pop dx
8042 pop cx
8043 pop bx
8044 pop ax
8046 push ax
8047 push cx
8048 push dx
8049 push bx
8051 dec dl ;; real drive is dl - 1
8052 jmp int13_legacy
8054 int13_cdemu_inactive:
8055 pop dx
8056 pop cx
8057 pop bx
8058 pop ax
8060 #endif // BX_ELTORITO_BOOT
8062 int13_noeltorito:
8064 push ax
8065 push cx
8066 push dx
8067 push bx
8069 int13_legacy:
8071 push dx ;; push eltorito value of dx instead of sp
8073 push bp
8074 push si
8075 push di
8077 push es
8078 push ds
8079 push ss
8080 pop ds
8082 ;; now the 16-bit registers can be restored with:
8083 ;; pop ds; pop es; popa; iret
8084 ;; arguments passed to functions should be
8085 ;; DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS
8087 test dl, #0x80
8088 jnz int13_notfloppy
8090 push #int13_out
8091 jmp _int13_diskette_function
8093 int13_notfloppy:
8095 #if BX_USE_ATADRV
8097 cmp dl, #0xE0
8098 jb int13_notcdrom
8100 // ebx is modified: BSD 5.2.1 boot loader problem
8101 // someone should figure out which 32 bit register that actually are used
8103 shr ebx, #16
8104 push bx
8106 call _int13_cdrom
8108 pop bx
8109 shl ebx, #16
8111 jmp int13_out
8113 int13_notcdrom:
8115 #endif
8117 int13_disk:
8118 call _int13_harddisk
8120 int13_out:
8121 pop ds
8122 pop es
8123 popa
8124 iret
8127 ;----------
8128 ;- INT18h -
8129 ;----------
8130 int18_handler: ;; Boot Failure routing
8131 call _int18_panic_msg
8132 hlt
8133 iret
8135 ;----------
8136 ;- INT19h -
8137 ;----------
8138 int19_relocated: ;; Boot function, relocated
8140 ;; int19 was beginning to be really complex, so now it
8141 ;; just calls an C function, that does the work
8142 ;; it returns in BL the boot drive, and in AX the boot segment
8143 ;; the boot segment will be 0x0000 if something has failed
8145 push bp
8146 mov bp, sp
8148 ;; drop ds
8149 xor ax, ax
8150 mov ds, ax
8152 ;; 1st boot device
8153 mov ax, #0x0001
8154 push ax
8155 call _int19_function
8156 inc sp
8157 inc sp
8158 ;; bl contains the boot drive
8159 ;; ax contains the boot segment or 0 if failure
8161 test ax, ax ;; if ax is 0 try next boot device
8162 jnz boot_setup
8164 ;; 2nd boot device
8165 mov ax, #0x0002
8166 push ax
8167 call _int19_function
8168 inc sp
8169 inc sp
8170 test ax, ax ;; if ax is 0 try next boot device
8171 jnz boot_setup
8173 ;; 3rd boot device
8174 mov ax, #0x0003
8175 push ax
8176 call _int19_function
8177 inc sp
8178 inc sp
8179 test ax, ax ;; if ax is 0 call int18
8180 jz int18_handler
8182 boot_setup:
8183 mov dl, bl ;; set drive so guest os find it
8184 shl eax, #0x04 ;; convert seg to ip
8185 mov 2[bp], ax ;; set ip
8187 shr eax, #0x04 ;; get cs back
8188 and ax, #0xF000 ;; remove what went in ip
8189 mov 4[bp], ax ;; set cs
8190 xor ax, ax
8191 mov es, ax ;; set es to zero fixes [ 549815 ]
8192 mov [bp], ax ;; set bp to zero
8193 mov ax, #0xaa55 ;; set ok flag
8195 pop bp
8196 iret ;; Beam me up Scotty
8198 ;----------
8199 ;- INT1Ch -
8200 ;----------
8201 int1c_handler: ;; User Timer Tick
8202 iret
8205 ;----------------------
8206 ;- POST: Floppy Drive -
8207 ;----------------------
8208 floppy_drive_post:
8209 mov ax, #0x0000
8210 mov ds, ax
8212 mov al, #0x00
8213 mov 0x043e, al ;; drive 0 & 1 uncalibrated, no interrupt has occurred
8215 mov 0x043f, al ;; diskette motor status: read op, drive0, motors off
8217 mov 0x0440, al ;; diskette motor timeout counter: not active
8218 mov 0x0441, al ;; diskette controller status return code
8220 mov 0x0442, al ;; disk & diskette controller status register 0
8221 mov 0x0443, al ;; diskette controller status register 1
8222 mov 0x0444, al ;; diskette controller status register 2
8223 mov 0x0445, al ;; diskette controller cylinder number
8224 mov 0x0446, al ;; diskette controller head number
8225 mov 0x0447, al ;; diskette controller sector number
8226 mov 0x0448, al ;; diskette controller bytes written
8228 mov 0x048b, al ;; diskette configuration data
8230 ;; -----------------------------------------------------------------
8231 ;; (048F) diskette controller information
8232 ;;
8233 mov al, #0x10 ;; get CMOS diskette drive type
8234 out 0x70, AL
8235 in AL, 0x71
8236 mov ah, al ;; save byte to AH
8238 look_drive0:
8239 shr al, #4 ;; look at top 4 bits for drive 0
8240 jz f0_missing ;; jump if no drive0
8241 mov bl, #0x07 ;; drive0 determined, multi-rate, has changed line
8242 jmp look_drive1
8243 f0_missing:
8244 mov bl, #0x00 ;; no drive0
8246 look_drive1:
8247 mov al, ah ;; restore from AH
8248 and al, #0x0f ;; look at bottom 4 bits for drive 1
8249 jz f1_missing ;; jump if no drive1
8250 or bl, #0x70 ;; drive1 determined, multi-rate, has changed line
8251 f1_missing:
8252 ;; leave high bits in BL zerod
8253 mov 0x048f, bl ;; put new val in BDA (diskette controller information)
8254 ;; -----------------------------------------------------------------
8256 mov al, #0x00
8257 mov 0x0490, al ;; diskette 0 media state
8258 mov 0x0491, al ;; diskette 1 media state
8260 ;; diskette 0,1 operational starting state
8261 ;; drive type has not been determined,
8262 ;; has no changed detection line
8263 mov 0x0492, al
8264 mov 0x0493, al
8266 mov 0x0494, al ;; diskette 0 current cylinder
8267 mov 0x0495, al ;; diskette 1 current cylinder
8269 mov al, #0x02
8270 out #0x0a, al ;; clear DMA-1 channel 2 mask bit
8272 SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
8273 SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
8274 SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
8276 ret
8279 ;--------------------
8280 ;- POST: HARD DRIVE -
8281 ;--------------------
8282 ; relocated here because the primary POST area isnt big enough.
8283 hard_drive_post:
8284 // IRQ 14 = INT 76h
8285 // INT 76h calls INT 15h function ax=9100
8287 mov al, #0x0a ; 0000 1010 = reserved, disable IRQ 14
8288 mov dx, #0x03f6
8289 out dx, al
8291 mov ax, #0x0000
8292 mov ds, ax
8293 mov 0x0474, al /* hard disk status of last operation */
8294 mov 0x0477, al /* hard disk port offset (XT only ???) */
8295 mov 0x048c, al /* hard disk status register */
8296 mov 0x048d, al /* hard disk error register */
8297 mov 0x048e, al /* hard disk task complete flag */
8298 mov al, #0x01
8299 mov 0x0475, al /* hard disk number attached */
8300 mov al, #0xc0
8301 mov 0x0476, al /* hard disk control byte */
8302 SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
8303 SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
8304 ;; INT 41h: hard disk 0 configuration pointer
8305 ;; INT 46h: hard disk 1 configuration pointer
8306 SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D)
8307 SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D)
8309 ;; move disk geometry data from CMOS to EBDA disk parameter table(s)
8310 mov al, #0x12
8311 out #0x70, al
8312 in al, #0x71
8313 and al, #0xf0
8314 cmp al, #0xf0
8315 je post_d0_extended
8316 jmp check_for_hd1
8317 post_d0_extended:
8318 mov al, #0x19
8319 out #0x70, al
8320 in al, #0x71
8321 cmp al, #47 ;; decimal 47 - user definable
8322 je post_d0_type47
8323 HALT(__LINE__)
8324 post_d0_type47:
8325 ;; CMOS purpose param table offset
8326 ;; 1b cylinders low 0
8327 ;; 1c cylinders high 1
8328 ;; 1d heads 2
8329 ;; 1e write pre-comp low 5
8330 ;; 1f write pre-comp high 6
8331 ;; 20 retries/bad map/heads>8 8
8332 ;; 21 landing zone low C
8333 ;; 22 landing zone high D
8334 ;; 23 sectors/track E
8336 mov ax, #EBDA_SEG
8337 mov ds, ax
8339 ;;; Filling EBDA table for hard disk 0.
8340 mov al, #0x1f
8341 out #0x70, al
8342 in al, #0x71
8343 mov ah, al
8344 mov al, #0x1e
8345 out #0x70, al
8346 in al, #0x71
8347 mov (0x003d + 0x05), ax ;; write precomp word
8349 mov al, #0x20
8350 out #0x70, al
8351 in al, #0x71
8352 mov (0x003d + 0x08), al ;; drive control byte
8354 mov al, #0x22
8355 out #0x70, al
8356 in al, #0x71
8357 mov ah, al
8358 mov al, #0x21
8359 out #0x70, al
8360 in al, #0x71
8361 mov (0x003d + 0x0C), ax ;; landing zone word
8363 mov al, #0x1c ;; get cylinders word in AX
8364 out #0x70, al
8365 in al, #0x71 ;; high byte
8366 mov ah, al
8367 mov al, #0x1b
8368 out #0x70, al
8369 in al, #0x71 ;; low byte
8370 mov bx, ax ;; BX = cylinders
8372 mov al, #0x1d
8373 out #0x70, al
8374 in al, #0x71
8375 mov cl, al ;; CL = heads
8377 mov al, #0x23
8378 out #0x70, al
8379 in al, #0x71
8380 mov dl, al ;; DL = sectors
8382 cmp bx, #1024
8383 jnbe hd0_post_logical_chs ;; if cylinders > 1024, use translated style CHS
8385 hd0_post_physical_chs:
8386 ;; no logical CHS mapping used, just physical CHS
8387 ;; use Standard Fixed Disk Parameter Table (FDPT)
8388 mov (0x003d + 0x00), bx ;; number of physical cylinders
8389 mov (0x003d + 0x02), cl ;; number of physical heads
8390 mov (0x003d + 0x0E), dl ;; number of physical sectors
8391 jmp check_for_hd1
8393 hd0_post_logical_chs:
8394 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
8395 mov (0x003d + 0x09), bx ;; number of physical cylinders
8396 mov (0x003d + 0x0b), cl ;; number of physical heads
8397 mov (0x003d + 0x04), dl ;; number of physical sectors
8398 mov (0x003d + 0x0e), dl ;; number of logical sectors (same)
8399 mov al, #0xa0
8400 mov (0x003d + 0x03), al ;; A0h signature, indicates translated table
8402 cmp bx, #2048
8403 jnbe hd0_post_above_2048
8404 ;; 1024 < c <= 2048 cylinders
8405 shr bx, #0x01
8406 shl cl, #0x01
8407 jmp hd0_post_store_logical
8409 hd0_post_above_2048:
8410 cmp bx, #4096
8411 jnbe hd0_post_above_4096
8412 ;; 2048 < c <= 4096 cylinders
8413 shr bx, #0x02
8414 shl cl, #0x02
8415 jmp hd0_post_store_logical
8417 hd0_post_above_4096:
8418 cmp bx, #8192
8419 jnbe hd0_post_above_8192
8420 ;; 4096 < c <= 8192 cylinders
8421 shr bx, #0x03
8422 shl cl, #0x03
8423 jmp hd0_post_store_logical
8425 hd0_post_above_8192:
8426 ;; 8192 < c <= 16384 cylinders
8427 shr bx, #0x04
8428 shl cl, #0x04
8430 hd0_post_store_logical:
8431 mov (0x003d + 0x00), bx ;; number of physical cylinders
8432 mov (0x003d + 0x02), cl ;; number of physical heads
8433 ;; checksum
8434 mov cl, #0x0f ;; repeat count
8435 mov si, #0x003d ;; offset to disk0 FDPT
8436 mov al, #0x00 ;; sum
8437 hd0_post_checksum_loop:
8438 add al, [si]
8439 inc si
8440 dec cl
8441 jnz hd0_post_checksum_loop
8442 not al ;; now take 2s complement
8443 inc al
8444 mov [si], al
8445 ;;; Done filling EBDA table for hard disk 0.
8448 check_for_hd1:
8449 ;; is there really a second hard disk? if not, return now
8450 mov al, #0x12
8451 out #0x70, al
8452 in al, #0x71
8453 and al, #0x0f
8454 jnz post_d1_exists
8455 ret
8456 post_d1_exists:
8457 ;; check that the hd type is really 0x0f.
8458 cmp al, #0x0f
8459 jz post_d1_extended
8460 HALT(__LINE__)
8461 post_d1_extended:
8462 ;; check that the extended type is 47 - user definable
8463 mov al, #0x1a
8464 out #0x70, al
8465 in al, #0x71
8466 cmp al, #47 ;; decimal 47 - user definable
8467 je post_d1_type47
8468 HALT(__LINE__)
8469 post_d1_type47:
8470 ;; Table for disk1.
8471 ;; CMOS purpose param table offset
8472 ;; 0x24 cylinders low 0
8473 ;; 0x25 cylinders high 1
8474 ;; 0x26 heads 2
8475 ;; 0x27 write pre-comp low 5
8476 ;; 0x28 write pre-comp high 6
8477 ;; 0x29 heads>8 8
8478 ;; 0x2a landing zone low C
8479 ;; 0x2b landing zone high D
8480 ;; 0x2c sectors/track E
8481 ;;; Fill EBDA table for hard disk 1.
8482 mov ax, #EBDA_SEG
8483 mov ds, ax
8484 mov al, #0x28
8485 out #0x70, al
8486 in al, #0x71
8487 mov ah, al
8488 mov al, #0x27
8489 out #0x70, al
8490 in al, #0x71
8491 mov (0x004d + 0x05), ax ;; write precomp word
8493 mov al, #0x29
8494 out #0x70, al
8495 in al, #0x71
8496 mov (0x004d + 0x08), al ;; drive control byte
8498 mov al, #0x2b
8499 out #0x70, al
8500 in al, #0x71
8501 mov ah, al
8502 mov al, #0x2a
8503 out #0x70, al
8504 in al, #0x71
8505 mov (0x004d + 0x0C), ax ;; landing zone word
8507 mov al, #0x25 ;; get cylinders word in AX
8508 out #0x70, al
8509 in al, #0x71 ;; high byte
8510 mov ah, al
8511 mov al, #0x24
8512 out #0x70, al
8513 in al, #0x71 ;; low byte
8514 mov bx, ax ;; BX = cylinders
8516 mov al, #0x26
8517 out #0x70, al
8518 in al, #0x71
8519 mov cl, al ;; CL = heads
8521 mov al, #0x2c
8522 out #0x70, al
8523 in al, #0x71
8524 mov dl, al ;; DL = sectors
8526 cmp bx, #1024
8527 jnbe hd1_post_logical_chs ;; if cylinders > 1024, use translated style CHS
8529 hd1_post_physical_chs:
8530 ;; no logical CHS mapping used, just physical CHS
8531 ;; use Standard Fixed Disk Parameter Table (FDPT)
8532 mov (0x004d + 0x00), bx ;; number of physical cylinders
8533 mov (0x004d + 0x02), cl ;; number of physical heads
8534 mov (0x004d + 0x0E), dl ;; number of physical sectors
8535 ret
8537 hd1_post_logical_chs:
8538 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
8539 mov (0x004d + 0x09), bx ;; number of physical cylinders
8540 mov (0x004d + 0x0b), cl ;; number of physical heads
8541 mov (0x004d + 0x04), dl ;; number of physical sectors
8542 mov (0x004d + 0x0e), dl ;; number of logical sectors (same)
8543 mov al, #0xa0
8544 mov (0x004d + 0x03), al ;; A0h signature, indicates translated table
8546 cmp bx, #2048
8547 jnbe hd1_post_above_2048
8548 ;; 1024 < c <= 2048 cylinders
8549 shr bx, #0x01
8550 shl cl, #0x01
8551 jmp hd1_post_store_logical
8553 hd1_post_above_2048:
8554 cmp bx, #4096
8555 jnbe hd1_post_above_4096
8556 ;; 2048 < c <= 4096 cylinders
8557 shr bx, #0x02
8558 shl cl, #0x02
8559 jmp hd1_post_store_logical
8561 hd1_post_above_4096:
8562 cmp bx, #8192
8563 jnbe hd1_post_above_8192
8564 ;; 4096 < c <= 8192 cylinders
8565 shr bx, #0x03
8566 shl cl, #0x03
8567 jmp hd1_post_store_logical
8569 hd1_post_above_8192:
8570 ;; 8192 < c <= 16384 cylinders
8571 shr bx, #0x04
8572 shl cl, #0x04
8574 hd1_post_store_logical:
8575 mov (0x004d + 0x00), bx ;; number of physical cylinders
8576 mov (0x004d + 0x02), cl ;; number of physical heads
8577 ;; checksum
8578 mov cl, #0x0f ;; repeat count
8579 mov si, #0x004d ;; offset to disk0 FDPT
8580 mov al, #0x00 ;; sum
8581 hd1_post_checksum_loop:
8582 add al, [si]
8583 inc si
8584 dec cl
8585 jnz hd1_post_checksum_loop
8586 not al ;; now take 2s complement
8587 inc al
8588 mov [si], al
8589 ;;; Done filling EBDA table for hard disk 1.
8591 ret
8593 ;--------------------
8594 ;- POST: EBDA segment
8595 ;--------------------
8596 ; relocated here because the primary POST area isnt big enough.
8597 ebda_post:
8598 #if BX_USE_EBDA
8599 mov ax, #EBDA_SEG
8600 mov ds, ax
8601 mov byte ptr [0x0], #EBDA_SIZE
8602 #endif
8603 xor ax, ax ; mov EBDA seg into 40E
8604 mov ds, ax
8605 mov word ptr [0x40E], #EBDA_SEG
8606 ret;;
8608 ;--------------------
8609 ;- POST: EOI + jmp via [0x40:67)
8610 ;--------------------
8611 ; relocated here because the primary POST area isnt big enough.
8612 eoi_jmp_post:
8613 call eoi_both_pics
8615 xor ax, ax
8616 mov ds, ax
8618 jmp far ptr [0x467]
8621 ;--------------------
8622 eoi_both_pics:
8623 mov al, #0x20
8624 out #0xA0, al ;; slave PIC EOI
8625 eoi_master_pic:
8626 mov al, #0x20
8627 out #0x20, al ;; master PIC EOI
8628 ret
8630 ;--------------------
8631 BcdToBin:
8632 ;; in: AL in BCD format
8633 ;; out: AL in binary format, AH will always be 0
8634 ;; trashes BX
8635 mov bl, al
8636 and bl, #0x0f ;; bl has low digit
8637 shr al, #4 ;; al has high digit
8638 mov bh, #10
8639 mul al, bh ;; multiply high digit by 10 (result in AX)
8640 add al, bl ;; then add low digit
8641 ret
8643 ;--------------------
8644 timer_tick_post:
8645 ;; Setup the Timer Ticks Count (0x46C:dword) and
8646 ;; Timer Ticks Roller Flag (0x470:byte)
8647 ;; The Timer Ticks Count needs to be set according to
8648 ;; the current CMOS time, as if ticks have been occurring
8649 ;; at 18.2hz since midnight up to this point. Calculating
8650 ;; this is a little complicated. Here are the factors I gather
8651 ;; regarding this. 14,318,180 hz was the original clock speed,
8652 ;; chosen so it could be divided by either 3 to drive the 5Mhz CPU
8653 ;; at the time, or 4 to drive the CGA video adapter. The div3
8654 ;; source was divided again by 4 to feed a 1.193Mhz signal to
8655 ;; the timer. With a maximum 16bit timer count, this is again
8656 ;; divided down by 65536 to 18.2hz.
8657 ;;
8658 ;; 14,318,180 Hz clock
8659 ;; /3 = 4,772,726 Hz fed to orginal 5Mhz CPU
8660 ;; /4 = 1,193,181 Hz fed to timer
8661 ;; /65536 (maximum timer count) = 18.20650736 ticks/second
8662 ;; 1 second = 18.20650736 ticks
8663 ;; 1 minute = 1092.390442 ticks
8664 ;; 1 hour = 65543.42651 ticks
8665 ;;
8666 ;; Given the values in the CMOS clock, one could calculate
8667 ;; the number of ticks by the following:
8668 ;; ticks = (BcdToBin(seconds) * 18.206507) +
8669 ;; (BcdToBin(minutes) * 1092.3904)
8670 ;; (BcdToBin(hours) * 65543.427)
8671 ;; To get a little more accuracy, since Im using integer
8672 ;; arithmatic, I use:
8673 ;; ticks = (BcdToBin(seconds) * 18206507) / 1000000 +
8674 ;; (BcdToBin(minutes) * 10923904) / 10000 +
8675 ;; (BcdToBin(hours) * 65543427) / 1000
8677 ;; assuming DS=0000
8679 ;; get CMOS seconds
8680 xor eax, eax ;; clear EAX
8681 mov al, #0x00
8682 out #0x70, al
8683 in al, #0x71 ;; AL has CMOS seconds in BCD
8684 call BcdToBin ;; EAX now has seconds in binary
8685 mov edx, #18206507
8686 mul eax, edx
8687 mov ebx, #1000000
8688 xor edx, edx
8689 div eax, ebx
8690 mov ecx, eax ;; ECX will accumulate total ticks
8692 ;; get CMOS minutes
8693 xor eax, eax ;; clear EAX
8694 mov al, #0x02
8695 out #0x70, al
8696 in al, #0x71 ;; AL has CMOS minutes in BCD
8697 call BcdToBin ;; EAX now has minutes in binary
8698 mov edx, #10923904
8699 mul eax, edx
8700 mov ebx, #10000
8701 xor edx, edx
8702 div eax, ebx
8703 add ecx, eax ;; add to total ticks
8705 ;; get CMOS hours
8706 xor eax, eax ;; clear EAX
8707 mov al, #0x04
8708 out #0x70, al
8709 in al, #0x71 ;; AL has CMOS hours in BCD
8710 call BcdToBin ;; EAX now has hours in binary
8711 mov edx, #65543427
8712 mul eax, edx
8713 mov ebx, #1000
8714 xor edx, edx
8715 div eax, ebx
8716 add ecx, eax ;; add to total ticks
8718 mov 0x46C, ecx ;; Timer Ticks Count
8719 xor al, al
8720 mov 0x470, al ;; Timer Ticks Rollover Flag
8721 ret
8723 ;--------------------
8724 int76_handler:
8725 ;; record completion in BIOS task complete flag
8726 push ax
8727 push ds
8728 mov ax, #0x0040
8729 mov ds, ax
8730 mov 0x008E, #0xff
8731 call eoi_both_pics
8732 pop ds
8733 pop ax
8734 iret
8737 ;--------------------
8738 #if BX_APM
8740 use32 386
8741 #define APM_PROT32
8742 #include "apmbios.S"
8744 use16 386
8745 #define APM_PROT16
8746 #include "apmbios.S"
8748 #define APM_REAL
8749 #include "apmbios.S"
8751 #endif
8753 ;--------------------
8754 #if BX_PCIBIOS
8755 use32 386
8756 .align 16
8757 bios32_structure:
8758 db 0x5f, 0x33, 0x32, 0x5f ;; "_32_" signature
8759 dw bios32_entry_point, 0xf ;; 32 bit physical address
8760 db 0 ;; revision level
8761 ;; length in paragraphs and checksum stored in a word to prevent errors
8762 dw (~(((bios32_entry_point >> 8) + (bios32_entry_point & 0xff) + 0x32) \
8763 & 0xff) << 8) + 0x01
8764 db 0,0,0,0,0 ;; reserved
8766 .align 16
8767 bios32_entry_point:
8768 pushf
8769 cmp eax, #0x49435024
8770 jne unknown_service
8771 mov eax, #0x80000000
8772 mov dx, #0x0cf8
8773 out dx, eax
8774 mov dx, #0x0cfc
8775 in eax, dx
8776 cmp eax, #0x12378086
8777 jne unknown_service
8778 mov ebx, #0x000f0000
8779 mov ecx, #0
8780 mov edx, #pcibios_protected
8781 xor al, al
8782 jmp bios32_end
8783 unknown_service:
8784 mov al, #0x80
8785 bios32_end:
8786 popf
8787 retf
8789 .align 16
8790 pcibios_protected:
8791 pushf
8792 cli
8793 push esi
8794 push edi
8795 cmp al, #0x01 ;; installation check
8796 jne pci_pro_f02
8797 mov bx, #0x0210
8798 mov cx, #0
8799 mov edx, #0x20494350
8800 mov al, #0x01
8801 jmp pci_pro_ok
8802 pci_pro_f02: ;; find pci device
8803 cmp al, #0x02
8804 jne pci_pro_f08
8805 shl ecx, #16
8806 mov cx, dx
8807 mov bx, #0x0000
8808 mov di, #0x00
8809 pci_pro_devloop:
8810 call pci_pro_select_reg
8811 mov dx, #0x0cfc
8812 in eax, dx
8813 cmp eax, ecx
8814 jne pci_pro_nextdev
8815 cmp si, #0
8816 je pci_pro_ok
8817 dec si
8818 pci_pro_nextdev:
8819 inc bx
8820 cmp bx, #0x0100
8821 jne pci_pro_devloop
8822 mov ah, #0x86
8823 jmp pci_pro_fail
8824 pci_pro_f08: ;; read configuration byte
8825 cmp al, #0x08
8826 jne pci_pro_f09
8827 call pci_pro_select_reg
8828 push edx
8829 mov dx, di
8830 and dx, #0x03
8831 add dx, #0x0cfc
8832 in al, dx
8833 pop edx
8834 mov cl, al
8835 jmp pci_pro_ok
8836 pci_pro_f09: ;; read configuration word
8837 cmp al, #0x09
8838 jne pci_pro_f0a
8839 call pci_pro_select_reg
8840 push edx
8841 mov dx, di
8842 and dx, #0x02
8843 add dx, #0x0cfc
8844 in ax, dx
8845 pop edx
8846 mov cx, ax
8847 jmp pci_pro_ok
8848 pci_pro_f0a: ;; read configuration dword
8849 cmp al, #0x0a
8850 jne pci_pro_f0b
8851 call pci_pro_select_reg
8852 push edx
8853 mov dx, #0x0cfc
8854 in eax, dx
8855 pop edx
8856 mov ecx, eax
8857 jmp pci_pro_ok
8858 pci_pro_f0b: ;; write configuration byte
8859 cmp al, #0x0b
8860 jne pci_pro_f0c
8861 call pci_pro_select_reg
8862 push edx
8863 mov dx, di
8864 and dx, #0x03
8865 add dx, #0x0cfc
8866 mov al, cl
8867 out dx, al
8868 pop edx
8869 jmp pci_pro_ok
8870 pci_pro_f0c: ;; write configuration word
8871 cmp al, #0x0c
8872 jne pci_pro_f0d
8873 call pci_pro_select_reg
8874 push edx
8875 mov dx, di
8876 and dx, #0x02
8877 add dx, #0x0cfc
8878 mov ax, cx
8879 out dx, ax
8880 pop edx
8881 jmp pci_pro_ok
8882 pci_pro_f0d: ;; write configuration dword
8883 cmp al, #0x0d
8884 jne pci_pro_unknown
8885 call pci_pro_select_reg
8886 push edx
8887 mov dx, #0x0cfc
8888 mov eax, ecx
8889 out dx, eax
8890 pop edx
8891 jmp pci_pro_ok
8892 pci_pro_unknown:
8893 mov ah, #0x81
8894 pci_pro_fail:
8895 pop edi
8896 pop esi
8897 sti
8898 popf
8899 stc
8900 retf
8901 pci_pro_ok:
8902 xor ah, ah
8903 pop edi
8904 pop esi
8905 sti
8906 popf
8907 clc
8908 retf
8910 pci_pro_select_reg:
8911 push edx
8912 mov eax, #0x800000
8913 mov ax, bx
8914 shl eax, #8
8915 and di, #0xff
8916 or ax, di
8917 and al, #0xfc
8918 mov dx, #0x0cf8
8919 out dx, eax
8920 pop edx
8921 ret
8923 use16 386
8925 pcibios_real:
8926 push eax
8927 push dx
8928 mov eax, #0x80000000
8929 mov dx, #0x0cf8
8930 out dx, eax
8931 mov dx, #0x0cfc
8932 in eax, dx
8933 cmp eax, #0x12378086
8934 je pci_present
8935 pop dx
8936 pop eax
8937 mov ah, #0xff
8938 stc
8939 ret
8940 pci_present:
8941 pop dx
8942 pop eax
8943 cmp al, #0x01 ;; installation check
8944 jne pci_real_f02
8945 mov ax, #0x0001
8946 mov bx, #0x0210
8947 mov cx, #0
8948 mov edx, #0x20494350
8949 mov edi, #0xf0000
8950 mov di, #pcibios_protected
8951 clc
8952 ret
8953 pci_real_f02: ;; find pci device
8954 push esi
8955 push edi
8956 cmp al, #0x02
8957 jne pci_real_f08
8958 shl ecx, #16
8959 mov cx, dx
8960 mov bx, #0x0000
8961 mov di, #0x00
8962 pci_real_devloop:
8963 call pci_real_select_reg
8964 mov dx, #0x0cfc
8965 in eax, dx
8966 cmp eax, ecx
8967 jne pci_real_nextdev
8968 cmp si, #0
8969 je pci_real_ok
8970 dec si
8971 pci_real_nextdev:
8972 inc bx
8973 cmp bx, #0x0100
8974 jne pci_real_devloop
8975 mov dx, cx
8976 shr ecx, #16
8977 mov ah, #0x86
8978 jmp pci_real_fail
8979 pci_real_f08: ;; read configuration byte
8980 cmp al, #0x08
8981 jne pci_real_f09
8982 call pci_real_select_reg
8983 push dx
8984 mov dx, di
8985 and dx, #0x03
8986 add dx, #0x0cfc
8987 in al, dx
8988 pop dx
8989 mov cl, al
8990 jmp pci_real_ok
8991 pci_real_f09: ;; read configuration word
8992 cmp al, #0x09
8993 jne pci_real_f0a
8994 call pci_real_select_reg
8995 push dx
8996 mov dx, di
8997 and dx, #0x02
8998 add dx, #0x0cfc
8999 in ax, dx
9000 pop dx
9001 mov cx, ax
9002 jmp pci_real_ok
9003 pci_real_f0a: ;; read configuration dword
9004 cmp al, #0x0a
9005 jne pci_real_f0b
9006 call pci_real_select_reg
9007 push dx
9008 mov dx, #0x0cfc
9009 in eax, dx
9010 pop dx
9011 mov ecx, eax
9012 jmp pci_real_ok
9013 pci_real_f0b: ;; write configuration byte
9014 cmp al, #0x0b
9015 jne pci_real_f0c
9016 call pci_real_select_reg
9017 push dx
9018 mov dx, di
9019 and dx, #0x03
9020 add dx, #0x0cfc
9021 mov al, cl
9022 out dx, al
9023 pop dx
9024 jmp pci_real_ok
9025 pci_real_f0c: ;; write configuration word
9026 cmp al, #0x0c
9027 jne pci_real_f0d
9028 call pci_real_select_reg
9029 push dx
9030 mov dx, di
9031 and dx, #0x02
9032 add dx, #0x0cfc
9033 mov ax, cx
9034 out dx, ax
9035 pop dx
9036 jmp pci_real_ok
9037 pci_real_f0d: ;; write configuration dword
9038 cmp al, #0x0d
9039 jne pci_real_unknown
9040 call pci_real_select_reg
9041 push dx
9042 mov dx, #0x0cfc
9043 mov eax, ecx
9044 out dx, eax
9045 pop dx
9046 jmp pci_real_ok
9047 pci_real_unknown:
9048 mov ah, #0x81
9049 pci_real_fail:
9050 pop edi
9051 pop esi
9052 stc
9053 ret
9054 pci_real_ok:
9055 xor ah, ah
9056 pop edi
9057 pop esi
9058 clc
9059 ret
9061 pci_real_select_reg:
9062 push dx
9063 mov eax, #0x800000
9064 mov ax, bx
9065 shl eax, #8
9066 and di, #0xff
9067 or ax, di
9068 and al, #0xfc
9069 mov dx, #0x0cf8
9070 out dx, eax
9071 pop dx
9072 ret
9074 .align 16
9075 pci_routing_table_structure:
9076 db 0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature
9077 db 0, 1 ;; version
9078 dw 32 + (6 * 16) ;; table size
9079 db 0 ;; PCI interrupt router bus
9080 db 0x08 ;; PCI interrupt router DevFunc
9081 dw 0x0000 ;; PCI exclusive IRQs
9082 dw 0x8086 ;; compatible PCI interrupt router vendor ID
9083 dw 0x7000 ;; compatible PCI interrupt router device ID
9084 dw 0,0 ;; Miniport data
9085 db 0,0,0,0,0,0,0,0,0,0,0 ;; reserved
9086 db 0x07 ;; checksum
9087 ;; first slot entry PCI-to-ISA (embedded)
9088 db 0 ;; pci bus number
9089 db 0x08 ;; pci device number (bit 7-3)
9090 db 0x60 ;; link value INTA#: pointer into PCI2ISA config space
9091 dw 0xdef8 ;; IRQ bitmap INTA#
9092 db 0x61 ;; link value INTB#
9093 dw 0xdef8 ;; IRQ bitmap INTB#
9094 db 0x62 ;; link value INTC#
9095 dw 0xdef8 ;; IRQ bitmap INTC#
9096 db 0x63 ;; link value INTD#
9097 dw 0xdef8 ;; IRQ bitmap INTD#
9098 db 0 ;; physical slot (0 = embedded)
9099 db 0 ;; reserved
9100 ;; second slot entry: 1st PCI slot
9101 db 0 ;; pci bus number
9102 db 0x10 ;; pci device number (bit 7-3)
9103 db 0x61 ;; link value INTA#
9104 dw 0xdef8 ;; IRQ bitmap INTA#
9105 db 0x62 ;; link value INTB#
9106 dw 0xdef8 ;; IRQ bitmap INTB#
9107 db 0x63 ;; link value INTC#
9108 dw 0xdef8 ;; IRQ bitmap INTC#
9109 db 0x60 ;; link value INTD#
9110 dw 0xdef8 ;; IRQ bitmap INTD#
9111 db 1 ;; physical slot (0 = embedded)
9112 db 0 ;; reserved
9113 ;; third slot entry: 2nd PCI slot
9114 db 0 ;; pci bus number
9115 db 0x18 ;; pci device number (bit 7-3)
9116 db 0x62 ;; link value INTA#
9117 dw 0xdef8 ;; IRQ bitmap INTA#
9118 db 0x63 ;; link value INTB#
9119 dw 0xdef8 ;; IRQ bitmap INTB#
9120 db 0x60 ;; link value INTC#
9121 dw 0xdef8 ;; IRQ bitmap INTC#
9122 db 0x61 ;; link value INTD#
9123 dw 0xdef8 ;; IRQ bitmap INTD#
9124 db 2 ;; physical slot (0 = embedded)
9125 db 0 ;; reserved
9126 ;; 4th slot entry: 3rd PCI slot
9127 db 0 ;; pci bus number
9128 db 0x20 ;; pci device number (bit 7-3)
9129 db 0x63 ;; link value INTA#
9130 dw 0xdef8 ;; IRQ bitmap INTA#
9131 db 0x60 ;; link value INTB#
9132 dw 0xdef8 ;; IRQ bitmap INTB#
9133 db 0x61 ;; link value INTC#
9134 dw 0xdef8 ;; IRQ bitmap INTC#
9135 db 0x62 ;; link value INTD#
9136 dw 0xdef8 ;; IRQ bitmap INTD#
9137 db 3 ;; physical slot (0 = embedded)
9138 db 0 ;; reserved
9139 ;; 5th slot entry: 4rd PCI slot
9140 db 0 ;; pci bus number
9141 db 0x28 ;; pci device number (bit 7-3)
9142 db 0x60 ;; link value INTA#
9143 dw 0xdef8 ;; IRQ bitmap INTA#
9144 db 0x61 ;; link value INTB#
9145 dw 0xdef8 ;; IRQ bitmap INTB#
9146 db 0x62 ;; link value INTC#
9147 dw 0xdef8 ;; IRQ bitmap INTC#
9148 db 0x63 ;; link value INTD#
9149 dw 0xdef8 ;; IRQ bitmap INTD#
9150 db 4 ;; physical slot (0 = embedded)
9151 db 0 ;; reserved
9152 ;; 6th slot entry: 5rd PCI slot
9153 db 0 ;; pci bus number
9154 db 0x30 ;; pci device number (bit 7-3)
9155 db 0x61 ;; link value INTA#
9156 dw 0xdef8 ;; IRQ bitmap INTA#
9157 db 0x62 ;; link value INTB#
9158 dw 0xdef8 ;; IRQ bitmap INTB#
9159 db 0x63 ;; link value INTC#
9160 dw 0xdef8 ;; IRQ bitmap INTC#
9161 db 0x60 ;; link value INTD#
9162 dw 0xdef8 ;; IRQ bitmap INTD#
9163 db 5 ;; physical slot (0 = embedded)
9164 db 0 ;; reserved
9166 pci_irq_list:
9167 db 11, 10, 9, 5;
9169 pcibios_init_sel_reg:
9170 push eax
9171 mov eax, #0x800000
9172 mov ax, bx
9173 shl eax, #8
9174 and dl, #0xfc
9175 or al, dl
9176 mov dx, #0x0cf8
9177 out dx, eax
9178 pop eax
9179 ret
9181 pcibios_init_set_elcr:
9182 push ax
9183 push cx
9184 mov dx, #0x04d0
9185 test al, #0x08
9186 jz is_master_pic
9187 inc dx
9188 and al, #0x07
9189 is_master_pic:
9190 mov cl, al
9191 mov bl, #0x01
9192 shl bl, cl
9193 in al, dx
9194 or al, bl
9195 out dx, al
9196 pop cx
9197 pop ax
9198 ret
9200 pcibios_init:
9201 push ds
9202 push bp
9203 mov ax, #0xf000
9204 mov ds, ax
9205 mov dx, #0x04d0 ;; reset ELCR1 + ELCR2
9206 mov al, #0x00
9207 out dx, al
9208 inc dx
9209 out dx, al
9210 mov si, #pci_routing_table_structure
9211 mov bh, [si+8]
9212 mov bl, [si+9]
9213 mov dl, #0x00
9214 call pcibios_init_sel_reg
9215 mov dx, #0x0cfc
9216 in eax, dx
9217 cmp eax, [si+12] ;; check irq router
9218 jne pci_init_end
9219 mov dl, [si+34]
9220 call pcibios_init_sel_reg
9221 push bx ;; save irq router bus + devfunc
9222 mov dx, #0x0cfc
9223 mov ax, #0x8080
9224 out dx, ax ;; reset PIRQ route control
9225 inc dx
9226 inc dx
9227 out dx, ax
9228 mov ax, [si+6]
9229 sub ax, #0x20
9230 shr ax, #4
9231 mov cx, ax
9232 add si, #0x20 ;; set pointer to 1st entry
9233 mov bp, sp
9234 mov ax, #pci_irq_list
9235 push ax
9236 xor ax, ax
9237 push ax
9238 pci_init_loop1:
9239 mov bh, [si]
9240 mov bl, [si+1]
9241 pci_init_loop2:
9242 mov dl, #0x00
9243 call pcibios_init_sel_reg
9244 mov dx, #0x0cfc
9245 in ax, dx
9246 cmp ax, #0xffff
9247 jnz pci_test_int_pin
9248 test bl, #0x07
9249 jz next_pir_entry
9250 jmp next_pci_func
9251 pci_test_int_pin:
9252 mov dl, #0x3c
9253 call pcibios_init_sel_reg
9254 mov dx, #0x0cfd
9255 in al, dx
9256 and al, #0x07
9257 jz next_pci_func
9258 dec al ;; determine pirq reg
9259 mov dl, #0x03
9260 mul al, dl
9261 add al, #0x02
9262 xor ah, ah
9263 mov bx, ax
9264 mov al, [si+bx]
9265 mov dl, al
9266 mov bx, [bp]
9267 call pcibios_init_sel_reg
9268 mov dx, #0x0cfc
9269 and al, #0x03
9270 add dl, al
9271 in al, dx
9272 cmp al, #0x80
9273 jb pirq_found
9274 mov bx, [bp-2] ;; pci irq list pointer
9275 mov al, [bx]
9276 out dx, al
9277 inc bx
9278 mov [bp-2], bx
9279 call pcibios_init_set_elcr
9280 pirq_found:
9281 mov bh, [si]
9282 mov bl, [si+1]
9283 add bl, [bp-3] ;; pci function number
9284 mov dl, #0x3c
9285 call pcibios_init_sel_reg
9286 mov dx, #0x0cfc
9287 out dx, al
9288 next_pci_func:
9289 inc byte ptr[bp-3]
9290 inc bl
9291 test bl, #0x07
9292 jnz pci_init_loop2
9293 next_pir_entry:
9294 add si, #0x10
9295 mov byte ptr[bp-3], #0x00
9296 loop pci_init_loop1
9297 mov sp, bp
9298 pop bx
9299 pci_init_end:
9300 pop bp
9301 pop ds
9302 ret
9303 #endif // BX_PCIBIOS
9305 ; parallel port detection: base address in DX, index in BX, timeout in CL
9306 detect_parport:
9307 push dx
9308 add dx, #2
9309 in al, dx
9310 and al, #0xdf ; clear input mode
9311 out dx, al
9312 pop dx
9313 mov al, #0xaa
9314 out dx, al
9315 in al, dx
9316 cmp al, #0xaa
9317 jne no_parport
9318 push bx
9319 shl bx, #1
9320 mov [bx+0x408], dx ; Parallel I/O address
9321 pop bx
9322 mov [bx+0x478], cl ; Parallel printer timeout
9323 inc bx
9324 no_parport:
9325 ret
9327 ; serial port detection: base address in DX, index in BX, timeout in CL
9328 detect_serial:
9329 push dx
9330 inc dx
9331 mov al, #0x02
9332 out dx, al
9333 in al, dx
9334 cmp al, #0x02
9335 jne no_serial
9336 inc dx
9337 in al, dx
9338 cmp al, #0x02
9339 jne no_serial
9340 dec dx
9341 xor al, al
9342 out dx, al
9343 pop dx
9344 push bx
9345 shl bx, #1
9346 mov [bx+0x400], dx ; Serial I/O address
9347 pop bx
9348 mov [bx+0x47c], cl ; Serial timeout
9349 inc bx
9350 ret
9351 no_serial:
9352 pop dx
9353 ret
9355 rom_checksum:
9356 push ax
9357 push bx
9358 push cx
9359 xor ax, ax
9360 xor bx, bx
9361 xor cx, cx
9362 mov ch, [2]
9363 shl cx, #1
9364 checksum_loop:
9365 add al, [bx]
9366 inc bx
9367 loop checksum_loop
9368 and al, #0xff
9369 pop cx
9370 pop bx
9371 pop ax
9372 ret
9374 rom_scan:
9375 ;; Scan for existence of valid expansion ROMS.
9376 ;; Video ROM: from 0xC0000..0xC7FFF in 2k increments
9377 ;; General ROM: from 0xC8000..0xDFFFF in 2k increments
9378 ;; System ROM: only 0xE0000
9379 ;;
9380 ;; Header:
9381 ;; Offset Value
9382 ;; 0 0x55
9383 ;; 1 0xAA
9384 ;; 2 ROM length in 512-byte blocks
9385 ;; 3 ROM initialization entry point (FAR CALL)
9387 mov cx, #0xc000
9388 rom_scan_loop:
9389 mov ds, cx
9390 mov ax, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
9391 cmp [0], #0xAA55 ;; look for signature
9392 jne rom_scan_increment
9393 call rom_checksum
9394 jnz rom_scan_increment
9395 mov al, [2] ;; change increment to ROM length in 512-byte blocks
9397 ;; We want our increment in 512-byte quantities, rounded to
9398 ;; the nearest 2k quantity, since we only scan at 2k intervals.
9399 test al, #0x03
9400 jz block_count_rounded
9401 and al, #0xfc ;; needs rounding up
9402 add al, #0x04
9403 block_count_rounded:
9405 xor bx, bx ;; Restore DS back to 0000:
9406 mov ds, bx
9407 push ax ;; Save AX
9408 ;; Push addr of ROM entry point
9409 push cx ;; Push seg
9410 push #0x0003 ;; Push offset
9411 mov bp, sp ;; Call ROM init routine using seg:off on stack
9412 db 0xff ;; call_far ss:[bp+0]
9413 db 0x5e
9414 db 0
9415 cli ;; In case expansion ROM BIOS turns IF on
9416 add sp, #2 ;; Pop offset value
9417 pop cx ;; Pop seg value (restore CX)
9418 pop ax ;; Restore AX
9419 rom_scan_increment:
9420 shl ax, #5 ;; convert 512-bytes blocks to 16-byte increments
9421 ;; because the segment selector is shifted left 4 bits.
9422 add cx, ax
9423 cmp cx, #0xe000
9424 jbe rom_scan_loop
9426 xor ax, ax ;; Restore DS back to 0000:
9427 mov ds, ax
9428 ret
9430 ;; for 'C' strings and other data, insert them here with
9431 ;; a the following hack:
9432 ;; DATA_SEG_DEFS_HERE
9435 ;--------
9436 ;- POST -
9437 ;--------
9438 .org 0xe05b ; POST Entry Point
9439 post:
9441 xor ax, ax
9443 ;; first reset the DMA controllers
9444 out 0x0d,al
9445 out 0xda,al
9447 ;; then initialize the DMA controllers
9448 mov al, #0xC0
9449 out 0xD6, al ; cascade mode of channel 4 enabled
9450 mov al, #0x00
9451 out 0xD4, al ; unmask channel 4
9453 ;; Examine CMOS shutdown status.
9454 mov AL, #0x0f
9455 out 0x70, AL
9456 in AL, 0x71
9458 ;; backup status
9459 mov bl, al
9461 ;; Reset CMOS shutdown status.
9462 mov AL, #0x0f
9463 out 0x70, AL ; select CMOS register Fh
9464 mov AL, #0x00
9465 out 0x71, AL ; set shutdown action to normal
9467 ;; Examine CMOS shutdown status.
9468 mov al, bl
9470 ;; 0x00, 0x09, 0x0D+ = normal startup
9471 cmp AL, #0x00
9472 jz normal_post
9473 cmp AL, #0x0d
9474 jae normal_post
9475 cmp AL, #0x09
9476 je normal_post
9478 ;; 0x05 = eoi + jmp via [0x40:0x67] jump
9479 cmp al, #0x05
9480 je eoi_jmp_post
9482 ;; Examine CMOS shutdown status.
9483 ;; 0x01,0x02,0x03,0x04,0x06,0x07,0x08, 0x0a, 0x0b, 0x0c = Unimplemented shutdown status.
9484 push bx
9485 call _shutdown_status_panic
9487 #if 0
9488 HALT(__LINE__)
9490 ;#if 0
9491 ; 0xb0, 0x20, /* mov al, #0x20 */
9492 ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */
9493 ;#endif
9495 pop es
9496 pop ds
9497 popa
9498 iret
9499 #endif
9501 normal_post:
9502 ; case 0: normal startup
9504 cli
9505 mov ax, #0xfffe
9506 mov sp, ax
9507 mov ax, #0x0000
9508 mov ds, ax
9509 mov ss, ax
9511 ;; zero out BIOS data area (40:00..40:ff)
9512 mov es, ax
9513 mov cx, #0x0080 ;; 128 words
9514 mov di, #0x0400
9515 cld
9516 rep
9517 stosw
9519 call _log_bios_start
9521 ;; set all interrupts to default handler
9522 mov bx, #0x0000 ;; offset index
9523 mov cx, #0x0100 ;; counter (256 interrupts)
9524 mov ax, #dummy_iret_handler
9525 mov dx, #0xF000
9527 post_default_ints:
9528 mov [bx], ax
9529 inc bx
9530 inc bx
9531 mov [bx], dx
9532 inc bx
9533 inc bx
9534 loop post_default_ints
9536 ;; set vector 0x79 to zero
9537 ;; this is used by 'gardian angel' protection system
9538 SET_INT_VECTOR(0x79, #0, #0)
9540 ;; base memory in K 40:13 (word)
9541 mov ax, #BASE_MEM_IN_K
9542 mov 0x0413, ax
9545 ;; Manufacturing Test 40:12
9546 ;; zerod out above
9548 ;; Warm Boot Flag 0040:0072
9549 ;; value of 1234h = skip memory checks
9550 ;; zerod out above
9553 ;; Printer Services vector
9554 SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
9556 ;; Bootstrap failure vector
9557 SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
9559 ;; Bootstrap Loader vector
9560 SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
9562 ;; User Timer Tick vector
9563 SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
9565 ;; Memory Size Check vector
9566 SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
9568 ;; Equipment Configuration Check vector
9569 SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
9571 ;; System Services
9572 SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
9574 ;; EBDA setup
9575 call ebda_post
9577 ;; PIT setup
9578 SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
9579 ;; int 1C already points at dummy_iret_handler (above)
9580 mov al, #0x34 ; timer0: binary count, 16bit count, mode 2
9581 out 0x43, al
9582 #ifdef VMXASSIST
9583 mov al, #0x0b ; #0xe90b = 20 Hz (temporary, until we fix xen/vmx support)
9584 out 0x40, al ; lsb
9585 mov al, #0xe9
9586 out 0x40, al ; msb
9587 #else
9588 mov al, #0x00 ; maximum count of 0000H = 18.2Hz
9589 out 0x40, al
9590 out 0x40, al
9591 #endif
9593 ;; Keyboard
9594 SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
9595 SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
9597 xor ax, ax
9598 mov ds, ax
9599 mov 0x0417, al /* keyboard shift flags, set 1 */
9600 mov 0x0418, al /* keyboard shift flags, set 2 */
9601 mov 0x0419, al /* keyboard alt-numpad work area */
9602 mov 0x0471, al /* keyboard ctrl-break flag */
9603 mov 0x0497, al /* keyboard status flags 4 */
9604 mov al, #0x10
9605 mov 0x0496, al /* keyboard status flags 3 */
9608 /* keyboard head of buffer pointer */
9609 mov bx, #0x001E
9610 mov 0x041A, bx
9612 /* keyboard end of buffer pointer */
9613 mov 0x041C, bx
9615 /* keyboard pointer to start of buffer */
9616 mov bx, #0x001E
9617 mov 0x0480, bx
9619 /* keyboard pointer to end of buffer */
9620 mov bx, #0x003E
9621 mov 0x0482, bx
9623 /* init the keyboard */
9624 call _keyboard_init
9626 ;; mov CMOS Equipment Byte to BDA Equipment Word
9627 mov ax, 0x0410
9628 mov al, #0x14
9629 out 0x70, al
9630 in al, 0x71
9631 mov 0x0410, ax
9634 ;; Parallel setup
9635 SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
9636 xor ax, ax
9637 mov ds, ax
9638 xor bx, bx
9639 mov cl, #0x14 ; timeout value
9640 mov dx, #0x378 ; Parallel I/O address, port 1
9641 call detect_parport
9642 mov dx, #0x278 ; Parallel I/O address, port 2
9643 call detect_parport
9644 shl bx, #0x0e
9645 mov ax, 0x410 ; Equipment word bits 14..15 determing # parallel ports
9646 and ax, #0x3fff
9647 or ax, bx ; set number of parallel ports
9648 mov 0x410, ax
9650 ;; Serial setup
9651 SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
9652 SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
9653 xor bx, bx
9654 mov cl, #0x0a ; timeout value
9655 mov dx, #0x03f8 ; Serial I/O address, port 1
9656 call detect_serial
9657 mov dx, #0x02f8 ; Serial I/O address, port 2
9658 call detect_serial
9659 mov dx, #0x03e8 ; Serial I/O address, port 3
9660 call detect_serial
9661 mov dx, #0x02e8 ; Serial I/O address, port 4
9662 call detect_serial
9663 shl bx, #0x09
9664 mov ax, 0x410 ; Equipment word bits 9..11 determing # serial ports
9665 and ax, #0xf1ff
9666 or ax, bx ; set number of serial port
9667 mov 0x410, ax
9669 ;; CMOS RTC
9670 SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
9671 SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
9672 SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
9673 ;; BIOS DATA AREA 0x4CE ???
9674 call timer_tick_post
9676 ;; PS/2 mouse setup
9677 SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
9679 ;; IRQ13 (FPU exception) setup
9680 SET_INT_VECTOR(0x75, #0xF000, #int75_handler)
9682 ;; Video setup
9683 SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
9685 ;; PIC
9686 mov al, #0x11 ; send initialisation commands
9687 out 0x20, al
9688 out 0xa0, al
9689 #ifdef VMXASSIST
9690 ;; The vm86 emulator expects interrupts to be mapped beyond the reserved
9691 ;; vectors (0 through 31). Since rombios fully controls the hardware, we
9692 ;; map it the way the emulator needs it and expect that it will do the
9693 ;; proper 8086 interrupt translation (that is, master pic base is at 0x8
9694 ;; and slave pic base is at 0x70).
9695 mov al, #0x20
9696 out 0x21, al
9697 mov al, #0x28
9698 out 0xa1, al
9699 #else
9700 mov al, #0x08
9701 out 0x21, al
9702 mov al, #0x70
9703 out 0xa1, al
9704 #endif
9705 mov al, #0x04
9706 out 0x21, al
9707 mov al, #0x02
9708 out 0xa1, al
9709 mov al, #0x01
9710 out 0x21, al
9711 out 0xa1, al
9712 mov al, #0xb8
9713 out 0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6
9714 #if BX_USE_PS2_MOUSE
9715 mov al, #0x8f
9716 #else
9717 mov al, #0x9f
9718 #endif
9719 out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14
9721 #ifdef VMXASSIST
9722 call _copy_e820_table
9723 #endif
9725 call rom_scan
9727 call _print_bios_banner
9729 ;;
9730 ;; Floppy setup
9731 ;;
9732 call floppy_drive_post
9734 #if BX_USE_ATADRV
9736 ;;
9737 ;; Hard Drive setup
9738 ;;
9739 call hard_drive_post
9741 ;;
9742 ;; ATA/ATAPI driver setup
9743 ;;
9744 call _ata_init
9745 call _ata_detect
9746 ;;
9747 #else // BX_USE_ATADRV
9749 ;;
9750 ;; Hard Drive setup
9751 ;;
9752 call hard_drive_post
9754 #endif // BX_USE_ATADRV
9756 #if BX_ELTORITO_BOOT
9757 ;;
9758 ;; eltorito floppy/harddisk emulation from cd
9759 ;;
9760 call _cdemu_init
9761 ;;
9762 #endif // BX_ELTORITO_BOOT
9764 int #0x19
9765 //JMP_EP(0x0064) ; INT 19h location
9768 .org 0xe2c3 ; NMI Handler Entry Point
9769 nmi:
9770 ;; FIXME the NMI handler should not panic
9771 ;; but iret when called from int75 (fpu exception)
9772 call _nmi_handler_msg
9773 iret
9775 int75_handler:
9776 out 0xf0, al // clear irq13
9777 call eoi_both_pics // clear interrupt
9778 int 2 // legacy nmi call
9779 iret
9781 ;-------------------------------------------
9782 ;- INT 13h Fixed Disk Services Entry Point -
9783 ;-------------------------------------------
9784 .org 0xe3fe ; INT 13h Fixed Disk Services Entry Point
9785 int13_handler:
9786 //JMPL(int13_relocated)
9787 jmp int13_relocated
9789 .org 0xe401 ; Fixed Disk Parameter Table
9791 ;----------
9792 ;- INT19h -
9793 ;----------
9794 .org 0xe6f2 ; INT 19h Boot Load Service Entry Point
9795 int19_handler:
9797 jmp int19_relocated
9798 ;-------------------------------------------
9799 ;- System BIOS Configuration Data Table
9800 ;-------------------------------------------
9801 .org BIOS_CONFIG_TABLE
9802 db 0x08 ; Table size (bytes) -Lo
9803 db 0x00 ; Table size (bytes) -Hi
9804 db SYS_MODEL_ID
9805 db SYS_SUBMODEL_ID
9806 db BIOS_REVISION
9807 ; Feature byte 1
9808 ; b7: 1=DMA channel 3 used by hard disk
9809 ; b6: 1=2 interrupt controllers present
9810 ; b5: 1=RTC present
9811 ; b4: 1=BIOS calls int 15h/4Fh every key
9812 ; b3: 1=wait for extern event supported (Int 15h/41h)
9813 ; b2: 1=extended BIOS data area used
9814 ; b1: 0=AT or ESDI bus, 1=MicroChannel
9815 ; b0: 1=Dual bus (MicroChannel + ISA)
9816 db (0 << 7) | \
9817 (1 << 6) | \
9818 (1 << 5) | \
9819 (BX_CALL_INT15_4F << 4) | \
9820 (0 << 3) | \
9821 (BX_USE_EBDA << 2) | \
9822 (0 << 1) | \
9823 (0 << 0)
9824 ; Feature byte 2
9825 ; b7: 1=32-bit DMA supported
9826 ; b6: 1=int16h, function 9 supported
9827 ; b5: 1=int15h/C6h (get POS data) supported
9828 ; b4: 1=int15h/C7h (get mem map info) supported
9829 ; b3: 1=int15h/C8h (en/dis CPU) supported
9830 ; b2: 1=non-8042 kb controller
9831 ; b1: 1=data streaming supported
9832 ; b0: reserved
9833 db (0 << 7) | \
9834 (1 << 6) | \
9835 (0 << 5) | \
9836 (0 << 4) | \
9837 (0 << 3) | \
9838 (0 << 2) | \
9839 (0 << 1) | \
9840 (0 << 0)
9841 ; Feature byte 3
9842 ; b7: not used
9843 ; b6: reserved
9844 ; b5: reserved
9845 ; b4: POST supports ROM-to-RAM enable/disable
9846 ; b3: SCSI on system board
9847 ; b2: info panel installed
9848 ; b1: Initial Machine Load (IML) system - BIOS on disk
9849 ; b0: SCSI supported in IML
9850 db 0x00
9851 ; Feature byte 4
9852 ; b7: IBM private
9853 ; b6: EEPROM present
9854 ; b5-3: ABIOS presence (011 = not supported)
9855 ; b2: private
9856 ; b1: memory split above 16Mb supported
9857 ; b0: POSTEXT directly supported by POST
9858 db 0x00
9859 ; Feature byte 5 (IBM)
9860 ; b1: enhanced mouse
9861 ; b0: flash EPROM
9862 db 0x00
9866 .org 0xe729 ; Baud Rate Generator Table
9868 ;----------
9869 ;- INT14h -
9870 ;----------
9871 .org 0xe739 ; INT 14h Serial Communications Service Entry Point
9872 int14_handler:
9873 push ds
9874 pusha
9875 mov ax, #0x0000
9876 mov ds, ax
9877 call _int14_function
9878 popa
9879 pop ds
9880 iret
9883 ;----------------------------------------
9884 ;- INT 16h Keyboard Service Entry Point -
9885 ;----------------------------------------
9886 .org 0xe82e
9887 int16_handler:
9889 sti
9890 push ds
9891 pushf
9892 pusha
9894 cmp ah, #0x00
9895 je int16_F00
9896 cmp ah, #0x10
9897 je int16_F00
9899 mov bx, #0xf000
9900 mov ds, bx
9901 call _int16_function
9902 popa
9903 popf
9904 pop ds
9905 jz int16_zero_set
9907 int16_zero_clear:
9908 push bp
9909 mov bp, sp
9910 //SEG SS
9911 and BYTE [bp + 0x06], #0xbf
9912 pop bp
9913 iret
9915 int16_zero_set:
9916 push bp
9917 mov bp, sp
9918 //SEG SS
9919 or BYTE [bp + 0x06], #0x40
9920 pop bp
9921 iret
9923 int16_F00:
9924 mov bx, #0x0040
9925 mov ds, bx
9927 int16_wait_for_key:
9928 cli
9929 mov bx, 0x001a
9930 cmp bx, 0x001c
9931 jne int16_key_found
9932 sti
9933 nop
9934 #if 0
9935 /* no key yet, call int 15h, function AX=9002 */
9936 0x50, /* push AX */
9937 0xb8, 0x02, 0x90, /* mov AX, #0x9002 */
9938 0xcd, 0x15, /* int 15h */
9939 0x58, /* pop AX */
9940 0xeb, 0xea, /* jmp WAIT_FOR_KEY */
9941 #endif
9942 jmp int16_wait_for_key
9944 int16_key_found:
9945 mov bx, #0xf000
9946 mov ds, bx
9947 call _int16_function
9948 popa
9949 popf
9950 pop ds
9951 #if 0
9952 /* notify int16 complete w/ int 15h, function AX=9102 */
9953 0x50, /* push AX */
9954 0xb8, 0x02, 0x91, /* mov AX, #0x9102 */
9955 0xcd, 0x15, /* int 15h */
9956 0x58, /* pop AX */
9957 #endif
9958 iret
9962 ;-------------------------------------------------
9963 ;- INT09h : Keyboard Hardware Service Entry Point -
9964 ;-------------------------------------------------
9965 .org 0xe987
9966 int09_handler:
9967 cli
9968 push ax
9970 mov al, #0xAD ;;disable keyboard
9971 out #0x64, al
9973 mov al, #0x0B
9974 out #0x20, al
9975 in al, #0x20
9976 and al, #0x02
9977 jz int09_finish
9979 in al, #0x60 ;;read key from keyboard controller
9980 //test al, #0x80 ;;look for key release
9981 //jnz int09_process_key ;; dont pass releases to intercept?
9983 ;; check for extended key
9984 cmp al, #0xe0
9985 jne int09_call_int15_4f
9987 push ds
9988 xor ax, ax
9989 mov ds, ax
9990 mov al, BYTE [0x496] ;; mf2_state |= 0x01
9991 or al, #0x01
9992 mov BYTE [0x496], al
9993 pop ds
9995 in al, #0x60 ;;read another key from keyboard controller
9997 sti
9999 int09_call_int15_4f:
10000 push ds
10001 pusha
10002 #ifdef BX_CALL_INT15_4F
10003 mov ah, #0x4f ;; allow for keyboard intercept
10004 stc
10005 int #0x15
10006 jnc int09_done
10007 #endif
10010 //int09_process_key:
10011 mov bx, #0xf000
10012 mov ds, bx
10013 call _int09_function
10015 int09_done:
10016 popa
10017 pop ds
10018 cli
10019 call eoi_master_pic
10021 int09_finish:
10022 mov al, #0xAE ;;enable keyboard
10023 out #0x64, al
10024 pop ax
10025 iret
10030 ;----------------------------------------
10031 ;- INT 13h Diskette Service Entry Point -
10032 ;----------------------------------------
10033 .org 0xec59
10034 int13_diskette:
10035 jmp int13_noeltorito
10037 ;---------------------------------------------
10038 ;- INT 0Eh Diskette Hardware ISR Entry Point -
10039 ;---------------------------------------------
10040 .org 0xef57 ; INT 0Eh Diskette Hardware ISR Entry Point
10041 int0e_handler:
10042 push ax
10043 push dx
10044 mov dx, #0x03f4
10045 in al, dx
10046 and al, #0xc0
10047 cmp al, #0xc0
10048 je int0e_normal
10049 mov dx, #0x03f5
10050 mov al, #0x08 ; sense interrupt status
10051 out dx, al
10052 int0e_loop1:
10053 mov dx, #0x03f4
10054 in al, dx
10055 and al, #0xc0
10056 cmp al, #0xc0
10057 jne int0e_loop1
10058 int0e_loop2:
10059 mov dx, #0x03f5
10060 in al, dx
10061 mov dx, #0x03f4
10062 in al, dx
10063 and al, #0xc0
10064 cmp al, #0xc0
10065 je int0e_loop2
10066 int0e_normal:
10067 push ds
10068 mov ax, #0x0000 ;; segment 0000
10069 mov ds, ax
10070 call eoi_master_pic
10071 mov al, 0x043e
10072 or al, #0x80 ;; diskette interrupt has occurred
10073 mov 0x043e, al
10074 pop ds
10075 pop dx
10076 pop ax
10077 iret
10080 .org 0xefc7 ; Diskette Controller Parameter Table
10081 diskette_param_table:
10082 ;; Since no provisions are made for multiple drive types, most
10083 ;; values in this table are ignored. I set parameters for 1.44M
10084 ;; floppy here
10085 db 0xAF
10086 db 0x02 ;; head load time 0000001, DMA used
10087 db 0x25
10088 db 0x02
10089 db 18
10090 db 0x1B
10091 db 0xFF
10092 db 0x6C
10093 db 0xF6
10094 db 0x0F
10095 db 0x08
10098 ;----------------------------------------
10099 ;- INT17h : Printer Service Entry Point -
10100 ;----------------------------------------
10101 .org 0xefd2
10102 int17_handler:
10103 push ds
10104 pusha
10105 mov ax, #0x0000
10106 mov ds, ax
10107 call _int17_function
10108 popa
10109 pop ds
10110 iret
10112 diskette_param_table2:
10113 ;; New diskette parameter table adding 3 parameters from IBM
10114 ;; Since no provisions are made for multiple drive types, most
10115 ;; values in this table are ignored. I set parameters for 1.44M
10116 ;; floppy here
10117 db 0xAF
10118 db 0x02 ;; head load time 0000001, DMA used
10119 db 0x25
10120 db 0x02
10121 db 18
10122 db 0x1B
10123 db 0xFF
10124 db 0x6C
10125 db 0xF6
10126 db 0x0F
10127 db 0x08
10128 db 79 ;; maximum track
10129 db 0 ;; data transfer rate
10130 db 4 ;; drive type in cmos
10132 .org 0xf045 ; INT 10 Functions 0-Fh Entry Point
10133 HALT(__LINE__)
10134 iret
10136 ;----------
10137 ;- INT10h -
10138 ;----------
10139 .org 0xf065 ; INT 10h Video Support Service Entry Point
10140 int10_handler:
10141 ;; dont do anything, since the VGA BIOS handles int10h requests
10142 iret
10144 .org 0xf0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
10146 ;----------
10147 ;- INT12h -
10148 ;----------
10149 .org 0xf841 ; INT 12h Memory Size Service Entry Point
10150 ; ??? different for Pentium (machine check)?
10151 int12_handler:
10152 push ds
10153 mov ax, #0x0040
10154 mov ds, ax
10155 mov ax, 0x0013
10156 pop ds
10157 iret
10159 ;----------
10160 ;- INT11h -
10161 ;----------
10162 .org 0xf84d ; INT 11h Equipment List Service Entry Point
10163 int11_handler:
10164 push ds
10165 mov ax, #0x0040
10166 mov ds, ax
10167 mov ax, 0x0010
10168 pop ds
10169 iret
10171 ;----------
10172 ;- INT15h -
10173 ;----------
10174 .org 0xf859 ; INT 15h System Services Entry Point
10175 int15_handler:
10176 pushf
10177 #if BX_APM
10178 cmp ah, #0x53
10179 je apm_call
10180 #endif
10181 push ds
10182 push es
10183 cmp ah, #0x86
10184 je int15_handler32
10185 cmp ah, #0xE8
10186 je int15_handler32
10187 pusha
10188 #if BX_USE_PS2_MOUSE
10189 cmp ah, #0xC2
10190 je int15_handler_mouse
10191 #endif
10192 call _int15_function
10193 int15_handler_mouse_ret:
10194 popa
10195 int15_handler32_ret:
10196 pop es
10197 pop ds
10198 popf
10199 jmp iret_modify_cf
10200 #if BX_APM
10201 apm_call:
10202 jmp _apmreal_entry
10203 #endif
10205 #if BX_USE_PS2_MOUSE
10206 int15_handler_mouse:
10207 call _int15_function_mouse
10208 jmp int15_handler_mouse_ret
10209 #endif
10211 int15_handler32:
10212 pushad
10213 call _int15_function32
10214 popad
10215 jmp int15_handler32_ret
10217 ;; Protected mode IDT descriptor
10218 ;;
10219 ;; I just make the limit 0, so the machine will shutdown
10220 ;; if an exception occurs during protected mode memory
10221 ;; transfers.
10222 ;;
10223 ;; Set base to f0000 to correspond to beginning of BIOS,
10224 ;; in case I actually define an IDT later
10225 ;; Set limit to 0
10227 pmode_IDT_info:
10228 dw 0x0000 ;; limit 15:00
10229 dw 0x0000 ;; base 15:00
10230 db 0x0f ;; base 23:16
10232 ;; Real mode IDT descriptor