ia64/xen-unstable

view tools/firmware/rombios/rombios.c @ 11221:7c9d7fc3dce5

[HVM] Fix SMBIOS entry point copy destination.
Spotted by Xiaowei Yang <xiaowei.yang@intel.com>
Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@localhost.localdomain
date Sat Aug 19 12:06:36 2006 +0100 (2006-08-19)
parents 7ba73e24c5a5
children f555a90bcc37
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 HVMASSIST
30 #undef HVMTEST
32 // Xen full virtualization does not handle unaligned IO with page crossing.
33 // Disable 32-bit PIO as a workaround.
34 #undef NO_PIO32
37 // ROM BIOS compatability entry points:
38 // ===================================
39 // $e05b ; POST Entry Point
40 // $e2c3 ; NMI Handler Entry Point
41 // $e3fe ; INT 13h Fixed Disk Services Entry Point
42 // $e401 ; Fixed Disk Parameter Table
43 // $e6f2 ; INT 19h Boot Load Service Entry Point
44 // $e6f5 ; Configuration Data Table
45 // $e729 ; Baud Rate Generator Table
46 // $e739 ; INT 14h Serial Communications Service Entry Point
47 // $e82e ; INT 16h Keyboard Service Entry Point
48 // $e987 ; INT 09h Keyboard Service Entry Point
49 // $ec59 ; INT 13h Diskette Service Entry Point
50 // $ef57 ; INT 0Eh Diskette Hardware ISR Entry Point
51 // $efc7 ; Diskette Controller Parameter Table
52 // $efd2 ; INT 17h Printer Service Entry Point
53 // $f045 ; INT 10 Functions 0-Fh Entry Point
54 // $f065 ; INT 10h Video Support Service Entry Point
55 // $f0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
56 // $f841 ; INT 12h Memory Size Service Entry Point
57 // $f84d ; INT 11h Equipment List Service Entry Point
58 // $f859 ; INT 15h System Services Entry Point
59 // $fa6e ; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
60 // $fe6e ; INT 1Ah Time-of-day Service Entry Point
61 // $fea5 ; INT 08h System Timer ISR Entry Point
62 // $fef3 ; Initial Interrupt Vector Offsets Loaded by POST
63 // $ff53 ; IRET Instruction for Dummy Interrupt Handler
64 // $ff54 ; INT 05h Print Screen Service Entry Point
65 // $fff0 ; Power-up Entry Point
66 // $fff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
67 // $fffe ; System Model ID
69 // NOTES for ATA/ATAPI driver (cbbochs@free.fr)
70 // Features
71 // - supports up to 4 ATA interfaces
72 // - device/geometry detection
73 // - 16bits/32bits device access
74 // - pchs/lba access
75 // - datain/dataout/packet command support
76 //
77 // NOTES for El-Torito Boot (cbbochs@free.fr)
78 // - CD-ROM booting is only available if ATA/ATAPI Driver is available
79 // - Current code is only able to boot mono-session cds
80 // - Current code can not boot and emulate a hard-disk
81 // the bios will panic otherwise
82 // - Current code also use memory in EBDA segement.
83 // - I used cmos byte 0x3D to store extended information on boot-device
84 // - Code has to be modified modified to handle multiple cdrom drives
85 // - Here are the cdrom boot failure codes:
86 // 1 : no atapi device found
87 // 2 : no atapi cdrom found
88 // 3 : can not read cd - BRVD
89 // 4 : cd is not eltorito (BRVD)
90 // 5 : cd is not eltorito (ISO TAG)
91 // 6 : cd is not eltorito (ELTORITO TAG)
92 // 7 : can not read cd - boot catalog
93 // 8 : boot catalog : bad header
94 // 9 : boot catalog : bad platform
95 // 10 : boot catalog : bad signature
96 // 11 : boot catalog : bootable flag not set
97 // 12 : can not read cd - boot image
98 //
99 // ATA driver
100 // - EBDA segment.
101 // I used memory starting at 0x121 in the segment
102 // - the translation policy is defined in cmos regs 0x39 & 0x3a
103 //
104 // TODO :
105 //
106 // int74
107 // - needs to be reworked. Uses direct [bp] offsets. (?)
108 //
109 // int13:
110 // - f04 (verify sectors) isn't complete (?)
111 // - f02/03/04 should set current cyl,etc in BDA (?)
112 // - rewrite int13_relocated & clean up int13 entry code
113 //
114 // NOTES:
115 // - NMI access (bit7 of addr written to 70h)
116 //
117 // ATA driver
118 // - should handle the "don't detect" bit (cmos regs 0x3b & 0x3c)
119 // - could send the multiple-sector read/write commands
120 //
121 // El-Torito
122 // - Emulate a Hard-disk (currently only diskette can be emulated) see "FIXME ElTorito Harddisk"
123 // - Implement remaining int13_cdemu functions (as defined by El-Torito specs)
124 // - cdrom drive is hardcoded to ide 0 device 1 in several places. see "FIXME ElTorito Hardcoded"
125 // - int13 Fix DL when emulating a cd. In that case DL is decremented before calling real int13.
126 // This is ok. But DL should be reincremented afterwards.
127 // - Fix all "FIXME ElTorito Various"
128 // - should be able to boot any cdrom instead of the first one
129 //
130 // BCC Bug: find a generic way to handle the bug of #asm after an "if" (fixed in 0.16.7)
132 #define DEBUG_ROMBIOS 0
134 #define DEBUG_ATA 0
135 #define DEBUG_INT13_HD 0
136 #define DEBUG_INT13_CD 0
137 #define DEBUG_INT13_ET 0
138 #define DEBUG_INT13_FL 0
139 #define DEBUG_INT15 0
140 #define DEBUG_INT16 0
141 #define DEBUG_INT1A 0
142 #define DEBUG_INT74 0
143 #define DEBUG_APM 0
145 #define BX_CPU 3
146 #define BX_USE_PS2_MOUSE 1
147 #define BX_CALL_INT15_4F 1
148 #define BX_USE_EBDA 1
149 #define BX_SUPPORT_FLOPPY 1
150 #define BX_FLOPPY_ON_CNT 37 /* 2 seconds */
151 #define BX_PCIBIOS 1
152 #define BX_APM 1
154 #define BX_USE_ATADRV 1
155 #define BX_ELTORITO_BOOT 1
157 #define BX_MAX_ATA_INTERFACES 4
158 #define BX_MAX_ATA_DEVICES (BX_MAX_ATA_INTERFACES*2)
160 #define BX_VIRTUAL_PORTS 1 /* normal output to Bochs ports */
161 #define BX_DEBUG_SERIAL 0 /* output to COM1 */
163 /* model byte 0xFC = AT */
164 #define SYS_MODEL_ID 0xFC
165 #define SYS_SUBMODEL_ID 0x00
166 #define BIOS_REVISION 1
167 #define BIOS_CONFIG_TABLE 0xe6f5
169 #ifndef BIOS_BUILD_DATE
170 # define BIOS_BUILD_DATE "06/23/99"
171 #endif
173 // 1K of base memory used for Extended Bios Data Area (EBDA)
174 // EBDA is used for PS/2 mouse support, and IDE BIOS, etc.
175 #define EBDA_SEG 0x9FC0
176 #define EBDA_SIZE 1 // In KiB
177 #define BASE_MEM_IN_K (640 - EBDA_SIZE)
179 // Define the application NAME
180 #ifdef HVMASSIST
181 # define BX_APPNAME "HVMAssist"
182 #elif PLEX86
183 # define BX_APPNAME "Plex86"
184 #else
185 # define BX_APPNAME "Bochs"
186 #endif
188 // Sanity Checks
189 #if BX_USE_ATADRV && BX_CPU<3
190 # error The ATA/ATAPI Driver can only to be used with a 386+ cpu
191 #endif
192 #if BX_USE_ATADRV && !BX_USE_EBDA
193 # error ATA/ATAPI Driver can only be used if EBDA is available
194 #endif
195 #if BX_ELTORITO_BOOT && !BX_USE_ATADRV
196 # error El-Torito Boot can only be use if ATA/ATAPI Driver is available
197 #endif
198 #if BX_PCIBIOS && BX_CPU<3
199 # error PCI BIOS can only be used with 386+ cpu
200 #endif
201 #if BX_APM && BX_CPU<3
202 # error APM BIOS can only be used with 386+ cpu
203 #endif
205 #ifndef BX_SMP_PROCESSORS
206 #define BX_SMP_PROCESSORS 1
207 # warning BX_SMP_PROCESSORS not defined, defaulting to 1
208 #endif
210 #define PANIC_PORT 0x400
211 #define PANIC_PORT2 0x401
212 #define INFO_PORT 0x402
213 #define DEBUG_PORT 0x403
215 // #20 is dec 20
216 // #$20 is hex 20 = 32
217 // #0x20 is hex 20 = 32
218 // LDA #$20
219 // JSR $E820
220 // LDD .i,S
221 // JSR $C682
222 // mov al, #$20
224 // all hex literals should be prefixed with '0x'
225 // grep "#[0-9a-fA-F][0-9a-fA-F]" rombios.c
226 // no mov SEG-REG, #value, must mov register into seg-reg
227 // grep -i "mov[ ]*.s" rombios.c
229 // This is for compiling with gcc2 and gcc3
230 #define ASM_START #asm
231 #define ASM_END #endasm
233 ASM_START
234 .rom
236 .org 0x0000
238 #if BX_CPU >= 3
239 use16 386
240 #else
241 use16 286
242 #endif
244 MACRO HALT
245 ;; the HALT macro is called with the line number of the HALT call.
246 ;; The line number is then sent to the PANIC_PORT, causing Bochs/Plex
247 ;; to print a BX_PANIC message. This will normally halt the simulation
248 ;; with a message such as "BIOS panic at rombios.c, line 4091".
249 ;; However, users can choose to make panics non-fatal and continue.
250 #if BX_VIRTUAL_PORTS
251 mov dx,#PANIC_PORT
252 mov ax,#?1
253 out dx,ax
254 #else
255 mov dx,#0x80
256 mov ax,#?1
257 out dx,al
258 #endif
259 MEND
261 MACRO JMP_AP
262 db 0xea
263 dw ?2
264 dw ?1
265 MEND
267 MACRO SET_INT_VECTOR
268 mov ax, ?3
269 mov ?1*4, ax
270 mov ax, ?2
271 mov ?1*4+2, ax
272 MEND
274 ASM_END
276 typedef unsigned char Bit8u;
277 typedef unsigned short Bit16u;
278 typedef unsigned short bx_bool;
279 typedef unsigned long Bit32u;
281 #if BX_USE_ATADRV
283 void memsetb(seg,offset,value,count);
284 void memcpyb(dseg,doffset,sseg,soffset,count);
285 void memcpyd(dseg,doffset,sseg,soffset,count);
287 // memset of count bytes
288 void
289 memsetb(seg,offset,value,count)
290 Bit16u seg;
291 Bit16u offset;
292 Bit16u value;
293 Bit16u count;
294 {
295 ASM_START
296 push bp
297 mov bp, sp
299 push ax
300 push cx
301 push es
302 push di
304 mov cx, 10[bp] ; count
305 cmp cx, #0x00
306 je memsetb_end
307 mov ax, 4[bp] ; segment
308 mov es, ax
309 mov ax, 6[bp] ; offset
310 mov di, ax
311 mov al, 8[bp] ; value
312 cld
313 rep
314 stosb
316 memsetb_end:
317 pop di
318 pop es
319 pop cx
320 pop ax
322 pop bp
323 ASM_END
324 }
326 // memcpy of count bytes
327 void
328 memcpyb(dseg,doffset,sseg,soffset,count)
329 Bit16u dseg;
330 Bit16u doffset;
331 Bit16u sseg;
332 Bit16u soffset;
333 Bit16u count;
334 {
335 ASM_START
336 push bp
337 mov bp, sp
339 push ax
340 push cx
341 push es
342 push di
343 push ds
344 push si
346 mov cx, 12[bp] ; count
347 cmp cx, #0x0000
348 je memcpyb_end
349 mov ax, 4[bp] ; dsegment
350 mov es, ax
351 mov ax, 6[bp] ; doffset
352 mov di, ax
353 mov ax, 8[bp] ; ssegment
354 mov ds, ax
355 mov ax, 10[bp] ; soffset
356 mov si, ax
357 cld
358 rep
359 movsb
361 memcpyb_end:
362 pop si
363 pop ds
364 pop di
365 pop es
366 pop cx
367 pop ax
369 pop bp
370 ASM_END
371 }
373 #if 0
374 // memcpy of count dword
375 void
376 memcpyd(dseg,doffset,sseg,soffset,count)
377 Bit16u dseg;
378 Bit16u doffset;
379 Bit16u sseg;
380 Bit16u soffset;
381 Bit16u count;
382 {
383 ASM_START
384 push bp
385 mov bp, sp
387 push ax
388 push cx
389 push es
390 push di
391 push ds
392 push si
394 mov cx, 12[bp] ; count
395 cmp cx, #0x0000
396 je memcpyd_end
397 mov ax, 4[bp] ; dsegment
398 mov es, ax
399 mov ax, 6[bp] ; doffset
400 mov di, ax
401 mov ax, 8[bp] ; ssegment
402 mov ds, ax
403 mov ax, 10[bp] ; soffset
404 mov si, ax
405 cld
406 rep
407 movsd
409 memcpyd_end:
410 pop si
411 pop ds
412 pop di
413 pop es
414 pop cx
415 pop ax
417 pop bp
418 ASM_END
419 }
420 #endif
421 #endif //BX_USE_ATADRV
423 // read_dword and write_dword functions
424 static Bit32u read_dword();
425 static void write_dword();
427 Bit32u
428 read_dword(seg, offset)
429 Bit16u seg;
430 Bit16u offset;
431 {
432 ASM_START
433 push bp
434 mov bp, sp
436 push bx
437 push ds
438 mov ax, 4[bp] ; segment
439 mov ds, ax
440 mov bx, 6[bp] ; offset
441 mov ax, [bx]
442 inc bx
443 inc bx
444 mov dx, [bx]
445 ;; ax = return value (word)
446 ;; dx = return value (word)
447 pop ds
448 pop bx
450 pop bp
451 ASM_END
452 }
454 void
455 write_dword(seg, offset, data)
456 Bit16u seg;
457 Bit16u offset;
458 Bit32u data;
459 {
460 ASM_START
461 push bp
462 mov bp, sp
464 push ax
465 push bx
466 push ds
467 mov ax, 4[bp] ; segment
468 mov ds, ax
469 mov bx, 6[bp] ; offset
470 mov ax, 8[bp] ; data word
471 mov [bx], ax ; write data word
472 inc bx
473 inc bx
474 mov ax, 10[bp] ; data word
475 mov [bx], ax ; write data word
476 pop ds
477 pop bx
478 pop ax
480 pop bp
481 ASM_END
482 }
484 // Bit32u (unsigned long) and long helper functions
485 ASM_START
487 ;; and function
488 landl:
489 landul:
490 SEG SS
491 and ax,[di]
492 SEG SS
493 and bx,2[di]
494 ret
496 ;; add function
497 laddl:
498 laddul:
499 SEG SS
500 add ax,[di]
501 SEG SS
502 adc bx,2[di]
503 ret
505 ;; cmp function
506 lcmpl:
507 lcmpul:
508 and eax, #0x0000FFFF
509 shl ebx, #16
510 add eax, ebx
511 shr ebx, #16
512 SEG SS
513 cmp eax, dword ptr [di]
514 ret
516 ;; sub function
517 lsubl:
518 lsubul:
519 SEG SS
520 sub ax,[di]
521 SEG SS
522 sbb bx,2[di]
523 ret
525 ;; mul function
526 lmull:
527 lmulul:
528 and eax, #0x0000FFFF
529 shl ebx, #16
530 add eax, ebx
531 SEG SS
532 mul eax, dword ptr [di]
533 mov ebx, eax
534 shr ebx, #16
535 ret
537 ;; dec function
538 ldecl:
539 ldecul:
540 SEG SS
541 dec dword ptr [bx]
542 ret
544 ;; or function
545 lorl:
546 lorul:
547 SEG SS
548 or ax,[di]
549 SEG SS
550 or bx,2[di]
551 ret
553 ;; inc function
554 lincl:
555 lincul:
556 SEG SS
557 inc dword ptr [bx]
558 ret
560 ;; tst function
561 ltstl:
562 ltstul:
563 and eax, #0x0000FFFF
564 shl ebx, #16
565 add eax, ebx
566 shr ebx, #16
567 test eax, eax
568 ret
570 ;; sr function
571 lsrul:
572 mov cx,di
573 jcxz lsr_exit
574 and eax, #0x0000FFFF
575 shl ebx, #16
576 add eax, ebx
577 lsr_loop:
578 shr eax, #1
579 loop lsr_loop
580 mov ebx, eax
581 shr ebx, #16
582 lsr_exit:
583 ret
585 ;; sl function
586 lsll:
587 lslul:
588 mov cx,di
589 jcxz lsl_exit
590 and eax, #0x0000FFFF
591 shl ebx, #16
592 add eax, ebx
593 lsl_loop:
594 shl eax, #1
595 loop lsl_loop
596 mov ebx, eax
597 shr ebx, #16
598 lsl_exit:
599 ret
601 idiv_:
602 cwd
603 idiv bx
604 ret
606 idiv_u:
607 xor dx,dx
608 div bx
609 ret
611 ldivul:
612 and eax, #0x0000FFFF
613 shl ebx, #16
614 add eax, ebx
615 xor edx, edx
616 SEG SS
617 mov bx, 2[di]
618 shl ebx, #16
619 SEG SS
620 mov bx, [di]
621 div ebx
622 mov ebx, eax
623 shr ebx, #16
624 ret
626 ASM_END
628 // for access to RAM area which is used by interrupt vectors
629 // and BIOS Data Area
631 typedef struct {
632 unsigned char filler1[0x400];
633 unsigned char filler2[0x6c];
634 Bit16u ticks_low;
635 Bit16u ticks_high;
636 Bit8u midnight_flag;
637 } bios_data_t;
639 #define BiosData ((bios_data_t *) 0)
641 #if BX_USE_ATADRV
642 typedef struct {
643 Bit16u heads; // # heads
644 Bit16u cylinders; // # cylinders
645 Bit16u spt; // # sectors / track
646 } chs_t;
648 // DPTE definition
649 typedef struct {
650 Bit16u iobase1;
651 Bit16u iobase2;
652 Bit8u prefix;
653 Bit8u unused;
654 Bit8u irq;
655 Bit8u blkcount;
656 Bit8u dma;
657 Bit8u pio;
658 Bit16u options;
659 Bit16u reserved;
660 Bit8u revision;
661 Bit8u checksum;
662 } dpte_t;
664 typedef struct {
665 Bit8u iface; // ISA or PCI
666 Bit16u iobase1; // IO Base 1
667 Bit16u iobase2; // IO Base 2
668 Bit8u irq; // IRQ
669 } ata_channel_t;
671 typedef struct {
672 Bit8u type; // Detected type of ata (ata/atapi/none/unknown)
673 Bit8u device; // Detected type of attached devices (hd/cd/none)
674 Bit8u removable; // Removable device flag
675 Bit8u lock; // Locks for removable devices
676 // Bit8u lba_capable; // LBA capable flag - always yes for bochs devices
677 Bit8u mode; // transfert mode : PIO 16/32 bits - IRQ - ISADMA - PCIDMA
678 Bit16u blksize; // block size
680 Bit8u translation; // type of translation
681 chs_t lchs; // Logical CHS
682 chs_t pchs; // Physical CHS
684 Bit32u sectors; // Total sectors count
685 } ata_device_t;
687 typedef struct {
688 // ATA channels info
689 ata_channel_t channels[BX_MAX_ATA_INTERFACES];
691 // ATA devices info
692 ata_device_t devices[BX_MAX_ATA_DEVICES];
693 //
694 // map between (bios hd id - 0x80) and ata channels
695 Bit8u hdcount, hdidmap[BX_MAX_ATA_DEVICES];
697 // map between (bios cd id - 0xE0) and ata channels
698 Bit8u cdcount, cdidmap[BX_MAX_ATA_DEVICES];
700 // Buffer for DPTE table
701 dpte_t dpte;
703 // Count of transferred sectors and bytes
704 Bit16u trsfsectors;
705 Bit32u trsfbytes;
707 } ata_t;
709 #if BX_ELTORITO_BOOT
710 // ElTorito Device Emulation data
711 typedef struct {
712 Bit8u active;
713 Bit8u media;
714 Bit8u emulated_drive;
715 Bit8u controller_index;
716 Bit16u device_spec;
717 Bit32u ilba;
718 Bit16u buffer_segment;
719 Bit16u load_segment;
720 Bit16u sector_count;
722 // Virtual device
723 chs_t vdevice;
724 } cdemu_t;
725 #endif // BX_ELTORITO_BOOT
727 // for access to EBDA area
728 // The EBDA structure should conform to
729 // http://www.cybertrails.com/~fys/rombios.htm document
730 // I made the ata and cdemu structs begin at 0x121 in the EBDA seg
731 typedef struct {
732 unsigned char filler1[0x3D];
734 // FDPT - Can be splitted in data members if needed
735 unsigned char fdpt0[0x10];
736 unsigned char fdpt1[0x10];
738 unsigned char filler2[0xC4];
740 // ATA Driver data
741 ata_t ata;
743 #if BX_ELTORITO_BOOT
744 // El Torito Emulation data
745 cdemu_t cdemu;
746 #endif // BX_ELTORITO_BOOT
748 } ebda_data_t;
750 #define EbdaData ((ebda_data_t *) 0)
752 // for access to the int13ext structure
753 typedef struct {
754 Bit8u size;
755 Bit8u reserved;
756 Bit16u count;
757 Bit16u offset;
758 Bit16u segment;
759 Bit32u lba1;
760 Bit32u lba2;
761 } int13ext_t;
763 #define Int13Ext ((int13ext_t *) 0)
765 // Disk Physical Table definition
766 typedef struct {
767 Bit16u size;
768 Bit16u infos;
769 Bit32u cylinders;
770 Bit32u heads;
771 Bit32u spt;
772 Bit32u sector_count1;
773 Bit32u sector_count2;
774 Bit16u blksize;
775 Bit16u dpte_segment;
776 Bit16u dpte_offset;
777 Bit16u key;
778 Bit8u dpi_length;
779 Bit8u reserved1;
780 Bit16u reserved2;
781 Bit8u host_bus[4];
782 Bit8u iface_type[8];
783 Bit8u iface_path[8];
784 Bit8u device_path[8];
785 Bit8u reserved3;
786 Bit8u checksum;
787 } dpt_t;
789 #define Int13DPT ((dpt_t *) 0)
791 #endif // BX_USE_ATADRV
793 typedef struct {
794 union {
795 struct {
796 Bit16u di, si, bp, sp;
797 Bit16u bx, dx, cx, ax;
798 } r16;
799 struct {
800 Bit16u filler[4];
801 Bit8u bl, bh, dl, dh, cl, ch, al, ah;
802 } r8;
803 } u;
804 } pusha_regs_t;
806 typedef struct {
807 union {
808 struct {
809 Bit32u edi, esi, ebp, esp;
810 Bit32u ebx, edx, ecx, eax;
811 } r32;
812 struct {
813 Bit16u di, filler1, si, filler2, bp, filler3, sp, filler4;
814 Bit16u bx, filler5, dx, filler6, cx, filler7, ax, filler8;
815 } r16;
816 struct {
817 Bit32u filler[4];
818 Bit8u bl, bh;
819 Bit16u filler1;
820 Bit8u dl, dh;
821 Bit16u filler2;
822 Bit8u cl, ch;
823 Bit16u filler3;
824 Bit8u al, ah;
825 Bit16u filler4;
826 } r8;
827 } u;
828 } pushad_regs_t;
830 typedef struct {
831 union {
832 struct {
833 Bit16u flags;
834 } r16;
835 struct {
836 Bit8u flagsl;
837 Bit8u flagsh;
838 } r8;
839 } u;
840 } flags_t;
842 #define SetCF(x) x.u.r8.flagsl |= 0x01
843 #define SetZF(x) x.u.r8.flagsl |= 0x40
844 #define ClearCF(x) x.u.r8.flagsl &= 0xfe
845 #define ClearZF(x) x.u.r8.flagsl &= 0xbf
846 #define GetCF(x) (x.u.r8.flagsl & 0x01)
848 typedef struct {
849 Bit16u ip;
850 Bit16u cs;
851 flags_t flags;
852 } iret_addr_t;
856 static Bit8u inb();
857 static Bit8u inb_cmos();
858 static void outb();
859 static void outb_cmos();
860 static Bit16u inw();
861 static void outw();
862 static void init_rtc();
863 static bx_bool rtc_updating();
865 static Bit8u read_byte();
866 static Bit16u read_word();
867 static void write_byte();
868 static void write_word();
869 static void bios_printf();
870 static void copy_e820_table();
872 static Bit8u inhibit_mouse_int_and_events();
873 static void enable_mouse_int_and_events();
874 static Bit8u send_to_mouse_ctrl();
875 static Bit8u get_mouse_data();
876 static void set_kbd_command_byte();
878 static void int09_function();
879 static void int13_harddisk();
880 static void int13_cdrom();
881 static void int13_cdemu();
882 static void int13_eltorito();
883 static void int13_diskette_function();
884 static void int14_function();
885 static void int15_function();
886 static void int16_function();
887 static void int17_function();
888 static Bit32u int19_function();
889 static void int1a_function();
890 static void int70_function();
891 static void int74_function();
892 static Bit16u get_CS();
893 //static Bit16u get_DS();
894 //static void set_DS();
895 static Bit16u get_SS();
896 static unsigned int enqueue_key();
897 static unsigned int dequeue_key();
898 static void get_hd_geometry();
899 static void set_diskette_ret_status();
900 static void set_diskette_current_cyl();
901 static void determine_floppy_media();
902 static bx_bool floppy_drive_exists();
903 static bx_bool floppy_drive_recal();
904 static bx_bool floppy_media_known();
905 static bx_bool floppy_media_sense();
906 static bx_bool set_enable_a20();
907 static void debugger_on();
908 static void debugger_off();
909 static void keyboard_init();
910 static void keyboard_panic();
911 static void shutdown_status_panic();
912 static void nmi_handler_msg();
914 static void print_bios_banner();
915 static void print_boot_device();
916 static void print_boot_failure();
917 static void print_cdromboot_failure();
919 # if BX_USE_ATADRV
921 // ATA / ATAPI driver
922 void ata_init();
923 void ata_detect();
924 void ata_reset();
926 Bit16u ata_cmd_non_data();
927 Bit16u ata_cmd_data_in();
928 Bit16u ata_cmd_data_out();
929 Bit16u ata_cmd_packet();
931 Bit16u atapi_get_sense();
932 Bit16u atapi_is_ready();
933 Bit16u atapi_is_cdrom();
935 #endif // BX_USE_ATADRV
937 #if BX_ELTORITO_BOOT
939 void cdemu_init();
940 Bit8u cdemu_isactive();
941 Bit8u cdemu_emulated_drive();
943 Bit16u cdrom_boot();
945 #endif // BX_ELTORITO_BOOT
947 static char bios_cvs_version_string[] = "$Revision: 1.138 $";
948 static char bios_date_string[] = "$Date: 2005/05/07 15:55:26 $";
950 static char CVSID[] = "$Id: rombios.c,v 1.138 2005/05/07 15:55:26 vruppert Exp $";
952 /* Offset to skip the CVS $Id: prefix */
953 #define bios_version_string (CVSID + 4)
955 #define BIOS_PRINTF_HALT 1
956 #define BIOS_PRINTF_SCREEN 2
957 #define BIOS_PRINTF_INFO 4
958 #define BIOS_PRINTF_DEBUG 8
959 #define BIOS_PRINTF_ALL (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO)
960 #define BIOS_PRINTF_DEBHALT (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO | BIOS_PRINTF_HALT)
962 #define printf(format, p...) bios_printf(BIOS_PRINTF_SCREEN, format, ##p)
964 // Defines the output macros.
965 // BX_DEBUG goes to INFO port until we can easily choose debug info on a
966 // per-device basis. Debug info are sent only in debug mode
967 #if DEBUG_ROMBIOS
968 # define BX_DEBUG(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
969 #else
970 # define BX_DEBUG(format, p...)
971 #endif
972 #define BX_INFO(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
973 #define BX_PANIC(format, p...) bios_printf(BIOS_PRINTF_DEBHALT, format, ##p)
975 #if DEBUG_ATA
976 # define BX_DEBUG_ATA(a...) BX_DEBUG(a)
977 #else
978 # define BX_DEBUG_ATA(a...)
979 #endif
980 #if DEBUG_INT13_HD
981 # define BX_DEBUG_INT13_HD(a...) BX_DEBUG(a)
982 #else
983 # define BX_DEBUG_INT13_HD(a...)
984 #endif
985 #if DEBUG_INT13_CD
986 # define BX_DEBUG_INT13_CD(a...) BX_DEBUG(a)
987 #else
988 # define BX_DEBUG_INT13_CD(a...)
989 #endif
990 #if DEBUG_INT13_ET
991 # define BX_DEBUG_INT13_ET(a...) BX_DEBUG(a)
992 #else
993 # define BX_DEBUG_INT13_ET(a...)
994 #endif
995 #if DEBUG_INT13_FL
996 # define BX_DEBUG_INT13_FL(a...) BX_DEBUG(a)
997 #else
998 # define BX_DEBUG_INT13_FL(a...)
999 #endif
1000 #if DEBUG_INT15
1001 # define BX_DEBUG_INT15(a...) BX_DEBUG(a)
1002 #else
1003 # define BX_DEBUG_INT15(a...)
1004 #endif
1005 #if DEBUG_INT16
1006 # define BX_DEBUG_INT16(a...) BX_DEBUG(a)
1007 #else
1008 # define BX_DEBUG_INT16(a...)
1009 #endif
1010 #if DEBUG_INT1A
1011 # define BX_DEBUG_INT1A(a...) BX_DEBUG(a)
1012 #else
1013 # define BX_DEBUG_INT1A(a...)
1014 #endif
1015 #if DEBUG_INT74
1016 # define BX_DEBUG_INT74(a...) BX_DEBUG(a)
1017 #else
1018 # define BX_DEBUG_INT74(a...)
1019 #endif
1021 #define SET_AL(val8) AX = ((AX & 0xff00) | (val8))
1022 #define SET_BL(val8) BX = ((BX & 0xff00) | (val8))
1023 #define SET_CL(val8) CX = ((CX & 0xff00) | (val8))
1024 #define SET_DL(val8) DX = ((DX & 0xff00) | (val8))
1025 #define SET_AH(val8) AX = ((AX & 0x00ff) | ((val8) << 8))
1026 #define SET_BH(val8) BX = ((BX & 0x00ff) | ((val8) << 8))
1027 #define SET_CH(val8) CX = ((CX & 0x00ff) | ((val8) << 8))
1028 #define SET_DH(val8) DX = ((DX & 0x00ff) | ((val8) << 8))
1030 #define GET_AL() ( AX & 0x00ff )
1031 #define GET_BL() ( BX & 0x00ff )
1032 #define GET_CL() ( CX & 0x00ff )
1033 #define GET_DL() ( DX & 0x00ff )
1034 #define GET_AH() ( AX >> 8 )
1035 #define GET_BH() ( BX >> 8 )
1036 #define GET_CH() ( CX >> 8 )
1037 #define GET_DH() ( DX >> 8 )
1039 #define GET_ELDL() ( ELDX & 0x00ff )
1040 #define GET_ELDH() ( ELDX >> 8 )
1042 #define SET_CF() FLAGS |= 0x0001
1043 #define CLEAR_CF() FLAGS &= 0xfffe
1044 #define GET_CF() (FLAGS & 0x0001)
1046 #define SET_ZF() FLAGS |= 0x0040
1047 #define CLEAR_ZF() FLAGS &= 0xffbf
1048 #define GET_ZF() (FLAGS & 0x0040)
1050 #define UNSUPPORTED_FUNCTION 0x86
1052 #define none 0
1053 #define MAX_SCAN_CODE 0x53
1055 static struct {
1056 Bit16u normal;
1057 Bit16u shift;
1058 Bit16u control;
1059 Bit16u alt;
1060 Bit8u lock_flags;
1061 } scan_to_scanascii[MAX_SCAN_CODE + 1] = {
1062 { none, none, none, none, none },
1063 { 0x011b, 0x011b, 0x011b, 0x0100, none }, /* escape */
1064 { 0x0231, 0x0221, none, 0x7800, none }, /* 1! */
1065 { 0x0332, 0x0340, 0x0300, 0x7900, none }, /* 2@ */
1066 { 0x0433, 0x0423, none, 0x7a00, none }, /* 3# */
1067 { 0x0534, 0x0524, none, 0x7b00, none }, /* 4$ */
1068 { 0x0635, 0x0625, none, 0x7c00, none }, /* 5% */
1069 { 0x0736, 0x075e, 0x071e, 0x7d00, none }, /* 6^ */
1070 { 0x0837, 0x0826, none, 0x7e00, none }, /* 7& */
1071 { 0x0938, 0x092a, none, 0x7f00, none }, /* 8* */
1072 { 0x0a39, 0x0a28, none, 0x8000, none }, /* 9( */
1073 { 0x0b30, 0x0b29, none, 0x8100, none }, /* 0) */
1074 { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200, none }, /* -_ */
1075 { 0x0d3d, 0x0d2b, none, 0x8300, none }, /* =+ */
1076 { 0x0e08, 0x0e08, 0x0e7f, none, none }, /* backspace */
1077 { 0x0f09, 0x0f00, none, none, none }, /* tab */
1078 { 0x1071, 0x1051, 0x1011, 0x1000, 0x40 }, /* Q */
1079 { 0x1177, 0x1157, 0x1117, 0x1100, 0x40 }, /* W */
1080 { 0x1265, 0x1245, 0x1205, 0x1200, 0x40 }, /* E */
1081 { 0x1372, 0x1352, 0x1312, 0x1300, 0x40 }, /* R */
1082 { 0x1474, 0x1454, 0x1414, 0x1400, 0x40 }, /* T */
1083 { 0x1579, 0x1559, 0x1519, 0x1500, 0x40 }, /* Y */
1084 { 0x1675, 0x1655, 0x1615, 0x1600, 0x40 }, /* U */
1085 { 0x1769, 0x1749, 0x1709, 0x1700, 0x40 }, /* I */
1086 { 0x186f, 0x184f, 0x180f, 0x1800, 0x40 }, /* O */
1087 { 0x1970, 0x1950, 0x1910, 0x1900, 0x40 }, /* P */
1088 { 0x1a5b, 0x1a7b, 0x1a1b, none, none }, /* [{ */
1089 { 0x1b5d, 0x1b7d, 0x1b1d, none, none }, /* ]} */
1090 { 0x1c0d, 0x1c0d, 0x1c0a, none, none }, /* Enter */
1091 { none, none, none, none, none }, /* L Ctrl */
1092 { 0x1e61, 0x1e41, 0x1e01, 0x1e00, 0x40 }, /* A */
1093 { 0x1f73, 0x1f53, 0x1f13, 0x1f00, 0x40 }, /* S */
1094 { 0x2064, 0x2044, 0x2004, 0x2000, 0x40 }, /* D */
1095 { 0x2166, 0x2146, 0x2106, 0x2100, 0x40 }, /* F */
1096 { 0x2267, 0x2247, 0x2207, 0x2200, 0x40 }, /* G */
1097 { 0x2368, 0x2348, 0x2308, 0x2300, 0x40 }, /* H */
1098 { 0x246a, 0x244a, 0x240a, 0x2400, 0x40 }, /* J */
1099 { 0x256b, 0x254b, 0x250b, 0x2500, 0x40 }, /* K */
1100 { 0x266c, 0x264c, 0x260c, 0x2600, 0x40 }, /* L */
1101 { 0x273b, 0x273a, none, none, none }, /* ;: */
1102 { 0x2827, 0x2822, none, none, none }, /* '" */
1103 { 0x2960, 0x297e, none, none, none }, /* `~ */
1104 { none, none, none, none, none }, /* L shift */
1105 { 0x2b5c, 0x2b7c, 0x2b1c, none, none }, /* |\ */
1106 { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, 0x40 }, /* Z */
1107 { 0x2d78, 0x2d58, 0x2d18, 0x2d00, 0x40 }, /* X */
1108 { 0x2e63, 0x2e43, 0x2e03, 0x2e00, 0x40 }, /* C */
1109 { 0x2f76, 0x2f56, 0x2f16, 0x2f00, 0x40 }, /* V */
1110 { 0x3062, 0x3042, 0x3002, 0x3000, 0x40 }, /* B */
1111 { 0x316e, 0x314e, 0x310e, 0x3100, 0x40 }, /* N */
1112 { 0x326d, 0x324d, 0x320d, 0x3200, 0x40 }, /* M */
1113 { 0x332c, 0x333c, none, none, none }, /* ,< */
1114 { 0x342e, 0x343e, none, none, none }, /* .> */
1115 { 0x352f, 0x353f, none, none, none }, /* /? */
1116 { none, none, none, none, none }, /* R Shift */
1117 { 0x372a, 0x372a, none, none, none }, /* * */
1118 { none, none, none, none, none }, /* L Alt */
1119 { 0x3920, 0x3920, 0x3920, 0x3920, none }, /* space */
1120 { none, none, none, none, none }, /* caps lock */
1121 { 0x3b00, 0x5400, 0x5e00, 0x6800, none }, /* F1 */
1122 { 0x3c00, 0x5500, 0x5f00, 0x6900, none }, /* F2 */
1123 { 0x3d00, 0x5600, 0x6000, 0x6a00, none }, /* F3 */
1124 { 0x3e00, 0x5700, 0x6100, 0x6b00, none }, /* F4 */
1125 { 0x3f00, 0x5800, 0x6200, 0x6c00, none }, /* F5 */
1126 { 0x4000, 0x5900, 0x6300, 0x6d00, none }, /* F6 */
1127 { 0x4100, 0x5a00, 0x6400, 0x6e00, none }, /* F7 */
1128 { 0x4200, 0x5b00, 0x6500, 0x6f00, none }, /* F8 */
1129 { 0x4300, 0x5c00, 0x6600, 0x7000, none }, /* F9 */
1130 { 0x4400, 0x5d00, 0x6700, 0x7100, none }, /* F10 */
1131 { none, none, none, none, none }, /* Num Lock */
1132 { none, none, none, none, none }, /* Scroll Lock */
1133 { 0x4700, 0x4737, 0x7700, none, 0x20 }, /* 7 Home */
1134 { 0x4800, 0x4838, none, none, 0x20 }, /* 8 UP */
1135 { 0x4900, 0x4939, 0x8400, none, 0x20 }, /* 9 PgUp */
1136 { 0x4a2d, 0x4a2d, none, none, none }, /* - */
1137 { 0x4b00, 0x4b34, 0x7300, none, 0x20 }, /* 4 Left */
1138 { 0x4c00, 0x4c35, none, none, 0x20 }, /* 5 */
1139 { 0x4d00, 0x4d36, 0x7400, none, 0x20 }, /* 6 Right */
1140 { 0x4e2b, 0x4e2b, none, none, none }, /* + */
1141 { 0x4f00, 0x4f31, 0x7500, none, 0x20 }, /* 1 End */
1142 { 0x5000, 0x5032, none, none, 0x20 }, /* 2 Down */
1143 { 0x5100, 0x5133, 0x7600, none, 0x20 }, /* 3 PgDn */
1144 { 0x5200, 0x5230, none, none, 0x20 }, /* 0 Ins */
1145 { 0x5300, 0x532e, none, none, 0x20 } /* Del */
1146 };
1148 Bit8u
1149 inb(port)
1150 Bit16u port;
1152 ASM_START
1153 push bp
1154 mov bp, sp
1156 push dx
1157 mov dx, 4[bp]
1158 in al, dx
1159 pop dx
1161 pop bp
1162 ASM_END
1165 #if BX_USE_ATADRV
1166 Bit16u
1167 inw(port)
1168 Bit16u port;
1170 ASM_START
1171 push bp
1172 mov bp, sp
1174 push dx
1175 mov dx, 4[bp]
1176 in ax, dx
1177 pop dx
1179 pop bp
1180 ASM_END
1182 #endif
1184 void
1185 outb(port, val)
1186 Bit16u port;
1187 Bit8u val;
1189 ASM_START
1190 push bp
1191 mov bp, sp
1193 push ax
1194 push dx
1195 mov dx, 4[bp]
1196 mov al, 6[bp]
1197 out dx, al
1198 pop dx
1199 pop ax
1201 pop bp
1202 ASM_END
1205 #if BX_USE_ATADRV
1206 void
1207 outw(port, val)
1208 Bit16u port;
1209 Bit16u val;
1211 ASM_START
1212 push bp
1213 mov bp, sp
1215 push ax
1216 push dx
1217 mov dx, 4[bp]
1218 mov ax, 6[bp]
1219 out dx, ax
1220 pop dx
1221 pop ax
1223 pop bp
1224 ASM_END
1226 #endif
1228 void
1229 outb_cmos(cmos_reg, val)
1230 Bit8u cmos_reg;
1231 Bit8u val;
1233 ASM_START
1234 push bp
1235 mov bp, sp
1237 mov al, 4[bp] ;; cmos_reg
1238 out 0x70, al
1239 mov al, 6[bp] ;; val
1240 out 0x71, al
1242 pop bp
1243 ASM_END
1246 Bit8u
1247 inb_cmos(cmos_reg)
1248 Bit8u cmos_reg;
1250 ASM_START
1251 push bp
1252 mov bp, sp
1254 mov al, 4[bp] ;; cmos_reg
1255 out 0x70, al
1256 in al, 0x71
1258 pop bp
1259 ASM_END
1262 void
1263 init_rtc()
1265 outb_cmos(0x0a, 0x26);
1266 outb_cmos(0x0b, 0x02);
1267 inb_cmos(0x0c);
1268 inb_cmos(0x0d);
1271 bx_bool
1272 rtc_updating()
1274 // This function checks to see if the update-in-progress bit
1275 // is set in CMOS Status Register A. If not, it returns 0.
1276 // If it is set, it tries to wait until there is a transition
1277 // to 0, and will return 0 if such a transition occurs. A 1
1278 // is returned only after timing out. The maximum period
1279 // that this bit should be set is constrained to 244useconds.
1280 // The count I use below guarantees coverage or more than
1281 // this time, with any reasonable IPS setting.
1283 Bit16u count;
1285 count = 25000;
1286 while (--count != 0) {
1287 if ( (inb_cmos(0x0a) & 0x80) == 0 )
1288 return(0);
1290 return(1); // update-in-progress never transitioned to 0
1294 Bit8u
1295 read_byte(seg, offset)
1296 Bit16u seg;
1297 Bit16u offset;
1299 ASM_START
1300 push bp
1301 mov bp, sp
1303 push bx
1304 push ds
1305 mov ax, 4[bp] ; segment
1306 mov ds, ax
1307 mov bx, 6[bp] ; offset
1308 mov al, [bx]
1309 ;; al = return value (byte)
1310 pop ds
1311 pop bx
1313 pop bp
1314 ASM_END
1317 Bit16u
1318 read_word(seg, offset)
1319 Bit16u seg;
1320 Bit16u offset;
1322 ASM_START
1323 push bp
1324 mov bp, sp
1326 push bx
1327 push ds
1328 mov ax, 4[bp] ; segment
1329 mov ds, ax
1330 mov bx, 6[bp] ; offset
1331 mov ax, [bx]
1332 ;; ax = return value (word)
1333 pop ds
1334 pop bx
1336 pop bp
1337 ASM_END
1340 void
1341 write_byte(seg, offset, data)
1342 Bit16u seg;
1343 Bit16u offset;
1344 Bit8u data;
1346 ASM_START
1347 push bp
1348 mov bp, sp
1350 push ax
1351 push bx
1352 push ds
1353 mov ax, 4[bp] ; segment
1354 mov ds, ax
1355 mov bx, 6[bp] ; offset
1356 mov al, 8[bp] ; data byte
1357 mov [bx], al ; write data byte
1358 pop ds
1359 pop bx
1360 pop ax
1362 pop bp
1363 ASM_END
1366 void
1367 write_word(seg, offset, data)
1368 Bit16u seg;
1369 Bit16u offset;
1370 Bit16u data;
1372 ASM_START
1373 push bp
1374 mov bp, sp
1376 push ax
1377 push bx
1378 push ds
1379 mov ax, 4[bp] ; segment
1380 mov ds, ax
1381 mov bx, 6[bp] ; offset
1382 mov ax, 8[bp] ; data word
1383 mov [bx], ax ; write data word
1384 pop ds
1385 pop bx
1386 pop ax
1388 pop bp
1389 ASM_END
1392 Bit16u
1393 get_CS()
1395 ASM_START
1396 mov ax, cs
1397 ASM_END
1400 // Bit16u
1401 //get_DS()
1402 //{
1403 //ASM_START
1404 // mov ax, ds
1405 //ASM_END
1406 //}
1407 //
1408 // void
1409 //set_DS(ds_selector)
1410 // Bit16u ds_selector;
1411 //{
1412 //ASM_START
1413 // push bp
1414 // mov bp, sp
1415 //
1416 // push ax
1417 // mov ax, 4[bp] ; ds_selector
1418 // mov ds, ax
1419 // pop ax
1420 //
1421 // pop bp
1422 //ASM_END
1423 //}
1425 Bit16u
1426 get_SS()
1428 ASM_START
1429 mov ax, ss
1430 ASM_END
1433 #ifdef HVMASSIST
1434 void
1435 copy_e820_table()
1437 Bit8u nr_entries = read_byte(0x9000, 0x1e8);
1438 if (nr_entries > 32)
1439 nr_entries = 32;
1440 write_word(0xe000, 0x8, nr_entries);
1441 memcpyb(0xe000, 0x10, 0x9000, 0x2d0, nr_entries * 0x14);
1443 #endif /* HVMASSIST */
1445 #if BX_DEBUG_SERIAL
1446 /* serial debug port*/
1447 #define BX_DEBUG_PORT 0x03f8
1449 /* data */
1450 #define UART_RBR 0x00
1451 #define UART_THR 0x00
1453 /* control */
1454 #define UART_IER 0x01
1455 #define UART_IIR 0x02
1456 #define UART_FCR 0x02
1457 #define UART_LCR 0x03
1458 #define UART_MCR 0x04
1459 #define UART_DLL 0x00
1460 #define UART_DLM 0x01
1462 /* status */
1463 #define UART_LSR 0x05
1464 #define UART_MSR 0x06
1465 #define UART_SCR 0x07
1467 int uart_can_tx_byte(base_port)
1468 Bit16u base_port;
1470 return inb(base_port + UART_LSR) & 0x20;
1473 void uart_wait_to_tx_byte(base_port)
1474 Bit16u base_port;
1476 while (!uart_can_tx_byte(base_port));
1479 void uart_wait_until_sent(base_port)
1480 Bit16u base_port;
1482 while (!(inb(base_port + UART_LSR) & 0x40));
1485 void uart_tx_byte(base_port, data)
1486 Bit16u base_port;
1487 Bit8u data;
1489 uart_wait_to_tx_byte(base_port);
1490 outb(base_port + UART_THR, data);
1491 uart_wait_until_sent(base_port);
1493 #endif
1495 void
1496 wrch(c)
1497 Bit8u c;
1499 ASM_START
1500 push bp
1501 mov bp, sp
1503 push bx
1504 mov ah, #0x0e
1505 mov al, 4[bp]
1506 xor bx,bx
1507 int #0x10
1508 pop bx
1510 pop bp
1511 ASM_END
1514 void
1515 send(action, c)
1516 Bit16u action;
1517 Bit8u c;
1519 #if BX_DEBUG_SERIAL
1520 if (c == '\n') uart_tx_byte(BX_DEBUG_PORT, '\r');
1521 uart_tx_byte(BX_DEBUG_PORT, c);
1522 #endif
1523 #ifdef HVMASSIST
1524 outb(0xE9, c);
1525 #endif
1526 #if BX_VIRTUAL_PORTS
1527 if (action & BIOS_PRINTF_DEBUG) outb(DEBUG_PORT, c);
1528 if (action & BIOS_PRINTF_INFO) outb(INFO_PORT, c);
1529 #endif
1530 if (action & BIOS_PRINTF_SCREEN) {
1531 if (c == '\n') wrch('\r');
1532 wrch(c);
1536 void
1537 put_int(action, val, width, neg)
1538 Bit16u action;
1539 short val, width;
1540 bx_bool neg;
1542 short nval = val / 10;
1543 if (nval)
1544 put_int(action, nval, width - 1, neg);
1545 else {
1546 while (--width > 0) send(action, ' ');
1547 if (neg) send(action, '-');
1549 send(action, val - (nval * 10) + '0');
1552 void
1553 put_uint(action, val, width, neg)
1554 Bit16u action;
1555 unsigned short val;
1556 short width;
1557 bx_bool neg;
1559 unsigned short nval = val / 10;
1560 if (nval)
1561 put_uint(action, nval, width - 1, neg);
1562 else {
1563 while (--width > 0) send(action, ' ');
1564 if (neg) send(action, '-');
1566 send(action, val - (nval * 10) + '0');
1569 //--------------------------------------------------------------------------
1570 // bios_printf()
1571 // A compact variable argument printf function which prints its output via
1572 // an I/O port so that it can be logged by Bochs/Plex.
1573 // Currently, only %x is supported (or %02x, %04x, etc).
1574 //
1575 // Supports %[format_width][format]
1576 // where format can be d,x,c,s
1577 //--------------------------------------------------------------------------
1578 void
1579 bios_printf(action, s)
1580 Bit16u action;
1581 Bit8u *s;
1583 Bit8u c, format_char;
1584 bx_bool in_format;
1585 short i;
1586 Bit16u *arg_ptr;
1587 Bit16u arg_seg, arg, nibble, shift_count, format_width;
1589 arg_ptr = &s;
1590 arg_seg = get_SS();
1592 in_format = 0;
1593 format_width = 0;
1595 if ((action & BIOS_PRINTF_DEBHALT) == BIOS_PRINTF_DEBHALT) {
1596 #if BX_VIRTUAL_PORTS
1597 outb(PANIC_PORT2, 0x00);
1598 #endif
1599 bios_printf (BIOS_PRINTF_SCREEN, "FATAL: ");
1602 while (c = read_byte(get_CS(), s)) {
1603 if ( c == '%' ) {
1604 in_format = 1;
1605 format_width = 0;
1607 else if (in_format) {
1608 if ( (c>='0') && (c<='9') ) {
1609 format_width = (format_width * 10) + (c - '0');
1611 else {
1612 arg_ptr++; // increment to next arg
1613 arg = read_word(arg_seg, arg_ptr);
1614 if (c == 'x') {
1615 if (format_width == 0)
1616 format_width = 4;
1617 for (i=format_width-1; i>=0; i--) {
1618 nibble = (arg >> (4 * i)) & 0x000f;
1619 send (action, (nibble<=9)? (nibble+'0') : (nibble-10+'A'));
1622 else if (c == 'u') {
1623 put_uint(action, arg, format_width, 0);
1625 else if (c == 'd') {
1626 if (arg & 0x8000)
1627 put_int(action, -arg, format_width - 1, 1);
1628 else
1629 put_int(action, arg, format_width, 0);
1631 else if (c == 's') {
1632 bios_printf(action & (~BIOS_PRINTF_HALT), arg);
1634 else if (c == 'c') {
1635 send(action, arg);
1637 else
1638 BX_PANIC("bios_printf: unknown format\n");
1639 in_format = 0;
1642 else {
1643 send(action, c);
1645 s ++;
1648 if (action & BIOS_PRINTF_HALT) {
1649 // freeze in a busy loop.
1650 ASM_START
1651 cli
1652 halt2_loop:
1653 hlt
1654 jmp halt2_loop
1655 ASM_END
1659 //--------------------------------------------------------------------------
1660 // keyboard_init
1661 //--------------------------------------------------------------------------
1662 // this file is based on LinuxBIOS implementation of keyboard.c
1663 // could convert to #asm to gain space
1664 void
1665 keyboard_init()
1667 Bit16u max;
1669 /* ------------------- Flush buffers ------------------------*/
1670 /* Wait until buffer is empty */
1671 max=0xffff;
1672 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
1674 /* flush incoming keys */
1675 max=0x2000;
1676 while (--max > 0) {
1677 outb(0x80, 0x00);
1678 if (inb(0x64) & 0x01) {
1679 inb(0x60);
1680 max = 0x2000;
1684 // Due to timer issues, and if the IPS setting is > 15000000,
1685 // the incoming keys might not be flushed here. That will
1686 // cause a panic a few lines below. See sourceforge bug report :
1687 // [ 642031 ] FATAL: Keyboard RESET error:993
1689 /* ------------------- controller side ----------------------*/
1690 /* send cmd = 0xAA, self test 8042 */
1691 outb(0x64, 0xaa);
1693 /* Wait until buffer is empty */
1694 max=0xffff;
1695 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
1696 if (max==0x0) keyboard_panic(00);
1698 /* Wait for data */
1699 max=0xffff;
1700 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x01);
1701 if (max==0x0) keyboard_panic(01);
1703 /* read self-test result, 0x55 should be returned from 0x60 */
1704 if ((inb(0x60) != 0x55)){
1705 keyboard_panic(991);
1708 /* send cmd = 0xAB, keyboard interface test */
1709 outb(0x64,0xab);
1711 /* Wait until buffer is empty */
1712 max=0xffff;
1713 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x10);
1714 if (max==0x0) keyboard_panic(10);
1716 /* Wait for data */
1717 max=0xffff;
1718 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x11);
1719 if (max==0x0) keyboard_panic(11);
1721 /* read keyboard interface test result, */
1722 /* 0x00 should be returned form 0x60 */
1723 if ((inb(0x60) != 0x00)) {
1724 keyboard_panic(992);
1727 /* Enable Keyboard clock */
1728 outb(0x64,0xae);
1729 outb(0x64,0xa8);
1731 /* ------------------- keyboard side ------------------------*/
1732 /* reset kerboard and self test (keyboard side) */
1733 outb(0x60, 0xff);
1735 /* Wait until buffer is empty */
1736 max=0xffff;
1737 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x20);
1738 if (max==0x0) keyboard_panic(20);
1740 /* Wait for data */
1741 max=0xffff;
1742 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x21);
1743 if (max==0x0) keyboard_panic(21);
1745 /* keyboard should return ACK */
1746 if ((inb(0x60) != 0xfa)) {
1747 keyboard_panic(993);
1750 /* Wait for data */
1751 max=0xffff;
1752 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x31);
1753 if (max==0x0) keyboard_panic(31);
1755 if ((inb(0x60) != 0xaa)) {
1756 keyboard_panic(994);
1759 /* Disable keyboard */
1760 outb(0x60, 0xf5);
1762 /* Wait until buffer is empty */
1763 max=0xffff;
1764 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x40);
1765 if (max==0x0) keyboard_panic(40);
1767 /* Wait for data */
1768 max=0xffff;
1769 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x41);
1770 if (max==0x0) keyboard_panic(41);
1772 /* keyboard should return ACK */
1773 if ((inb(0x60) != 0xfa)) {
1774 keyboard_panic(995);
1777 /* Write Keyboard Mode */
1778 outb(0x64, 0x60);
1780 /* Wait until buffer is empty */
1781 max=0xffff;
1782 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x50);
1783 if (max==0x0) keyboard_panic(50);
1785 /* send cmd: scan code convert, disable mouse, enable IRQ 1 */
1786 outb(0x60, 0x61);
1788 /* Wait until buffer is empty */
1789 max=0xffff;
1790 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x60);
1791 if (max==0x0) keyboard_panic(60);
1793 /* Enable keyboard */
1794 outb(0x60, 0xf4);
1796 /* Wait until buffer is empty */
1797 max=0xffff;
1798 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x70);
1799 if (max==0x0) keyboard_panic(70);
1801 /* Wait for data */
1802 max=0xffff;
1803 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x71);
1804 if (max==0x0) keyboard_panic(70);
1806 /* keyboard should return ACK */
1807 if ((inb(0x60) != 0xfa)) {
1808 keyboard_panic(996);
1811 outb(0x80, 0x77);
1814 //--------------------------------------------------------------------------
1815 // keyboard_panic
1816 //--------------------------------------------------------------------------
1817 void
1818 keyboard_panic(status)
1819 Bit16u status;
1821 // If you're getting a 993 keyboard panic here,
1822 // please see the comment in keyboard_init
1824 BX_PANIC("Keyboard error:%u\n",status);
1827 //--------------------------------------------------------------------------
1828 // shutdown_status_panic
1829 // called when the shutdown statsu is not implemented, displays the status
1830 //--------------------------------------------------------------------------
1831 void
1832 shutdown_status_panic(status)
1833 Bit16u status;
1835 BX_PANIC("Unimplemented shutdown status: %02x\n",(Bit8u)status);
1838 //--------------------------------------------------------------------------
1839 // print_bios_banner
1840 // displays a the bios version
1841 //--------------------------------------------------------------------------
1842 void
1843 print_bios_banner()
1845 printf(BX_APPNAME" BIOS, %d cpu%s, ", BX_SMP_PROCESSORS, BX_SMP_PROCESSORS>1?"s":"");
1846 printf("%s %s\n", bios_cvs_version_string, bios_date_string);
1847 printf("\n");
1850 //--------------------------------------------------------------------------
1851 // print_boot_device
1852 // displays the boot device
1853 //--------------------------------------------------------------------------
1855 static char drivetypes[][10]={"Floppy","Hard Disk","CD-Rom"};
1857 void
1858 print_boot_device(cdboot, drive)
1859 Bit8u cdboot; Bit16u drive;
1861 Bit8u i;
1863 // cdboot contains 0 if floppy/harddisk, 1 otherwise
1864 // drive contains real/emulated boot drive
1866 if(cdboot)i=2; // CD-Rom
1867 else if((drive&0x0080)==0x00)i=0; // Floppy
1868 else if((drive&0x0080)==0x80)i=1; // Hard drive
1869 else return;
1871 printf("Booting from %s...\n",drivetypes[i]);
1874 //--------------------------------------------------------------------------
1875 // print_boot_failure
1876 // displays the reason why boot failed
1877 //--------------------------------------------------------------------------
1878 void
1879 print_boot_failure(cdboot, drive, reason, lastdrive)
1880 Bit8u cdboot; Bit8u drive; Bit8u lastdrive;
1882 Bit16u drivenum = drive&0x7f;
1884 // cdboot: 1 if boot from cd, 0 otherwise
1885 // drive : drive number
1886 // reason: 0 signature check failed, 1 read error
1887 // lastdrive: 1 boot drive is the last one in boot sequence
1889 if (cdboot)
1890 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s failed\n",drivetypes[2]);
1891 else if (drive & 0x80)
1892 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[1],drivenum);
1893 else
1894 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[0],drivenum);
1896 if (lastdrive==1) {
1897 if (reason==0)
1898 BX_PANIC("Not a bootable disk\n");
1899 else
1900 BX_PANIC("Could not read the boot disk\n");
1904 //--------------------------------------------------------------------------
1905 // print_cdromboot_failure
1906 // displays the reason why boot failed
1907 //--------------------------------------------------------------------------
1908 void
1909 print_cdromboot_failure( code )
1910 Bit16u code;
1912 bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "CDROM boot failure code : %04x\n",code);
1914 return;
1917 void
1918 nmi_handler_msg()
1920 BX_PANIC("NMI Handler called\n");
1923 void
1924 int18_panic_msg()
1926 BX_PANIC("INT18: BOOT FAILURE\n");
1929 void
1930 log_bios_start()
1932 #if BX_DEBUG_SERIAL
1933 outb(BX_DEBUG_PORT+UART_LCR, 0x03); /* setup for serial logging: 8N1 */
1934 #endif
1935 BX_INFO("%s\n", bios_version_string);
1938 bx_bool
1939 set_enable_a20(val)
1940 bx_bool val;
1942 Bit8u oldval;
1944 // Use PS2 System Control port A to set A20 enable
1946 // get current setting first
1947 oldval = inb(0x92);
1949 // change A20 status
1950 if (val)
1951 outb(0x92, oldval | 0x02);
1952 else
1953 outb(0x92, oldval & 0xfd);
1955 return((oldval & 0x02) != 0);
1958 void
1959 debugger_on()
1961 outb(0xfedc, 0x01);
1964 void
1965 debugger_off()
1967 outb(0xfedc, 0x00);
1970 #if BX_USE_ATADRV
1972 // ---------------------------------------------------------------------------
1973 // Start of ATA/ATAPI Driver
1974 // ---------------------------------------------------------------------------
1976 // Global defines -- ATA register and register bits.
1977 // command block & control block regs
1978 #define ATA_CB_DATA 0 // data reg in/out pio_base_addr1+0
1979 #define ATA_CB_ERR 1 // error in pio_base_addr1+1
1980 #define ATA_CB_FR 1 // feature reg out pio_base_addr1+1
1981 #define ATA_CB_SC 2 // sector count in/out pio_base_addr1+2
1982 #define ATA_CB_SN 3 // sector number in/out pio_base_addr1+3
1983 #define ATA_CB_CL 4 // cylinder low in/out pio_base_addr1+4
1984 #define ATA_CB_CH 5 // cylinder high in/out pio_base_addr1+5
1985 #define ATA_CB_DH 6 // device head in/out pio_base_addr1+6
1986 #define ATA_CB_STAT 7 // primary status in pio_base_addr1+7
1987 #define ATA_CB_CMD 7 // command out pio_base_addr1+7
1988 #define ATA_CB_ASTAT 6 // alternate status in pio_base_addr2+6
1989 #define ATA_CB_DC 6 // device control out pio_base_addr2+6
1990 #define ATA_CB_DA 7 // device address in pio_base_addr2+7
1992 #define ATA_CB_ER_ICRC 0x80 // ATA Ultra DMA bad CRC
1993 #define ATA_CB_ER_BBK 0x80 // ATA bad block
1994 #define ATA_CB_ER_UNC 0x40 // ATA uncorrected error
1995 #define ATA_CB_ER_MC 0x20 // ATA media change
1996 #define ATA_CB_ER_IDNF 0x10 // ATA id not found
1997 #define ATA_CB_ER_MCR 0x08 // ATA media change request
1998 #define ATA_CB_ER_ABRT 0x04 // ATA command aborted
1999 #define ATA_CB_ER_NTK0 0x02 // ATA track 0 not found
2000 #define ATA_CB_ER_NDAM 0x01 // ATA address mark not found
2002 #define ATA_CB_ER_P_SNSKEY 0xf0 // ATAPI sense key (mask)
2003 #define ATA_CB_ER_P_MCR 0x08 // ATAPI Media Change Request
2004 #define ATA_CB_ER_P_ABRT 0x04 // ATAPI command abort
2005 #define ATA_CB_ER_P_EOM 0x02 // ATAPI End of Media
2006 #define ATA_CB_ER_P_ILI 0x01 // ATAPI Illegal Length Indication
2008 // ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC)
2009 #define ATA_CB_SC_P_TAG 0xf8 // ATAPI tag (mask)
2010 #define ATA_CB_SC_P_REL 0x04 // ATAPI release
2011 #define ATA_CB_SC_P_IO 0x02 // ATAPI I/O
2012 #define ATA_CB_SC_P_CD 0x01 // ATAPI C/D
2014 // bits 7-4 of the device/head (CB_DH) reg
2015 #define ATA_CB_DH_DEV0 0xa0 // select device 0
2016 #define ATA_CB_DH_DEV1 0xb0 // select device 1
2018 // status reg (CB_STAT and CB_ASTAT) bits
2019 #define ATA_CB_STAT_BSY 0x80 // busy
2020 #define ATA_CB_STAT_RDY 0x40 // ready
2021 #define ATA_CB_STAT_DF 0x20 // device fault
2022 #define ATA_CB_STAT_WFT 0x20 // write fault (old name)
2023 #define ATA_CB_STAT_SKC 0x10 // seek complete
2024 #define ATA_CB_STAT_SERV 0x10 // service
2025 #define ATA_CB_STAT_DRQ 0x08 // data request
2026 #define ATA_CB_STAT_CORR 0x04 // corrected
2027 #define ATA_CB_STAT_IDX 0x02 // index
2028 #define ATA_CB_STAT_ERR 0x01 // error (ATA)
2029 #define ATA_CB_STAT_CHK 0x01 // check (ATAPI)
2031 // device control reg (CB_DC) bits
2032 #define ATA_CB_DC_HD15 0x08 // bit should always be set to one
2033 #define ATA_CB_DC_SRST 0x04 // soft reset
2034 #define ATA_CB_DC_NIEN 0x02 // disable interrupts
2036 // Most mandtory and optional ATA commands (from ATA-3),
2037 #define ATA_CMD_CFA_ERASE_SECTORS 0xC0
2038 #define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03
2039 #define ATA_CMD_CFA_TRANSLATE_SECTOR 0x87
2040 #define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD
2041 #define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38
2042 #define ATA_CMD_CHECK_POWER_MODE1 0xE5
2043 #define ATA_CMD_CHECK_POWER_MODE2 0x98
2044 #define ATA_CMD_DEVICE_RESET 0x08
2045 #define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90
2046 #define ATA_CMD_FLUSH_CACHE 0xE7
2047 #define ATA_CMD_FORMAT_TRACK 0x50
2048 #define ATA_CMD_IDENTIFY_DEVICE 0xEC
2049 #define ATA_CMD_IDENTIFY_DEVICE_PACKET 0xA1
2050 #define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xA1
2051 #define ATA_CMD_IDLE1 0xE3
2052 #define ATA_CMD_IDLE2 0x97
2053 #define ATA_CMD_IDLE_IMMEDIATE1 0xE1
2054 #define ATA_CMD_IDLE_IMMEDIATE2 0x95
2055 #define ATA_CMD_INITIALIZE_DRIVE_PARAMETERS 0x91
2056 #define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
2057 #define ATA_CMD_NOP 0x00
2058 #define ATA_CMD_PACKET 0xA0
2059 #define ATA_CMD_READ_BUFFER 0xE4
2060 #define ATA_CMD_READ_DMA 0xC8
2061 #define ATA_CMD_READ_DMA_QUEUED 0xC7
2062 #define ATA_CMD_READ_MULTIPLE 0xC4
2063 #define ATA_CMD_READ_SECTORS 0x20
2064 #define ATA_CMD_READ_VERIFY_SECTORS 0x40
2065 #define ATA_CMD_RECALIBRATE 0x10
2066 #define ATA_CMD_SEEK 0x70
2067 #define ATA_CMD_SET_FEATURES 0xEF
2068 #define ATA_CMD_SET_MULTIPLE_MODE 0xC6
2069 #define ATA_CMD_SLEEP1 0xE6
2070 #define ATA_CMD_SLEEP2 0x99
2071 #define ATA_CMD_STANDBY1 0xE2
2072 #define ATA_CMD_STANDBY2 0x96
2073 #define ATA_CMD_STANDBY_IMMEDIATE1 0xE0
2074 #define ATA_CMD_STANDBY_IMMEDIATE2 0x94
2075 #define ATA_CMD_WRITE_BUFFER 0xE8
2076 #define ATA_CMD_WRITE_DMA 0xCA
2077 #define ATA_CMD_WRITE_DMA_QUEUED 0xCC
2078 #define ATA_CMD_WRITE_MULTIPLE 0xC5
2079 #define ATA_CMD_WRITE_SECTORS 0x30
2080 #define ATA_CMD_WRITE_VERIFY 0x3C
2082 #define ATA_IFACE_NONE 0x00
2083 #define ATA_IFACE_ISA 0x00
2084 #define ATA_IFACE_PCI 0x01
2086 #define ATA_TYPE_NONE 0x00
2087 #define ATA_TYPE_UNKNOWN 0x01
2088 #define ATA_TYPE_ATA 0x02
2089 #define ATA_TYPE_ATAPI 0x03
2091 #define ATA_DEVICE_NONE 0x00
2092 #define ATA_DEVICE_HD 0xFF
2093 #define ATA_DEVICE_CDROM 0x05
2095 #define ATA_MODE_NONE 0x00
2096 #define ATA_MODE_PIO16 0x00
2097 #define ATA_MODE_PIO32 0x01
2098 #define ATA_MODE_ISADMA 0x02
2099 #define ATA_MODE_PCIDMA 0x03
2100 #define ATA_MODE_USEIRQ 0x10
2102 #define ATA_TRANSLATION_NONE 0
2103 #define ATA_TRANSLATION_LBA 1
2104 #define ATA_TRANSLATION_LARGE 2
2105 #define ATA_TRANSLATION_RECHS 3
2107 #define ATA_DATA_NO 0x00
2108 #define ATA_DATA_IN 0x01
2109 #define ATA_DATA_OUT 0x02
2111 // ---------------------------------------------------------------------------
2112 // ATA/ATAPI driver : initialization
2113 // ---------------------------------------------------------------------------
2114 void ata_init( )
2116 Bit16u ebda_seg=read_word(0x0040,0x000E);
2117 Bit8u channel, device;
2119 // Channels info init.
2120 for (channel=0; channel<BX_MAX_ATA_INTERFACES; channel++) {
2121 write_byte(ebda_seg,&EbdaData->ata.channels[channel].iface,ATA_IFACE_NONE);
2122 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1,0x0);
2123 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2,0x0);
2124 write_byte(ebda_seg,&EbdaData->ata.channels[channel].irq,0);
2127 // Devices info init.
2128 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2129 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
2130 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_NONE);
2131 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable,0);
2132 write_byte(ebda_seg,&EbdaData->ata.devices[device].lock,0);
2133 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode,ATA_MODE_NONE);
2134 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,0);
2135 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation,ATA_TRANSLATION_NONE);
2136 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads,0);
2137 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders,0);
2138 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt,0);
2139 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads,0);
2140 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders,0);
2141 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt,0);
2143 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors,0L);
2146 // hdidmap and cdidmap init.
2147 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2148 write_byte(ebda_seg,&EbdaData->ata.hdidmap[device],BX_MAX_ATA_DEVICES);
2149 write_byte(ebda_seg,&EbdaData->ata.cdidmap[device],BX_MAX_ATA_DEVICES);
2152 write_byte(ebda_seg,&EbdaData->ata.hdcount,0);
2153 write_byte(ebda_seg,&EbdaData->ata.cdcount,0);
2156 // ---------------------------------------------------------------------------
2157 // ATA/ATAPI driver : device detection
2158 // ---------------------------------------------------------------------------
2160 void ata_detect( )
2162 Bit16u ebda_seg=read_word(0x0040,0x000E);
2163 Bit8u hdcount, cdcount, device, type;
2164 Bit8u buffer[0x0200];
2166 #if BX_MAX_ATA_INTERFACES > 0
2167 write_byte(ebda_seg,&EbdaData->ata.channels[0].iface,ATA_IFACE_ISA);
2168 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase1,0x1f0);
2169 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase2,0x3f0);
2170 write_byte(ebda_seg,&EbdaData->ata.channels[0].irq,14);
2171 #endif
2172 #if BX_MAX_ATA_INTERFACES > 1
2173 write_byte(ebda_seg,&EbdaData->ata.channels[1].iface,ATA_IFACE_ISA);
2174 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase1,0x170);
2175 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase2,0x370);
2176 write_byte(ebda_seg,&EbdaData->ata.channels[1].irq,15);
2177 #endif
2178 #if BX_MAX_ATA_INTERFACES > 2
2179 write_byte(ebda_seg,&EbdaData->ata.channels[2].iface,ATA_IFACE_ISA);
2180 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase1,0x1e8);
2181 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase2,0x3e0);
2182 write_byte(ebda_seg,&EbdaData->ata.channels[2].irq,12);
2183 #endif
2184 #if BX_MAX_ATA_INTERFACES > 3
2185 write_byte(ebda_seg,&EbdaData->ata.channels[3].iface,ATA_IFACE_ISA);
2186 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase1,0x168);
2187 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase2,0x360);
2188 write_byte(ebda_seg,&EbdaData->ata.channels[3].irq,11);
2189 #endif
2190 #if BX_MAX_ATA_INTERFACES > 4
2191 #error Please fill the ATA interface informations
2192 #endif
2194 // Device detection
2195 hdcount=cdcount=0;
2197 for(device=0; device<BX_MAX_ATA_DEVICES; device++) {
2198 Bit16u iobase1, iobase2;
2199 Bit8u channel, slave, shift;
2200 Bit8u sc, sn, cl, ch, st;
2202 channel = device / 2;
2203 slave = device % 2;
2205 iobase1 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1);
2206 iobase2 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2);
2208 // Disable interrupts
2209 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2211 // Look for device
2212 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2213 outb(iobase1+ATA_CB_SC, 0x55);
2214 outb(iobase1+ATA_CB_SN, 0xaa);
2215 outb(iobase1+ATA_CB_SC, 0xaa);
2216 outb(iobase1+ATA_CB_SN, 0x55);
2217 outb(iobase1+ATA_CB_SC, 0x55);
2218 outb(iobase1+ATA_CB_SN, 0xaa);
2220 // If we found something
2221 sc = inb(iobase1+ATA_CB_SC);
2222 sn = inb(iobase1+ATA_CB_SN);
2224 if ( (sc == 0x55) && (sn == 0xaa) ) {
2225 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_UNKNOWN);
2227 // reset the channel
2228 ata_reset (device);
2230 // check for ATA or ATAPI
2231 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2232 sc = inb(iobase1+ATA_CB_SC);
2233 sn = inb(iobase1+ATA_CB_SN);
2234 if ( (sc==0x01) && (sn==0x01) ) {
2235 cl = inb(iobase1+ATA_CB_CL);
2236 ch = inb(iobase1+ATA_CB_CH);
2237 st = inb(iobase1+ATA_CB_STAT);
2239 if ( (cl==0x14) && (ch==0xeb) ) {
2240 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATAPI);
2242 else if ( (cl==0x00) && (ch==0x00) && (st!=0x00) ) {
2243 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATA);
2248 type=read_byte(ebda_seg,&EbdaData->ata.devices[device].type);
2250 // Now we send a IDENTIFY command to ATA device
2251 if(type == ATA_TYPE_ATA) {
2252 Bit32u sectors;
2253 Bit16u cylinders, heads, spt, blksize;
2254 Bit8u translation, removable, mode;
2256 // default mode to PIO16
2257 mode = ATA_MODE_PIO16;
2259 //Temporary values to do the transfer
2260 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2261 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2263 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE, 1, 0, 0, 0, 0L, get_SS(),buffer) !=0 )
2264 BX_PANIC("ata-detect: Failed to detect ATA device\n");
2266 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2267 #ifndef NO_PIO32
2268 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2269 #endif
2271 blksize = read_word(get_SS(),buffer+10);
2273 cylinders = read_word(get_SS(),buffer+(1*2)); // word 1
2274 heads = read_word(get_SS(),buffer+(3*2)); // word 3
2275 spt = read_word(get_SS(),buffer+(6*2)); // word 6
2277 sectors = read_dword(get_SS(),buffer+(60*2)); // word 60 and word 61
2279 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2280 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2281 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2282 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2283 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads, heads);
2284 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders, cylinders);
2285 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt, spt);
2286 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors, sectors);
2287 BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel, slave,cylinders, heads, spt);
2289 translation = inb_cmos(0x39 + channel/2);
2290 for (shift=device%4; shift>0; shift--) translation >>= 2;
2291 translation &= 0x03;
2293 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation, translation);
2295 switch (translation) {
2296 case ATA_TRANSLATION_NONE:
2297 BX_INFO("none");
2298 break;
2299 case ATA_TRANSLATION_LBA:
2300 BX_INFO("lba");
2301 break;
2302 case ATA_TRANSLATION_LARGE:
2303 BX_INFO("large");
2304 break;
2305 case ATA_TRANSLATION_RECHS:
2306 BX_INFO("r-echs");
2307 break;
2309 switch (translation) {
2310 case ATA_TRANSLATION_NONE:
2311 break;
2312 case ATA_TRANSLATION_LBA:
2313 spt = 63;
2314 sectors /= 63;
2315 heads = sectors / 1024;
2316 if (heads>128) heads = 255;
2317 else if (heads>64) heads = 128;
2318 else if (heads>32) heads = 64;
2319 else if (heads>16) heads = 32;
2320 else heads=16;
2321 cylinders = sectors / heads;
2322 break;
2323 case ATA_TRANSLATION_RECHS:
2324 // Take care not to overflow
2325 if (heads==16) {
2326 if(cylinders>61439) cylinders=61439;
2327 heads=15;
2328 cylinders = (Bit16u)((Bit32u)(cylinders)*16/15);
2330 // then go through the large bitshift process
2331 case ATA_TRANSLATION_LARGE:
2332 while(cylinders > 1024) {
2333 cylinders >>= 1;
2334 heads <<= 1;
2336 // If we max out the head count
2337 if (heads > 127) break;
2339 break;
2341 // clip to 1024 cylinders in lchs
2342 if (cylinders > 1024) cylinders=1024;
2343 BX_INFO(" LCHS=%d/%d/%d\n", cylinders, heads, spt);
2345 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, heads);
2346 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, cylinders);
2347 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, spt);
2349 // fill hdidmap
2350 write_byte(ebda_seg,&EbdaData->ata.hdidmap[hdcount], device);
2351 hdcount++;
2354 // Now we send a IDENTIFY command to ATAPI device
2355 if(type == ATA_TYPE_ATAPI) {
2357 Bit8u type, removable, mode;
2358 Bit16u blksize;
2360 // default mode to PIO16
2361 mode = ATA_MODE_PIO16;
2363 //Temporary values to do the transfer
2364 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_CDROM);
2365 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2367 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE_PACKET, 1, 0, 0, 0, 0L, get_SS(),buffer) != 0)
2368 BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
2370 type = read_byte(get_SS(),buffer+1) & 0x1f;
2371 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2372 #ifndef NO_PIO32
2373 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2374 #endif
2375 blksize = 2048;
2377 write_byte(ebda_seg,&EbdaData->ata.devices[device].device, type);
2378 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2379 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2380 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2382 // fill cdidmap
2383 write_byte(ebda_seg,&EbdaData->ata.cdidmap[cdcount], device);
2384 cdcount++;
2388 Bit32u sizeinmb;
2389 Bit16u ataversion;
2390 Bit8u c, i, version, model[41];
2392 switch (type) {
2393 case ATA_TYPE_ATA:
2394 sizeinmb = read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors);
2395 sizeinmb >>= 11;
2396 case ATA_TYPE_ATAPI:
2397 // Read ATA/ATAPI version
2398 ataversion=((Bit16u)(read_byte(get_SS(),buffer+161))<<8)|read_byte(get_SS(),buffer+160);
2399 for(version=15;version>0;version--) {
2400 if((ataversion&(1<<version))!=0)
2401 break;
2404 // Read model name
2405 for(i=0;i<20;i++){
2406 write_byte(get_SS(),model+(i*2),read_byte(get_SS(),buffer+(i*2)+54+1));
2407 write_byte(get_SS(),model+(i*2)+1,read_byte(get_SS(),buffer+(i*2)+54));
2410 // Reformat
2411 write_byte(get_SS(),model+40,0x00);
2412 for(i=39;i>0;i--){
2413 if(read_byte(get_SS(),model+i)==0x20)
2414 write_byte(get_SS(),model+i,0x00);
2415 else break;
2417 break;
2420 switch (type) {
2421 case ATA_TYPE_ATA:
2422 printf("ata%d %s: ",channel,slave?" slave":"master");
2423 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2424 printf(" ATA-%d Hard-Disk (%d MBytes)\n",version,(Bit16u)sizeinmb);
2425 break;
2426 case ATA_TYPE_ATAPI:
2427 printf("ata%d %s: ",channel,slave?" slave":"master");
2428 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2429 if(read_byte(ebda_seg,&EbdaData->ata.devices[device].device)==ATA_DEVICE_CDROM)
2430 printf(" ATAPI-%d CD-Rom/DVD-Rom\n",version);
2431 else
2432 printf(" ATAPI-%d Device\n",version);
2433 break;
2434 case ATA_TYPE_UNKNOWN:
2435 printf("ata%d %s: Unknown device\n",channel,slave?" slave":"master");
2436 break;
2441 // Store the devices counts
2442 write_byte(ebda_seg,&EbdaData->ata.hdcount, hdcount);
2443 write_byte(ebda_seg,&EbdaData->ata.cdcount, cdcount);
2444 write_byte(0x40,0x75, hdcount);
2446 printf("\n");
2448 // FIXME : should use bios=cmos|auto|disable bits
2449 // FIXME : should know about translation bits
2450 // FIXME : move hard_drive_post here
2454 // ---------------------------------------------------------------------------
2455 // ATA/ATAPI driver : software reset
2456 // ---------------------------------------------------------------------------
2457 // ATA-3
2458 // 8.2.1 Software reset - Device 0
2460 void ata_reset(device)
2461 Bit16u device;
2463 Bit16u ebda_seg=read_word(0x0040,0x000E);
2464 Bit16u iobase1, iobase2;
2465 Bit8u channel, slave, sn, sc;
2466 Bit16u max;
2468 channel = device / 2;
2469 slave = device % 2;
2471 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2472 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2474 // Reset
2476 // 8.2.1 (a) -- set SRST in DC
2477 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN | ATA_CB_DC_SRST);
2479 // 8.2.1 (b) -- wait for BSY
2480 max=0xff;
2481 while(--max>0) {
2482 Bit8u status = inb(iobase1+ATA_CB_STAT);
2483 if ((status & ATA_CB_STAT_BSY) != 0) break;
2486 // 8.2.1 (f) -- clear SRST
2487 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2489 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_NONE) {
2491 // 8.2.1 (g) -- check for sc==sn==0x01
2492 // select device
2493 outb(iobase1+ATA_CB_DH, slave?ATA_CB_DH_DEV1:ATA_CB_DH_DEV0);
2494 sc = inb(iobase1+ATA_CB_SC);
2495 sn = inb(iobase1+ATA_CB_SN);
2497 if ( (sc==0x01) && (sn==0x01) ) {
2499 // 8.2.1 (h) -- wait for not BSY
2500 max=0xff;
2501 while(--max>0) {
2502 Bit8u status = inb(iobase1+ATA_CB_STAT);
2503 if ((status & ATA_CB_STAT_BSY) == 0) break;
2508 // 8.2.1 (i) -- wait for DRDY
2509 max=0xfff;
2510 while(--max>0) {
2511 Bit8u status = inb(iobase1+ATA_CB_STAT);
2512 if ((status & ATA_CB_STAT_RDY) != 0) break;
2515 // Enable interrupts
2516 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2519 // ---------------------------------------------------------------------------
2520 // ATA/ATAPI driver : execute a non data command
2521 // ---------------------------------------------------------------------------
2523 Bit16u ata_cmd_non_data()
2524 {return 0;}
2526 // ---------------------------------------------------------------------------
2527 // ATA/ATAPI driver : execute a data-in command
2528 // ---------------------------------------------------------------------------
2529 // returns
2530 // 0 : no error
2531 // 1 : BUSY bit set
2532 // 2 : read error
2533 // 3 : expected DRQ=1
2534 // 4 : no sectors left to read/verify
2535 // 5 : more sectors to read/verify
2536 // 6 : no sectors left to write
2537 // 7 : more sectors to write
2538 Bit16u ata_cmd_data_in(device, command, count, cylinder, head, sector, lba, segment, offset)
2539 Bit16u device, command, count, cylinder, head, sector, segment, offset;
2540 Bit32u lba;
2542 Bit16u ebda_seg=read_word(0x0040,0x000E);
2543 Bit16u iobase1, iobase2, blksize;
2544 Bit8u channel, slave;
2545 Bit8u status, current, mode;
2547 channel = device / 2;
2548 slave = device % 2;
2550 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2551 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2552 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2553 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2554 if (mode == ATA_MODE_PIO32) blksize>>=2;
2555 else blksize>>=1;
2557 // sector will be 0 only on lba access. Convert to lba-chs
2558 if (sector == 0) {
2559 sector = (Bit16u) (lba & 0x000000ffL);
2560 lba >>= 8;
2561 cylinder = (Bit16u) (lba & 0x0000ffffL);
2562 lba >>= 16;
2563 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
2566 // Reset count of transferred data
2567 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2568 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2569 current = 0;
2571 status = inb(iobase1 + ATA_CB_STAT);
2572 if (status & ATA_CB_STAT_BSY) return 1;
2574 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2575 outb(iobase1 + ATA_CB_FR, 0x00);
2576 outb(iobase1 + ATA_CB_SC, count);
2577 outb(iobase1 + ATA_CB_SN, sector);
2578 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2579 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2580 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
2581 outb(iobase1 + ATA_CB_CMD, command);
2583 while (1) {
2584 status = inb(iobase1 + ATA_CB_STAT);
2585 if ( !(status & ATA_CB_STAT_BSY) ) break;
2588 if (status & ATA_CB_STAT_ERR) {
2589 BX_DEBUG_ATA("ata_cmd_data_in : read error\n");
2590 return 2;
2591 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2592 BX_DEBUG_ATA("ata_cmd_data_in : DRQ not set (status %02x)\n", (unsigned) status);
2593 return 3;
2596 // FIXME : move seg/off translation here
2598 ASM_START
2599 sti ;; enable higher priority interrupts
2600 ASM_END
2602 while (1) {
2604 ASM_START
2605 push bp
2606 mov bp, sp
2607 mov di, _ata_cmd_data_in.offset + 2[bp]
2608 mov ax, _ata_cmd_data_in.segment + 2[bp]
2609 mov cx, _ata_cmd_data_in.blksize + 2[bp]
2611 ;; adjust if there will be an overrun. 2K max sector size
2612 cmp di, #0xf800 ;;
2613 jbe ata_in_no_adjust
2615 ata_in_adjust:
2616 sub di, #0x0800 ;; sub 2 kbytes from offset
2617 add ax, #0x0080 ;; add 2 Kbytes to segment
2619 ata_in_no_adjust:
2620 mov es, ax ;; segment in es
2622 mov dx, _ata_cmd_data_in.iobase1 + 2[bp] ;; ATA data read port
2624 mov ah, _ata_cmd_data_in.mode + 2[bp]
2625 cmp ah, #ATA_MODE_PIO32
2626 je ata_in_32
2628 ata_in_16:
2629 rep
2630 insw ;; CX words transfered from port(DX) to ES:[DI]
2631 jmp ata_in_done
2633 ata_in_32:
2634 rep
2635 insd ;; CX dwords transfered from port(DX) to ES:[DI]
2637 ata_in_done:
2638 mov _ata_cmd_data_in.offset + 2[bp], di
2639 mov _ata_cmd_data_in.segment + 2[bp], es
2640 pop bp
2641 ASM_END
2643 current++;
2644 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
2645 count--;
2646 status = inb(iobase1 + ATA_CB_STAT);
2647 if (count == 0) {
2648 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2649 != ATA_CB_STAT_RDY ) {
2650 BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n", (unsigned) status);
2651 return 4;
2653 break;
2655 else {
2656 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2657 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
2658 BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n", (unsigned) status);
2659 return 5;
2661 continue;
2664 // Enable interrupts
2665 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2666 return 0;
2669 // ---------------------------------------------------------------------------
2670 // ATA/ATAPI driver : execute a data-out command
2671 // ---------------------------------------------------------------------------
2672 // returns
2673 // 0 : no error
2674 // 1 : BUSY bit set
2675 // 2 : read error
2676 // 3 : expected DRQ=1
2677 // 4 : no sectors left to read/verify
2678 // 5 : more sectors to read/verify
2679 // 6 : no sectors left to write
2680 // 7 : more sectors to write
2681 Bit16u ata_cmd_data_out(device, command, count, cylinder, head, sector, lba, segment, offset)
2682 Bit16u device, command, count, cylinder, head, sector, segment, offset;
2683 Bit32u lba;
2685 Bit16u ebda_seg=read_word(0x0040,0x000E);
2686 Bit16u iobase1, iobase2, blksize;
2687 Bit8u channel, slave;
2688 Bit8u status, current, mode;
2690 channel = device / 2;
2691 slave = device % 2;
2693 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2694 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2695 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2696 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2697 if (mode == ATA_MODE_PIO32) blksize>>=2;
2698 else blksize>>=1;
2700 // sector will be 0 only on lba access. Convert to lba-chs
2701 if (sector == 0) {
2702 sector = (Bit16u) (lba & 0x000000ffL);
2703 lba >>= 8;
2704 cylinder = (Bit16u) (lba & 0x0000ffffL);
2705 lba >>= 16;
2706 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
2709 // Reset count of transferred data
2710 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2711 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2712 current = 0;
2714 status = inb(iobase1 + ATA_CB_STAT);
2715 if (status & ATA_CB_STAT_BSY) return 1;
2717 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2718 outb(iobase1 + ATA_CB_FR, 0x00);
2719 outb(iobase1 + ATA_CB_SC, count);
2720 outb(iobase1 + ATA_CB_SN, sector);
2721 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2722 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2723 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
2724 outb(iobase1 + ATA_CB_CMD, command);
2726 while (1) {
2727 status = inb(iobase1 + ATA_CB_STAT);
2728 if ( !(status & ATA_CB_STAT_BSY) ) break;
2731 if (status & ATA_CB_STAT_ERR) {
2732 BX_DEBUG_ATA("ata_cmd_data_out : read error\n");
2733 return 2;
2734 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2735 BX_DEBUG_ATA("ata_cmd_data_out : DRQ not set (status %02x)\n", (unsigned) status);
2736 return 3;
2739 // FIXME : move seg/off translation here
2741 ASM_START
2742 sti ;; enable higher priority interrupts
2743 ASM_END
2745 while (1) {
2747 ASM_START
2748 push bp
2749 mov bp, sp
2750 mov si, _ata_cmd_data_out.offset + 2[bp]
2751 mov ax, _ata_cmd_data_out.segment + 2[bp]
2752 mov cx, _ata_cmd_data_out.blksize + 2[bp]
2754 ;; adjust if there will be an overrun. 2K max sector size
2755 cmp si, #0xf800 ;;
2756 jbe ata_out_no_adjust
2758 ata_out_adjust:
2759 sub si, #0x0800 ;; sub 2 kbytes from offset
2760 add ax, #0x0080 ;; add 2 Kbytes to segment
2762 ata_out_no_adjust:
2763 mov es, ax ;; segment in es
2765 mov dx, _ata_cmd_data_out.iobase1 + 2[bp] ;; ATA data write port
2767 mov ah, _ata_cmd_data_out.mode + 2[bp]
2768 cmp ah, #ATA_MODE_PIO32
2769 je ata_out_32
2771 ata_out_16:
2772 seg ES
2773 rep
2774 outsw ;; CX words transfered from port(DX) to ES:[SI]
2775 jmp ata_out_done
2777 ata_out_32:
2778 seg ES
2779 rep
2780 outsd ;; CX dwords transfered from port(DX) to ES:[SI]
2782 ata_out_done:
2783 mov _ata_cmd_data_out.offset + 2[bp], si
2784 mov _ata_cmd_data_out.segment + 2[bp], es
2785 pop bp
2786 ASM_END
2788 current++;
2789 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
2790 count--;
2791 status = inb(iobase1 + ATA_CB_STAT);
2792 if (count == 0) {
2793 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2794 != ATA_CB_STAT_RDY ) {
2795 BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n", (unsigned) status);
2796 return 6;
2798 break;
2800 else {
2801 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2802 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
2803 BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n", (unsigned) status);
2804 return 7;
2806 continue;
2809 // Enable interrupts
2810 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2811 return 0;
2814 // ---------------------------------------------------------------------------
2815 // ATA/ATAPI driver : execute a packet command
2816 // ---------------------------------------------------------------------------
2817 // returns
2818 // 0 : no error
2819 // 1 : error in parameters
2820 // 2 : BUSY bit set
2821 // 3 : error
2822 // 4 : not ready
2823 Bit16u ata_cmd_packet(device, cmdlen, cmdseg, cmdoff, header, length, inout, bufseg, bufoff)
2824 Bit8u cmdlen,inout;
2825 Bit16u device,cmdseg, cmdoff, bufseg, bufoff;
2826 Bit16u header;
2827 Bit32u length;
2829 Bit16u ebda_seg=read_word(0x0040,0x000E);
2830 Bit16u iobase1, iobase2;
2831 Bit16u lcount, lbefore, lafter, count;
2832 Bit8u channel, slave;
2833 Bit8u status, mode, lmode;
2834 Bit32u total, transfer;
2836 channel = device / 2;
2837 slave = device % 2;
2839 // Data out is not supported yet
2840 if (inout == ATA_DATA_OUT) {
2841 BX_INFO("ata_cmd_packet: DATA_OUT not supported yet\n");
2842 return 1;
2845 // The header length must be even
2846 if (header & 1) {
2847 BX_DEBUG_ATA("ata_cmd_packet : header must be even (%04x)\n",header);
2848 return 1;
2851 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2852 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2853 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2854 transfer= 0L;
2856 if (cmdlen < 12) cmdlen=12;
2857 if (cmdlen > 12) cmdlen=16;
2858 cmdlen>>=1;
2860 // Reset count of transferred data
2861 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2862 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2864 status = inb(iobase1 + ATA_CB_STAT);
2865 if (status & ATA_CB_STAT_BSY) return 2;
2867 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2868 // outb(iobase1 + ATA_CB_FR, 0x00);
2869 // outb(iobase1 + ATA_CB_SC, 0x00);
2870 // outb(iobase1 + ATA_CB_SN, 0x00);
2871 outb(iobase1 + ATA_CB_CL, 0xfff0 & 0x00ff);
2872 outb(iobase1 + ATA_CB_CH, 0xfff0 >> 8);
2873 outb(iobase1 + ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2874 outb(iobase1 + ATA_CB_CMD, ATA_CMD_PACKET);
2876 // Device should ok to receive command
2877 while (1) {
2878 status = inb(iobase1 + ATA_CB_STAT);
2879 if ( !(status & ATA_CB_STAT_BSY) ) break;
2882 if (status & ATA_CB_STAT_ERR) {
2883 BX_DEBUG_ATA("ata_cmd_packet : error, status is %02x\n",status);
2884 return 3;
2885 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2886 BX_DEBUG_ATA("ata_cmd_packet : DRQ not set (status %02x)\n", (unsigned) status);
2887 return 4;
2890 // Normalize address
2891 cmdseg += (cmdoff / 16);
2892 cmdoff %= 16;
2894 // Send command to device
2895 ASM_START
2896 sti ;; enable higher priority interrupts
2898 push bp
2899 mov bp, sp
2901 mov si, _ata_cmd_packet.cmdoff + 2[bp]
2902 mov ax, _ata_cmd_packet.cmdseg + 2[bp]
2903 mov cx, _ata_cmd_packet.cmdlen + 2[bp]
2904 mov es, ax ;; segment in es
2906 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data write port
2908 seg ES
2909 rep
2910 outsw ;; CX words transfered from port(DX) to ES:[SI]
2912 pop bp
2913 ASM_END
2915 if (inout == ATA_DATA_NO) {
2916 status = inb(iobase1 + ATA_CB_STAT);
2918 else {
2919 while (1) {
2921 status = inb(iobase1 + ATA_CB_STAT);
2923 // Check if command completed
2924 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_DRQ) ) ==0 ) break;
2926 if (status & ATA_CB_STAT_ERR) {
2927 BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status);
2928 return 3;
2931 // Device must be ready to send data
2932 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2933 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
2934 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", status);
2935 return 4;
2938 // Normalize address
2939 bufseg += (bufoff / 16);
2940 bufoff %= 16;
2942 // Get the byte count
2943 lcount = ((Bit16u)(inb(iobase1 + ATA_CB_CH))<<8)+inb(iobase1 + ATA_CB_CL);
2945 // adjust to read what we want
2946 if(header>lcount) {
2947 lbefore=lcount;
2948 header-=lcount;
2949 lcount=0;
2951 else {
2952 lbefore=header;
2953 header=0;
2954 lcount-=lbefore;
2957 if(lcount>length) {
2958 lafter=lcount-length;
2959 lcount=length;
2960 length=0;
2962 else {
2963 lafter=0;
2964 length-=lcount;
2967 // Save byte count
2968 count = lcount;
2970 BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore+lcount+lafter,lbefore,lcount,lafter);
2971 BX_DEBUG_ATA("to 0x%04x:0x%04x\n",bufseg,bufoff);
2973 // If counts not dividable by 4, use 16bits mode
2974 lmode = mode;
2975 if (lbefore & 0x03) lmode=ATA_MODE_PIO16;
2976 if (lcount & 0x03) lmode=ATA_MODE_PIO16;
2977 if (lafter & 0x03) lmode=ATA_MODE_PIO16;
2979 // adds an extra byte if count are odd. before is always even
2980 if (lcount & 0x01) {
2981 lcount+=1;
2982 if ((lafter > 0) && (lafter & 0x01)) {
2983 lafter-=1;
2987 if (lmode == ATA_MODE_PIO32) {
2988 lcount>>=2; lbefore>>=2; lafter>>=2;
2990 else {
2991 lcount>>=1; lbefore>>=1; lafter>>=1;
2994 ; // FIXME bcc bug
2996 ASM_START
2997 push bp
2998 mov bp, sp
3000 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data read port
3002 mov cx, _ata_cmd_packet.lbefore + 2[bp]
3003 jcxz ata_packet_no_before
3005 mov ah, _ata_cmd_packet.lmode + 2[bp]
3006 cmp ah, #ATA_MODE_PIO32
3007 je ata_packet_in_before_32
3009 ata_packet_in_before_16:
3010 in ax, dx
3011 loop ata_packet_in_before_16
3012 jmp ata_packet_no_before
3014 ata_packet_in_before_32:
3015 push eax
3016 ata_packet_in_before_32_loop:
3017 in eax, dx
3018 loop ata_packet_in_before_32_loop
3019 pop eax
3021 ata_packet_no_before:
3022 mov cx, _ata_cmd_packet.lcount + 2[bp]
3023 jcxz ata_packet_after
3025 mov di, _ata_cmd_packet.bufoff + 2[bp]
3026 mov ax, _ata_cmd_packet.bufseg + 2[bp]
3027 mov es, ax
3029 mov ah, _ata_cmd_packet.lmode + 2[bp]
3030 cmp ah, #ATA_MODE_PIO32
3031 je ata_packet_in_32
3033 ata_packet_in_16:
3034 rep
3035 insw ;; CX words transfered tp port(DX) to ES:[DI]
3036 jmp ata_packet_after
3038 ata_packet_in_32:
3039 rep
3040 insd ;; CX dwords transfered to port(DX) to ES:[DI]
3042 ata_packet_after:
3043 mov cx, _ata_cmd_packet.lafter + 2[bp]
3044 jcxz ata_packet_done
3046 mov ah, _ata_cmd_packet.lmode + 2[bp]
3047 cmp ah, #ATA_MODE_PIO32
3048 je ata_packet_in_after_32
3050 ata_packet_in_after_16:
3051 in ax, dx
3052 loop ata_packet_in_after_16
3053 jmp ata_packet_done
3055 ata_packet_in_after_32:
3056 push eax
3057 ata_packet_in_after_32_loop:
3058 in eax, dx
3059 loop ata_packet_in_after_32_loop
3060 pop eax
3062 ata_packet_done:
3063 pop bp
3064 ASM_END
3066 // Compute new buffer address
3067 bufoff += count;
3069 // Save transferred bytes count
3070 transfer += count;
3071 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,transfer);
3075 // Final check, device must be ready
3076 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
3077 != ATA_CB_STAT_RDY ) {
3078 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", (unsigned) status);
3079 return 4;
3082 // Enable interrupts
3083 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3084 return 0;
3087 // ---------------------------------------------------------------------------
3088 // End of ATA/ATAPI Driver
3089 // ---------------------------------------------------------------------------
3091 // ---------------------------------------------------------------------------
3092 // Start of ATA/ATAPI generic functions
3093 // ---------------------------------------------------------------------------
3095 Bit16u
3096 atapi_get_sense(device)
3097 Bit16u device;
3099 Bit8u atacmd[12];
3100 Bit8u buffer[16];
3101 Bit8u i;
3103 memsetb(get_SS(),atacmd,0,12);
3105 // Request SENSE
3106 atacmd[0]=0x03;
3107 atacmd[4]=0x20;
3108 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 16L, ATA_DATA_IN, get_SS(), buffer) != 0)
3109 return 0x0002;
3111 if ((buffer[0] & 0x7e) == 0x70) {
3112 return (((Bit16u)buffer[2]&0x0f)*0x100)+buffer[12];
3115 return 0;
3118 Bit16u
3119 atapi_is_ready(device)
3120 Bit16u device;
3122 Bit8u atacmd[12];
3123 Bit8u buffer[];
3125 memsetb(get_SS(),atacmd,0,12);
3127 // Test Unit Ready
3128 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3129 return 0x000f;
3131 if (atapi_get_sense(device) !=0 ) {
3132 memsetb(get_SS(),atacmd,0,12);
3134 // try to send Test Unit Ready again
3135 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3136 return 0x000f;
3138 return atapi_get_sense(device);
3140 return 0;
3143 Bit16u
3144 atapi_is_cdrom(device)
3145 Bit8u device;
3147 Bit16u ebda_seg=read_word(0x0040,0x000E);
3149 if (device >= BX_MAX_ATA_DEVICES)
3150 return 0;
3152 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_ATAPI)
3153 return 0;
3155 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].device) != ATA_DEVICE_CDROM)
3156 return 0;
3158 return 1;
3161 // ---------------------------------------------------------------------------
3162 // End of ATA/ATAPI generic functions
3163 // ---------------------------------------------------------------------------
3165 #endif // BX_USE_ATADRV
3167 #if BX_ELTORITO_BOOT
3169 // ---------------------------------------------------------------------------
3170 // Start of El-Torito boot functions
3171 // ---------------------------------------------------------------------------
3173 void
3174 cdemu_init()
3176 Bit16u ebda_seg=read_word(0x0040,0x000E);
3178 // the only important data is this one for now
3179 write_byte(ebda_seg,&EbdaData->cdemu.active,0x00);
3182 Bit8u
3183 cdemu_isactive()
3185 Bit16u ebda_seg=read_word(0x0040,0x000E);
3187 return(read_byte(ebda_seg,&EbdaData->cdemu.active));
3190 Bit8u
3191 cdemu_emulated_drive()
3193 Bit16u ebda_seg=read_word(0x0040,0x000E);
3195 return(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
3198 static char isotag[6]="CD001";
3199 static char eltorito[24]="EL TORITO SPECIFICATION";
3200 //
3201 // Returns ah: emulated drive, al: error code
3202 //
3203 Bit16u
3204 cdrom_boot()
3206 Bit16u ebda_seg=read_word(0x0040,0x000E);
3207 Bit8u atacmd[12], buffer[2048];
3208 Bit32u lba;
3209 Bit16u boot_segment, nbsectors, i, error;
3210 Bit8u device;
3212 // Find out the first cdrom
3213 for (device=0; device<BX_MAX_ATA_DEVICES;device++) {
3214 if (atapi_is_cdrom(device)) break;
3217 // if not found
3218 if(device >= BX_MAX_ATA_DEVICES) return 2;
3220 // Read the Boot Record Volume Descriptor
3221 memsetb(get_SS(),atacmd,0,12);
3222 atacmd[0]=0x28; // READ command
3223 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3224 atacmd[8]=(0x01 & 0x00ff); // Sectors
3225 atacmd[2]=(0x11 & 0xff000000) >> 24; // LBA
3226 atacmd[3]=(0x11 & 0x00ff0000) >> 16;
3227 atacmd[4]=(0x11 & 0x0000ff00) >> 8;
3228 atacmd[5]=(0x11 & 0x000000ff);
3229 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3230 return 3;
3232 // Validity checks
3233 if(buffer[0]!=0)return 4;
3234 for(i=0;i<5;i++){
3235 if(buffer[1+i]!=read_byte(0xf000,&isotag[i]))return 5;
3237 for(i=0;i<23;i++)
3238 if(buffer[7+i]!=read_byte(0xf000,&eltorito[i]))return 6;
3240 // ok, now we calculate the Boot catalog address
3241 lba=buffer[0x4A]*0x1000000+buffer[0x49]*0x10000+buffer[0x48]*0x100+buffer[0x47];
3243 // And we read the Boot Catalog
3244 memsetb(get_SS(),atacmd,0,12);
3245 atacmd[0]=0x28; // READ command
3246 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3247 atacmd[8]=(0x01 & 0x00ff); // Sectors
3248 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3249 atacmd[3]=(lba & 0x00ff0000) >> 16;
3250 atacmd[4]=(lba & 0x0000ff00) >> 8;
3251 atacmd[5]=(lba & 0x000000ff);
3252 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3253 return 7;
3255 // Validation entry
3256 if(buffer[0x00]!=0x01)return 8; // Header
3257 if(buffer[0x01]!=0x00)return 9; // Platform
3258 if(buffer[0x1E]!=0x55)return 10; // key 1
3259 if(buffer[0x1F]!=0xAA)return 10; // key 2
3261 // Initial/Default Entry
3262 if(buffer[0x20]!=0x88)return 11; // Bootable
3264 write_byte(ebda_seg,&EbdaData->cdemu.media,buffer[0x21]);
3265 if(buffer[0x21]==0){
3266 // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
3267 // Win2000 cd boot needs to know it booted from cd
3268 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0xE0);
3270 else if(buffer[0x21]<4)
3271 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x00);
3272 else
3273 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x80);
3275 write_byte(ebda_seg,&EbdaData->cdemu.controller_index,device/2);
3276 write_byte(ebda_seg,&EbdaData->cdemu.device_spec,device%2);
3278 boot_segment=buffer[0x23]*0x100+buffer[0x22];
3279 if(boot_segment==0x0000)boot_segment=0x07C0;
3281 write_word(ebda_seg,&EbdaData->cdemu.load_segment,boot_segment);
3282 write_word(ebda_seg,&EbdaData->cdemu.buffer_segment,0x0000);
3284 nbsectors=buffer[0x27]*0x100+buffer[0x26];
3285 write_word(ebda_seg,&EbdaData->cdemu.sector_count,nbsectors);
3287 lba=buffer[0x2B]*0x1000000+buffer[0x2A]*0x10000+buffer[0x29]*0x100+buffer[0x28];
3288 write_dword(ebda_seg,&EbdaData->cdemu.ilba,lba);
3290 // And we read the image in memory
3291 memsetb(get_SS(),atacmd,0,12);
3292 atacmd[0]=0x28; // READ command
3293 atacmd[7]=((1+(nbsectors-1)/4) & 0xff00) >> 8; // Sectors
3294 atacmd[8]=((1+(nbsectors-1)/4) & 0x00ff); // Sectors
3295 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3296 atacmd[3]=(lba & 0x00ff0000) >> 16;
3297 atacmd[4]=(lba & 0x0000ff00) >> 8;
3298 atacmd[5]=(lba & 0x000000ff);
3299 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, nbsectors*512L, ATA_DATA_IN, boot_segment,0)) != 0)
3300 return 12;
3302 // Remember the media type
3303 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
3304 case 0x01: // 1.2M floppy
3305 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,15);
3306 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3307 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3308 break;
3309 case 0x02: // 1.44M floppy
3310 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,18);
3311 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3312 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3313 break;
3314 case 0x03: // 2.88M floppy
3315 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,36);
3316 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3317 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3318 break;
3319 case 0x04: // Harddrive
3320 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,read_byte(boot_segment,446+6)&0x3f);
3321 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,
3322 (read_byte(boot_segment,446+6)<<2) + read_byte(boot_segment,446+7) + 1);
3323 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,read_byte(boot_segment,446+5) + 1);
3324 break;
3327 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0) {
3328 // Increase bios installed hardware number of devices
3329 if(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)==0x00)
3330 write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
3331 else
3332 write_byte(ebda_seg, &EbdaData->ata.hdcount, read_byte(ebda_seg, &EbdaData->ata.hdcount) + 1);
3336 // everything is ok, so from now on, the emulation is active
3337 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0)
3338 write_byte(ebda_seg,&EbdaData->cdemu.active,0x01);
3340 // return the boot drive + no error
3341 return (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)*0x100)+0;
3344 // ---------------------------------------------------------------------------
3345 // End of El-Torito boot functions
3346 // ---------------------------------------------------------------------------
3347 #endif // BX_ELTORITO_BOOT
3349 void
3350 int14_function(regs, ds, iret_addr)
3351 pusha_regs_t regs; // regs pushed from PUSHA instruction
3352 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
3353 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
3355 Bit16u addr,timer,val16;
3356 Bit8u timeout;
3358 ASM_START
3359 sti
3360 ASM_END
3362 addr = read_word(0x0040, (regs.u.r16.dx << 1));
3363 timeout = read_byte(0x0040, 0x007C + regs.u.r16.dx);
3364 if ((regs.u.r16.dx < 4) && (addr > 0)) {
3365 switch (regs.u.r8.ah) {
3366 case 0:
3367 outb(addr+3, inb(addr+3) | 0x80);
3368 if (regs.u.r8.al & 0xE0 == 0) {
3369 outb(addr, 0x17);
3370 outb(addr+1, 0x04);
3371 } else {
3372 val16 = 0x600 >> ((regs.u.r8.al & 0xE0) >> 5);
3373 outb(addr, val16 & 0xFF);
3374 outb(addr+1, val16 >> 8);
3376 outb(addr+3, regs.u.r8.al & 0x1F);
3377 regs.u.r8.ah = inb(addr+5);
3378 regs.u.r8.al = inb(addr+6);
3379 ClearCF(iret_addr.flags);
3380 break;
3381 case 1:
3382 timer = read_word(0x0040, 0x006C);
3383 while (((inb(addr+5) & 0x60) != 0x60) && (timeout)) {
3384 val16 = read_word(0x0040, 0x006C);
3385 if (val16 != timer) {
3386 timer = val16;
3387 timeout--;
3390 if (timeout) outb(addr, regs.u.r8.al);
3391 regs.u.r8.ah = inb(addr+5);
3392 if (!timeout) regs.u.r8.ah |= 0x80;
3393 ClearCF(iret_addr.flags);
3394 break;
3395 case 2:
3396 timer = read_word(0x0040, 0x006C);
3397 while (((inb(addr+5) & 0x01) == 0) && (timeout)) {
3398 val16 = read_word(0x0040, 0x006C);
3399 if (val16 != timer) {
3400 timer = val16;
3401 timeout--;
3404 if (timeout) {
3405 regs.u.r8.ah = 0;
3406 regs.u.r8.al = inb(addr);
3407 } else {
3408 regs.u.r8.ah = inb(addr+5);
3410 ClearCF(iret_addr.flags);
3411 break;
3412 case 3:
3413 regs.u.r8.ah = inb(addr+5);
3414 regs.u.r8.al = inb(addr+6);
3415 ClearCF(iret_addr.flags);
3416 break;
3417 default:
3418 SetCF(iret_addr.flags); // Unsupported
3420 } else {
3421 SetCF(iret_addr.flags); // Unsupported
3425 void
3426 int15_function(regs, ES, DS, FLAGS)
3427 pusha_regs_t regs; // REGS pushed via pusha
3428 Bit16u ES, DS, FLAGS;
3430 Bit16u ebda_seg=read_word(0x0040,0x000E);
3431 bx_bool prev_a20_enable;
3432 Bit16u base15_00;
3433 Bit8u base23_16;
3434 Bit16u ss;
3435 Bit16u CX,DX;
3437 Bit16u bRegister;
3438 Bit8u irqDisable;
3440 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
3442 switch (regs.u.r8.ah) {
3443 case 0x24: /* A20 Control */
3444 switch (regs.u.r8.al) {
3445 case 0x00:
3446 set_enable_a20(0);
3447 CLEAR_CF();
3448 regs.u.r8.ah = 0;
3449 break;
3450 case 0x01:
3451 set_enable_a20(1);
3452 CLEAR_CF();
3453 regs.u.r8.ah = 0;
3454 break;
3455 case 0x02:
3456 regs.u.r8.al = (inb(0x92) >> 1) & 0x01;
3457 CLEAR_CF();
3458 regs.u.r8.ah = 0;
3459 break;
3460 case 0x03:
3461 CLEAR_CF();
3462 regs.u.r8.ah = 0;
3463 regs.u.r16.bx = 3;
3464 break;
3465 default:
3466 BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs.u.r8.al);
3467 SET_CF();
3468 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3470 break;
3472 case 0x41:
3473 SET_CF();
3474 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3475 break;
3477 case 0x4f:
3478 /* keyboard intercept */
3479 #if BX_CPU < 2
3480 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3481 #else
3482 // nop
3483 #endif
3484 SET_CF();
3485 break;
3487 case 0x52: // removable media eject
3488 CLEAR_CF();
3489 regs.u.r8.ah = 0; // "ok ejection may proceed"
3490 break;
3492 case 0x83: {
3493 if( regs.u.r8.al == 0 ) {
3494 // Set Interval requested.
3495 if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
3496 // Interval not already set.
3497 write_byte( 0x40, 0xA0, 1 ); // Set status byte.
3498 write_word( 0x40, 0x98, ES ); // Byte location, segment
3499 write_word( 0x40, 0x9A, regs.u.r16.bx ); // Byte location, offset
3500 write_word( 0x40, 0x9C, regs.u.r16.dx ); // Low word, delay
3501 write_word( 0x40, 0x9E, regs.u.r16.cx ); // High word, delay.
3502 CLEAR_CF( );
3503 irqDisable = inb( 0xA1 );
3504 outb( 0xA1, irqDisable & 0xFE );
3505 bRegister = inb_cmos( 0xB ); // Unmask IRQ8 so INT70 will get through.
3506 outb_cmos( 0xB, bRegister | 0x40 ); // Turn on the Periodic Interrupt timer
3507 } else {
3508 // Interval already set.
3509 BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
3510 SET_CF();
3511 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3513 } else if( regs.u.r8.al == 1 ) {
3514 // Clear Interval requested
3515 write_byte( 0x40, 0xA0, 0 ); // Clear status byte
3516 CLEAR_CF( );
3517 bRegister = inb_cmos( 0xB );
3518 outb_cmos( 0xB, bRegister & ~0x40 ); // Turn off the Periodic Interrupt timer
3519 } else {
3520 BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
3521 SET_CF();
3522 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3523 regs.u.r8.al--;
3526 break;
3529 case 0x87:
3530 #if BX_CPU < 3
3531 # error "Int15 function 87h not supported on < 80386"
3532 #endif
3533 // +++ should probably have descriptor checks
3534 // +++ should have exception handlers
3536 // turn off interrupts
3537 ASM_START
3538 cli
3539 ASM_END
3541 prev_a20_enable = set_enable_a20(1); // enable A20 line
3543 // 128K max of transfer on 386+ ???
3544 // source == destination ???
3546 // ES:SI points to descriptor table
3547 // offset use initially comments
3548 // ==============================================
3549 // 00..07 Unused zeros Null descriptor
3550 // 08..0f GDT zeros filled in by BIOS
3551 // 10..17 source ssssssss source of data
3552 // 18..1f dest dddddddd destination of data
3553 // 20..27 CS zeros filled in by BIOS
3554 // 28..2f SS zeros filled in by BIOS
3556 //es:si
3557 //eeee0
3558 //0ssss
3559 //-----
3561 // check for access rights of source & dest here
3563 // Initialize GDT descriptor
3564 base15_00 = (ES << 4) + regs.u.r16.si;
3565 base23_16 = ES >> 12;
3566 if (base15_00 < (ES<<4))
3567 base23_16++;
3568 write_word(ES, regs.u.r16.si+0x08+0, 47); // limit 15:00 = 6 * 8bytes/descriptor
3569 write_word(ES, regs.u.r16.si+0x08+2, base15_00);// base 15:00
3570 write_byte(ES, regs.u.r16.si+0x08+4, base23_16);// base 23:16
3571 write_byte(ES, regs.u.r16.si+0x08+5, 0x93); // access
3572 write_word(ES, regs.u.r16.si+0x08+6, 0x0000); // base 31:24/reserved/limit 19:16
3574 // Initialize CS descriptor
3575 write_word(ES, regs.u.r16.si+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
3576 write_word(ES, regs.u.r16.si+0x20+2, 0x0000);// base 15:00
3577 write_byte(ES, regs.u.r16.si+0x20+4, 0x000f);// base 23:16
3578 write_byte(ES, regs.u.r16.si+0x20+5, 0x9b); // access
3579 write_word(ES, regs.u.r16.si+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
3581 // Initialize SS descriptor
3582 ss = get_SS();
3583 base15_00 = ss << 4;
3584 base23_16 = ss >> 12;
3585 write_word(ES, regs.u.r16.si+0x28+0, 0xffff); // limit 15:00 = normal 64K limit
3586 write_word(ES, regs.u.r16.si+0x28+2, base15_00);// base 15:00
3587 write_byte(ES, regs.u.r16.si+0x28+4, base23_16);// base 23:16
3588 write_byte(ES, regs.u.r16.si+0x28+5, 0x93); // access
3589 write_word(ES, regs.u.r16.si+0x28+6, 0x0000); // base 31:24/reserved/limit 19:16
3591 CX = regs.u.r16.cx;
3592 ASM_START
3593 // Compile generates locals offset info relative to SP.
3594 // Get CX (word count) from stack.
3595 mov bx, sp
3596 SEG SS
3597 mov cx, _int15_function.CX [bx]
3599 // since we need to set SS:SP, save them to the BDA
3600 // for future restore
3601 push eax
3602 xor eax, eax
3603 mov ds, ax
3604 mov 0x0469, ss
3605 mov 0x0467, sp
3607 SEG ES
3608 lgdt [si + 0x08]
3609 SEG CS
3610 lidt [pmode_IDT_info]
3611 ;; perhaps do something with IDT here
3613 ;; set PE bit in CR0
3614 mov eax, cr0
3615 or al, #0x01
3616 mov cr0, eax
3617 ;; far jump to flush CPU queue after transition to protected mode
3618 JMP_AP(0x0020, protected_mode)
3620 protected_mode:
3621 ;; GDT points to valid descriptor table, now load SS, DS, ES
3622 mov ax, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
3623 mov ss, ax
3624 mov ax, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
3625 mov ds, ax
3626 mov ax, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
3627 mov es, ax
3628 xor si, si
3629 xor di, di
3630 cld
3631 rep
3632 movsw ;; move CX words from DS:SI to ES:DI
3634 ;; make sure DS and ES limits are 64KB
3635 mov ax, #0x28
3636 mov ds, ax
3637 mov es, ax
3639 ;; reset PG bit in CR0 ???
3640 mov eax, cr0
3641 and al, #0xFE
3642 mov cr0, eax
3644 ;; far jump to flush CPU queue after transition to real mode
3645 JMP_AP(0xf000, real_mode)
3647 real_mode:
3648 ;; restore IDT to normal real-mode defaults
3649 SEG CS
3650 lidt [rmode_IDT_info]
3652 // restore SS:SP from the BDA
3653 xor ax, ax
3654 mov ds, ax
3655 mov ss, 0x0469
3656 mov sp, 0x0467
3657 pop eax
3658 ASM_END
3660 set_enable_a20(prev_a20_enable);
3662 // turn back on interrupts
3663 ASM_START
3664 sti
3665 ASM_END
3667 regs.u.r8.ah = 0;
3668 CLEAR_CF();
3669 break;
3672 case 0x88:
3673 // Get the amount of extended memory (above 1M)
3674 #if BX_CPU < 2
3675 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3676 SET_CF();
3677 #else
3678 regs.u.r8.al = inb_cmos(0x30);
3679 regs.u.r8.ah = inb_cmos(0x31);
3681 // limit to 15M
3682 if(regs.u.r16.ax > 0x3c00)
3683 regs.u.r16.ax = 0x3c00;
3685 CLEAR_CF();
3686 #endif
3687 break;
3689 case 0x90:
3690 /* Device busy interrupt. Called by Int 16h when no key available */
3691 break;
3693 case 0x91:
3694 /* Interrupt complete. Called by Int 16h when key becomes available */
3695 break;
3697 case 0xbf:
3698 BX_INFO("*** int 15h function AH=bf not yet supported!\n");
3699 SET_CF();
3700 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3701 break;
3703 case 0xC0:
3704 #if 0
3705 SET_CF();
3706 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3707 break;
3708 #endif
3709 CLEAR_CF();
3710 regs.u.r8.ah = 0;
3711 regs.u.r16.bx = BIOS_CONFIG_TABLE;
3712 ES = 0xF000;
3713 break;
3715 case 0xc1:
3716 ES = ebda_seg;
3717 CLEAR_CF();
3718 break;
3720 case 0xd8:
3721 bios_printf(BIOS_PRINTF_DEBUG, "EISA BIOS not present\n");
3722 SET_CF();
3723 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3724 break;
3726 default:
3727 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
3728 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
3729 SET_CF();
3730 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3731 break;
3735 #if BX_USE_PS2_MOUSE
3736 void
3737 int15_function_mouse(regs, ES, DS, FLAGS)
3738 pusha_regs_t regs; // REGS pushed via pusha
3739 Bit16u ES, DS, FLAGS;
3741 Bit16u ebda_seg=read_word(0x0040,0x000E);
3742 Bit8u mouse_flags_1, mouse_flags_2;
3743 Bit16u mouse_driver_seg;
3744 Bit16u mouse_driver_offset;
3745 Bit8u comm_byte, prev_command_byte;
3746 Bit8u ret, mouse_data1, mouse_data2, mouse_data3;
3748 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
3750 switch (regs.u.r8.ah) {
3751 case 0xC2:
3752 // Return Codes status in AH
3753 // =========================
3754 // 00: success
3755 // 01: invalid subfunction (AL > 7)
3756 // 02: invalid input value (out of allowable range)
3757 // 03: interface error
3758 // 04: resend command received from mouse controller,
3759 // device driver should attempt command again
3760 // 05: cannot enable mouse, since no far call has been installed
3761 // 80/86: mouse service not implemented
3763 switch (regs.u.r8.al) {
3764 case 0: // Disable/Enable Mouse
3765 BX_DEBUG_INT15("case 0:\n");
3766 switch (regs.u.r8.bh) {
3767 case 0: // Disable Mouse
3768 BX_DEBUG_INT15("case 0: disable mouse\n");
3769 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3770 ret = send_to_mouse_ctrl(0xF5); // disable mouse command
3771 if (ret == 0) {
3772 ret = get_mouse_data(&mouse_data1);
3773 if ( (ret == 0) || (mouse_data1 == 0xFA) ) {
3774 CLEAR_CF();
3775 regs.u.r8.ah = 0;
3776 return;
3780 // error
3781 SET_CF();
3782 regs.u.r8.ah = ret;
3783 return;
3784 break;
3786 case 1: // Enable Mouse
3787 BX_DEBUG_INT15("case 1: enable mouse\n");
3788 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
3789 if ( (mouse_flags_2 & 0x80) == 0 ) {
3790 BX_DEBUG_INT15("INT 15h C2 Enable Mouse, no far call handler\n");
3791 SET_CF(); // error
3792 regs.u.r8.ah = 5; // no far call installed
3793 return;
3795 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3796 ret = send_to_mouse_ctrl(0xF4); // enable mouse command
3797 if (ret == 0) {
3798 ret = get_mouse_data(&mouse_data1);
3799 if ( (ret == 0) && (mouse_data1 == 0xFA) ) {
3800 enable_mouse_int_and_events(); // turn IRQ12 and packet generation on
3801 CLEAR_CF();
3802 regs.u.r8.ah = 0;
3803 return;
3806 SET_CF();
3807 regs.u.r8.ah = ret;
3808 return;
3810 default: // invalid subfunction
3811 BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs.u.r8.bh);
3812 SET_CF(); // error
3813 regs.u.r8.ah = 1; // invalid subfunction
3814 return;
3816 break;
3818 case 1: // Reset Mouse
3819 case 5: // Initialize Mouse
3820 BX_DEBUG_INT15("case 1 or 5:\n");
3821 if (regs.u.r8.al == 5) {
3822 if (regs.u.r8.bh != 3) {
3823 SET_CF();
3824 regs.u.r8.ah = 0x02; // invalid input
3825 return;
3827 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
3828 mouse_flags_2 = (mouse_flags_2 & 0x00) | regs.u.r8.bh;
3829 mouse_flags_1 = 0x00;
3830 write_byte(ebda_seg, 0x0026, mouse_flags_1);
3831 write_byte(ebda_seg, 0x0027, mouse_flags_2);
3834 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3835 ret = send_to_mouse_ctrl(0xFF); // reset mouse command
3836 if (ret == 0) {
3837 ret = get_mouse_data(&mouse_data3);
3838 // if no mouse attached, it will return RESEND
3839 if (mouse_data3 == 0xfe) {
3840 SET_CF();
3841 return;
3843 if (mouse_data3 != 0xfa)
3844 BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3);
3845 if ( ret == 0 ) {
3846 ret = get_mouse_data(&mouse_data1);
3847 if ( ret == 0 ) {
3848 ret = get_mouse_data(&mouse_data2);
3849 if ( ret == 0 ) {
3850 // turn IRQ12 and packet generation on
3851 enable_mouse_int_and_events();
3852 CLEAR_CF();
3853 regs.u.r8.ah = 0;
3854 regs.u.r8.bl = mouse_data1;
3855 regs.u.r8.bh = mouse_data2;
3856 return;
3862 // error
3863 SET_CF();
3864 regs.u.r8.ah = ret;
3865 return;
3867 case 2: // Set Sample Rate
3868 BX_DEBUG_INT15("case 2:\n");
3869 switch (regs.u.r8.bh) {
3870 case 0: mouse_data1 = 10; break; // 10 reports/sec
3871 case 1: mouse_data1 = 20; break; // 20 reports/sec
3872 case 2: mouse_data1 = 40; break; // 40 reports/sec
3873 case 3: mouse_data1 = 60; break; // 60 reports/sec
3874 case 4: mouse_data1 = 80; break; // 80 reports/sec
3875 case 5: mouse_data1 = 100; break; // 100 reports/sec (default)
3876 case 6: mouse_data1 = 200; break; // 200 reports/sec
3877 default: mouse_data1 = 0;
3879 if (mouse_data1 > 0) {
3880 ret = send_to_mouse_ctrl(0xF3); // set sample rate command
3881 if (ret == 0) {
3882 ret = get_mouse_data(&mouse_data2);
3883 ret = send_to_mouse_ctrl(mouse_data1);
3884 ret = get_mouse_data(&mouse_data2);
3885 CLEAR_CF();
3886 regs.u.r8.ah = 0;
3887 } else {
3888 // error
3889 SET_CF();
3890 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3892 } else {
3893 // error
3894 SET_CF();
3895 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3897 break;
3899 case 3: // Set Resolution
3900 BX_DEBUG_INT15("case 3:\n");
3901 // BX:
3902 // 0 = 25 dpi, 1 count per millimeter
3903 // 1 = 50 dpi, 2 counts per millimeter
3904 // 2 = 100 dpi, 4 counts per millimeter
3905 // 3 = 200 dpi, 8 counts per millimeter
3906 CLEAR_CF();
3907 regs.u.r8.ah = 0;
3908 break;
3910 case 4: // Get Device ID
3911 BX_DEBUG_INT15("case 4:\n");
3912 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3913 ret = send_to_mouse_ctrl(0xF2); // get mouse ID command
3914 if (ret == 0) {
3915 ret = get_mouse_data(&mouse_data1);
3916 ret = get_mouse_data(&mouse_data2);
3917 CLEAR_CF();
3918 regs.u.r8.ah = 0;
3919 regs.u.r8.bh = mouse_data2;
3920 } else {
3921 // error
3922 SET_CF();
3923 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3925 break;
3927 case 6: // Return Status & Set Scaling Factor...
3928 BX_DEBUG_INT15("case 6:\n");
3929 switch (regs.u.r8.bh) {
3930 case 0: // Return Status
3931 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3932 ret = send_to_mouse_ctrl(0xE9); // get mouse info command
3933 if (ret == 0) {
3934 ret = get_mouse_data(&mouse_data1);
3935 if (mouse_data1 != 0xfa)
3936 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
3937 if (ret == 0) {
3938 ret = get_mouse_data(&mouse_data1);
3939 if ( ret == 0 ) {
3940 ret = get_mouse_data(&mouse_data2);
3941 if ( ret == 0 ) {
3942 ret = get_mouse_data(&mouse_data3);
3943 if ( ret == 0 ) {
3944 CLEAR_CF();
3945 regs.u.r8.ah = 0;
3946 regs.u.r8.bl = mouse_data1;
3947 regs.u.r8.cl = mouse_data2;
3948 regs.u.r8.dl = mouse_data3;
3949 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
3950 return;
3957 // error
3958 SET_CF();
3959 regs.u.r8.ah = ret;
3960 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
3961 return;
3963 case 1: // Set Scaling Factor to 1:1
3964 case 2: // Set Scaling Factor to 2:1
3965 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3966 if (regs.u.r8.bh == 1) {
3967 ret = send_to_mouse_ctrl(0xE6);
3968 } else {
3969 ret = send_to_mouse_ctrl(0xE7);
3971 if (ret == 0) {
3972 get_mouse_data(&mouse_data1);
3973 ret = (mouse_data1 != 0xFA);
3975 if (ret == 0) {
3976 CLEAR_CF();
3977 regs.u.r8.ah = 0;
3978 } else {
3979 // error
3980 SET_CF();
3981 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3983 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
3984 break;
3986 default:
3987 BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs.u.r8.bh);
3989 break;
3991 case 7: // Set Mouse Handler Address
3992 BX_DEBUG_INT15("case 7:\n");
3993 mouse_driver_seg = ES;
3994 mouse_driver_offset = regs.u.r16.bx;
3995 write_word(ebda_seg, 0x0022, mouse_driver_offset);
3996 write_word(ebda_seg, 0x0024, mouse_driver_seg);
3997 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
3998 if (mouse_driver_offset == 0 && mouse_driver_seg == 0) {
3999 /* remove handler */
4000 if ( (mouse_flags_2 & 0x80) != 0 ) {
4001 mouse_flags_2 &= ~0x80;
4002 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4005 else {
4006 /* install handler */
4007 mouse_flags_2 |= 0x80;
4009 write_byte(ebda_seg, 0x0027, mouse_flags_2);
4010 CLEAR_CF();
4011 regs.u.r8.ah = 0;
4012 break;
4014 default:
4015 BX_DEBUG_INT15("case default:\n");
4016 regs.u.r8.ah = 1; // invalid function
4017 SET_CF();
4019 break;
4021 default:
4022 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4023 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4024 SET_CF();
4025 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4026 break;
4029 #endif
4031 void
4032 int15_function32(regs, ES, DS, FLAGS)
4033 pushad_regs_t regs; // REGS pushed via pushad
4034 Bit16u ES, DS, FLAGS;
4036 Bit32u extended_memory_size=0; // 64bits long
4037 Bit16u CX,DX;
4039 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4041 switch (regs.u.r8.ah) {
4042 case 0x86:
4043 // Wait for CX:DX microseconds. currently using the
4044 // refresh request port 0x61 bit4, toggling every 15usec
4046 CX = regs.u.r16.cx;
4047 DX = regs.u.r16.dx;
4049 ASM_START
4050 sti
4052 ;; Get the count in eax
4053 mov bx, sp
4054 SEG SS
4055 mov ax, _int15_function.CX [bx]
4056 shl eax, #16
4057 SEG SS
4058 mov ax, _int15_function.DX [bx]
4060 ;; convert to numbers of 15usec ticks
4061 mov ebx, #15
4062 xor edx, edx
4063 div eax, ebx
4064 mov ecx, eax
4066 ;; wait for ecx number of refresh requests
4067 in al, #0x61
4068 and al,#0x10
4069 mov ah, al
4071 or ecx, ecx
4072 je int1586_tick_end
4073 int1586_tick:
4074 in al, #0x61
4075 and al,#0x10
4076 cmp al, ah
4077 je int1586_tick
4078 mov ah, al
4079 dec ecx
4080 jnz int1586_tick
4081 int1586_tick_end:
4082 ASM_END
4084 break;
4086 case 0xe8:
4087 switch(regs.u.r8.al)
4089 case 0x20: // coded by osmaker aka K.J.
4090 if(regs.u.r32.edx == 0x534D4150) /* SMAP */
4092 #ifdef HVMASSIST
4093 if ((regs.u.r16.bx / 0x14) * 0x14 == regs.u.r16.bx) {
4094 Bit16u e820_table_size = read_word(0xe000, 0x8) * 0x14;
4096 if (regs.u.r16.bx + 0x14 <= e820_table_size) {
4097 memcpyb(ES, regs.u.r16.di,
4098 0xe000, 0x10 + regs.u.r16.bx, 0x14);
4100 regs.u.r32.ebx += 0x14;
4101 if ((regs.u.r32.ebx + 0x14 - 1) > e820_table_size)
4102 regs.u.r32.ebx = 0;
4103 regs.u.r32.eax = 0x534D4150;
4104 regs.u.r32.ecx = 0x14;
4105 CLEAR_CF();
4106 return;
4107 } else if (regs.u.r16.bx == 1) {
4108 extended_memory_size = inb_cmos(0x35);
4109 extended_memory_size <<= 8;
4110 extended_memory_size |= inb_cmos(0x34);
4111 extended_memory_size *= 64;
4112 if (extended_memory_size > 0x3bc000) // greater than EFF00000???
4114 extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4116 extended_memory_size *= 1024;
4117 extended_memory_size += 15728640; // make up for the 16mb of memory that is chopped off
4119 if (extended_memory_size <= 15728640)
4121 extended_memory_size = inb_cmos(0x31);
4122 extended_memory_size <<= 8;
4123 extended_memory_size |= inb_cmos(0x30);
4124 extended_memory_size *= 1024;
4127 write_word(ES, regs.u.r16.di, 0x0000);
4128 write_word(ES, regs.u.r16.di+2, 0x0010);
4129 write_word(ES, regs.u.r16.di+4, 0x0000);
4130 write_word(ES, regs.u.r16.di+6, 0x0000);
4132 write_word(ES, regs.u.r16.di+8, extended_memory_size);
4133 extended_memory_size >>= 16;
4134 write_word(ES, regs.u.r16.di+10, extended_memory_size);
4135 extended_memory_size >>= 16;
4136 write_word(ES, regs.u.r16.di+12, extended_memory_size);
4137 extended_memory_size >>= 16;
4138 write_word(ES, regs.u.r16.di+14, extended_memory_size);
4140 write_word(ES, regs.u.r16.di+16, 0x1);
4141 write_word(ES, regs.u.r16.di+18, 0x0);
4143 regs.u.r32.ebx = 0;
4144 regs.u.r32.eax = 0x534D4150;
4145 regs.u.r32.ecx = 0x14;
4146 CLEAR_CF();
4147 return;
4148 } else { /* AX=E820, DX=534D4150, BX unrecognized */
4149 goto int15_unimplemented;
4151 #else
4152 switch(regs.u.r16.bx)
4154 case 0:
4155 write_word(ES, regs.u.r16.di, 0x00);
4156 write_word(ES, regs.u.r16.di+2, 0x00);
4157 write_word(ES, regs.u.r16.di+4, 0x00);
4158 write_word(ES, regs.u.r16.di+6, 0x00);
4160 write_word(ES, regs.u.r16.di+8, 0xFC00);
4161 write_word(ES, regs.u.r16.di+10, 0x0009);
4162 write_word(ES, regs.u.r16.di+12, 0x0000);
4163 write_word(ES, regs.u.r16.di+14, 0x0000);
4165 write_word(ES, regs.u.r16.di+16, 0x1);
4166 write_word(ES, regs.u.r16.di+18, 0x0);
4168 regs.u.r32.ebx = 1;
4170 regs.u.r32.eax = 0x534D4150;
4171 regs.u.r32.ecx = 0x14;
4172 CLEAR_CF();
4173 return;
4174 break;
4175 case 1:
4176 extended_memory_size = inb_cmos(0x35);
4177 extended_memory_size <<= 8;
4178 extended_memory_size |= inb_cmos(0x34);
4179 extended_memory_size *= 64;
4180 if(extended_memory_size > 0x3bc000) // greater than EFF00000???
4182 extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4184 extended_memory_size *= 1024;
4185 extended_memory_size += 15728640; // make up for the 16mb of memory that is chopped off
4187 if(extended_memory_size <= 15728640)
4189 extended_memory_size = inb_cmos(0x31);
4190 extended_memory_size <<= 8;
4191 extended_memory_size |= inb_cmos(0x30);
4192 extended_memory_size *= 1024;
4195 write_word(ES, regs.u.r16.di, 0x0000);
4196 write_word(ES, regs.u.r16.di+2, 0x0010);
4197 write_word(ES, regs.u.r16.di+4, 0x0000);
4198 write_word(ES, regs.u.r16.di+6, 0x0000);
4200 write_word(ES, regs.u.r16.di+8, extended_memory_size);
4201 extended_memory_size >>= 16;
4202 write_word(ES, regs.u.r16.di+10, extended_memory_size);
4203 extended_memory_size >>= 16;
4204 write_word(ES, regs.u.r16.di+12, extended_memory_size);
4205 extended_memory_size >>= 16;
4206 write_word(ES, regs.u.r16.di+14, extended_memory_size);
4208 write_word(ES, regs.u.r16.di+16, 0x1);
4209 write_word(ES, regs.u.r16.di+18, 0x0);
4211 regs.u.r32.ebx = 0;
4212 regs.u.r32.eax = 0x534D4150;
4213 regs.u.r32.ecx = 0x14;
4214 CLEAR_CF();
4215 return;
4216 break;
4217 default: /* AX=E820, DX=534D4150, BX unrecognized */
4218 goto int15_unimplemented;
4219 break;
4221 #endif
4222 } else {
4223 // if DX != 0x534D4150)
4224 goto int15_unimplemented;
4226 break;
4228 case 0x01:
4229 // do we have any reason to fail here ?
4230 CLEAR_CF();
4232 // my real system sets ax and bx to 0
4233 // this is confirmed by Ralph Brown list
4234 // but syslinux v1.48 is known to behave
4235 // strangely if ax is set to 0
4236 // regs.u.r16.ax = 0;
4237 // regs.u.r16.bx = 0;
4239 // Get the amount of extended memory (above 1M)
4240 regs.u.r8.cl = inb_cmos(0x30);
4241 regs.u.r8.ch = inb_cmos(0x31);
4243 // limit to 15M
4244 if(regs.u.r16.cx > 0x3c00)
4246 regs.u.r16.cx = 0x3c00;
4249 // Get the amount of extended memory above 16M in 64k blocs
4250 regs.u.r8.dl = inb_cmos(0x34);
4251 regs.u.r8.dh = inb_cmos(0x35);
4253 // Set configured memory equal to extended memory
4254 regs.u.r16.ax = regs.u.r16.cx;
4255 regs.u.r16.bx = regs.u.r16.dx;
4256 break;
4257 default: /* AH=0xE8?? but not implemented */
4258 goto int15_unimplemented;
4260 break;
4261 int15_unimplemented:
4262 // fall into the default
4263 default:
4264 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4265 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4266 SET_CF();
4267 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4268 break;
4272 void
4273 int16_function(DI, SI, BP, SP, BX, DX, CX, AX, FLAGS)
4274 Bit16u DI, SI, BP, SP, BX, DX, CX, AX, FLAGS;
4276 Bit8u scan_code, ascii_code, shift_flags, count;
4277 Bit16u kbd_code, max;
4279 BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX, BX, CX, DX);
4281 switch (GET_AH()) {
4282 case 0x00: /* read keyboard input */
4284 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4285 BX_PANIC("KBD: int16h: out of keyboard input\n");
4287 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4288 else if (ascii_code == 0xE0) ascii_code = 0;
4289 AX = (scan_code << 8) | ascii_code;
4290 break;
4292 case 0x01: /* check keyboard status */
4293 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4294 SET_ZF();
4295 return;
4297 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4298 else if (ascii_code == 0xE0) ascii_code = 0;
4299 AX = (scan_code << 8) | ascii_code;
4300 CLEAR_ZF();
4301 break;
4303 case 0x02: /* get shift flag status */
4304 shift_flags = read_byte(0x0040, 0x17);
4305 SET_AL(shift_flags);
4306 break;
4308 case 0x05: /* store key-stroke into buffer */
4309 if ( !enqueue_key(GET_CH(), GET_CL()) ) {
4310 SET_AL(1);
4312 else {
4313 SET_AL(0);
4315 break;
4317 case 0x09: /* GET KEYBOARD FUNCTIONALITY */
4318 // bit Bochs Description
4319 // 7 0 reserved
4320 // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
4321 // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
4322 // 4 1 INT 16/AH=0Ah supported
4323 // 3 0 INT 16/AX=0306h supported
4324 // 2 0 INT 16/AX=0305h supported
4325 // 1 0 INT 16/AX=0304h supported
4326 // 0 0 INT 16/AX=0300h supported
4327 //
4328 SET_AL(0x30);
4329 break;
4331 case 0x0A: /* GET KEYBOARD ID */
4332 count = 2;
4333 kbd_code = 0x0;
4334 outb(0x60, 0xf2);
4335 /* Wait for data */
4336 max=0xffff;
4337 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4338 if (max>0x0) {
4339 if ((inb(0x60) == 0xfa)) {
4340 do {
4341 max=0xffff;
4342 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4343 if (max>0x0) {
4344 kbd_code >>= 8;
4345 kbd_code |= (inb(0x60) << 8);
4347 } while (--count>0);
4350 BX=kbd_code;
4351 break;
4353 case 0x10: /* read MF-II keyboard input */
4355 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4356 BX_PANIC("KBD: int16h: out of keyboard input\n");
4358 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4359 AX = (scan_code << 8) | ascii_code;
4360 break;
4362 case 0x11: /* check MF-II keyboard status */
4363 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4364 SET_ZF();
4365 return;
4367 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4368 AX = (scan_code << 8) | ascii_code;
4369 CLEAR_ZF();
4370 break;
4372 case 0x12: /* get extended keyboard status */
4373 shift_flags = read_byte(0x0040, 0x17);
4374 SET_AL(shift_flags);
4375 shift_flags = read_byte(0x0040, 0x18);
4376 SET_AH(shift_flags);
4377 BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX);
4378 break;
4380 case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
4381 SET_AH(0x80); // function int16 ah=0x10-0x12 supported
4382 break;
4384 case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
4385 // don't change AH : function int16 ah=0x20-0x22 NOT supported
4386 break;
4388 case 0x6F:
4389 if (GET_AL() == 0x08)
4390 SET_AH(0x02); // unsupported, aka normal keyboard
4392 default:
4393 BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
4397 unsigned int
4398 dequeue_key(scan_code, ascii_code, incr)
4399 Bit8u *scan_code;
4400 Bit8u *ascii_code;
4401 unsigned int incr;
4403 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail;
4404 Bit16u ss;
4405 Bit8u acode, scode;
4407 #if BX_CPU < 2
4408 buffer_start = 0x001E;
4409 buffer_end = 0x003E;
4410 #else
4411 buffer_start = read_word(0x0040, 0x0080);
4412 buffer_end = read_word(0x0040, 0x0082);
4413 #endif
4415 buffer_head = read_word(0x0040, 0x001a);
4416 buffer_tail = read_word(0x0040, 0x001c);
4418 if (buffer_head != buffer_tail) {
4419 ss = get_SS();
4420 acode = read_byte(0x0040, buffer_head);
4421 scode = read_byte(0x0040, buffer_head+1);
4422 write_byte(ss, ascii_code, acode);
4423 write_byte(ss, scan_code, scode);
4425 if (incr) {
4426 buffer_head += 2;
4427 if (buffer_head >= buffer_end)
4428 buffer_head = buffer_start;
4429 write_word(0x0040, 0x001a, buffer_head);
4431 return(1);
4433 else {
4434 return(0);
4438 static char panic_msg_keyb_buffer_full[] = "%s: keyboard input buffer full\n";
4440 Bit8u
4441 inhibit_mouse_int_and_events()
4443 Bit8u command_byte, prev_command_byte;
4445 // Turn off IRQ generation and aux data line
4446 if ( inb(0x64) & 0x02 )
4447 BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
4448 outb(0x64, 0x20); // get command byte
4449 while ( (inb(0x64) & 0x01) != 0x01 );
4450 prev_command_byte = inb(0x60);
4451 command_byte = prev_command_byte;
4452 //while ( (inb(0x64) & 0x02) );
4453 if ( inb(0x64) & 0x02 )
4454 BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
4455 command_byte &= 0xfd; // turn off IRQ 12 generation
4456 command_byte |= 0x20; // disable mouse serial clock line
4457 outb(0x64, 0x60); // write command byte
4458 outb(0x60, command_byte);
4459 return(prev_command_byte);
4462 void
4463 enable_mouse_int_and_events()
4465 Bit8u command_byte;
4467 // Turn on IRQ generation and aux data line
4468 if ( inb(0x64) & 0x02 )
4469 BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
4470 outb(0x64, 0x20); // get command byte
4471 while ( (inb(0x64) & 0x01) != 0x01 );
4472 command_byte = inb(0x60);
4473 //while ( (inb(0x64) & 0x02) );
4474 if ( inb(0x64) & 0x02 )
4475 BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
4476 command_byte |= 0x02; // turn on IRQ 12 generation
4477 command_byte &= 0xdf; // enable mouse serial clock line
4478 outb(0x64, 0x60); // write command byte
4479 outb(0x60, command_byte);
4482 Bit8u
4483 send_to_mouse_ctrl(sendbyte)
4484 Bit8u sendbyte;
4486 Bit8u response;
4488 // wait for chance to write to ctrl
4489 if ( inb(0x64) & 0x02 )
4490 BX_PANIC(panic_msg_keyb_buffer_full,"sendmouse");
4491 outb(0x64, 0xD4);
4492 outb(0x60, sendbyte);
4493 return(0);
4497 Bit8u
4498 get_mouse_data(data)
4499 Bit8u *data;
4501 Bit8u response;
4502 Bit16u ss;
4504 while ( (inb(0x64) & 0x21) != 0x21 ) {
4507 response = inb(0x60);
4509 ss = get_SS();
4510 write_byte(ss, data, response);
4511 return(0);
4514 void
4515 set_kbd_command_byte(command_byte)
4516 Bit8u command_byte;
4518 if ( inb(0x64) & 0x02 )
4519 BX_PANIC(panic_msg_keyb_buffer_full,"setkbdcomm");
4520 outb(0x64, 0xD4);
4522 outb(0x64, 0x60); // write command byte
4523 outb(0x60, command_byte);
4526 void
4527 int09_function(DI, SI, BP, SP, BX, DX, CX, AX)
4528 Bit16u DI, SI, BP, SP, BX, DX, CX, AX;
4530 Bit8u scancode, asciicode, shift_flags;
4531 Bit8u mf2_flags, mf2_state, led_flags;
4533 //
4534 // DS has been set to F000 before call
4535 //
4538 scancode = GET_AL();
4540 if (scancode == 0) {
4541 BX_INFO("KBD: int09 handler: AL=0\n");
4542 return;
4546 shift_flags = read_byte(0x0040, 0x17);
4547 mf2_flags = read_byte(0x0040, 0x18);
4548 mf2_state = read_byte(0x0040, 0x96);
4549 led_flags = read_byte(0x0040, 0x97);
4550 asciicode = 0;
4552 switch (scancode) {
4553 case 0x3a: /* Caps Lock press */
4554 shift_flags ^= 0x40;
4555 write_byte(0x0040, 0x17, shift_flags);
4556 mf2_flags |= 0x40;
4557 write_byte(0x0040, 0x18, mf2_flags);
4558 led_flags ^= 0x04;
4559 write_byte(0x0040, 0x97, led_flags);
4560 break;
4561 case 0xba: /* Caps Lock release */
4562 mf2_flags &= ~0x40;
4563 write_byte(0x0040, 0x18, mf2_flags);
4564 break;
4566 case 0x2a: /* L Shift press */
4567 /*shift_flags &= ~0x40;*/
4568 shift_flags |= 0x02;
4569 write_byte(0x0040, 0x17, shift_flags);
4570 led_flags &= ~0x04;
4571 write_byte(0x0040, 0x97, led_flags);
4572 break;
4573 case 0xaa: /* L Shift release */
4574 shift_flags &= ~0x02;
4575 write_byte(0x0040, 0x17, shift_flags);
4576 break;
4578 case 0x36: /* R Shift press */
4579 /*shift_flags &= ~0x40;*/
4580 shift_flags |= 0x01;
4581 write_byte(0x0040, 0x17, shift_flags);
4582 led_flags &= ~0x04;
4583 write_byte(0x0040, 0x97, led_flags);
4584 break;
4585 case 0xb6: /* R Shift release */
4586 shift_flags &= ~0x01;
4587 write_byte(0x0040, 0x17, shift_flags);
4588 break;
4590 case 0x1d: /* Ctrl press */
4591 shift_flags |= 0x04;
4592 write_byte(0x0040, 0x17, shift_flags);
4593 if (mf2_state & 0x01) {
4594 mf2_flags |= 0x04;
4595 } else {
4596 mf2_flags |= 0x01;
4598 write_byte(0x0040, 0x18, mf2_flags);
4599 break;
4600 case 0x9d: /* Ctrl release */
4601 shift_flags &= ~0x04;
4602 write_byte(0x0040, 0x17, shift_flags);
4603 if (mf2_state & 0x01) {
4604 mf2_flags &= ~0x04;
4605 } else {
4606 mf2_flags &= ~0x01;
4608 write_byte(0x0040, 0x18, mf2_flags);
4609 break;
4611 case 0x38: /* Alt press */
4612 shift_flags |= 0x08;
4613 write_byte(0x0040, 0x17, shift_flags);
4614 if (mf2_state & 0x01) {
4615 mf2_flags |= 0x08;
4616 } else {
4617 mf2_flags |= 0x02;
4619 write_byte(0x0040, 0x18, mf2_flags);
4620 break;
4621 case 0xb8: /* Alt release */
4622 shift_flags &= ~0x08;
4623 write_byte(0x0040, 0x17, shift_flags);
4624 if (mf2_state & 0x01) {
4625 mf2_flags &= ~0x08;
4626 } else {
4627 mf2_flags &= ~0x02;
4629 write_byte(0x0040, 0x18, mf2_flags);
4630 break;
4632 case 0x45: /* Num Lock press */
4633 if ((mf2_state & 0x01) == 0) {
4634 mf2_flags |= 0x20;
4635 write_byte(0x0040, 0x18, mf2_flags);
4636 shift_flags ^= 0x20;
4637 led_flags ^= 0x02;
4638 write_byte(0x0040, 0x17, shift_flags);
4639 write_byte(0x0040, 0x97, led_flags);
4641 break;
4642 case 0xc5: /* Num Lock release */
4643 if ((mf2_state & 0x01) == 0) {
4644 mf2_flags &= ~0x20;
4645 write_byte(0x0040, 0x18, mf2_flags);
4647 break;
4649 case 0x46: /* Scroll Lock press */
4650 mf2_flags |= 0x10;
4651 write_byte(0x0040, 0x18, mf2_flags);
4652 shift_flags ^= 0x10;
4653 led_flags ^= 0x01;
4654 write_byte(0x0040, 0x17, shift_flags);
4655 write_byte(0x0040, 0x97, led_flags);
4656 break;
4658 case 0xc6: /* Scroll Lock release */
4659 mf2_flags &= ~0x10;
4660 write_byte(0x0040, 0x18, mf2_flags);
4661 break;
4663 default:
4664 if (scancode & 0x80) return; /* toss key releases ... */
4665 if (scancode > MAX_SCAN_CODE) {
4666 BX_INFO("KBD: int09h_handler(): unknown scancode read!\n");
4667 return;
4669 if (shift_flags & 0x08) { /* ALT */
4670 asciicode = scan_to_scanascii[scancode].alt;
4671 scancode = scan_to_scanascii[scancode].alt >> 8;
4673 else if (shift_flags & 0x04) { /* CONTROL */
4674 asciicode = scan_to_scanascii[scancode].control;
4675 scancode = scan_to_scanascii[scancode].control >> 8;
4677 else if (shift_flags & 0x03) { /* LSHIFT + RSHIFT */
4678 /* check if lock state should be ignored
4679 * because a SHIFT key are pressed */
4681 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
4682 asciicode = scan_to_scanascii[scancode].normal;
4683 scancode = scan_to_scanascii[scancode].normal >> 8;
4685 else {
4686 asciicode = scan_to_scanascii[scancode].shift;
4687 scancode = scan_to_scanascii[scancode].shift >> 8;
4690 else {
4691 /* check if lock is on */
4692 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
4693 asciicode = scan_to_scanascii[scancode].shift;
4694 scancode = scan_to_scanascii[scancode].shift >> 8;
4696 else {
4697 asciicode = scan_to_scanascii[scancode].normal;
4698 scancode = scan_to_scanascii[scancode].normal >> 8;
4701 if (scancode==0 && asciicode==0) {
4702 BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
4704 enqueue_key(scancode, asciicode);
4705 break;
4707 mf2_state &= ~0x01;
4710 unsigned int
4711 enqueue_key(scan_code, ascii_code)
4712 Bit8u scan_code, ascii_code;
4714 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail, temp_tail;
4716 //BX_INFO("KBD: enqueue_key() called scan:%02x, ascii:%02x\n",
4717 // scan_code, ascii_code);
4719 #if BX_CPU < 2
4720 buffer_start = 0x001E;
4721 buffer_end = 0x003E;
4722 #else
4723 buffer_start = read_word(0x0040, 0x0080);
4724 buffer_end = read_word(0x0040, 0x0082);
4725 #endif
4727 buffer_head = read_word(0x0040, 0x001A);
4728 buffer_tail = read_word(0x0040, 0x001C);
4730 temp_tail = buffer_tail;
4731 buffer_tail += 2;
4732 if (buffer_tail >= buffer_end)
4733 buffer_tail = buffer_start;
4735 if (buffer_tail == buffer_head) {
4736 return(0);
4739 write_byte(0x0040, temp_tail, ascii_code);
4740 write_byte(0x0040, temp_tail+1, scan_code);
4741 write_word(0x0040, 0x001C, buffer_tail);
4742 return(1);
4746 void
4747 int74_function(make_farcall, Z, Y, X, status)
4748 Bit16u make_farcall, Z, Y, X, status;
4750 Bit16u ebda_seg=read_word(0x0040,0x000E);
4751 Bit8u in_byte, index, package_count;
4752 Bit8u mouse_flags_1, mouse_flags_2;
4754 BX_DEBUG_INT74("entering int74_function\n");
4755 make_farcall = 0;
4757 in_byte = inb(0x64);
4758 if ( (in_byte & 0x21) != 0x21 ) {
4759 return;
4761 in_byte = inb(0x60);
4762 BX_DEBUG_INT74("int74: read byte %02x\n", in_byte);
4764 mouse_flags_1 = read_byte(ebda_seg, 0x0026);
4765 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4767 if ( (mouse_flags_2 & 0x80) != 0x80 ) {
4768 // BX_PANIC("int74_function:\n");
4769 return;
4772 package_count = mouse_flags_2 & 0x07;
4773 index = mouse_flags_1 & 0x07;
4774 write_byte(ebda_seg, 0x28 + index, in_byte);
4776 if ( (index+1) >= package_count ) {
4777 BX_DEBUG_INT74("int74_function: make_farcall=1\n");
4778 status = read_byte(ebda_seg, 0x0028 + 0);
4779 X = read_byte(ebda_seg, 0x0028 + 1);
4780 Y = read_byte(ebda_seg, 0x0028 + 2);
4781 Z = 0;
4782 mouse_flags_1 = 0;
4783 // check if far call handler installed
4784 if (mouse_flags_2 & 0x80)
4785 make_farcall = 1;
4787 else {
4788 mouse_flags_1++;
4790 write_byte(ebda_seg, 0x0026, mouse_flags_1);
4793 #define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
4795 #if BX_USE_ATADRV
4797 void
4798 int13_harddisk(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
4799 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
4801 Bit32u lba;
4802 Bit16u ebda_seg=read_word(0x0040,0x000E);
4803 Bit16u cylinder, head, sector;
4804 Bit16u segment, offset;
4805 Bit16u npc, nph, npspt, nlc, nlh, nlspt;
4806 Bit16u size, count;
4807 Bit8u device, status;
4809 BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
4811 write_byte(0x0040, 0x008e, 0); // clear completion flag
4813 // basic check : device has to be defined
4814 if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES) ) {
4815 BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
4816 goto int13_fail;
4819 // Get the ata channel
4820 device=read_byte(ebda_seg,&EbdaData->ata.hdidmap[GET_ELDL()-0x80]);
4822 // basic check : device has to be valid
4823 if (device >= BX_MAX_ATA_DEVICES) {
4824 BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
4825 goto int13_fail;
4828 switch (GET_AH()) {
4830 case 0x00: /* disk controller reset */
4831 ata_reset (device);
4832 goto int13_success;
4833 break;
4835 case 0x01: /* read disk status */
4836 status = read_byte(0x0040, 0x0074);
4837 SET_AH(status);
4838 SET_DISK_RET_STATUS(0);
4839 /* set CF if error status read */
4840 if (status) goto int13_fail_nostatus;
4841 else goto int13_success_noah;
4842 break;
4844 case 0x02: // read disk sectors
4845 case 0x03: // write disk sectors
4846 case 0x04: // verify disk sectors
4848 count = GET_AL();
4849 cylinder = GET_CH();
4850 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
4851 sector = (GET_CL() & 0x3f);
4852 head = GET_DH();
4854 segment = ES;
4855 offset = BX;
4857 if ( (count > 128) || (count == 0) ) {
4858 BX_INFO("int13_harddisk: function %02x, count out of range!\n",GET_AH());
4859 goto int13_fail;
4862 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
4863 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
4864 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
4866 // sanity check on cyl heads, sec
4867 if( (cylinder >= nlc) || (head >= nlh) || (sector > nlspt )) {
4868 BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder, head, sector);
4869 goto int13_fail;
4872 // FIXME verify
4873 if ( GET_AH() == 0x04 ) goto int13_success;
4875 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
4876 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
4878 // if needed, translate lchs to lba, and execute command
4879 if ( (nph != nlh) || (npspt != nlspt)) {
4880 lba = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
4881 sector = 0; // this forces the command to be lba
4884 if ( GET_AH() == 0x02 )
4885 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, cylinder, head, sector, lba, segment, offset);
4886 else
4887 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, cylinder, head, sector, lba, segment, offset);
4889 // Set nb of sector transferred
4890 SET_AL(read_word(ebda_seg, &EbdaData->ata.trsfsectors));
4892 if (status != 0) {
4893 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
4894 SET_AH(0x0c);
4895 goto int13_fail_noah;
4898 goto int13_success;
4899 break;
4901 case 0x05: /* format disk track */
4902 BX_INFO("format disk track called\n");
4903 goto int13_success;
4904 return;
4905 break;
4907 case 0x08: /* read disk drive parameters */
4909 // Get logical geometry from table
4910 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
4911 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
4912 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
4913 count = read_byte(ebda_seg, &EbdaData->ata.hdcount);
4915 nlc = nlc - 2; /* 0 based , last sector not used */
4916 SET_AL(0);
4917 SET_CH(nlc & 0xff);
4918 SET_CL(((nlc >> 2) & 0xc0) | (nlspt & 0x3f));
4919 SET_DH(nlh - 1);
4920 SET_DL(count); /* FIXME returns 0, 1, or n hard drives */
4922 // FIXME should set ES & DI
4924 goto int13_success;
4925 break;
4927 case 0x10: /* check drive ready */
4928 // should look at 40:8E also???
4930 // Read the status from controller
4931 status = inb(read_word(ebda_seg, &EbdaData->ata.channels[device/2].iobase1) + ATA_CB_STAT);
4932 if ( (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY ) {
4933 goto int13_success;
4935 else {
4936 SET_AH(0xAA);
4937 goto int13_fail_noah;
4939 break;
4941 case 0x15: /* read disk drive size */
4943 // Get physical geometry from table
4944 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
4945 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
4946 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
4948 // Compute sector count seen by int13
4949 lba = (Bit32u)(npc - 1) * (Bit32u)nph * (Bit32u)npspt;
4950 CX = lba >> 16;
4951 DX = lba & 0xffff;
4953 SET_AH(3); // hard disk accessible
4954 goto int13_success_noah;
4955 break;
4957 case 0x41: // IBM/MS installation check
4958 BX=0xaa55; // install check
4959 SET_AH(0x30); // EDD 3.0
4960 CX=0x0007; // ext disk access and edd, removable supported
4961 goto int13_success_noah;
4962 break;
4964 case 0x42: // IBM/MS extended read
4965 case 0x43: // IBM/MS extended write
4966 case 0x44: // IBM/MS verify
4967 case 0x47: // IBM/MS extended seek
4969 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
4970 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
4971 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
4973 // Can't use 64 bits lba
4974 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
4975 if (lba != 0L) {
4976 BX_PANIC("int13_harddisk: function %02x. Can't use 64bits lba\n",GET_AH());
4977 goto int13_fail;
4980 // Get 32 bits lba and check
4981 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
4982 if (lba >= read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors) ) {
4983 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
4984 goto int13_fail;
4987 // If verify or seek
4988 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
4989 goto int13_success;
4991 // Execute the command
4992 if ( GET_AH() == 0x42 )
4993 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba, segment, offset);
4994 else
4995 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
4997 count=read_word(ebda_seg, &EbdaData->ata.trsfsectors);
4998 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5000 if (status != 0) {
5001 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5002 SET_AH(0x0c);
5003 goto int13_fail_noah;
5006 goto int13_success;
5007 break;
5009 case 0x45: // IBM/MS lock/unlock drive
5010 case 0x49: // IBM/MS extended media change
5011 goto int13_success; // Always success for HD
5012 break;
5014 case 0x46: // IBM/MS eject media
5015 SET_AH(0xb2); // Volume Not Removable
5016 goto int13_fail_noah; // Always fail for HD
5017 break;
5019 case 0x48: // IBM/MS get drive parameters
5020 size=read_word(DS,SI+(Bit16u)&Int13DPT->size);
5022 // Buffer is too small
5023 if(size < 0x1a)
5024 goto int13_fail;
5026 // EDD 1.x
5027 if(size >= 0x1a) {
5028 Bit16u blksize;
5030 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5031 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5032 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5033 lba = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors);
5034 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5036 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5037 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x02); // geometry is valid
5038 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, (Bit32u)npc);
5039 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, (Bit32u)nph);
5040 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, (Bit32u)npspt);
5041 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, lba); // FIXME should be Bit64
5042 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0L);
5043 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5046 // EDD 2.x
5047 if(size >= 0x1e) {
5048 Bit8u channel, dev, irq, mode, checksum, i, translation;
5049 Bit16u iobase1, iobase2, options;
5051 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5053 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5054 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5056 // Fill in dpte
5057 channel = device / 2;
5058 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5059 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5060 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5061 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5062 translation = read_byte(ebda_seg, &EbdaData->ata.devices[device].translation);
5064 options = (translation==ATA_TRANSLATION_NONE?0:1<<3); // chs translation
5065 options |= (1<<4); // lba translation
5066 options |= (mode==ATA_MODE_PIO32?1:0<<7);
5067 options |= (translation==ATA_TRANSLATION_LBA?1:0<<9);
5068 options |= (translation==ATA_TRANSLATION_RECHS?3:0<<9);
5070 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5071 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5072 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5073 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5074 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5075 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5076 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5077 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5078 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5079 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5080 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5082 checksum=0;
5083 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5084 checksum = ~checksum;
5085 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5088 // EDD 3.x
5089 if(size >= 0x42) {
5090 Bit8u channel, iface, checksum, i;
5091 Bit16u iobase1;
5093 channel = device / 2;
5094 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5095 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5097 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5098 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5099 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5100 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5101 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5103 if (iface==ATA_IFACE_ISA) {
5104 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5105 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5106 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5107 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5109 else {
5110 // FIXME PCI
5112 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5113 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5114 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5115 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5117 if (iface==ATA_IFACE_ISA) {
5118 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5119 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5120 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5122 else {
5123 // FIXME PCI
5125 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5126 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5127 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5128 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5130 checksum=0;
5131 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5132 checksum = ~checksum;
5133 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5136 goto int13_success;
5137 break;
5139 case 0x4e: // // IBM/MS set hardware configuration
5140 // DMA, prefetch, PIO maximum not supported
5141 switch (GET_AL()) {
5142 case 0x01:
5143 case 0x03:
5144 case 0x04:
5145 case 0x06:
5146 goto int13_success;
5147 break;
5148 default :
5149 goto int13_fail;
5151 break;
5153 case 0x09: /* initialize drive parameters */
5154 case 0x0c: /* seek to specified cylinder */
5155 case 0x0d: /* alternate disk reset */
5156 case 0x11: /* recalibrate */
5157 case 0x14: /* controller internal diagnostic */
5158 BX_INFO("int13h_harddisk function %02xh unimplemented, returns success\n", GET_AH());
5159 goto int13_success;
5160 break;
5162 case 0x0a: /* read disk sectors with ECC */
5163 case 0x0b: /* write disk sectors with ECC */
5164 case 0x18: // set media type for format
5165 case 0x50: // IBM/MS send packet command
5166 default:
5167 BX_INFO("int13_harddisk function %02xh unsupported, returns fail\n", GET_AH());
5168 goto int13_fail;
5169 break;
5172 int13_fail:
5173 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5174 int13_fail_noah:
5175 SET_DISK_RET_STATUS(GET_AH());
5176 int13_fail_nostatus:
5177 SET_CF(); // error occurred
5178 return;
5180 int13_success:
5181 SET_AH(0x00); // no error
5182 int13_success_noah:
5183 SET_DISK_RET_STATUS(0x00);
5184 CLEAR_CF(); // no error
5185 return;
5188 // ---------------------------------------------------------------------------
5189 // Start of int13 for cdrom
5190 // ---------------------------------------------------------------------------
5192 void
5193 int13_cdrom(EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5194 Bit16u EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5196 Bit16u ebda_seg=read_word(0x0040,0x000E);
5197 Bit8u device, status, locks;
5198 Bit8u atacmd[12];
5199 Bit32u lba;
5200 Bit16u count, segment, offset, i, size;
5202 BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5203 // BX_DEBUG_INT13_CD("int13_cdrom: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
5205 SET_DISK_RET_STATUS(0x00);
5207 /* basic check : device should be 0xE0+ */
5208 if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES) ) {
5209 BX_INFO("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5210 goto int13_fail;
5213 // Get the ata channel
5214 device=read_byte(ebda_seg,&EbdaData->ata.cdidmap[GET_ELDL()-0xE0]);
5216 /* basic check : device has to be valid */
5217 if (device >= BX_MAX_ATA_DEVICES) {
5218 BX_INFO("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5219 goto int13_fail;
5222 switch (GET_AH()) {
5224 // all those functions return SUCCESS
5225 case 0x00: /* disk controller reset */
5226 case 0x09: /* initialize drive parameters */
5227 case 0x0c: /* seek to specified cylinder */
5228 case 0x0d: /* alternate disk reset */
5229 case 0x10: /* check drive ready */
5230 case 0x11: /* recalibrate */
5231 case 0x14: /* controller internal diagnostic */
5232 case 0x16: /* detect disk change */
5233 goto int13_success;
5234 break;
5236 // all those functions return disk write-protected
5237 case 0x03: /* write disk sectors */
5238 case 0x05: /* format disk track */
5239 case 0x43: // IBM/MS extended write
5240 SET_AH(0x03);
5241 goto int13_fail_noah;
5242 break;
5244 case 0x01: /* read disk status */
5245 status = read_byte(0x0040, 0x0074);
5246 SET_AH(status);
5247 SET_DISK_RET_STATUS(0);
5249 /* set CF if error status read */
5250 if (status) goto int13_fail_nostatus;
5251 else goto int13_success_noah;
5252 break;
5254 case 0x15: /* read disk drive size */
5255 SET_AH(0x02);
5256 goto int13_fail_noah;
5257 break;
5259 case 0x41: // IBM/MS installation check
5260 BX=0xaa55; // install check
5261 SET_AH(0x30); // EDD 2.1
5262 CX=0x0007; // ext disk access, removable and edd
5263 goto int13_success_noah;
5264 break;
5266 case 0x42: // IBM/MS extended read
5267 case 0x44: // IBM/MS verify sectors
5268 case 0x47: // IBM/MS extended seek
5270 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5271 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5272 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5274 // Can't use 64 bits lba
5275 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5276 if (lba != 0L) {
5277 BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
5278 goto int13_fail;
5281 // Get 32 bits lba
5282 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5284 // If verify or seek
5285 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5286 goto int13_success;
5288 memsetb(get_SS(),atacmd,0,12);
5289 atacmd[0]=0x28; // READ command
5290 atacmd[7]=(count & 0xff00) >> 8; // Sectors
5291 atacmd[8]=(count & 0x00ff); // Sectors
5292 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
5293 atacmd[3]=(lba & 0x00ff0000) >> 16;
5294 atacmd[4]=(lba & 0x0000ff00) >> 8;
5295 atacmd[5]=(lba & 0x000000ff);
5296 status = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, count*2048L, ATA_DATA_IN, segment,offset);
5298 count = (Bit16u)(read_dword(ebda_seg, &EbdaData->ata.trsfbytes) >> 11);
5299 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5301 if (status != 0) {
5302 BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status);
5303 SET_AH(0x0c);
5304 goto int13_fail_noah;
5307 goto int13_success;
5308 break;
5310 case 0x45: // IBM/MS lock/unlock drive
5311 if (GET_AL() > 2) goto int13_fail;
5313 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
5315 switch (GET_AL()) {
5316 case 0 : // lock
5317 if (locks == 0xff) {
5318 SET_AH(0xb4);
5319 SET_AL(1);
5320 goto int13_fail_noah;
5322 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, ++locks);
5323 SET_AL(1);
5324 break;
5325 case 1 : // unlock
5326 if (locks == 0x00) {
5327 SET_AH(0xb0);
5328 SET_AL(0);
5329 goto int13_fail_noah;
5331 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, --locks);
5332 SET_AL(locks==0?0:1);
5333 break;
5334 case 2 : // status
5335 SET_AL(locks==0?0:1);
5336 break;
5338 goto int13_success;
5339 break;
5341 case 0x46: // IBM/MS eject media
5342 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
5344 if (locks != 0) {
5345 SET_AH(0xb1); // media locked
5346 goto int13_fail_noah;
5348 // FIXME should handle 0x31 no media in device
5349 // FIXME should handle 0xb5 valid request failed
5351 // Call removable media eject
5352 ASM_START
5353 push bp
5354 mov bp, sp
5356 mov ah, #0x52
5357 int 15
5358 mov _int13_cdrom.status + 2[bp], ah
5359 jnc int13_cdrom_rme_end
5360 mov _int13_cdrom.status, #1
5361 int13_cdrom_rme_end:
5362 pop bp
5363 ASM_END
5365 if (status != 0) {
5366 SET_AH(0xb1); // media locked
5367 goto int13_fail_noah;
5370 goto int13_success;
5371 break;
5373 case 0x48: // IBM/MS get drive parameters
5374 size = read_word(DS,SI+(Bit16u)&Int13Ext->size);
5376 // Buffer is too small
5377 if(size < 0x1a)
5378 goto int13_fail;
5380 // EDD 1.x
5381 if(size >= 0x1a) {
5382 Bit16u cylinders, heads, spt, blksize;
5384 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5386 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5387 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x74); // removable, media change, lockable, max values
5388 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, 0xffffffff);
5389 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, 0xffffffff);
5390 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, 0xffffffff);
5391 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, 0xffffffff); // FIXME should be Bit64
5392 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0xffffffff);
5393 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5396 // EDD 2.x
5397 if(size >= 0x1e) {
5398 Bit8u channel, dev, irq, mode, checksum, i;
5399 Bit16u iobase1, iobase2, options;
5401 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5403 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5404 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5406 // Fill in dpte
5407 channel = device / 2;
5408 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5409 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5410 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5411 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5413 // FIXME atapi device
5414 options = (1<<4); // lba translation
5415 options |= (1<<5); // removable device
5416 options |= (1<<6); // atapi device
5417 options |= (mode==ATA_MODE_PIO32?1:0<<7);
5419 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5420 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5421 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5422 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5423 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5424 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5425 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5426 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5427 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5428 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5429 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5431 checksum=0;
5432 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5433 checksum = ~checksum;
5434 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5437 // EDD 3.x
5438 if(size >= 0x42) {
5439 Bit8u channel, iface, checksum, i;
5440 Bit16u iobase1;
5442 channel = device / 2;
5443 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5444 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5446 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5447 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5448 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5449 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5450 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5452 if (iface==ATA_IFACE_ISA) {
5453 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5454 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5455 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5456 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5458 else {
5459 // FIXME PCI
5461 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5462 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5463 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5464 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5466 if (iface==ATA_IFACE_ISA) {
5467 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5468 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5469 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5471 else {
5472 // FIXME PCI
5474 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5475 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5476 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5477 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5479 checksum=0;
5480 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5481 checksum = ~checksum;
5482 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5485 goto int13_success;
5486 break;
5488 case 0x49: // IBM/MS extended media change
5489 // always send changed ??
5490 SET_AH(06);
5491 goto int13_fail_nostatus;
5492 break;
5494 case 0x4e: // // IBM/MS set hardware configuration
5495 // DMA, prefetch, PIO maximum not supported
5496 switch (GET_AL()) {
5497 case 0x01:
5498 case 0x03:
5499 case 0x04:
5500 case 0x06:
5501 goto int13_success;
5502 break;
5503 default :
5504 goto int13_fail;
5506 break;
5508 // all those functions return unimplemented
5509 case 0x02: /* read sectors */
5510 case 0x04: /* verify sectors */
5511 case 0x08: /* read disk drive parameters */
5512 case 0x0a: /* read disk sectors with ECC */
5513 case 0x0b: /* write disk sectors with ECC */
5514 case 0x18: /* set media type for format */
5515 case 0x50: // ? - send packet command
5516 default:
5517 BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
5518 goto int13_fail;
5519 break;
5522 int13_fail:
5523 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5524 int13_fail_noah:
5525 SET_DISK_RET_STATUS(GET_AH());
5526 int13_fail_nostatus:
5527 SET_CF(); // error occurred
5528 return;
5530 int13_success:
5531 SET_AH(0x00); // no error
5532 int13_success_noah:
5533 SET_DISK_RET_STATUS(0x00);
5534 CLEAR_CF(); // no error
5535 return;
5538 // ---------------------------------------------------------------------------
5539 // End of int13 for cdrom
5540 // ---------------------------------------------------------------------------
5542 #if BX_ELTORITO_BOOT
5543 // ---------------------------------------------------------------------------
5544 // Start of int13 for eltorito functions
5545 // ---------------------------------------------------------------------------
5547 void
5548 int13_eltorito(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
5549 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
5551 Bit16u ebda_seg=read_word(0x0040,0x000E);
5553 BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5554 // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
5556 switch (GET_AH()) {
5558 // FIXME ElTorito Various. Should be implemented
5559 case 0x4a: // ElTorito - Initiate disk emu
5560 case 0x4c: // ElTorito - Initiate disk emu and boot
5561 case 0x4d: // ElTorito - Return Boot catalog
5562 BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX);
5563 goto int13_fail;
5564 break;
5566 case 0x4b: // ElTorito - Terminate disk emu
5567 // FIXME ElTorito Hardcoded
5568 write_byte(DS,SI+0x00,0x13);
5569 write_byte(DS,SI+0x01,read_byte(ebda_seg,&EbdaData->cdemu.media));
5570 write_byte(DS,SI+0x02,read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
5571 write_byte(DS,SI+0x03,read_byte(ebda_seg,&EbdaData->cdemu.controller_index));
5572 write_dword(DS,SI+0x04,read_dword(ebda_seg,&EbdaData->cdemu.ilba));
5573 write_word(DS,SI+0x08,read_word(ebda_seg,&EbdaData->cdemu.device_spec));
5574 write_word(DS,SI+0x0a,read_word(ebda_seg,&EbdaData->cdemu.buffer_segment));
5575 write_word(DS,SI+0x0c,read_word(ebda_seg,&EbdaData->cdemu.load_segment));
5576 write_word(DS,SI+0x0e,read_word(ebda_seg,&EbdaData->cdemu.sector_count));
5577 write_byte(DS,SI+0x10,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.cylinders));
5578 write_byte(DS,SI+0x11,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.spt));
5579 write_byte(DS,SI+0x12,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.heads));
5581 // If we have to terminate emulation
5582 if(GET_AL() == 0x00) {
5583 // FIXME ElTorito Various. Should be handled accordingly to spec
5584 write_byte(ebda_seg,&EbdaData->cdemu.active, 0x00); // bye bye
5587 goto int13_success;
5588 break;
5590 default:
5591 BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
5592 goto int13_fail;
5593 break;
5596 int13_fail:
5597 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5598 SET_DISK_RET_STATUS(GET_AH());
5599 SET_CF(); // error occurred
5600 return;
5602 int13_success:
5603 SET_AH(0x00); // no error
5604 SET_DISK_RET_STATUS(0x00);
5605 CLEAR_CF(); // no error
5606 return;
5609 // ---------------------------------------------------------------------------
5610 // End of int13 for eltorito functions
5611 // ---------------------------------------------------------------------------
5613 // ---------------------------------------------------------------------------
5614 // Start of int13 when emulating a device from the cd
5615 // ---------------------------------------------------------------------------
5617 void
5618 int13_cdemu(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
5619 Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
5621 Bit16u ebda_seg=read_word(0x0040,0x000E);
5622 Bit8u device, status;
5623 Bit16u vheads, vspt, vcylinders;
5624 Bit16u head, sector, cylinder, nbsectors;
5625 Bit32u vlba, ilba, slba, elba;
5626 Bit16u before, segment, offset;
5627 Bit8u atacmd[12];
5629 BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5630 //BX_DEBUG_INT13_ET("int13_cdemu: SS=%04x ES=%04x DI=%04x SI=%04x\n", get_SS(), ES, DI, SI);
5632 /* at this point, we are emulating a floppy/harddisk */
5634 // Recompute the device number
5635 device = read_byte(ebda_seg,&EbdaData->cdemu.controller_index) * 2;
5636 device += read_byte(ebda_seg,&EbdaData->cdemu.device_spec);
5638 SET_DISK_RET_STATUS(0x00);
5640 /* basic checks : emulation should be active, dl should equal the emulated drive */
5641 if( (read_byte(ebda_seg,&EbdaData->cdemu.active) ==0 )
5642 || (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive ) != GET_DL())) {
5643 BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
5644 goto int13_fail;
5647 switch (GET_AH()) {
5649 // all those functions return SUCCESS
5650 case 0x00: /* disk controller reset */
5651 case 0x09: /* initialize drive parameters */
5652 case 0x0c: /* seek to specified cylinder */
5653 case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
5654 case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
5655 case 0x11: /* recalibrate */
5656 case 0x14: /* controller internal diagnostic */
5657 case 0x16: /* detect disk change */
5658 goto int13_success;
5659 break;
5661 // all those functions return disk write-protected
5662 case 0x03: /* write disk sectors */
5663 case 0x05: /* format disk track */
5664 SET_AH(0x03);
5665 goto int13_fail_noah;
5666 break;
5668 case 0x01: /* read disk status */
5669 status=read_byte(0x0040, 0x0074);
5670 SET_AH(status);
5671 SET_DISK_RET_STATUS(0);
5673 /* set CF if error status read */
5674 if (status) goto int13_fail_nostatus;
5675 else goto int13_success_noah;
5676 break;
5678 case 0x02: // read disk sectors
5679 case 0x04: // verify disk sectors
5680 vspt = read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
5681 vcylinders = read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders);
5682 vheads = read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads);
5684 ilba = read_dword(ebda_seg,&EbdaData->cdemu.ilba);
5686 sector = GET_CL() & 0x003f;
5687 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
5688 head = GET_DH();
5689 nbsectors = GET_AL();
5690 segment = ES;
5691 offset = BX;
5693 // no sector to read ?
5694 if(nbsectors==0) goto int13_success;
5696 // sanity checks sco openserver needs this!
5697 if ((sector > vspt)
5698 || (cylinder >= vcylinders)
5699 || (head >= vheads)) {
5700 goto int13_fail;
5703 // After controls, verify do nothing
5704 if (GET_AH() == 0x04) goto int13_success;
5706 segment = ES+(BX / 16);
5707 offset = BX % 16;
5709 // calculate the virtual lba inside the image
5710 vlba=((((Bit32u)cylinder*(Bit32u)vheads)+(Bit32u)head)*(Bit32u)vspt)+((Bit32u)(sector-1));
5712 // In advance so we don't loose the count
5713 SET_AL(nbsectors);
5715 // start lba on cd
5716 slba = (Bit32u)vlba/4;
5717 before= (Bit16u)vlba%4;
5719 // end lba on cd
5720 elba = (Bit32u)(vlba+nbsectors-1)/4;
5722 memsetb(get_SS(),atacmd,0,12);
5723 atacmd[0]=0x28; // READ command
5724 atacmd[7]=((Bit16u)(elba-slba+1) & 0xff00) >> 8; // Sectors
5725 atacmd[8]=((Bit16u)(elba-slba+1) & 0x00ff); // Sectors
5726 atacmd[2]=(ilba+slba & 0xff000000) >> 24; // LBA
5727 atacmd[3]=(ilba+slba & 0x00ff0000) >> 16;
5728 atacmd[4]=(ilba+slba & 0x0000ff00) >> 8;
5729 atacmd[5]=(ilba+slba & 0x000000ff);
5730 if((status = ata_cmd_packet(device, 12, get_SS(), atacmd, before*512, nbsectors*512L, ATA_DATA_IN, segment,offset)) != 0) {
5731 BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status);
5732 SET_AH(0x02);
5733 SET_AL(0);
5734 goto int13_fail_noah;
5737 goto int13_success;
5738 break;
5740 case 0x08: /* read disk drive parameters */
5741 vspt=read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
5742 vcylinders=read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders) - 1;
5743 vheads=read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads) - 1;
5745 SET_AL( 0x00 );
5746 SET_BL( 0x00 );
5747 SET_CH( vcylinders & 0xff );
5748 SET_CL((( vcylinders >> 2) & 0xc0) | ( vspt & 0x3f ));
5749 SET_DH( vheads );
5750 SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2
5751 // FIXME ElTorito Harddisk. should send the HD count
5753 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
5754 case 0x01: SET_BL( 0x02 ); break;
5755 case 0x02: SET_BL( 0x04 ); break;
5756 case 0x03: SET_BL( 0x06 ); break;
5759 ASM_START
5760 push bp
5761 mov bp, sp
5762 mov ax, #diskette_param_table2
5763 mov _int13_cdemu.DI+2[bp], ax
5764 mov _int13_cdemu.ES+2[bp], cs
5765 pop bp
5766 ASM_END
5767 goto int13_success;
5768 break;
5770 case 0x15: /* read disk drive size */
5771 // FIXME ElTorito Harddisk. What geometry to send ?
5772 SET_AH(0x03);
5773 goto int13_success_noah;
5774 break;
5776 // all those functions return unimplemented
5777 case 0x0a: /* read disk sectors with ECC */
5778 case 0x0b: /* write disk sectors with ECC */
5779 case 0x18: /* set media type for format */
5780 case 0x41: // IBM/MS installation check
5781 // FIXME ElTorito Harddisk. Darwin would like to use EDD
5782 case 0x42: // IBM/MS extended read
5783 case 0x43: // IBM/MS extended write
5784 case 0x44: // IBM/MS verify sectors
5785 case 0x45: // IBM/MS lock/unlock drive
5786 case 0x46: // IBM/MS eject media
5787 case 0x47: // IBM/MS extended seek
5788 case 0x48: // IBM/MS get drive parameters
5789 case 0x49: // IBM/MS extended media change
5790 case 0x4e: // ? - set hardware configuration
5791 case 0x50: // ? - send packet command
5792 default:
5793 BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
5794 goto int13_fail;
5795 break;
5798 int13_fail:
5799 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5800 int13_fail_noah:
5801 SET_DISK_RET_STATUS(GET_AH());
5802 int13_fail_nostatus:
5803 SET_CF(); // error occurred
5804 return;
5806 int13_success:
5807 SET_AH(0x00); // no error
5808 int13_success_noah:
5809 SET_DISK_RET_STATUS(0x00);
5810 CLEAR_CF(); // no error
5811 return;
5814 // ---------------------------------------------------------------------------
5815 // End of int13 when emulating a device from the cd
5816 // ---------------------------------------------------------------------------
5818 #endif // BX_ELTORITO_BOOT
5820 #else //BX_USE_ATADRV
5822 void
5823 outLBA(cylinder,hd_heads,head,hd_sectors,sector,dl)
5824 Bit16u cylinder;
5825 Bit16u hd_heads;
5826 Bit16u head;
5827 Bit16u hd_sectors;
5828 Bit16u sector;
5829 Bit16u dl;
5831 ASM_START
5832 push bp
5833 mov bp, sp
5834 push eax
5835 push ebx
5836 push edx
5837 xor eax,eax
5838 mov ax,4[bp] // cylinder
5839 xor ebx,ebx
5840 mov bl,6[bp] // hd_heads
5841 imul ebx
5843 mov bl,8[bp] // head
5844 add eax,ebx
5845 mov bl,10[bp] // hd_sectors
5846 imul ebx
5847 mov bl,12[bp] // sector
5848 add eax,ebx
5850 dec eax
5851 mov dx,#0x1f3
5852 out dx,al
5853 mov dx,#0x1f4
5854 mov al,ah
5855 out dx,al
5856 shr eax,#16
5857 mov dx,#0x1f5
5858 out dx,al
5859 and ah,#0xf
5860 mov bl,14[bp] // dl
5861 and bl,#1
5862 shl bl,#4
5863 or ah,bl
5864 or ah,#0xe0
5865 mov al,ah
5866 mov dx,#0x01f6
5867 out dx,al
5868 pop edx
5869 pop ebx
5870 pop eax
5871 pop bp
5872 ASM_END
5875 void
5876 int13_harddisk(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5877 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5879 Bit8u drive, num_sectors, sector, head, status, mod;
5880 Bit8u drive_map;
5881 Bit8u n_drives;
5882 Bit16u cyl_mod, ax;
5883 Bit16u max_cylinder, cylinder, total_sectors;
5884 Bit16u hd_cylinders;
5885 Bit8u hd_heads, hd_sectors;
5886 Bit16u val16;
5887 Bit8u sector_count;
5888 unsigned int i;
5889 Bit16u tempbx;
5890 Bit16u dpsize;
5892 Bit16u count, segment, offset;
5893 Bit32u lba;
5894 Bit16u error;
5896 BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5898 write_byte(0x0040, 0x008e, 0); // clear completion flag
5900 /* at this point, DL is >= 0x80 to be passed from the floppy int13h
5901 handler code */
5902 /* check how many disks first (cmos reg 0x12), return an error if
5903 drive not present */
5904 drive_map = inb_cmos(0x12);
5905 drive_map = (((drive_map & 0xf0)==0) ? 0 : 1) |
5906 (((drive_map & 0x0f)==0) ? 0 : 2);
5907 n_drives = (drive_map==0) ? 0 :
5908 ((drive_map==3) ? 2 : 1);
5910 if (!(drive_map & (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
5911 SET_AH(0x01);
5912 SET_DISK_RET_STATUS(0x01);
5913 SET_CF(); /* error occurred */
5914 return;
5917 switch (GET_AH()) {
5919 case 0x00: /* disk controller reset */
5920 BX_DEBUG_INT13_HD("int13_f00\n");
5922 SET_AH(0);
5923 SET_DISK_RET_STATUS(0);
5924 set_diskette_ret_status(0);
5925 set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
5926 set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
5927 CLEAR_CF(); /* successful */
5928 return;
5929 break;
5931 case 0x01: /* read disk status */
5932 BX_DEBUG_INT13_HD("int13_f01\n");
5933 status = read_byte(0x0040, 0x0074);
5934 SET_AH(status);
5935 SET_DISK_RET_STATUS(0);
5936 /* set CF if error status read */
5937 if (status) SET_CF();
5938 else CLEAR_CF();
5939 return;
5940 break;
5942 case 0x04: // verify disk sectors
5943 case 0x02: // read disk sectors
5944 drive = GET_ELDL();
5945 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
5947 num_sectors = GET_AL();
5948 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
5949 sector = (GET_CL() & 0x3f);
5950 head = GET_DH();
5953 if (hd_cylinders > 1024) {
5954 if (hd_cylinders <= 2048) {
5955 cylinder <<= 1;
5957 else if (hd_cylinders <= 4096) {
5958 cylinder <<= 2;
5960 else if (hd_cylinders <= 8192) {
5961 cylinder <<= 3;
5963 else { // hd_cylinders <= 16384
5964 cylinder <<= 4;
5967 ax = head / hd_heads;
5968 cyl_mod = ax & 0xff;
5969 head = ax >> 8;
5970 cylinder |= cyl_mod;
5973 if ( (cylinder >= hd_cylinders) ||
5974 (sector > hd_sectors) ||
5975 (head >= hd_heads) ) {
5976 SET_AH(1);
5977 SET_DISK_RET_STATUS(1);
5978 SET_CF(); /* error occurred */
5979 return;
5982 if ( (num_sectors > 128) || (num_sectors == 0) )
5983 BX_PANIC("int13_harddisk(): num_sectors out of range!\n");
5985 if (head > 15)
5986 BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
5988 if ( GET_AH() == 0x04 ) {
5989 SET_AH(0);
5990 SET_DISK_RET_STATUS(0);
5991 CLEAR_CF();
5992 return;
5995 status = inb(0x1f7);
5996 if (status & 0x80) {
5997 BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
5999 outb(0x01f2, num_sectors);
6000 /* activate LBA? (tomv) */
6001 if (hd_heads > 16) {
6002 BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder, head, sector);
6003 outLBA(cylinder,hd_heads,head,hd_sectors,sector,drive);
6005 else {
6006 outb(0x01f3, sector);
6007 outb(0x01f4, cylinder & 0x00ff);
6008 outb(0x01f5, cylinder >> 8);
6009 outb(0x01f6, 0xa0 | ((drive & 0x01)<<4) | (head & 0x0f));
6011 outb(0x01f7, 0x20);
6013 while (1) {
6014 status = inb(0x1f7);
6015 if ( !(status & 0x80) ) break;
6018 if (status & 0x01) {
6019 BX_PANIC("hard drive BIOS:(read/verify) read error\n");
6020 } else if ( !(status & 0x08) ) {
6021 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6022 BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
6025 sector_count = 0;
6026 tempbx = BX;
6028 ASM_START
6029 sti ;; enable higher priority interrupts
6030 ASM_END
6032 while (1) {
6033 ASM_START
6034 ;; store temp bx in real DI register
6035 push bp
6036 mov bp, sp
6037 mov di, _int13_harddisk.tempbx + 2 [bp]
6038 pop bp
6040 ;; adjust if there will be an overrun
6041 cmp di, #0xfe00
6042 jbe i13_f02_no_adjust
6043 i13_f02_adjust:
6044 sub di, #0x0200 ; sub 512 bytes from offset
6045 mov ax, es
6046 add ax, #0x0020 ; add 512 to segment
6047 mov es, ax
6049 i13_f02_no_adjust:
6050 mov cx, #0x0100 ;; counter (256 words = 512b)
6051 mov dx, #0x01f0 ;; AT data read port
6053 rep
6054 insw ;; CX words transfered from port(DX) to ES:[DI]
6056 i13_f02_done:
6057 ;; store real DI register back to temp bx
6058 push bp
6059 mov bp, sp
6060 mov _int13_harddisk.tempbx + 2 [bp], di
6061 pop bp
6062 ASM_END
6064 sector_count++;
6065 num_sectors--;
6066 if (num_sectors == 0) {
6067 status = inb(0x1f7);
6068 if ( (status & 0xc9) != 0x40 )
6069 BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status);
6070 break;
6072 else {
6073 status = inb(0x1f7);
6074 if ( (status & 0xc9) != 0x48 )
6075 BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status);
6076 continue;
6080 SET_AH(0);
6081 SET_DISK_RET_STATUS(0);
6082 SET_AL(sector_count);
6083 CLEAR_CF(); /* successful */
6084 return;
6085 break;
6088 case 0x03: /* write disk sectors */
6089 BX_DEBUG_INT13_HD("int13_f03\n");
6090 drive = GET_ELDL ();
6091 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6093 num_sectors = GET_AL();
6094 cylinder = GET_CH();
6095 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
6096 sector = (GET_CL() & 0x3f);
6097 head = GET_DH();
6099 if (hd_cylinders > 1024) {
6100 if (hd_cylinders <= 2048) {
6101 cylinder <<= 1;
6103 else if (hd_cylinders <= 4096) {
6104 cylinder <<= 2;
6106 else if (hd_cylinders <= 8192) {
6107 cylinder <<= 3;
6109 else { // hd_cylinders <= 16384
6110 cylinder <<= 4;
6113 ax = head / hd_heads;
6114 cyl_mod = ax & 0xff;
6115 head = ax >> 8;
6116 cylinder |= cyl_mod;
6119 if ( (cylinder >= hd_cylinders) ||
6120 (sector > hd_sectors) ||
6121 (head >= hd_heads) ) {
6122 SET_AH( 1);
6123 SET_DISK_RET_STATUS(1);
6124 SET_CF(); /* error occurred */
6125 return;
6128 if ( (num_sectors > 128) || (num_sectors == 0) )
6129 BX_PANIC("int13_harddisk(): num_sectors out of range!\n");
6131 if (head > 15)
6132 BX_PANIC("hard drive BIOS:(read) head > 15\n");
6134 status = inb(0x1f7);
6135 if (status & 0x80) {
6136 BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
6138 // should check for Drive Ready Bit also in status reg
6139 outb(0x01f2, num_sectors);
6141 /* activate LBA? (tomv) */
6142 if (hd_heads > 16) {
6143 BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder, head, sector);
6144 outLBA(cylinder,hd_heads,head,hd_sectors,sector,GET_ELDL());
6146 else {
6147 outb(0x01f3, sector);
6148 outb(0x01f4, cylinder & 0x00ff);
6149 outb(0x01f5, cylinder >> 8);
6150 outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head & 0x0f));
6152 outb(0x01f7, 0x30);
6154 // wait for busy bit to turn off after seeking
6155 while (1) {
6156 status = inb(0x1f7);
6157 if ( !(status & 0x80) ) break;
6160 if ( !(status & 0x08) ) {
6161 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6162 BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
6165 sector_count = 0;
6166 tempbx = BX;
6168 ASM_START
6169 sti ;; enable higher priority interrupts
6170 ASM_END
6172 while (1) {
6173 ASM_START
6174 ;; store temp bx in real SI register
6175 push bp
6176 mov bp, sp
6177 mov si, _int13_harddisk.tempbx + 2 [bp]
6178 pop bp
6180 ;; adjust if there will be an overrun
6181 cmp si, #0xfe00
6182 jbe i13_f03_no_adjust
6183 i13_f03_adjust:
6184 sub si, #0x0200 ; sub 512 bytes from offset
6185 mov ax, es
6186 add ax, #0x0020 ; add 512 to segment
6187 mov es, ax
6189 i13_f03_no_adjust:
6190 mov cx, #0x0100 ;; counter (256 words = 512b)
6191 mov dx, #0x01f0 ;; AT data read port
6193 seg ES
6194 rep
6195 outsw ;; CX words tranfered from ES:[SI] to port(DX)
6197 ;; store real SI register back to temp bx
6198 push bp
6199 mov bp, sp
6200 mov _int13_harddisk.tempbx + 2 [bp], si
6201 pop bp
6202 ASM_END
6204 sector_count++;
6205 num_sectors--;
6206 if (num_sectors == 0) {
6207 status = inb(0x1f7);
6208 if ( (status & 0xe9) != 0x40 )
6209 BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status);
6210 break;
6212 else {
6213 status = inb(0x1f7);
6214 if ( (status & 0xc9) != 0x48 )
6215 BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status);
6216 continue;
6220 SET_AH(0);
6221 SET_DISK_RET_STATUS(0);
6222 SET_AL(sector_count);
6223 CLEAR_CF(); /* successful */
6224 return;
6225 break;
6227 case 0x05: /* format disk track */
6228 BX_DEBUG_INT13_HD("int13_f05\n");
6229 BX_PANIC("format disk track called\n");
6230 /* nop */
6231 SET_AH(0);
6232 SET_DISK_RET_STATUS(0);
6233 CLEAR_CF(); /* successful */
6234 return;
6235 break;
6237 case 0x08: /* read disk drive parameters */
6238 BX_DEBUG_INT13_HD("int13_f08\n");
6240 drive = GET_ELDL ();
6241 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6243 // translate CHS
6244 //
6245 if (hd_cylinders <= 1024) {
6246 // hd_cylinders >>= 0;
6247 // hd_heads <<= 0;
6249 else if (hd_cylinders <= 2048) {
6250 hd_cylinders >>= 1;
6251 hd_heads <<= 1;
6253 else if (hd_cylinders <= 4096) {
6254 hd_cylinders >>= 2;
6255 hd_heads <<= 2;
6257 else if (hd_cylinders <= 8192) {
6258 hd_cylinders >>= 3;
6259 hd_heads <<= 3;
6261 else { // hd_cylinders <= 16384
6262 hd_cylinders >>= 4;
6263 hd_heads <<= 4;
6266 max_cylinder = hd_cylinders - 2; /* 0 based */
6267 SET_AL(0);
6268 SET_CH(max_cylinder & 0xff);
6269 SET_CL(((max_cylinder >> 2) & 0xc0) | (hd_sectors & 0x3f));
6270 SET_DH(hd_heads - 1);
6271 SET_DL(n_drives); /* returns 0, 1, or 2 hard drives */
6272 SET_AH(0);
6273 SET_DISK_RET_STATUS(0);
6274 CLEAR_CF(); /* successful */
6276 return;
6277 break;
6279 case 0x09: /* initialize drive parameters */
6280 BX_DEBUG_INT13_HD("int13_f09\n");
6281 SET_AH(0);
6282 SET_DISK_RET_STATUS(0);
6283 CLEAR_CF(); /* successful */
6284 return;
6285 break;
6287 case 0x0a: /* read disk sectors with ECC */
6288 BX_DEBUG_INT13_HD("int13_f0a\n");
6289 case 0x0b: /* write disk sectors with ECC */
6290 BX_DEBUG_INT13_HD("int13_f0b\n");
6291 BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
6292 return;
6293 break;
6295 case 0x0c: /* seek to specified cylinder */
6296 BX_DEBUG_INT13_HD("int13_f0c\n");
6297 BX_INFO("int13h function 0ch (seek) not implemented!\n");
6298 SET_AH(0);
6299 SET_DISK_RET_STATUS(0);
6300 CLEAR_CF(); /* successful */
6301 return;
6302 break;
6304 case 0x0d: /* alternate disk reset */
6305 BX_DEBUG_INT13_HD("int13_f0d\n");
6306 SET_AH(0);
6307 SET_DISK_RET_STATUS(0);
6308 CLEAR_CF(); /* successful */
6309 return;
6310 break;
6312 case 0x10: /* check drive ready */
6313 BX_DEBUG_INT13_HD("int13_f10\n");
6314 //SET_AH(0);
6315 //SET_DISK_RET_STATUS(0);
6316 //CLEAR_CF(); /* successful */
6317 //return;
6318 //break;
6320 // should look at 40:8E also???
6321 status = inb(0x01f7);
6322 if ( (status & 0xc0) == 0x40 ) {
6323 SET_AH(0);
6324 SET_DISK_RET_STATUS(0);
6325 CLEAR_CF(); // drive ready
6326 return;
6328 else {
6329 SET_AH(0xAA);
6330 SET_DISK_RET_STATUS(0xAA);
6331 SET_CF(); // not ready
6332 return;
6334 break;
6336 case 0x11: /* recalibrate */
6337 BX_DEBUG_INT13_HD("int13_f11\n");
6338 SET_AH(0);
6339 SET_DISK_RET_STATUS(0);
6340 CLEAR_CF(); /* successful */
6341 return;
6342 break;
6344 case 0x14: /* controller internal diagnostic */
6345 BX_DEBUG_INT13_HD("int13_f14\n");
6346 SET_AH(0);
6347 SET_DISK_RET_STATUS(0);
6348 CLEAR_CF(); /* successful */
6349 SET_AL(0);
6350 return;
6351 break;
6353 case 0x15: /* read disk drive size */
6354 drive = GET_ELDL();
6355 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6356 ASM_START
6357 push bp
6358 mov bp, sp
6359 mov al, _int13_harddisk.hd_heads + 2 [bp]
6360 mov ah, _int13_harddisk.hd_sectors + 2 [bp]
6361 mul al, ah ;; ax = heads * sectors
6362 mov bx, _int13_harddisk.hd_cylinders + 2 [bp]
6363 dec bx ;; use (cylinders - 1) ???
6364 mul ax, bx ;; dx:ax = (cylinders -1) * (heads * sectors)
6365 ;; now we need to move the 32bit result dx:ax to what the
6366 ;; BIOS wants which is cx:dx.
6367 ;; and then into CX:DX on the stack
6368 mov _int13_harddisk.CX + 2 [bp], dx
6369 mov _int13_harddisk.DX + 2 [bp], ax
6370 pop bp
6371 ASM_END
6372 SET_AH(3); // hard disk accessible
6373 SET_DISK_RET_STATUS(0); // ??? should this be 0
6374 CLEAR_CF(); // successful
6375 return;
6376 break;
6378 case 0x18: // set media type for format
6379 case 0x41: // IBM/MS
6380 case 0x42: // IBM/MS
6381 case 0x43: // IBM/MS
6382 case 0x44: // IBM/MS
6383 case 0x45: // IBM/MS lock/unlock drive
6384 case 0x46: // IBM/MS eject media
6385 case 0x47: // IBM/MS extended seek
6386 case 0x49: // IBM/MS extended media change
6387 case 0x50: // IBM/MS send packet command
6388 default:
6389 BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
6391 SET_AH(1); // code=invalid function in AH or invalid parameter
6392 SET_DISK_RET_STATUS(1);
6393 SET_CF(); /* unsuccessful */
6394 return;
6395 break;
6399 static char panic_msg_reg12h[] = "HD%d cmos reg 12h not type F\n";
6400 static char panic_msg_reg19h[] = "HD%d cmos reg %02xh not user definable type 47\n";
6402 void
6403 get_hd_geometry(drive, hd_cylinders, hd_heads, hd_sectors)
6404 Bit8u drive;
6405 Bit16u *hd_cylinders;
6406 Bit8u *hd_heads;
6407 Bit8u *hd_sectors;
6409 Bit8u hd_type;
6410 Bit16u ss;
6411 Bit16u cylinders;
6412 Bit8u iobase;
6414 ss = get_SS();
6415 if (drive == 0x80) {
6416 hd_type = inb_cmos(0x12) & 0xf0;
6417 if (hd_type != 0xf0)
6418 BX_INFO(panic_msg_reg12h,0);
6419 hd_type = inb_cmos(0x19); // HD0: extended type
6420 if (hd_type != 47)
6421 BX_INFO(panic_msg_reg19h,0,0x19);
6422 iobase = 0x1b;
6423 } else {
6424 hd_type = inb_cmos(0x12) & 0x0f;
6425 if (hd_type != 0x0f)
6426 BX_INFO(panic_msg_reg12h,1);
6427 hd_type = inb_cmos(0x1a); // HD0: extended type
6428 if (hd_type != 47)
6429 BX_INFO(panic_msg_reg19h,0,0x1a);
6430 iobase = 0x24;
6433 // cylinders
6434 cylinders = inb_cmos(iobase) | (inb_cmos(iobase+1) << 8);
6435 write_word(ss, hd_cylinders, cylinders);
6437 // heads
6438 write_byte(ss, hd_heads, inb_cmos(iobase+2));
6440 // sectors per track
6441 write_byte(ss, hd_sectors, inb_cmos(iobase+8));
6444 #endif //else BX_USE_ATADRV
6447 //////////////////////
6448 // FLOPPY functions //
6449 //////////////////////
6451 bx_bool
6452 floppy_media_known(drive)
6453 Bit16u drive;
6455 Bit8u val8;
6456 Bit16u media_state_offset;
6458 val8 = read_byte(0x0040, 0x003e); // diskette recal status
6459 if (drive)
6460 val8 >>= 1;
6461 val8 &= 0x01;
6462 if (val8 == 0)
6463 return(0);
6465 media_state_offset = 0x0090;
6466 if (drive)
6467 media_state_offset += 1;
6469 val8 = read_byte(0x0040, media_state_offset);
6470 val8 = (val8 >> 4) & 0x01;
6471 if (val8 == 0)
6472 return(0);
6474 // check pass, return KNOWN
6475 return(1);
6478 bx_bool
6479 floppy_media_sense(drive)
6480 Bit16u drive;
6482 bx_bool retval;
6483 Bit16u media_state_offset;
6484 Bit8u drive_type, config_data, media_state;
6486 if (floppy_drive_recal(drive) == 0) {
6487 return(0);
6490 // for now cheat and get drive type from CMOS,
6491 // assume media is same as drive type
6493 // ** config_data **
6494 // Bitfields for diskette media control:
6495 // Bit(s) Description (Table M0028)
6496 // 7-6 last data rate set by controller
6497 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6498 // 5-4 last diskette drive step rate selected
6499 // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
6500 // 3-2 {data rate at start of operation}
6501 // 1-0 reserved
6503 // ** media_state **
6504 // Bitfields for diskette drive media state:
6505 // Bit(s) Description (Table M0030)
6506 // 7-6 data rate
6507 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6508 // 5 double stepping required (e.g. 360kB in 1.2MB)
6509 // 4 media type established
6510 // 3 drive capable of supporting 4MB media
6511 // 2-0 on exit from BIOS, contains
6512 // 000 trying 360kB in 360kB
6513 // 001 trying 360kB in 1.2MB
6514 // 010 trying 1.2MB in 1.2MB
6515 // 011 360kB in 360kB established
6516 // 100 360kB in 1.2MB established
6517 // 101 1.2MB in 1.2MB established
6518 // 110 reserved
6519 // 111 all other formats/drives
6521 drive_type = inb_cmos(0x10);
6522 if (drive == 0)
6523 drive_type >>= 4;
6524 else
6525 drive_type &= 0x0f;
6526 if ( drive_type == 1 ) {
6527 // 360K 5.25" drive
6528 config_data = 0x00; // 0000 0000
6529 media_state = 0x25; // 0010 0101
6530 retval = 1;
6532 else if ( drive_type == 2 ) {
6533 // 1.2 MB 5.25" drive
6534 config_data = 0x00; // 0000 0000
6535 media_state = 0x25; // 0010 0101 // need double stepping??? (bit 5)
6536 retval = 1;
6538 else if ( drive_type == 3 ) {
6539 // 720K 3.5" drive
6540 config_data = 0x00; // 0000 0000 ???
6541 media_state = 0x17; // 0001 0111
6542 retval = 1;
6544 else if ( drive_type == 4 ) {
6545 // 1.44 MB 3.5" drive
6546 config_data = 0x00; // 0000 0000
6547 media_state = 0x17; // 0001 0111
6548 retval = 1;
6550 else if ( drive_type == 5 ) {
6551 // 2.88 MB 3.5" drive
6552 config_data = 0xCC; // 1100 1100
6553 media_state = 0xD7; // 1101 0111
6554 retval = 1;
6556 //
6557 // Extended floppy size uses special cmos setting
6558 else if ( drive_type == 6 ) {
6559 // 160k 5.25" drive
6560 config_data = 0x00; // 0000 0000
6561 media_state = 0x27; // 0010 0111
6562 retval = 1;
6564 else if ( drive_type == 7 ) {
6565 // 180k 5.25" drive
6566 config_data = 0x00; // 0000 0000
6567 media_state = 0x27; // 0010 0111
6568 retval = 1;
6570 else if ( drive_type == 8 ) {
6571 // 320k 5.25" drive
6572 config_data = 0x00; // 0000 0000
6573 media_state = 0x27; // 0010 0111
6574 retval = 1;
6577 else {
6578 // not recognized
6579 config_data = 0x00; // 0000 0000
6580 media_state = 0x00; // 0000 0000
6581 retval = 0;
6584 if (drive == 0)
6585 media_state_offset = 0x90;
6586 else
6587 media_state_offset = 0x91;
6588 write_byte(0x0040, 0x008B, config_data);
6589 write_byte(0x0040, media_state_offset, media_state);
6591 return(retval);
6594 bx_bool
6595 floppy_drive_recal(drive)
6596 Bit16u drive;
6598 Bit8u val8, dor;
6599 Bit16u curr_cyl_offset;
6601 // set 40:3e bit 7 to 0
6602 val8 = read_byte(0x0000, 0x043e);
6603 val8 &= 0x7f;
6604 write_byte(0x0000, 0x043e, val8);
6606 // turn on motor of selected drive, DMA & int enabled, normal operation
6607 if (drive)
6608 dor = 0x20;
6609 else
6610 dor = 0x10;
6611 dor |= 0x0c;
6612 dor |= drive;
6613 outb(0x03f2, dor);
6615 // reset the disk motor timeout value of INT 08
6616 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
6618 // check port 3f4 for drive readiness
6619 val8 = inb(0x3f4);
6620 if ( (val8 & 0xf0) != 0x80 )
6621 BX_PANIC("floppy recal:f07: ctrl not ready\n");
6623 // send Recalibrate command (2 bytes) to controller
6624 outb(0x03f5, 0x07); // 07: Recalibrate
6625 outb(0x03f5, drive); // 0=drive0, 1=drive1
6627 // turn on interrupts
6628 ASM_START
6629 sti
6630 ASM_END
6632 // wait on 40:3e bit 7 to become 1
6633 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6634 while ( val8 == 0 ) {
6635 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6638 val8 = 0; // separate asm from while() loop
6639 // turn off interrupts
6640 ASM_START
6641 cli
6642 ASM_END
6644 // set 40:3e bit 7 to 0, and calibrated bit
6645 val8 = read_byte(0x0000, 0x043e);
6646 val8 &= 0x7f;
6647 if (drive) {
6648 val8 |= 0x02; // Drive 1 calibrated
6649 curr_cyl_offset = 0x0095;
6651 else {
6652 val8 |= 0x01; // Drive 0 calibrated
6653 curr_cyl_offset = 0x0094;
6655 write_byte(0x0040, 0x003e, val8);
6656 write_byte(0x0040, curr_cyl_offset, 0); // current cylinder is 0
6658 return(1);
6663 bx_bool
6664 floppy_drive_exists(drive)
6665 Bit16u drive;
6667 Bit8u drive_type;
6669 // check CMOS to see if drive exists
6670 drive_type = inb_cmos(0x10);
6671 if (drive == 0)
6672 drive_type >>= 4;
6673 else
6674 drive_type &= 0x0f;
6675 if ( drive_type == 0 )
6676 return(0);
6677 else
6678 return(1);
6681 #if BX_SUPPORT_FLOPPY
6682 void
6683 int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
6684 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
6686 Bit8u drive, num_sectors, track, sector, head, status;
6687 Bit16u base_address, base_count, base_es;
6688 Bit8u page, mode_register, val8, dor;
6689 Bit8u return_status[7];
6690 Bit8u drive_type, num_floppies, ah;
6691 Bit16u es, last_addr;
6693 BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6694 // BX_DEBUG_INT13_FL("int13_diskette: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), get_DS(), ES, DI, SI);
6696 ah = GET_AH();
6698 switch ( ah ) {
6699 case 0x00: // diskette controller reset
6700 BX_DEBUG_INT13_FL("floppy f00\n");
6701 drive = GET_ELDL();
6702 if (drive > 1) {
6703 SET_AH(1); // invalid param
6704 set_diskette_ret_status(1);
6705 SET_CF();
6706 return;
6708 drive_type = inb_cmos(0x10);
6710 if (drive == 0)
6711 drive_type >>= 4;
6712 else
6713 drive_type &= 0x0f;
6714 if (drive_type == 0) {
6715 SET_AH(0x80); // drive not responding
6716 set_diskette_ret_status(0x80);
6717 SET_CF();
6718 return;
6720 SET_AH(0);
6721 set_diskette_ret_status(0);
6722 CLEAR_CF(); // successful
6723 set_diskette_current_cyl(drive, 0); // current cylinder
6724 return;
6726 case 0x01: // Read Diskette Status
6727 CLEAR_CF();
6728 val8 = read_byte(0x0000, 0x0441);
6729 SET_AH(val8);
6730 if (val8) {
6731 SET_CF();
6733 return;
6735 case 0x02: // Read Diskette Sectors
6736 case 0x03: // Write Diskette Sectors
6737 case 0x04: // Verify Diskette Sectors
6738 num_sectors = GET_AL();
6739 track = GET_CH();
6740 sector = GET_CL();
6741 head = GET_DH();
6742 drive = GET_ELDL();
6744 if ( (drive > 1) || (head > 1) ||
6745 (num_sectors == 0) || (num_sectors > 72) ) {
6746 BX_INFO("floppy: drive>1 || head>1 ...\n");
6747 SET_AH(1);
6748 set_diskette_ret_status(1);
6749 SET_AL(0); // no sectors read
6750 SET_CF(); // error occurred
6751 return;
6754 // see if drive exists
6755 if (floppy_drive_exists(drive) == 0) {
6756 SET_AH(0x80); // not responding
6757 set_diskette_ret_status(0x80);
6758 SET_AL(0); // no sectors read
6759 SET_CF(); // error occurred
6760 return;
6763 // see if media in drive, and type is known
6764 if (floppy_media_known(drive) == 0) {
6765 if (floppy_media_sense(drive) == 0) {
6766 SET_AH(0x0C); // Media type not found
6767 set_diskette_ret_status(0x0C);
6768 SET_AL(0); // no sectors read
6769 SET_CF(); // error occurred
6770 return;
6774 if (ah == 0x02) {
6775 // Read Diskette Sectors
6777 //-----------------------------------
6778 // set up DMA controller for transfer
6779 //-----------------------------------
6781 // es:bx = pointer to where to place information from diskette
6782 // port 04: DMA-1 base and current address, channel 2
6783 // port 05: DMA-1 base and current count, channel 2
6784 page = (ES >> 12); // upper 4 bits
6785 base_es = (ES << 4); // lower 16bits contributed by ES
6786 base_address = base_es + BX; // lower 16 bits of address
6787 // contributed by ES:BX
6788 if ( base_address < base_es ) {
6789 // in case of carry, adjust page by 1
6790 page++;
6792 base_count = (num_sectors * 512) - 1;
6794 // check for 64K boundary overrun
6795 last_addr = base_address + base_count;
6796 if (last_addr < base_address) {
6797 SET_AH(0x09);
6798 set_diskette_ret_status(0x09);
6799 SET_AL(0); // no sectors read
6800 SET_CF(); // error occurred
6801 return;
6804 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
6805 outb(0x000a, 0x06);
6807 BX_DEBUG_INT13_FL("clear flip-flop\n");
6808 outb(0x000c, 0x00); // clear flip-flop
6809 outb(0x0004, base_address);
6810 outb(0x0004, base_address>>8);
6811 BX_DEBUG_INT13_FL("clear flip-flop\n");
6812 outb(0x000c, 0x00); // clear flip-flop
6813 outb(0x0005, base_count);
6814 outb(0x0005, base_count>>8);
6816 // port 0b: DMA-1 Mode Register
6817 mode_register = 0x46; // single mode, increment, autoinit disable,
6818 // transfer type=write, channel 2
6819 BX_DEBUG_INT13_FL("setting mode register\n");
6820 outb(0x000b, mode_register);
6822 BX_DEBUG_INT13_FL("setting page register\n");
6823 // port 81: DMA-1 Page Register, channel 2
6824 outb(0x0081, page);
6826 BX_DEBUG_INT13_FL("unmask chan 2\n");
6827 outb(0x000a, 0x02); // unmask channel 2
6829 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
6830 outb(0x000a, 0x02);
6832 //--------------------------------------
6833 // set up floppy controller for transfer
6834 //--------------------------------------
6836 // set 40:3e bit 7 to 0
6837 val8 = read_byte(0x0000, 0x043e);
6838 val8 &= 0x7f;
6839 write_byte(0x0000, 0x043e, val8);
6841 // turn on motor of selected drive, DMA & int enabled, normal operation
6842 if (drive)
6843 dor = 0x20;
6844 else
6845 dor = 0x10;
6846 dor |= 0x0c;
6847 dor |= drive;
6848 outb(0x03f2, dor);
6850 // reset the disk motor timeout value of INT 08
6851 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
6853 // check port 3f4 for drive readiness
6854 val8 = inb(0x3f4);
6855 if ( (val8 & 0xf0) != 0x80 )
6856 BX_PANIC("int13_diskette:f02: ctrl not ready\n");
6858 // send read-normal-data command (9 bytes) to controller
6859 outb(0x03f5, 0xe6); // e6: read normal data
6860 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
6861 outb(0x03f5, track);
6862 outb(0x03f5, head);
6863 outb(0x03f5, sector);
6864 outb(0x03f5, 2); // 512 byte sector size
6865 outb(0x03f5, 0); // last sector number possible on track
6866 outb(0x03f5, 0); // Gap length
6867 outb(0x03f5, 0xff); // Gap length
6869 // turn on interrupts
6870 ASM_START
6871 sti
6872 ASM_END
6874 // wait on 40:3e bit 7 to become 1
6875 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6876 while ( val8 == 0 ) {
6877 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6880 val8 = 0; // separate asm from while() loop
6881 // turn off interrupts
6882 ASM_START
6883 cli
6884 ASM_END
6886 // set 40:3e bit 7 to 0
6887 val8 = read_byte(0x0000, 0x043e);
6888 val8 &= 0x7f;
6889 write_byte(0x0000, 0x043e, val8);
6891 // check port 3f4 for accessibility to status bytes
6892 val8 = inb(0x3f4);
6893 if ( (val8 & 0xc0) != 0xc0 )
6894 BX_PANIC("int13_diskette: ctrl not ready\n");
6896 // read 7 return status bytes from controller
6897 // using loop index broken, have to unroll...
6898 return_status[0] = inb(0x3f5);
6899 return_status[1] = inb(0x3f5);
6900 return_status[2] = inb(0x3f5);
6901 return_status[3] = inb(0x3f5);
6902 return_status[4] = inb(0x3f5);
6903 return_status[5] = inb(0x3f5);
6904 return_status[6] = inb(0x3f5);
6905 // record in BIOS Data Area
6906 write_byte(0x0040, 0x0042, return_status[0]);
6907 write_byte(0x0040, 0x0043, return_status[1]);
6908 write_byte(0x0040, 0x0044, return_status[2]);
6909 write_byte(0x0040, 0x0045, return_status[3]);
6910 write_byte(0x0040, 0x0046, return_status[4]);
6911 write_byte(0x0040, 0x0047, return_status[5]);
6912 write_byte(0x0040, 0x0048, return_status[6]);
6914 if ( (return_status[0] & 0xc0) != 0 ) {
6915 SET_AH(0x20);
6916 set_diskette_ret_status(0x20);
6917 SET_AL(0); // no sectors read
6918 SET_CF(); // error occurred
6919 return;
6922 // ??? should track be new val from return_status[3] ?
6923 set_diskette_current_cyl(drive, track);
6924 // AL = number of sectors read (same value as passed)
6925 SET_AH(0x00); // success
6926 CLEAR_CF(); // success
6927 return;
6929 else if (ah == 0x03) {
6930 // Write Diskette Sectors
6932 //-----------------------------------
6933 // set up DMA controller for transfer
6934 //-----------------------------------
6936 // es:bx = pointer to where to place information from diskette
6937 // port 04: DMA-1 base and current address, channel 2
6938 // port 05: DMA-1 base and current count, channel 2
6939 page = (ES >> 12); // upper 4 bits
6940 base_es = (ES << 4); // lower 16bits contributed by ES
6941 base_address = base_es + BX; // lower 16 bits of address
6942 // contributed by ES:BX
6943 if ( base_address < base_es ) {
6944 // in case of carry, adjust page by 1
6945 page++;
6947 base_count = (num_sectors * 512) - 1;
6949 // check for 64K boundary overrun
6950 last_addr = base_address + base_count;
6951 if (last_addr < base_address) {
6952 SET_AH(0x09);
6953 set_diskette_ret_status(0x09);
6954 SET_AL(0); // no sectors read
6955 SET_CF(); // error occurred
6956 return;
6959 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
6960 outb(0x000a, 0x06);
6962 outb(0x000c, 0x00); // clear flip-flop
6963 outb(0x0004, base_address);
6964 outb(0x0004, base_address>>8);
6965 outb(0x000c, 0x00); // clear flip-flop
6966 outb(0x0005, base_count);
6967 outb(0x0005, base_count>>8);
6969 // port 0b: DMA-1 Mode Register
6970 mode_register = 0x4a; // single mode, increment, autoinit disable,
6971 // transfer type=read, channel 2
6972 outb(0x000b, mode_register);
6974 // port 81: DMA-1 Page Register, channel 2
6975 outb(0x0081, page);
6977 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
6978 outb(0x000a, 0x02);
6980 //--------------------------------------
6981 // set up floppy controller for transfer
6982 //--------------------------------------
6984 // set 40:3e bit 7 to 0
6985 val8 = read_byte(0x0000, 0x043e);
6986 val8 &= 0x7f;
6987 write_byte(0x0000, 0x043e, val8);
6989 // turn on motor of selected drive, DMA & int enabled, normal operation
6990 if (drive)
6991 dor = 0x20;
6992 else
6993 dor = 0x10;
6994 dor |= 0x0c;
6995 dor |= drive;
6996 outb(0x03f2, dor);
6998 // reset the disk motor timeout value of INT 08
6999 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
7001 // check port 3f4 for drive readiness
7002 val8 = inb(0x3f4);
7003 if ( (val8 & 0xf0) != 0x80 )
7004 BX_PANIC("int13_diskette:f03: ctrl not ready\n");
7006 // send read-normal-data command (9 bytes) to controller
7007 outb(0x03f5, 0xc5); // c5: write normal data
7008 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7009 outb(0x03f5, track);
7010 outb(0x03f5, head);
7011 outb(0x03f5, sector);
7012 outb(0x03f5, 2); // 512 byte sector size
7013 outb(0x03f5, 0); // last sector number possible on track
7014 outb(0x03f5, 0); // Gap length
7015 outb(0x03f5, 0xff); // Gap length
7017 // turn on interrupts
7018 ASM_START
7019 sti
7020 ASM_END
7022 // wait on 40:3e bit 7 to become 1
7023 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7024 while ( val8 == 0 ) {
7025 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7028 val8 = 0; // separate asm from while() loop
7029 // turn off interrupts
7030 ASM_START
7031 cli
7032 ASM_END
7034 // set 40:3e bit 7 to 0
7035 val8 = read_byte(0x0000, 0x043e);
7036 val8 &= 0x7f;
7037 write_byte(0x0000, 0x043e, val8);
7039 // check port 3f4 for accessibility to status bytes
7040 val8 = inb(0x3f4);
7041 if ( (val8 & 0xc0) != 0xc0 )
7042 BX_PANIC("int13_diskette: ctrl not ready\n");
7044 // read 7 return status bytes from controller
7045 // using loop index broken, have to unroll...
7046 return_status[0] = inb(0x3f5);
7047 return_status[1] = inb(0x3f5);
7048 return_status[2] = inb(0x3f5);
7049 return_status[3] = inb(0x3f5);
7050 return_status[4] = inb(0x3f5);
7051 return_status[5] = inb(0x3f5);
7052 return_status[6] = inb(0x3f5);
7053 // record in BIOS Data Area
7054 write_byte(0x0040, 0x0042, return_status[0]);
7055 write_byte(0x0040, 0x0043, return_status[1]);
7056 write_byte(0x0040, 0x0044, return_status[2]);
7057 write_byte(0x0040, 0x0045, return_status[3]);
7058 write_byte(0x0040, 0x0046, return_status[4]);
7059 write_byte(0x0040, 0x0047, return_status[5]);
7060 write_byte(0x0040, 0x0048, return_status[6]);
7062 if ( (return_status[0] & 0xc0) != 0 ) {
7063 if ( (return_status[1] & 0x02) != 0 ) {
7064 // diskette not writable.
7065 // AH=status code=0x03 (tried to write on write-protected disk)
7066 // AL=number of sectors written=0
7067 AX = 0x0300;
7068 SET_CF();
7069 return;
7070 } else {
7071 BX_PANIC("int13_diskette_function: read error\n");
7075 // ??? should track be new val from return_status[3] ?
7076 set_diskette_current_cyl(drive, track);
7077 // AL = number of sectors read (same value as passed)
7078 SET_AH(0x00); // success
7079 CLEAR_CF(); // success
7080 return;
7082 else { // if (ah == 0x04)
7083 // Verify Diskette Sectors
7085 // ??? should track be new val from return_status[3] ?
7086 set_diskette_current_cyl(drive, track);
7087 // AL = number of sectors verified (same value as passed)
7088 CLEAR_CF(); // success
7089 SET_AH(0x00); // success
7090 return;
7094 case 0x05: // format diskette track
7095 BX_DEBUG_INT13_FL("floppy f05\n");
7097 num_sectors = GET_AL();
7098 track = GET_CH();
7099 head = GET_DH();
7100 drive = GET_ELDL();
7102 if ((drive > 1) || (head > 1) || (track > 79) ||
7103 (num_sectors == 0) || (num_sectors > 18)) {
7104 SET_AH(1);
7105 set_diskette_ret_status(1);
7106 SET_CF(); // error occurred
7109 // see if drive exists
7110 if (floppy_drive_exists(drive) == 0) {
7111 SET_AH(0x80); // drive not responding
7112 set_diskette_ret_status(0x80);
7113 SET_CF(); // error occurred
7114 return;
7117 // see if media in drive, and type is known
7118 if (floppy_media_known(drive) == 0) {
7119 if (floppy_media_sense(drive) == 0) {
7120 SET_AH(0x0C); // Media type not found
7121 set_diskette_ret_status(0x0C);
7122 SET_AL(0); // no sectors read
7123 SET_CF(); // error occurred
7124 return;
7128 // set up DMA controller for transfer
7129 page = (ES >> 12); // upper 4 bits
7130 base_es = (ES << 4); // lower 16bits contributed by ES
7131 base_address = base_es + BX; // lower 16 bits of address
7132 // contributed by ES:BX
7133 if ( base_address < base_es ) {
7134 // in case of carry, adjust page by 1
7135 page++;
7137 base_count = (num_sectors * 4) - 1;
7139 // check for 64K boundary overrun
7140 last_addr = base_address + base_count;
7141 if (last_addr < base_address) {
7142 SET_AH(0x09);
7143 set_diskette_ret_status(0x09);
7144 SET_AL(0); // no sectors read
7145 SET_CF(); // error occurred
7146 return;
7149 outb(0x000a, 0x06);
7150 outb(0x000c, 0x00); // clear flip-flop
7151 outb(0x0004, base_address);
7152 outb(0x0004, base_address>>8);
7153 outb(0x000c, 0x00); // clear flip-flop
7154 outb(0x0005, base_count);
7155 outb(0x0005, base_count>>8);
7156 mode_register = 0x4a; // single mode, increment, autoinit disable,
7157 // transfer type=read, channel 2
7158 outb(0x000b, mode_register);
7159 // port 81: DMA-1 Page Register, channel 2
7160 outb(0x0081, page);
7161 outb(0x000a, 0x02);
7163 // set up floppy controller for transfer
7164 val8 = read_byte(0x0000, 0x043e);
7165 val8 &= 0x7f;
7166 write_byte(0x0000, 0x043e, val8);
7167 // turn on motor of selected drive, DMA & int enabled, normal operation
7168 if (drive)
7169 dor = 0x20;
7170 else
7171 dor = 0x10;
7172 dor |= 0x0c;
7173 dor |= drive;
7174 outb(0x03f2, dor);
7176 // reset the disk motor timeout value of INT 08
7177 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
7179 // check port 3f4 for drive readiness
7180 val8 = inb(0x3f4);
7181 if ( (val8 & 0xf0) != 0x80 )
7182 BX_PANIC("int13_diskette:f05: ctrl not ready\n");
7184 // send read-normal-data command (6 bytes) to controller
7185 outb(0x03f5, 0x4d); // 4d: format track
7186 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7187 outb(0x03f5, 2); // 512 byte sector size
7188 outb(0x03f5, num_sectors); // number of sectors per track
7189 outb(0x03f5, 0); // Gap length
7190 outb(0x03f5, 0xf6); // Fill byte
7191 // turn on interrupts
7192 ASM_START
7193 sti
7194 ASM_END
7195 // wait on 40:3e bit 7 to become 1
7196 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7197 while ( val8 == 0 ) {
7198 val8 = (read_byte(0x0000, 0x043e) & 0x80);
7200 val8 = 0; // separate asm from while() loop
7201 // turn off interrupts
7202 ASM_START
7203 cli
7204 ASM_END
7205 // set 40:3e bit 7 to 0
7206 val8 = read_byte(0x0000, 0x043e);
7207 val8 &= 0x7f;
7208 write_byte(0x0000, 0x043e, val8);
7209 // check port 3f4 for accessibility to status bytes
7210 val8 = inb(0x3f4);
7211 if ( (val8 & 0xc0) != 0xc0 )
7212 BX_PANIC("int13_diskette: ctrl not ready\n");
7214 // read 7 return status bytes from controller
7215 // using loop index broken, have to unroll...
7216 return_status[0] = inb(0x3f5);
7217 return_status[1] = inb(0x3f5);
7218 return_status[2] = inb(0x3f5);
7219 return_status[3] = inb(0x3f5);
7220 return_status[4] = inb(0x3f5);
7221 return_status[5] = inb(0x3f5);
7222 return_status[6] = inb(0x3f5);
7223 // record in BIOS Data Area
7224 write_byte(0x0040, 0x0042, return_status[0]);
7225 write_byte(0x0040, 0x0043, return_status[1]);
7226 write_byte(0x0040, 0x0044, return_status[2]);
7227 write_byte(0x0040, 0x0045, return_status[3]);
7228 write_byte(0x0040, 0x0046, return_status[4]);
7229 write_byte(0x0040, 0x0047, return_status[5]);
7230 write_byte(0x0040, 0x0048, return_status[6]);
7232 if ( (return_status[0] & 0xc0) != 0 ) {
7233 if ( (return_status[1] & 0x02) != 0 ) {
7234 // diskette not writable.
7235 // AH=status code=0x03 (tried to write on write-protected disk)
7236 // AL=number of sectors written=0
7237 AX = 0x0300;
7238 SET_CF();
7239 return;
7240 } else {
7241 BX_PANIC("int13_diskette_function: write error\n");
7245 SET_AH(0);
7246 set_diskette_ret_status(0);
7247 set_diskette_current_cyl(drive, 0);
7248 CLEAR_CF(); // successful
7249 return;
7252 case 0x08: // read diskette drive parameters
7253 BX_DEBUG_INT13_FL("floppy f08\n");
7254 drive = GET_ELDL();
7256 if (drive > 1) {
7257 AX = 0;
7258 BX = 0;
7259 CX = 0;
7260 DX = 0;
7261 ES = 0;
7262 DI = 0;
7263 SET_DL(num_floppies);
7264 SET_CF();
7265 return;
7268 drive_type = inb_cmos(0x10);
7269 num_floppies = 0;
7270 if (drive_type & 0xf0)
7271 num_floppies++;
7272 if (drive_type & 0x0f)
7273 num_floppies++;
7275 if (drive == 0)
7276 drive_type >>= 4;
7277 else
7278 drive_type &= 0x0f;
7280 SET_BH(0);
7281 SET_BL(drive_type);
7282 SET_AH(0);
7283 SET_AL(0);
7284 SET_DL(num_floppies);
7286 switch (drive_type) {
7287 case 0: // none
7288 CX = 0;
7289 SET_DH(0); // max head #
7290 break;
7292 case 1: // 360KB, 5.25"
7293 CX = 0x2709; // 40 tracks, 9 sectors
7294 SET_DH(1); // max head #
7295 break;
7297 case 2: // 1.2MB, 5.25"
7298 CX = 0x4f0f; // 80 tracks, 15 sectors
7299 SET_DH(1); // max head #
7300 break;
7302 case 3: // 720KB, 3.5"
7303 CX = 0x4f09; // 80 tracks, 9 sectors
7304 SET_DH(1); // max head #
7305 break;
7307 case 4: // 1.44MB, 3.5"
7308 CX = 0x4f12; // 80 tracks, 18 sectors
7309 SET_DH(1); // max head #
7310 break;
7312 case 5: // 2.88MB, 3.5"
7313 CX = 0x4f24; // 80 tracks, 36 sectors
7314 SET_DH(1); // max head #
7315 break;
7317 case 6: // 160k, 5.25"
7318 CX = 0x2708; // 40 tracks, 8 sectors
7319 SET_DH(0); // max head #
7320 break;
7322 case 7: // 180k, 5.25"
7323 CX = 0x2709; // 40 tracks, 9 sectors
7324 SET_DH(0); // max head #
7325 break;
7327 case 8: // 320k, 5.25"
7328 CX = 0x2708; // 40 tracks, 8 sectors
7329 SET_DH(1); // max head #
7330 break;
7332 default: // ?
7333 BX_PANIC("floppy: int13: bad floppy type\n");
7336 /* set es & di to point to 11 byte diskette param table in ROM */
7337 ASM_START
7338 push bp
7339 mov bp, sp
7340 mov ax, #diskette_param_table2
7341 mov _int13_diskette_function.DI+2[bp], ax
7342 mov _int13_diskette_function.ES+2[bp], cs
7343 pop bp
7344 ASM_END
7345 CLEAR_CF(); // success
7346 /* disk status not changed upon success */
7347 return;
7350 case 0x15: // read diskette drive type
7351 BX_DEBUG_INT13_FL("floppy f15\n");
7352 drive = GET_ELDL();
7353 if (drive > 1) {
7354 SET_AH(0); // only 2 drives supported
7355 // set_diskette_ret_status here ???
7356 SET_CF();
7357 return;
7359 drive_type = inb_cmos(0x10);
7361 if (drive == 0)
7362 drive_type >>= 4;
7363 else
7364 drive_type &= 0x0f;
7365 CLEAR_CF(); // successful, not present
7366 if (drive_type==0) {
7367 SET_AH(0); // drive not present
7369 else {
7370 SET_AH(1); // drive present, does not support change line
7373 return;
7375 case 0x16: // get diskette change line status
7376 BX_DEBUG_INT13_FL("floppy f16\n");
7377 drive = GET_ELDL();
7378 if (drive > 1) {
7379 SET_AH(0x01); // invalid drive
7380 set_diskette_ret_status(0x01);
7381 SET_CF();
7382 return;
7385 SET_AH(0x06); // change line not supported
7386 set_diskette_ret_status(0x06);
7387 SET_CF();
7388 return;
7390 case 0x17: // set diskette type for format(old)
7391 BX_DEBUG_INT13_FL("floppy f17\n");
7392 /* not used for 1.44M floppies */
7393 SET_AH(0x01); // not supported
7394 set_diskette_ret_status(1); /* not supported */
7395 SET_CF();
7396 return;
7398 case 0x18: // set diskette type for format(new)
7399 BX_DEBUG_INT13_FL("floppy f18\n");
7400 SET_AH(0x01); // do later
7401 set_diskette_ret_status(1);
7402 SET_CF();
7403 return;
7405 default:
7406 BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
7408 // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
7409 SET_AH(0x01); // ???
7410 set_diskette_ret_status(1);
7411 SET_CF();
7412 return;
7413 // }
7416 #else // #if BX_SUPPORT_FLOPPY
7417 void
7418 int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
7419 Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
7421 Bit8u val8;
7423 switch ( GET_AH() ) {
7425 case 0x01: // Read Diskette Status
7426 CLEAR_CF();
7427 val8 = read_byte(0x0000, 0x0441);
7428 SET_AH(val8);
7429 if (val8) {
7430 SET_CF();
7432 return;
7434 default:
7435 SET_CF();
7436 write_byte(0x0000, 0x0441, 0x01);
7437 SET_AH(0x01);
7440 #endif // #if BX_SUPPORT_FLOPPY
7442 void
7443 set_diskette_ret_status(value)
7444 Bit8u value;
7446 write_byte(0x0040, 0x0041, value);
7449 void
7450 set_diskette_current_cyl(drive, cyl)
7451 Bit8u drive;
7452 Bit8u cyl;
7454 if (drive > 1)
7455 BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
7456 write_byte(0x0040, 0x0094+drive, cyl);
7459 void
7460 determine_floppy_media(drive)
7461 Bit16u drive;
7463 #if 0
7464 Bit8u val8, DOR, ctrl_info;
7466 ctrl_info = read_byte(0x0040, 0x008F);
7467 if (drive==1)
7468 ctrl_info >>= 4;
7469 else
7470 ctrl_info &= 0x0f;
7472 #if 0
7473 if (drive == 0) {
7474 DOR = 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
7476 else {
7477 DOR = 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
7479 #endif
7481 if ( (ctrl_info & 0x04) != 0x04 ) {
7482 // Drive not determined means no drive exists, done.
7483 return;
7486 #if 0
7487 // check Main Status Register for readiness
7488 val8 = inb(0x03f4) & 0x80; // Main Status Register
7489 if (val8 != 0x80)
7490 BX_PANIC("d_f_m: MRQ bit not set\n");
7492 // change line
7494 // existing BDA values
7496 // turn on drive motor
7497 outb(0x03f2, DOR); // Digital Output Register
7498 //
7499 #endif
7500 BX_PANIC("d_f_m: OK so far\n");
7501 #endif
7504 void
7505 int17_function(regs, ds, iret_addr)
7506 pusha_regs_t regs; // regs pushed from PUSHA instruction
7507 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
7508 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
7510 Bit16u addr,timeout;
7511 Bit8u val8;
7513 ASM_START
7514 sti
7515 ASM_END
7517 addr = read_word(0x0040, (regs.u.r16.dx << 1) + 8);
7518 if ((regs.u.r8.ah < 3) && (regs.u.r16.dx < 3) && (addr > 0)) {
7519 timeout = read_byte(0x0040, 0x0078 + regs.u.r16.dx) << 8;
7520 if (regs.u.r8.ah == 0) {
7521 outb(addr, regs.u.r8.al);
7522 val8 = inb(addr+2);
7523 outb(addr+2, val8 | 0x01); // send strobe
7524 ASM_START
7525 nop
7526 ASM_END
7527 outb(addr+2, val8 & ~0x01);
7528 while (((inb(addr+1) & 0x40) == 0x40) && (timeout)) {
7529 timeout--;
7532 if (regs.u.r8.ah == 1) {
7533 val8 = inb(addr+2);
7534 outb(addr+2, val8 & ~0x04); // send init
7535 ASM_START
7536 nop
7537 ASM_END
7538 outb(addr+2, val8 | 0x04);
7540 val8 = inb(addr+1);
7541 regs.u.r8.ah = (val8 ^ 0x48);
7542 if (!timeout) regs.u.r8.ah |= 0x01;
7543 ClearCF(iret_addr.flags);
7544 } else {
7545 SetCF(iret_addr.flags); // Unsupported
7549 // returns bootsegment in ax, drive in bl
7550 Bit32u
7551 int19_function(bseqnr)
7552 Bit8u bseqnr;
7554 Bit16u ebda_seg=read_word(0x0040,0x000E);
7555 Bit16u bootseq;
7556 Bit8u bootdrv;
7557 Bit8u bootcd;
7558 Bit8u bootchk;
7559 Bit16u bootseg;
7560 Bit16u status;
7561 Bit8u lastdrive=0;
7563 // if BX_ELTORITO_BOOT is not defined, old behavior
7564 // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
7565 // in preparation for the intial INT 13h (0=floppy A:, 0x80=C:)
7566 // 0: system boot sequence, first drive C: then A:
7567 // 1: system boot sequence, first drive A: then C:
7568 // else BX_ELTORITO_BOOT is defined
7569 // CMOS regs 0x3D and 0x38 contain the boot sequence:
7570 // CMOS reg 0x3D & 0x0f : 1st boot device
7571 // CMOS reg 0x3D & 0xf0 : 2nd boot device
7572 // CMOS reg 0x38 & 0xf0 : 3rd boot device
7573 // boot device codes:
7574 // 0x00 : not defined
7575 // 0x01 : first floppy
7576 // 0x02 : first harddrive
7577 // 0x03 : first cdrom
7578 // else : boot failure
7580 // Get the boot sequence
7581 #if BX_ELTORITO_BOOT
7582 bootseq=inb_cmos(0x3d);
7583 bootseq|=((inb_cmos(0x38) & 0xf0) << 4);
7585 if (bseqnr==2) bootseq >>= 4;
7586 if (bseqnr==3) bootseq >>= 8;
7587 if (bootseq<0x10) lastdrive = 1;
7588 bootdrv=0x00; bootcd=0;
7589 switch(bootseq & 0x0f) {
7590 case 0x01: bootdrv=0x00; bootcd=0; break;
7591 case 0x02: bootdrv=0x80; bootcd=0; break;
7592 case 0x03: bootdrv=0x00; bootcd=1; break;
7593 default: return 0x00000000;
7595 #else
7596 bootseq=inb_cmos(0x2d);
7598 if (bseqnr==2) {
7599 bootseq ^= 0x20;
7600 lastdrive = 1;
7602 bootdrv=0x00; bootcd=0;
7603 if((bootseq&0x20)==0) bootdrv=0x80;
7604 #endif // BX_ELTORITO_BOOT
7606 #if BX_ELTORITO_BOOT
7607 // We have to boot from cd
7608 if (bootcd != 0) {
7609 status = cdrom_boot();
7611 // If failure
7612 if ( (status & 0x00ff) !=0 ) {
7613 print_cdromboot_failure(status);
7614 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
7615 return 0x00000000;
7618 bootseg = read_word(ebda_seg,&EbdaData->cdemu.load_segment);
7619 bootdrv = (Bit8u)(status>>8);
7622 #endif // BX_ELTORITO_BOOT
7624 // We have to boot from harddisk or floppy
7625 if (bootcd == 0) {
7626 bootseg=0x07c0;
7628 ASM_START
7629 push bp
7630 mov bp, sp
7632 mov ax, #0x0000
7633 mov _int19_function.status + 2[bp], ax
7634 mov dl, _int19_function.bootdrv + 2[bp]
7635 mov ax, _int19_function.bootseg + 2[bp]
7636 mov es, ax ;; segment
7637 mov bx, #0x0000 ;; offset
7638 mov ah, #0x02 ;; function 2, read diskette sector
7639 mov al, #0x01 ;; read 1 sector
7640 mov ch, #0x00 ;; track 0
7641 mov cl, #0x01 ;; sector 1
7642 mov dh, #0x00 ;; head 0
7643 int #0x13 ;; read sector
7644 jnc int19_load_done
7645 mov ax, #0x0001
7646 mov _int19_function.status + 2[bp], ax
7648 int19_load_done:
7649 pop bp
7650 ASM_END
7652 if (status != 0) {
7653 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
7654 return 0x00000000;
7658 // check signature if instructed by cmos reg 0x38, only for floppy
7659 // bootchk = 1 : signature check disabled
7660 // bootchk = 0 : signature check enabled
7661 if (bootdrv != 0) bootchk = 0;
7662 else bootchk = inb_cmos(0x38) & 0x01;
7664 #if BX_ELTORITO_BOOT
7665 // if boot from cd, no signature check
7666 if (bootcd != 0)
7667 bootchk = 1;
7668 #endif // BX_ELTORITO_BOOT
7670 if (bootchk == 0) {
7671 if (read_word(bootseg,0x1fe) != 0xaa55) {
7672 print_boot_failure(bootcd, bootdrv, 0, lastdrive);
7673 return 0x00000000;
7677 #if BX_ELTORITO_BOOT
7678 // Print out the boot string
7679 print_boot_device(bootcd, bootdrv);
7680 #else // BX_ELTORITO_BOOT
7681 print_boot_device(0, bootdrv);
7682 #endif // BX_ELTORITO_BOOT
7684 // return the boot segment
7685 return (((Bit32u)bootdrv) << 16) + bootseg;
7688 void
7689 int1a_function(regs, ds, iret_addr)
7690 pusha_regs_t regs; // regs pushed from PUSHA instruction
7691 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
7692 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
7694 Bit8u val8;
7696 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);
7698 ASM_START
7699 sti
7700 ASM_END
7702 switch (regs.u.r8.ah) {
7703 case 0: // get current clock count
7704 ASM_START
7705 cli
7706 ASM_END
7707 regs.u.r16.cx = BiosData->ticks_high;
7708 regs.u.r16.dx = BiosData->ticks_low;
7709 regs.u.r8.al = BiosData->midnight_flag;
7710 BiosData->midnight_flag = 0; // reset flag
7711 ASM_START
7712 sti
7713 ASM_END
7714 // AH already 0
7715 ClearCF(iret_addr.flags); // OK
7716 break;
7718 case 1: // Set Current Clock Count
7719 ASM_START
7720 cli
7721 ASM_END
7722 BiosData->ticks_high = regs.u.r16.cx;
7723 BiosData->ticks_low = regs.u.r16.dx;
7724 BiosData->midnight_flag = 0; // reset flag
7725 ASM_START
7726 sti
7727 ASM_END
7728 regs.u.r8.ah = 0;
7729 ClearCF(iret_addr.flags); // OK
7730 break;
7733 case 2: // Read CMOS Time
7734 if (rtc_updating()) {
7735 SetCF(iret_addr.flags);
7736 break;
7739 regs.u.r8.dh = inb_cmos(0x00); // Seconds
7740 regs.u.r8.cl = inb_cmos(0x02); // Minutes
7741 regs.u.r8.ch = inb_cmos(0x04); // Hours
7742 regs.u.r8.dl = inb_cmos(0x0b) & 0x01; // Stat Reg B
7743 regs.u.r8.ah = 0;
7744 regs.u.r8.al = regs.u.r8.ch;
7745 ClearCF(iret_addr.flags); // OK
7746 break;
7748 case 3: // Set CMOS Time
7749 // Using a debugger, I notice the following masking/setting
7750 // of bits in Status Register B, by setting Reg B to
7751 // a few values and getting its value after INT 1A was called.
7752 //
7753 // try#1 try#2 try#3
7754 // before 1111 1101 0111 1101 0000 0000
7755 // after 0110 0010 0110 0010 0000 0010
7756 //
7757 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7758 // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
7759 if (rtc_updating()) {
7760 init_rtc();
7761 // fall through as if an update were not in progress
7763 outb_cmos(0x00, regs.u.r8.dh); // Seconds
7764 outb_cmos(0x02, regs.u.r8.cl); // Minutes
7765 outb_cmos(0x04, regs.u.r8.ch); // Hours
7766 // Set Daylight Savings time enabled bit to requested value
7767 val8 = (inb_cmos(0x0b) & 0x60) | 0x02 | (regs.u.r8.dl & 0x01);
7768 // (reg B already selected)
7769 outb_cmos(0x0b, val8);
7770 regs.u.r8.ah = 0;
7771 regs.u.r8.al = val8; // val last written to Reg B
7772 ClearCF(iret_addr.flags); // OK
7773 break;
7775 case 4: // Read CMOS Date
7776 regs.u.r8.ah = 0;
7777 if (rtc_updating()) {
7778 SetCF(iret_addr.flags);
7779 break;
7781 regs.u.r8.cl = inb_cmos(0x09); // Year
7782 regs.u.r8.dh = inb_cmos(0x08); // Month
7783 regs.u.r8.dl = inb_cmos(0x07); // Day of Month
7784 regs.u.r8.ch = inb_cmos(0x32); // Century
7785 regs.u.r8.al = regs.u.r8.ch;
7786 ClearCF(iret_addr.flags); // OK
7787 break;
7789 case 5: // Set CMOS Date
7790 // Using a debugger, I notice the following masking/setting
7791 // of bits in Status Register B, by setting Reg B to
7792 // a few values and getting its value after INT 1A was called.
7793 //
7794 // try#1 try#2 try#3 try#4
7795 // before 1111 1101 0111 1101 0000 0010 0000 0000
7796 // after 0110 1101 0111 1101 0000 0010 0000 0000
7797 //
7798 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7799 // My assumption: RegB = (RegB & 01111111b)
7800 if (rtc_updating()) {
7801 init_rtc();
7802 SetCF(iret_addr.flags);
7803 break;
7805 outb_cmos(0x09, regs.u.r8.cl); // Year
7806 outb_cmos(0x08, regs.u.r8.dh); // Month
7807 outb_cmos(0x07, regs.u.r8.dl); // Day of Month
7808 outb_cmos(0x32, regs.u.r8.ch); // Century
7809 val8 = inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
7810 outb_cmos(0x0b, val8);
7811 regs.u.r8.ah = 0;
7812 regs.u.r8.al = val8; // AL = val last written to Reg B
7813 ClearCF(iret_addr.flags); // OK
7814 break;
7816 case 6: // Set Alarm Time in CMOS
7817 // Using a debugger, I notice the following masking/setting
7818 // of bits in Status Register B, by setting Reg B to
7819 // a few values and getting its value after INT 1A was called.
7820 //
7821 // try#1 try#2 try#3
7822 // before 1101 1111 0101 1111 0000 0000
7823 // after 0110 1111 0111 1111 0010 0000
7824 //
7825 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7826 // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
7827 val8 = inb_cmos(0x0b); // Get Status Reg B
7828 regs.u.r16.ax = 0;
7829 if (val8 & 0x20) {
7830 // Alarm interrupt enabled already
7831 SetCF(iret_addr.flags); // Error: alarm in use
7832 break;
7834 if (rtc_updating()) {
7835 init_rtc();
7836 // fall through as if an update were not in progress
7838 outb_cmos(0x01, regs.u.r8.dh); // Seconds alarm
7839 outb_cmos(0x03, regs.u.r8.cl); // Minutes alarm
7840 outb_cmos(0x05, regs.u.r8.ch); // Hours alarm
7841 outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
7842 // enable Status Reg B alarm bit, clear halt clock bit
7843 outb_cmos(0x0b, (val8 & 0x7f) | 0x20);
7844 ClearCF(iret_addr.flags); // OK
7845 break;
7847 case 7: // Turn off Alarm
7848 // Using a debugger, I notice the following masking/setting
7849 // of bits in Status Register B, by setting Reg B to
7850 // a few values and getting its value after INT 1A was called.
7851 //
7852 // try#1 try#2 try#3 try#4
7853 // before 1111 1101 0111 1101 0010 0000 0010 0010
7854 // after 0100 0101 0101 0101 0000 0000 0000 0010
7855 //
7856 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7857 // My assumption: RegB = (RegB & 01010111b)
7858 val8 = inb_cmos(0x0b); // Get Status Reg B
7859 // clear clock-halt bit, disable alarm bit
7860 outb_cmos(0x0b, val8 & 0x57); // disable alarm bit
7861 regs.u.r8.ah = 0;
7862 regs.u.r8.al = val8; // val last written to Reg B
7863 ClearCF(iret_addr.flags); // OK
7864 break;
7865 #if BX_PCIBIOS
7866 case 0xb1:
7867 // real mode PCI BIOS functions now handled in assembler code
7868 // this C code handles the error code for information only
7869 if (regs.u.r8.bl == 0xff) {
7870 BX_INFO("PCI BIOS: PCI not present\n");
7871 } else if (regs.u.r8.bl == 0x81) {
7872 BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs.u.r8.al);
7873 } else if (regs.u.r8.bl == 0x83) {
7874 BX_INFO("bad PCI vendor ID %04x\n", regs.u.r16.dx);
7875 } else if (regs.u.r8.bl == 0x86) {
7876 BX_INFO("PCI device %04x:%04x not found\n", regs.u.r16.dx, regs.u.r16.cx);
7878 regs.u.r8.ah = regs.u.r8.bl;
7879 SetCF(iret_addr.flags);
7880 break;
7881 #endif
7883 default:
7884 SetCF(iret_addr.flags); // Unsupported
7888 void
7889 int70_function(regs, ds, iret_addr)
7890 pusha_regs_t regs; // regs pushed from PUSHA instruction
7891 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
7892 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
7894 // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
7895 Bit8u registerB = 0, registerC = 0;
7897 // Check which modes are enabled and have occurred.
7898 registerB = inb_cmos( 0xB );
7899 registerC = inb_cmos( 0xC );
7901 if( ( registerB & 0x60 ) != 0 ) {
7902 if( ( registerC & 0x20 ) != 0 ) {
7903 // Handle Alarm Interrupt.
7904 ASM_START
7905 sti
7906 int #0x4a
7907 cli
7908 ASM_END
7910 if( ( registerC & 0x40 ) != 0 ) {
7911 // Handle Periodic Interrupt.
7913 if( read_byte( 0x40, 0xA0 ) != 0 ) {
7914 // Wait Interval (Int 15, AH=83) active.
7915 Bit32u time, toggle;
7917 time = read_dword( 0x40, 0x9C ); // Time left in microseconds.
7918 if( time < 0x3D1 ) {
7919 // Done waiting.
7920 Bit16u segment, offset;
7922 offset = read_word( 0x40, 0x98 );
7923 segment = read_word( 0x40, 0x9A );
7924 write_byte( 0x40, 0xA0, 0 ); // Turn of status byte.
7925 outb_cmos( 0xB, registerB & 0x37 ); // Clear the Periodic Interrupt.
7926 write_byte( segment, offset, 0x80 ); // Write to specified flag byte.
7927 } else {
7928 // Continue waiting.
7929 time -= 0x3D1;
7930 write_dword( 0x40, 0x9C, time );
7936 ASM_START
7937 call eoi_both_pics
7938 ASM_END
7942 ASM_START
7943 ;------------------------------------------
7944 ;- INT74h : PS/2 mouse hardware interrupt -
7945 ;------------------------------------------
7946 int74_handler:
7947 sti
7948 pusha
7949 push ds ;; save DS
7950 push #0x00 ;; placeholder for status
7951 push #0x00 ;; placeholder for X
7952 push #0x00 ;; placeholder for Y
7953 push #0x00 ;; placeholder for Z
7954 push #0x00 ;; placeholder for make_far_call boolean
7955 call _int74_function
7956 pop cx ;; remove make_far_call from stack
7957 jcxz int74_done
7959 ;; make far call to EBDA:0022
7960 push #0x00
7961 pop ds
7962 push 0x040E ;; push 0000:040E (opcodes 0xff, 0x36, 0x0E, 0x04)
7963 pop ds
7964 //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
7965 call far ptr[0x22]
7966 int74_done:
7967 cli
7968 call eoi_both_pics
7969 add sp, #8 ;; pop status, x, y, z
7971 pop ds ;; restore DS
7972 popa
7973 iret
7976 ;; This will perform an IRET, but will retain value of current CF
7977 ;; by altering flags on stack. Better than RETF #02.
7978 iret_modify_cf:
7979 jc carry_set
7980 push bp
7981 mov bp, sp
7982 and BYTE [bp + 0x06], #0xfe
7983 pop bp
7984 iret
7985 carry_set:
7986 push bp
7987 mov bp, sp
7988 or BYTE [bp + 0x06], #0x01
7989 pop bp
7990 iret
7993 ;----------------------
7994 ;- INT13h (relocated) -
7995 ;----------------------
7997 ; int13_relocated is a little bit messed up since I played with it
7998 ; I have to rewrite it:
7999 ; - call a function that detect which function to call
8000 ; - make all called C function get the same parameters list
8002 int13_relocated:
8004 #if BX_ELTORITO_BOOT
8005 ;; check for an eltorito function
8006 cmp ah,#0x4a
8007 jb int13_not_eltorito
8008 cmp ah,#0x4d
8009 ja int13_not_eltorito
8011 pusha
8012 push es
8013 push ds
8014 push ss
8015 pop ds
8017 push #int13_out
8018 jmp _int13_eltorito ;; ELDX not used
8020 int13_not_eltorito:
8021 push ax
8022 push bx
8023 push cx
8024 push dx
8026 ;; check if emulation active
8027 call _cdemu_isactive
8028 cmp al,#0x00
8029 je int13_cdemu_inactive
8031 ;; check if access to the emulated drive
8032 call _cdemu_emulated_drive
8033 pop dx
8034 push dx
8035 cmp al,dl ;; int13 on emulated drive
8036 jne int13_nocdemu
8038 pop dx
8039 pop cx
8040 pop bx
8041 pop ax
8043 pusha
8044 push es
8045 push ds
8046 push ss
8047 pop ds
8049 push #int13_out
8050 jmp _int13_cdemu ;; ELDX not used
8052 int13_nocdemu:
8053 and dl,#0xE0 ;; mask to get device class, including cdroms
8054 cmp al,dl ;; al is 0x00 or 0x80
8055 jne int13_cdemu_inactive ;; inactive for device class
8057 pop dx
8058 pop cx
8059 pop bx
8060 pop ax
8062 push ax
8063 push cx
8064 push dx
8065 push bx
8067 dec dl ;; real drive is dl - 1
8068 jmp int13_legacy
8070 int13_cdemu_inactive:
8071 pop dx
8072 pop cx
8073 pop bx
8074 pop ax
8076 #endif // BX_ELTORITO_BOOT
8078 int13_noeltorito:
8080 push ax
8081 push cx
8082 push dx
8083 push bx
8085 int13_legacy:
8087 push dx ;; push eltorito value of dx instead of sp
8089 push bp
8090 push si
8091 push di
8093 push es
8094 push ds
8095 push ss
8096 pop ds
8098 ;; now the 16-bit registers can be restored with:
8099 ;; pop ds; pop es; popa; iret
8100 ;; arguments passed to functions should be
8101 ;; DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS
8103 test dl, #0x80
8104 jnz int13_notfloppy
8106 push #int13_out
8107 jmp _int13_diskette_function
8109 int13_notfloppy:
8111 #if BX_USE_ATADRV
8113 cmp dl, #0xE0
8114 jb int13_notcdrom
8116 // ebx is modified: BSD 5.2.1 boot loader problem
8117 // someone should figure out which 32 bit register that actually are used
8119 shr ebx, #16
8120 push bx
8122 call _int13_cdrom
8124 pop bx
8125 shl ebx, #16
8127 jmp int13_out
8129 int13_notcdrom:
8131 #endif
8133 int13_disk:
8134 call _int13_harddisk
8136 int13_out:
8137 pop ds
8138 pop es
8139 popa
8140 iret
8143 ;----------
8144 ;- INT18h -
8145 ;----------
8146 int18_handler: ;; Boot Failure routing
8147 call _int18_panic_msg
8148 hlt
8149 iret
8151 ;----------
8152 ;- INT19h -
8153 ;----------
8154 int19_relocated: ;; Boot function, relocated
8156 ;; int19 was beginning to be really complex, so now it
8157 ;; just calls an C function, that does the work
8158 ;; it returns in BL the boot drive, and in AX the boot segment
8159 ;; the boot segment will be 0x0000 if something has failed
8161 push bp
8162 mov bp, sp
8164 ;; drop ds
8165 xor ax, ax
8166 mov ds, ax
8168 ;; 1st boot device
8169 mov ax, #0x0001
8170 push ax
8171 call _int19_function
8172 inc sp
8173 inc sp
8174 ;; bl contains the boot drive
8175 ;; ax contains the boot segment or 0 if failure
8177 test ax, ax ;; if ax is 0 try next boot device
8178 jnz boot_setup
8180 ;; 2nd boot device
8181 mov ax, #0x0002
8182 push ax
8183 call _int19_function
8184 inc sp
8185 inc sp
8186 test ax, ax ;; if ax is 0 try next boot device
8187 jnz boot_setup
8189 ;; 3rd boot device
8190 mov ax, #0x0003
8191 push ax
8192 call _int19_function
8193 inc sp
8194 inc sp
8195 test ax, ax ;; if ax is 0 call int18
8196 jz int18_handler
8198 boot_setup:
8199 mov dl, bl ;; set drive so guest os find it
8200 shl eax, #0x04 ;; convert seg to ip
8201 mov 2[bp], ax ;; set ip
8203 shr eax, #0x04 ;; get cs back
8204 and ax, #0xF000 ;; remove what went in ip
8205 mov 4[bp], ax ;; set cs
8206 xor ax, ax
8207 mov es, ax ;; set es to zero fixes [ 549815 ]
8208 mov [bp], ax ;; set bp to zero
8209 mov ax, #0xaa55 ;; set ok flag
8211 pop bp
8212 iret ;; Beam me up Scotty
8214 ;----------
8215 ;- INT1Ch -
8216 ;----------
8217 int1c_handler: ;; User Timer Tick
8218 iret
8221 ;----------------------
8222 ;- POST: Floppy Drive -
8223 ;----------------------
8224 floppy_drive_post:
8225 mov ax, #0x0000
8226 mov ds, ax
8228 mov al, #0x00
8229 mov 0x043e, al ;; drive 0 & 1 uncalibrated, no interrupt has occurred
8231 mov 0x043f, al ;; diskette motor status: read op, drive0, motors off
8233 mov 0x0440, al ;; diskette motor timeout counter: not active
8234 mov 0x0441, al ;; diskette controller status return code
8236 mov 0x0442, al ;; disk & diskette controller status register 0
8237 mov 0x0443, al ;; diskette controller status register 1
8238 mov 0x0444, al ;; diskette controller status register 2
8239 mov 0x0445, al ;; diskette controller cylinder number
8240 mov 0x0446, al ;; diskette controller head number
8241 mov 0x0447, al ;; diskette controller sector number
8242 mov 0x0448, al ;; diskette controller bytes written
8244 mov 0x048b, al ;; diskette configuration data
8246 ;; -----------------------------------------------------------------
8247 ;; (048F) diskette controller information
8248 ;;
8249 mov al, #0x10 ;; get CMOS diskette drive type
8250 out 0x70, AL
8251 in AL, 0x71
8252 mov ah, al ;; save byte to AH
8254 look_drive0:
8255 shr al, #4 ;; look at top 4 bits for drive 0
8256 jz f0_missing ;; jump if no drive0
8257 mov bl, #0x07 ;; drive0 determined, multi-rate, has changed line
8258 jmp look_drive1
8259 f0_missing:
8260 mov bl, #0x00 ;; no drive0
8262 look_drive1:
8263 mov al, ah ;; restore from AH
8264 and al, #0x0f ;; look at bottom 4 bits for drive 1
8265 jz f1_missing ;; jump if no drive1
8266 or bl, #0x70 ;; drive1 determined, multi-rate, has changed line
8267 f1_missing:
8268 ;; leave high bits in BL zerod
8269 mov 0x048f, bl ;; put new val in BDA (diskette controller information)
8270 ;; -----------------------------------------------------------------
8272 mov al, #0x00
8273 mov 0x0490, al ;; diskette 0 media state
8274 mov 0x0491, al ;; diskette 1 media state
8276 ;; diskette 0,1 operational starting state
8277 ;; drive type has not been determined,
8278 ;; has no changed detection line
8279 mov 0x0492, al
8280 mov 0x0493, al
8282 mov 0x0494, al ;; diskette 0 current cylinder
8283 mov 0x0495, al ;; diskette 1 current cylinder
8285 mov al, #0x02
8286 out #0x0a, al ;; clear DMA-1 channel 2 mask bit
8288 SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
8289 SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
8290 SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
8292 ret
8295 ;--------------------
8296 ;- POST: HARD DRIVE -
8297 ;--------------------
8298 ; relocated here because the primary POST area isnt big enough.
8299 hard_drive_post:
8300 // IRQ 14 = INT 76h
8301 // INT 76h calls INT 15h function ax=9100
8303 mov al, #0x0a ; 0000 1010 = reserved, disable IRQ 14
8304 mov dx, #0x03f6
8305 out dx, al
8307 mov ax, #0x0000
8308 mov ds, ax
8309 mov 0x0474, al /* hard disk status of last operation */
8310 mov 0x0477, al /* hard disk port offset (XT only ???) */
8311 mov 0x048c, al /* hard disk status register */
8312 mov 0x048d, al /* hard disk error register */
8313 mov 0x048e, al /* hard disk task complete flag */
8314 mov al, #0x01
8315 mov 0x0475, al /* hard disk number attached */
8316 mov al, #0xc0
8317 mov 0x0476, al /* hard disk control byte */
8318 SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
8319 SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
8320 ;; INT 41h: hard disk 0 configuration pointer
8321 ;; INT 46h: hard disk 1 configuration pointer
8322 SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D)
8323 SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D)
8325 ;; move disk geometry data from CMOS to EBDA disk parameter table(s)
8326 mov al, #0x12
8327 out #0x70, al
8328 in al, #0x71
8329 and al, #0xf0
8330 cmp al, #0xf0
8331 je post_d0_extended
8332 jmp check_for_hd1
8333 post_d0_extended:
8334 mov al, #0x19
8335 out #0x70, al
8336 in al, #0x71
8337 cmp al, #47 ;; decimal 47 - user definable
8338 je post_d0_type47
8339 HALT(__LINE__)
8340 post_d0_type47:
8341 ;; CMOS purpose param table offset
8342 ;; 1b cylinders low 0
8343 ;; 1c cylinders high 1
8344 ;; 1d heads 2
8345 ;; 1e write pre-comp low 5
8346 ;; 1f write pre-comp high 6
8347 ;; 20 retries/bad map/heads>8 8
8348 ;; 21 landing zone low C
8349 ;; 22 landing zone high D
8350 ;; 23 sectors/track E
8352 mov ax, #EBDA_SEG
8353 mov ds, ax
8355 ;;; Filling EBDA table for hard disk 0.
8356 mov al, #0x1f
8357 out #0x70, al
8358 in al, #0x71
8359 mov ah, al
8360 mov al, #0x1e
8361 out #0x70, al
8362 in al, #0x71
8363 mov (0x003d + 0x05), ax ;; write precomp word
8365 mov al, #0x20
8366 out #0x70, al
8367 in al, #0x71
8368 mov (0x003d + 0x08), al ;; drive control byte
8370 mov al, #0x22
8371 out #0x70, al
8372 in al, #0x71
8373 mov ah, al
8374 mov al, #0x21
8375 out #0x70, al
8376 in al, #0x71
8377 mov (0x003d + 0x0C), ax ;; landing zone word
8379 mov al, #0x1c ;; get cylinders word in AX
8380 out #0x70, al
8381 in al, #0x71 ;; high byte
8382 mov ah, al
8383 mov al, #0x1b
8384 out #0x70, al
8385 in al, #0x71 ;; low byte
8386 mov bx, ax ;; BX = cylinders
8388 mov al, #0x1d
8389 out #0x70, al
8390 in al, #0x71
8391 mov cl, al ;; CL = heads
8393 mov al, #0x23
8394 out #0x70, al
8395 in al, #0x71
8396 mov dl, al ;; DL = sectors
8398 cmp bx, #1024
8399 jnbe hd0_post_logical_chs ;; if cylinders > 1024, use translated style CHS
8401 hd0_post_physical_chs:
8402 ;; no logical CHS mapping used, just physical CHS
8403 ;; use Standard Fixed Disk Parameter Table (FDPT)
8404 mov (0x003d + 0x00), bx ;; number of physical cylinders
8405 mov (0x003d + 0x02), cl ;; number of physical heads
8406 mov (0x003d + 0x0E), dl ;; number of physical sectors
8407 jmp check_for_hd1
8409 hd0_post_logical_chs:
8410 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
8411 mov (0x003d + 0x09), bx ;; number of physical cylinders
8412 mov (0x003d + 0x0b), cl ;; number of physical heads
8413 mov (0x003d + 0x04), dl ;; number of physical sectors
8414 mov (0x003d + 0x0e), dl ;; number of logical sectors (same)
8415 mov al, #0xa0
8416 mov (0x003d + 0x03), al ;; A0h signature, indicates translated table
8418 cmp bx, #2048
8419 jnbe hd0_post_above_2048
8420 ;; 1024 < c <= 2048 cylinders
8421 shr bx, #0x01
8422 shl cl, #0x01
8423 jmp hd0_post_store_logical
8425 hd0_post_above_2048:
8426 cmp bx, #4096
8427 jnbe hd0_post_above_4096
8428 ;; 2048 < c <= 4096 cylinders
8429 shr bx, #0x02
8430 shl cl, #0x02
8431 jmp hd0_post_store_logical
8433 hd0_post_above_4096:
8434 cmp bx, #8192
8435 jnbe hd0_post_above_8192
8436 ;; 4096 < c <= 8192 cylinders
8437 shr bx, #0x03
8438 shl cl, #0x03
8439 jmp hd0_post_store_logical
8441 hd0_post_above_8192:
8442 ;; 8192 < c <= 16384 cylinders
8443 shr bx, #0x04
8444 shl cl, #0x04
8446 hd0_post_store_logical:
8447 mov (0x003d + 0x00), bx ;; number of physical cylinders
8448 mov (0x003d + 0x02), cl ;; number of physical heads
8449 ;; checksum
8450 mov cl, #0x0f ;; repeat count
8451 mov si, #0x003d ;; offset to disk0 FDPT
8452 mov al, #0x00 ;; sum
8453 hd0_post_checksum_loop:
8454 add al, [si]
8455 inc si
8456 dec cl
8457 jnz hd0_post_checksum_loop
8458 not al ;; now take 2s complement
8459 inc al
8460 mov [si], al
8461 ;;; Done filling EBDA table for hard disk 0.
8464 check_for_hd1:
8465 ;; is there really a second hard disk? if not, return now
8466 mov al, #0x12
8467 out #0x70, al
8468 in al, #0x71
8469 and al, #0x0f
8470 jnz post_d1_exists
8471 ret
8472 post_d1_exists:
8473 ;; check that the hd type is really 0x0f.
8474 cmp al, #0x0f
8475 jz post_d1_extended
8476 HALT(__LINE__)
8477 post_d1_extended:
8478 ;; check that the extended type is 47 - user definable
8479 mov al, #0x1a
8480 out #0x70, al
8481 in al, #0x71
8482 cmp al, #47 ;; decimal 47 - user definable
8483 je post_d1_type47
8484 HALT(__LINE__)
8485 post_d1_type47:
8486 ;; Table for disk1.
8487 ;; CMOS purpose param table offset
8488 ;; 0x24 cylinders low 0
8489 ;; 0x25 cylinders high 1
8490 ;; 0x26 heads 2
8491 ;; 0x27 write pre-comp low 5
8492 ;; 0x28 write pre-comp high 6
8493 ;; 0x29 heads>8 8
8494 ;; 0x2a landing zone low C
8495 ;; 0x2b landing zone high D
8496 ;; 0x2c sectors/track E
8497 ;;; Fill EBDA table for hard disk 1.
8498 mov ax, #EBDA_SEG
8499 mov ds, ax
8500 mov al, #0x28
8501 out #0x70, al
8502 in al, #0x71
8503 mov ah, al
8504 mov al, #0x27
8505 out #0x70, al
8506 in al, #0x71
8507 mov (0x004d + 0x05), ax ;; write precomp word
8509 mov al, #0x29
8510 out #0x70, al
8511 in al, #0x71
8512 mov (0x004d + 0x08), al ;; drive control byte
8514 mov al, #0x2b
8515 out #0x70, al
8516 in al, #0x71
8517 mov ah, al
8518 mov al, #0x2a
8519 out #0x70, al
8520 in al, #0x71
8521 mov (0x004d + 0x0C), ax ;; landing zone word
8523 mov al, #0x25 ;; get cylinders word in AX
8524 out #0x70, al
8525 in al, #0x71 ;; high byte
8526 mov ah, al
8527 mov al, #0x24
8528 out #0x70, al
8529 in al, #0x71 ;; low byte
8530 mov bx, ax ;; BX = cylinders
8532 mov al, #0x26
8533 out #0x70, al
8534 in al, #0x71
8535 mov cl, al ;; CL = heads
8537 mov al, #0x2c
8538 out #0x70, al
8539 in al, #0x71
8540 mov dl, al ;; DL = sectors
8542 cmp bx, #1024
8543 jnbe hd1_post_logical_chs ;; if cylinders > 1024, use translated style CHS
8545 hd1_post_physical_chs:
8546 ;; no logical CHS mapping used, just physical CHS
8547 ;; use Standard Fixed Disk Parameter Table (FDPT)
8548 mov (0x004d + 0x00), bx ;; number of physical cylinders
8549 mov (0x004d + 0x02), cl ;; number of physical heads
8550 mov (0x004d + 0x0E), dl ;; number of physical sectors
8551 ret
8553 hd1_post_logical_chs:
8554 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
8555 mov (0x004d + 0x09), bx ;; number of physical cylinders
8556 mov (0x004d + 0x0b), cl ;; number of physical heads
8557 mov (0x004d + 0x04), dl ;; number of physical sectors
8558 mov (0x004d + 0x0e), dl ;; number of logical sectors (same)
8559 mov al, #0xa0
8560 mov (0x004d + 0x03), al ;; A0h signature, indicates translated table
8562 cmp bx, #2048
8563 jnbe hd1_post_above_2048
8564 ;; 1024 < c <= 2048 cylinders
8565 shr bx, #0x01
8566 shl cl, #0x01
8567 jmp hd1_post_store_logical
8569 hd1_post_above_2048:
8570 cmp bx, #4096
8571 jnbe hd1_post_above_4096
8572 ;; 2048 < c <= 4096 cylinders
8573 shr bx, #0x02
8574 shl cl, #0x02
8575 jmp hd1_post_store_logical
8577 hd1_post_above_4096:
8578 cmp bx, #8192
8579 jnbe hd1_post_above_8192
8580 ;; 4096 < c <= 8192 cylinders
8581 shr bx, #0x03
8582 shl cl, #0x03
8583 jmp hd1_post_store_logical
8585 hd1_post_above_8192:
8586 ;; 8192 < c <= 16384 cylinders
8587 shr bx, #0x04
8588 shl cl, #0x04
8590 hd1_post_store_logical:
8591 mov (0x004d + 0x00), bx ;; number of physical cylinders
8592 mov (0x004d + 0x02), cl ;; number of physical heads
8593 ;; checksum
8594 mov cl, #0x0f ;; repeat count
8595 mov si, #0x004d ;; offset to disk0 FDPT
8596 mov al, #0x00 ;; sum
8597 hd1_post_checksum_loop:
8598 add al, [si]
8599 inc si
8600 dec cl
8601 jnz hd1_post_checksum_loop
8602 not al ;; now take 2s complement
8603 inc al
8604 mov [si], al
8605 ;;; Done filling EBDA table for hard disk 1.
8607 ret
8609 ;--------------------
8610 ;- POST: EBDA segment
8611 ;--------------------
8612 ; relocated here because the primary POST area isnt big enough.
8613 ebda_post:
8614 #if BX_USE_EBDA
8615 mov ax, #EBDA_SEG
8616 mov ds, ax
8617 mov byte ptr [0x0], #EBDA_SIZE
8618 #endif
8619 xor ax, ax ; mov EBDA seg into 40E
8620 mov ds, ax
8621 mov word ptr [0x40E], #EBDA_SEG
8622 ret;;
8624 ;--------------------
8625 ;- POST: EOI + jmp via [0x40:67)
8626 ;--------------------
8627 ; relocated here because the primary POST area isnt big enough.
8628 eoi_jmp_post:
8629 call eoi_both_pics
8631 xor ax, ax
8632 mov ds, ax
8634 jmp far ptr [0x467]
8637 ;--------------------
8638 eoi_both_pics:
8639 mov al, #0x20
8640 out #0xA0, al ;; slave PIC EOI
8641 eoi_master_pic:
8642 mov al, #0x20
8643 out #0x20, al ;; master PIC EOI
8644 ret
8646 ;--------------------
8647 BcdToBin:
8648 ;; in: AL in BCD format
8649 ;; out: AL in binary format, AH will always be 0
8650 ;; trashes BX
8651 mov bl, al
8652 and bl, #0x0f ;; bl has low digit
8653 shr al, #4 ;; al has high digit
8654 mov bh, #10
8655 mul al, bh ;; multiply high digit by 10 (result in AX)
8656 add al, bl ;; then add low digit
8657 ret
8659 ;--------------------
8660 timer_tick_post:
8661 ;; Setup the Timer Ticks Count (0x46C:dword) and
8662 ;; Timer Ticks Roller Flag (0x470:byte)
8663 ;; The Timer Ticks Count needs to be set according to
8664 ;; the current CMOS time, as if ticks have been occurring
8665 ;; at 18.2hz since midnight up to this point. Calculating
8666 ;; this is a little complicated. Here are the factors I gather
8667 ;; regarding this. 14,318,180 hz was the original clock speed,
8668 ;; chosen so it could be divided by either 3 to drive the 5Mhz CPU
8669 ;; at the time, or 4 to drive the CGA video adapter. The div3
8670 ;; source was divided again by 4 to feed a 1.193Mhz signal to
8671 ;; the timer. With a maximum 16bit timer count, this is again
8672 ;; divided down by 65536 to 18.2hz.
8673 ;;
8674 ;; 14,318,180 Hz clock
8675 ;; /3 = 4,772,726 Hz fed to orginal 5Mhz CPU
8676 ;; /4 = 1,193,181 Hz fed to timer
8677 ;; /65536 (maximum timer count) = 18.20650736 ticks/second
8678 ;; 1 second = 18.20650736 ticks
8679 ;; 1 minute = 1092.390442 ticks
8680 ;; 1 hour = 65543.42651 ticks
8681 ;;
8682 ;; Given the values in the CMOS clock, one could calculate
8683 ;; the number of ticks by the following:
8684 ;; ticks = (BcdToBin(seconds) * 18.206507) +
8685 ;; (BcdToBin(minutes) * 1092.3904)
8686 ;; (BcdToBin(hours) * 65543.427)
8687 ;; To get a little more accuracy, since Im using integer
8688 ;; arithmatic, I use:
8689 ;; ticks = (BcdToBin(seconds) * 18206507) / 1000000 +
8690 ;; (BcdToBin(minutes) * 10923904) / 10000 +
8691 ;; (BcdToBin(hours) * 65543427) / 1000
8693 ;; assuming DS=0000
8695 ;; get CMOS seconds
8696 xor eax, eax ;; clear EAX
8697 mov al, #0x00
8698 out #0x70, al
8699 in al, #0x71 ;; AL has CMOS seconds in BCD
8700 call BcdToBin ;; EAX now has seconds in binary
8701 mov edx, #18206507
8702 mul eax, edx
8703 mov ebx, #1000000
8704 xor edx, edx
8705 div eax, ebx
8706 mov ecx, eax ;; ECX will accumulate total ticks
8708 ;; get CMOS minutes
8709 xor eax, eax ;; clear EAX
8710 mov al, #0x02
8711 out #0x70, al
8712 in al, #0x71 ;; AL has CMOS minutes in BCD
8713 call BcdToBin ;; EAX now has minutes in binary
8714 mov edx, #10923904
8715 mul eax, edx
8716 mov ebx, #10000
8717 xor edx, edx
8718 div eax, ebx
8719 add ecx, eax ;; add to total ticks
8721 ;; get CMOS hours
8722 xor eax, eax ;; clear EAX
8723 mov al, #0x04
8724 out #0x70, al
8725 in al, #0x71 ;; AL has CMOS hours in BCD
8726 call BcdToBin ;; EAX now has hours in binary
8727 mov edx, #65543427
8728 mul eax, edx
8729 mov ebx, #1000
8730 xor edx, edx
8731 div eax, ebx
8732 add ecx, eax ;; add to total ticks
8734 mov 0x46C, ecx ;; Timer Ticks Count
8735 xor al, al
8736 mov 0x470, al ;; Timer Ticks Rollover Flag
8737 ret
8739 ;--------------------
8740 int76_handler:
8741 ;; record completion in BIOS task complete flag
8742 push ax
8743 push ds
8744 mov ax, #0x0040
8745 mov ds, ax
8746 mov 0x008E, #0xff
8747 call eoi_both_pics
8748 pop ds
8749 pop ax
8750 iret
8753 ;--------------------
8754 #if BX_APM
8756 use32 386
8757 #define APM_PROT32
8758 #include "apmbios.S"
8760 use16 386
8761 #define APM_PROT16
8762 #include "apmbios.S"
8764 #define APM_REAL
8765 #include "apmbios.S"
8767 #endif
8769 ;--------------------
8770 #if BX_PCIBIOS
8771 use32 386
8772 .align 16
8773 bios32_structure:
8774 db 0x5f, 0x33, 0x32, 0x5f ;; "_32_" signature
8775 dw bios32_entry_point, 0xf ;; 32 bit physical address
8776 db 0 ;; revision level
8777 ;; length in paragraphs and checksum stored in a word to prevent errors
8778 dw (~(((bios32_entry_point >> 8) + (bios32_entry_point & 0xff) + 0x32) \
8779 & 0xff) << 8) + 0x01
8780 db 0,0,0,0,0 ;; reserved
8782 .align 16
8783 bios32_entry_point:
8784 pushf
8785 cmp eax, #0x49435024
8786 jne unknown_service
8787 mov eax, #0x80000000
8788 mov dx, #0x0cf8
8789 out dx, eax
8790 mov dx, #0x0cfc
8791 in eax, dx
8792 cmp eax, #0x12378086
8793 jne unknown_service
8794 mov ebx, #0x000f0000
8795 mov ecx, #0
8796 mov edx, #pcibios_protected
8797 xor al, al
8798 jmp bios32_end
8799 unknown_service:
8800 mov al, #0x80
8801 bios32_end:
8802 popf
8803 retf
8805 .align 16
8806 pcibios_protected:
8807 pushf
8808 cli
8809 push esi
8810 push edi
8811 cmp al, #0x01 ;; installation check
8812 jne pci_pro_f02
8813 mov bx, #0x0210
8814 mov cx, #0
8815 mov edx, #0x20494350
8816 mov al, #0x01
8817 jmp pci_pro_ok
8818 pci_pro_f02: ;; find pci device
8819 cmp al, #0x02
8820 jne pci_pro_f08
8821 shl ecx, #16
8822 mov cx, dx
8823 mov bx, #0x0000
8824 mov di, #0x00
8825 pci_pro_devloop:
8826 call pci_pro_select_reg
8827 mov dx, #0x0cfc
8828 in eax, dx
8829 cmp eax, ecx
8830 jne pci_pro_nextdev
8831 cmp si, #0
8832 je pci_pro_ok
8833 dec si
8834 pci_pro_nextdev:
8835 inc bx
8836 cmp bx, #0x0100
8837 jne pci_pro_devloop
8838 mov ah, #0x86
8839 jmp pci_pro_fail
8840 pci_pro_f08: ;; read configuration byte
8841 cmp al, #0x08
8842 jne pci_pro_f09
8843 call pci_pro_select_reg
8844 push edx
8845 mov dx, di
8846 and dx, #0x03
8847 add dx, #0x0cfc
8848 in al, dx
8849 pop edx
8850 mov cl, al
8851 jmp pci_pro_ok
8852 pci_pro_f09: ;; read configuration word
8853 cmp al, #0x09
8854 jne pci_pro_f0a
8855 call pci_pro_select_reg
8856 push edx
8857 mov dx, di
8858 and dx, #0x02
8859 add dx, #0x0cfc
8860 in ax, dx
8861 pop edx
8862 mov cx, ax
8863 jmp pci_pro_ok
8864 pci_pro_f0a: ;; read configuration dword
8865 cmp al, #0x0a
8866 jne pci_pro_f0b
8867 call pci_pro_select_reg
8868 push edx
8869 mov dx, #0x0cfc
8870 in eax, dx
8871 pop edx
8872 mov ecx, eax
8873 jmp pci_pro_ok
8874 pci_pro_f0b: ;; write configuration byte
8875 cmp al, #0x0b
8876 jne pci_pro_f0c
8877 call pci_pro_select_reg
8878 push edx
8879 mov dx, di
8880 and dx, #0x03
8881 add dx, #0x0cfc
8882 mov al, cl
8883 out dx, al
8884 pop edx
8885 jmp pci_pro_ok
8886 pci_pro_f0c: ;; write configuration word
8887 cmp al, #0x0c
8888 jne pci_pro_f0d
8889 call pci_pro_select_reg
8890 push edx
8891 mov dx, di
8892 and dx, #0x02
8893 add dx, #0x0cfc
8894 mov ax, cx
8895 out dx, ax
8896 pop edx
8897 jmp pci_pro_ok
8898 pci_pro_f0d: ;; write configuration dword
8899 cmp al, #0x0d
8900 jne pci_pro_unknown
8901 call pci_pro_select_reg
8902 push edx
8903 mov dx, #0x0cfc
8904 mov eax, ecx
8905 out dx, eax
8906 pop edx
8907 jmp pci_pro_ok
8908 pci_pro_unknown:
8909 mov ah, #0x81
8910 pci_pro_fail:
8911 pop edi
8912 pop esi
8913 sti
8914 popf
8915 stc
8916 retf
8917 pci_pro_ok:
8918 xor ah, ah
8919 pop edi
8920 pop esi
8921 sti
8922 popf
8923 clc
8924 retf
8926 pci_pro_select_reg:
8927 push edx
8928 mov eax, #0x800000
8929 mov ax, bx
8930 shl eax, #8
8931 and di, #0xff
8932 or ax, di
8933 and al, #0xfc
8934 mov dx, #0x0cf8
8935 out dx, eax
8936 pop edx
8937 ret
8939 use16 386
8941 pcibios_real:
8942 push eax
8943 push dx
8944 mov eax, #0x80000000
8945 mov dx, #0x0cf8
8946 out dx, eax
8947 mov dx, #0x0cfc
8948 in eax, dx
8949 cmp eax, #0x12378086
8950 je pci_present
8951 pop dx
8952 pop eax
8953 mov ah, #0xff
8954 stc
8955 ret
8956 pci_present:
8957 pop dx
8958 pop eax
8959 cmp al, #0x01 ;; installation check
8960 jne pci_real_f02
8961 mov ax, #0x0001
8962 mov bx, #0x0210
8963 mov cx, #0
8964 mov edx, #0x20494350
8965 mov edi, #0xf0000
8966 mov di, #pcibios_protected
8967 clc
8968 ret
8969 pci_real_f02: ;; find pci device
8970 push esi
8971 push edi
8972 cmp al, #0x02
8973 jne pci_real_f08
8974 shl ecx, #16
8975 mov cx, dx
8976 mov bx, #0x0000
8977 mov di, #0x00
8978 pci_real_devloop:
8979 call pci_real_select_reg
8980 mov dx, #0x0cfc
8981 in eax, dx
8982 cmp eax, ecx
8983 jne pci_real_nextdev
8984 cmp si, #0
8985 je pci_real_ok
8986 dec si
8987 pci_real_nextdev:
8988 inc bx
8989 cmp bx, #0x0100
8990 jne pci_real_devloop
8991 mov dx, cx
8992 shr ecx, #16
8993 mov ah, #0x86
8994 jmp pci_real_fail
8995 pci_real_f08: ;; read configuration byte
8996 cmp al, #0x08
8997 jne pci_real_f09
8998 call pci_real_select_reg
8999 push dx
9000 mov dx, di
9001 and dx, #0x03
9002 add dx, #0x0cfc
9003 in al, dx
9004 pop dx
9005 mov cl, al
9006 jmp pci_real_ok
9007 pci_real_f09: ;; read configuration word
9008 cmp al, #0x09
9009 jne pci_real_f0a
9010 call pci_real_select_reg
9011 push dx
9012 mov dx, di
9013 and dx, #0x02
9014 add dx, #0x0cfc
9015 in ax, dx
9016 pop dx
9017 mov cx, ax
9018 jmp pci_real_ok
9019 pci_real_f0a: ;; read configuration dword
9020 cmp al, #0x0a
9021 jne pci_real_f0b
9022 call pci_real_select_reg
9023 push dx
9024 mov dx, #0x0cfc
9025 in eax, dx
9026 pop dx
9027 mov ecx, eax
9028 jmp pci_real_ok
9029 pci_real_f0b: ;; write configuration byte
9030 cmp al, #0x0b
9031 jne pci_real_f0c
9032 call pci_real_select_reg
9033 push dx
9034 mov dx, di
9035 and dx, #0x03
9036 add dx, #0x0cfc
9037 mov al, cl
9038 out dx, al
9039 pop dx
9040 jmp pci_real_ok
9041 pci_real_f0c: ;; write configuration word
9042 cmp al, #0x0c
9043 jne pci_real_f0d
9044 call pci_real_select_reg
9045 push dx
9046 mov dx, di
9047 and dx, #0x02
9048 add dx, #0x0cfc
9049 mov ax, cx
9050 out dx, ax
9051 pop dx
9052 jmp pci_real_ok
9053 pci_real_f0d: ;; write configuration dword
9054 cmp al, #0x0d
9055 jne pci_real_unknown
9056 call pci_real_select_reg
9057 push dx
9058 mov dx, #0x0cfc
9059 mov eax, ecx
9060 out dx, eax
9061 pop dx
9062 jmp pci_real_ok
9063 pci_real_unknown:
9064 mov ah, #0x81
9065 pci_real_fail:
9066 pop edi
9067 pop esi
9068 stc
9069 ret
9070 pci_real_ok:
9071 xor ah, ah
9072 pop edi
9073 pop esi
9074 clc
9075 ret
9077 pci_real_select_reg:
9078 push dx
9079 mov eax, #0x800000
9080 mov ax, bx
9081 shl eax, #8
9082 and di, #0xff
9083 or ax, di
9084 and al, #0xfc
9085 mov dx, #0x0cf8
9086 out dx, eax
9087 pop dx
9088 ret
9090 .align 16
9091 pci_routing_table_structure:
9092 db 0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature
9093 db 0, 1 ;; version
9094 dw 32 + (6 * 16) ;; table size
9095 db 0 ;; PCI interrupt router bus
9096 db 0x08 ;; PCI interrupt router DevFunc
9097 dw 0x0000 ;; PCI exclusive IRQs
9098 dw 0x8086 ;; compatible PCI interrupt router vendor ID
9099 dw 0x7000 ;; compatible PCI interrupt router device ID
9100 dw 0,0 ;; Miniport data
9101 db 0,0,0,0,0,0,0,0,0,0,0 ;; reserved
9102 db 0x07 ;; checksum
9103 ;; first slot entry PCI-to-ISA (embedded)
9104 db 0 ;; pci bus number
9105 db 0x08 ;; pci device number (bit 7-3)
9106 db 0x60 ;; link value INTA#: pointer into PCI2ISA config space
9107 dw 0xdef8 ;; IRQ bitmap INTA#
9108 db 0x61 ;; link value INTB#
9109 dw 0xdef8 ;; IRQ bitmap INTB#
9110 db 0x62 ;; link value INTC#
9111 dw 0xdef8 ;; IRQ bitmap INTC#
9112 db 0x63 ;; link value INTD#
9113 dw 0xdef8 ;; IRQ bitmap INTD#
9114 db 0 ;; physical slot (0 = embedded)
9115 db 0 ;; reserved
9116 ;; second slot entry: 1st PCI slot
9117 db 0 ;; pci bus number
9118 db 0x10 ;; pci device number (bit 7-3)
9119 db 0x61 ;; link value INTA#
9120 dw 0xdef8 ;; IRQ bitmap INTA#
9121 db 0x62 ;; link value INTB#
9122 dw 0xdef8 ;; IRQ bitmap INTB#
9123 db 0x63 ;; link value INTC#
9124 dw 0xdef8 ;; IRQ bitmap INTC#
9125 db 0x60 ;; link value INTD#
9126 dw 0xdef8 ;; IRQ bitmap INTD#
9127 db 1 ;; physical slot (0 = embedded)
9128 db 0 ;; reserved
9129 ;; third slot entry: 2nd PCI slot
9130 db 0 ;; pci bus number
9131 db 0x18 ;; pci device number (bit 7-3)
9132 db 0x62 ;; link value INTA#
9133 dw 0xdef8 ;; IRQ bitmap INTA#
9134 db 0x63 ;; link value INTB#
9135 dw 0xdef8 ;; IRQ bitmap INTB#
9136 db 0x60 ;; link value INTC#
9137 dw 0xdef8 ;; IRQ bitmap INTC#
9138 db 0x61 ;; link value INTD#
9139 dw 0xdef8 ;; IRQ bitmap INTD#
9140 db 2 ;; physical slot (0 = embedded)
9141 db 0 ;; reserved
9142 ;; 4th slot entry: 3rd PCI slot
9143 db 0 ;; pci bus number
9144 db 0x20 ;; pci device number (bit 7-3)
9145 db 0x63 ;; link value INTA#
9146 dw 0xdef8 ;; IRQ bitmap INTA#
9147 db 0x60 ;; link value INTB#
9148 dw 0xdef8 ;; IRQ bitmap INTB#
9149 db 0x61 ;; link value INTC#
9150 dw 0xdef8 ;; IRQ bitmap INTC#
9151 db 0x62 ;; link value INTD#
9152 dw 0xdef8 ;; IRQ bitmap INTD#
9153 db 3 ;; physical slot (0 = embedded)
9154 db 0 ;; reserved
9155 ;; 5th slot entry: 4rd PCI slot
9156 db 0 ;; pci bus number
9157 db 0x28 ;; pci device number (bit 7-3)
9158 db 0x60 ;; link value INTA#
9159 dw 0xdef8 ;; IRQ bitmap INTA#
9160 db 0x61 ;; link value INTB#
9161 dw 0xdef8 ;; IRQ bitmap INTB#
9162 db 0x62 ;; link value INTC#
9163 dw 0xdef8 ;; IRQ bitmap INTC#
9164 db 0x63 ;; link value INTD#
9165 dw 0xdef8 ;; IRQ bitmap INTD#
9166 db 4 ;; physical slot (0 = embedded)
9167 db 0 ;; reserved
9168 ;; 6th slot entry: 5rd PCI slot
9169 db 0 ;; pci bus number
9170 db 0x30 ;; pci device number (bit 7-3)
9171 db 0x61 ;; link value INTA#
9172 dw 0xdef8 ;; IRQ bitmap INTA#
9173 db 0x62 ;; link value INTB#
9174 dw 0xdef8 ;; IRQ bitmap INTB#
9175 db 0x63 ;; link value INTC#
9176 dw 0xdef8 ;; IRQ bitmap INTC#
9177 db 0x60 ;; link value INTD#
9178 dw 0xdef8 ;; IRQ bitmap INTD#
9179 db 5 ;; physical slot (0 = embedded)
9180 db 0 ;; reserved
9182 pci_irq_list:
9183 db 11, 10, 9, 5;
9185 pcibios_init_sel_reg:
9186 push eax
9187 mov eax, #0x800000
9188 mov ax, bx
9189 shl eax, #8
9190 and dl, #0xfc
9191 or al, dl
9192 mov dx, #0x0cf8
9193 out dx, eax
9194 pop eax
9195 ret
9197 pcibios_init_set_elcr:
9198 push ax
9199 push cx
9200 mov dx, #0x04d0
9201 test al, #0x08
9202 jz is_master_pic
9203 inc dx
9204 and al, #0x07
9205 is_master_pic:
9206 mov cl, al
9207 mov bl, #0x01
9208 shl bl, cl
9209 in al, dx
9210 or al, bl
9211 out dx, al
9212 pop cx
9213 pop ax
9214 ret
9216 pcibios_init:
9217 push ds
9218 push bp
9219 mov ax, #0xf000
9220 mov ds, ax
9221 mov dx, #0x04d0 ;; reset ELCR1 + ELCR2
9222 mov al, #0x00
9223 out dx, al
9224 inc dx
9225 out dx, al
9226 mov si, #pci_routing_table_structure
9227 mov bh, [si+8]
9228 mov bl, [si+9]
9229 mov dl, #0x00
9230 call pcibios_init_sel_reg
9231 mov dx, #0x0cfc
9232 in eax, dx
9233 cmp eax, [si+12] ;; check irq router
9234 jne pci_init_end
9235 mov dl, [si+34]
9236 call pcibios_init_sel_reg
9237 push bx ;; save irq router bus + devfunc
9238 mov dx, #0x0cfc
9239 mov ax, #0x8080
9240 out dx, ax ;; reset PIRQ route control
9241 inc dx
9242 inc dx
9243 out dx, ax
9244 mov ax, [si+6]
9245 sub ax, #0x20
9246 shr ax, #4
9247 mov cx, ax
9248 add si, #0x20 ;; set pointer to 1st entry
9249 mov bp, sp
9250 mov ax, #pci_irq_list
9251 push ax
9252 xor ax, ax
9253 push ax
9254 pci_init_loop1:
9255 mov bh, [si]
9256 mov bl, [si+1]
9257 pci_init_loop2:
9258 mov dl, #0x00
9259 call pcibios_init_sel_reg
9260 mov dx, #0x0cfc
9261 in ax, dx
9262 cmp ax, #0xffff
9263 jnz pci_test_int_pin
9264 test bl, #0x07
9265 jz next_pir_entry
9266 jmp next_pci_func
9267 pci_test_int_pin:
9268 mov dl, #0x3c
9269 call pcibios_init_sel_reg
9270 mov dx, #0x0cfd
9271 in al, dx
9272 and al, #0x07
9273 jz next_pci_func
9274 dec al ;; determine pirq reg
9275 mov dl, #0x03
9276 mul al, dl
9277 add al, #0x02
9278 xor ah, ah
9279 mov bx, ax
9280 mov al, [si+bx]
9281 mov dl, al
9282 mov bx, [bp]
9283 call pcibios_init_sel_reg
9284 mov dx, #0x0cfc
9285 and al, #0x03
9286 add dl, al
9287 in al, dx
9288 cmp al, #0x80
9289 jb pirq_found
9290 mov bx, [bp-2] ;; pci irq list pointer
9291 mov al, [bx]
9292 out dx, al
9293 inc bx
9294 mov [bp-2], bx
9295 call pcibios_init_set_elcr
9296 pirq_found:
9297 mov bh, [si]
9298 mov bl, [si+1]
9299 add bl, [bp-3] ;; pci function number
9300 mov dl, #0x3c
9301 call pcibios_init_sel_reg
9302 mov dx, #0x0cfc
9303 out dx, al
9304 next_pci_func:
9305 inc byte ptr[bp-3]
9306 inc bl
9307 test bl, #0x07
9308 jnz pci_init_loop2
9309 next_pir_entry:
9310 add si, #0x10
9311 mov byte ptr[bp-3], #0x00
9312 loop pci_init_loop1
9313 mov sp, bp
9314 pop bx
9315 pci_init_end:
9316 pop bp
9317 pop ds
9318 ret
9319 #endif // BX_PCIBIOS
9321 ; parallel port detection: base address in DX, index in BX, timeout in CL
9322 detect_parport:
9323 push dx
9324 add dx, #2
9325 in al, dx
9326 and al, #0xdf ; clear input mode
9327 out dx, al
9328 pop dx
9329 mov al, #0xaa
9330 out dx, al
9331 in al, dx
9332 cmp al, #0xaa
9333 jne no_parport
9334 push bx
9335 shl bx, #1
9336 mov [bx+0x408], dx ; Parallel I/O address
9337 pop bx
9338 mov [bx+0x478], cl ; Parallel printer timeout
9339 inc bx
9340 no_parport:
9341 ret
9343 ; serial port detection: base address in DX, index in BX, timeout in CL
9344 detect_serial:
9345 push dx
9346 inc dx
9347 mov al, #0x02
9348 out dx, al
9349 in al, dx
9350 cmp al, #0x02
9351 jne no_serial
9352 inc dx
9353 in al, dx
9354 cmp al, #0x02
9355 jne no_serial
9356 dec dx
9357 xor al, al
9358 out dx, al
9359 pop dx
9360 push bx
9361 shl bx, #1
9362 mov [bx+0x400], dx ; Serial I/O address
9363 pop bx
9364 mov [bx+0x47c], cl ; Serial timeout
9365 inc bx
9366 ret
9367 no_serial:
9368 pop dx
9369 ret
9371 rom_checksum:
9372 push ax
9373 push bx
9374 push cx
9375 xor ax, ax
9376 xor bx, bx
9377 xor cx, cx
9378 mov ch, [2]
9379 shl cx, #1
9380 checksum_loop:
9381 add al, [bx]
9382 inc bx
9383 loop checksum_loop
9384 and al, #0xff
9385 pop cx
9386 pop bx
9387 pop ax
9388 ret
9390 rom_scan:
9391 ;; Scan for existence of valid expansion ROMS.
9392 ;; Video ROM: from 0xC0000..0xC7FFF in 2k increments
9393 ;; General ROM: from 0xC8000..0xDFFFF in 2k increments
9394 ;; System ROM: only 0xE0000
9395 ;;
9396 ;; Header:
9397 ;; Offset Value
9398 ;; 0 0x55
9399 ;; 1 0xAA
9400 ;; 2 ROM length in 512-byte blocks
9401 ;; 3 ROM initialization entry point (FAR CALL)
9403 mov cx, #0xc000
9404 rom_scan_loop:
9405 mov ds, cx
9406 mov ax, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
9407 cmp [0], #0xAA55 ;; look for signature
9408 jne rom_scan_increment
9409 call rom_checksum
9410 jnz rom_scan_increment
9411 mov al, [2] ;; change increment to ROM length in 512-byte blocks
9413 ;; We want our increment in 512-byte quantities, rounded to
9414 ;; the nearest 2k quantity, since we only scan at 2k intervals.
9415 test al, #0x03
9416 jz block_count_rounded
9417 and al, #0xfc ;; needs rounding up
9418 add al, #0x04
9419 block_count_rounded:
9421 xor bx, bx ;; Restore DS back to 0000:
9422 mov ds, bx
9423 push ax ;; Save AX
9424 ;; Push addr of ROM entry point
9425 push cx ;; Push seg
9426 push #0x0003 ;; Push offset
9427 mov bp, sp ;; Call ROM init routine using seg:off on stack
9428 db 0xff ;; call_far ss:[bp+0]
9429 db 0x5e
9430 db 0
9431 cli ;; In case expansion ROM BIOS turns IF on
9432 add sp, #2 ;; Pop offset value
9433 pop cx ;; Pop seg value (restore CX)
9434 pop ax ;; Restore AX
9435 rom_scan_increment:
9436 shl ax, #5 ;; convert 512-bytes blocks to 16-byte increments
9437 ;; because the segment selector is shifted left 4 bits.
9438 add cx, ax
9439 cmp cx, #0xe000
9440 jbe rom_scan_loop
9442 xor ax, ax ;; Restore DS back to 0000:
9443 mov ds, ax
9444 ret
9446 #ifdef HVMASSIST
9448 ; Copy the SMBIOS entry point over from 0x9f000, where hvmloader left it.
9449 ; The entry point must be somewhere in 0xf0000-0xfffff on a 16-byte boundary,
9450 ; but the tables themeselves can be elsewhere.
9451 smbios_init:
9452 push ax
9453 push cx
9454 push es
9455 push ds
9456 push di
9457 push si
9459 mov cx, #0x001f ; 0x1f bytes to copy
9460 mov ax, #0xf000
9461 mov es, ax ; destination segment is 0xf0000
9462 mov di, #smbios_entry_point ; destination offset
9463 mov ax, #0x9f00
9464 mov ds, ax ; source segment is 0x9f000
9465 mov si, #0x0000 ; source offset is 0
9466 cld
9467 rep
9468 movsb
9470 pop si
9471 pop di
9472 pop ds
9473 pop es
9474 pop cx
9475 pop ax
9477 ret
9479 #endif
9483 ;; for 'C' strings and other data, insert them here with
9484 ;; a the following hack:
9485 ;; DATA_SEG_DEFS_HERE
9488 ;--------
9489 ;- POST -
9490 ;--------
9491 .org 0xe05b ; POST Entry Point
9492 post:
9494 xor ax, ax
9496 ;; first reset the DMA controllers
9497 out 0x0d,al
9498 out 0xda,al
9500 ;; then initialize the DMA controllers
9501 mov al, #0xC0
9502 out 0xD6, al ; cascade mode of channel 4 enabled
9503 mov al, #0x00
9504 out 0xD4, al ; unmask channel 4
9506 ;; Examine CMOS shutdown status.
9507 mov AL, #0x0f
9508 out 0x70, AL
9509 in AL, 0x71
9511 ;; backup status
9512 mov bl, al
9514 ;; Reset CMOS shutdown status.
9515 mov AL, #0x0f
9516 out 0x70, AL ; select CMOS register Fh
9517 mov AL, #0x00
9518 out 0x71, AL ; set shutdown action to normal
9520 ;; Examine CMOS shutdown status.
9521 mov al, bl
9523 ;; 0x00, 0x09, 0x0D+ = normal startup
9524 cmp AL, #0x00
9525 jz normal_post
9526 cmp AL, #0x0d
9527 jae normal_post
9528 cmp AL, #0x09
9529 je normal_post
9531 ;; 0x05 = eoi + jmp via [0x40:0x67] jump
9532 cmp al, #0x05
9533 je eoi_jmp_post
9535 ;; Examine CMOS shutdown status.
9536 ;; 0x01,0x02,0x03,0x04,0x06,0x07,0x08, 0x0a, 0x0b, 0x0c = Unimplemented shutdown status.
9537 push bx
9538 call _shutdown_status_panic
9540 #if 0
9541 HALT(__LINE__)
9543 ;#if 0
9544 ; 0xb0, 0x20, /* mov al, #0x20 */
9545 ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */
9546 ;#endif
9548 pop es
9549 pop ds
9550 popa
9551 iret
9552 #endif
9554 normal_post:
9555 ; case 0: normal startup
9557 cli
9558 mov ax, #0xfffe
9559 mov sp, ax
9560 mov ax, #0x0000
9561 mov ds, ax
9562 mov ss, ax
9564 ;; zero out BIOS data area (40:00..40:ff)
9565 mov es, ax
9566 mov cx, #0x0080 ;; 128 words
9567 mov di, #0x0400
9568 cld
9569 rep
9570 stosw
9572 call _log_bios_start
9574 ;; set all interrupts to default handler
9575 mov bx, #0x0000 ;; offset index
9576 mov cx, #0x0100 ;; counter (256 interrupts)
9577 mov ax, #dummy_iret_handler
9578 mov dx, #0xF000
9580 post_default_ints:
9581 mov [bx], ax
9582 inc bx
9583 inc bx
9584 mov [bx], dx
9585 inc bx
9586 inc bx
9587 loop post_default_ints
9589 ;; set vector 0x79 to zero
9590 ;; this is used by 'gardian angel' protection system
9591 SET_INT_VECTOR(0x79, #0, #0)
9593 ;; base memory in K 40:13 (word)
9594 mov ax, #BASE_MEM_IN_K
9595 mov 0x0413, ax
9598 ;; Manufacturing Test 40:12
9599 ;; zerod out above
9601 ;; Warm Boot Flag 0040:0072
9602 ;; value of 1234h = skip memory checks
9603 ;; zerod out above
9606 ;; Printer Services vector
9607 SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
9609 ;; Bootstrap failure vector
9610 SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
9612 ;; Bootstrap Loader vector
9613 SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
9615 ;; User Timer Tick vector
9616 SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
9618 ;; Memory Size Check vector
9619 SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
9621 ;; Equipment Configuration Check vector
9622 SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
9624 ;; System Services
9625 SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
9627 ;; EBDA setup
9628 call ebda_post
9630 ;; PIT setup
9631 SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
9632 ;; int 1C already points at dummy_iret_handler (above)
9633 mov al, #0x34 ; timer0: binary count, 16bit count, mode 2
9634 out 0x43, al
9635 #ifdef HVMASSIST
9636 mov al, #0x0b ; #0xe90b = 20 Hz (temporary, until we fix xen/vmx support)
9637 out 0x40, al ; lsb
9638 mov al, #0xe9
9639 out 0x40, al ; msb
9640 #else
9641 mov al, #0x00 ; maximum count of 0000H = 18.2Hz
9642 out 0x40, al
9643 out 0x40, al
9644 #endif
9646 ;; Keyboard
9647 SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
9648 SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
9650 xor ax, ax
9651 mov ds, ax
9652 mov 0x0417, al /* keyboard shift flags, set 1 */
9653 mov 0x0418, al /* keyboard shift flags, set 2 */
9654 mov 0x0419, al /* keyboard alt-numpad work area */
9655 mov 0x0471, al /* keyboard ctrl-break flag */
9656 mov 0x0497, al /* keyboard status flags 4 */
9657 mov al, #0x10
9658 mov 0x0496, al /* keyboard status flags 3 */
9661 /* keyboard head of buffer pointer */
9662 mov bx, #0x001E
9663 mov 0x041A, bx
9665 /* keyboard end of buffer pointer */
9666 mov 0x041C, bx
9668 /* keyboard pointer to start of buffer */
9669 mov bx, #0x001E
9670 mov 0x0480, bx
9672 /* keyboard pointer to end of buffer */
9673 mov bx, #0x003E
9674 mov 0x0482, bx
9676 /* init the keyboard */
9677 call _keyboard_init
9679 ;; mov CMOS Equipment Byte to BDA Equipment Word
9680 mov ax, 0x0410
9681 mov al, #0x14
9682 out 0x70, al
9683 in al, 0x71
9684 mov 0x0410, ax
9687 ;; Parallel setup
9688 SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
9689 xor ax, ax
9690 mov ds, ax
9691 xor bx, bx
9692 mov cl, #0x14 ; timeout value
9693 mov dx, #0x378 ; Parallel I/O address, port 1
9694 call detect_parport
9695 mov dx, #0x278 ; Parallel I/O address, port 2
9696 call detect_parport
9697 shl bx, #0x0e
9698 mov ax, 0x410 ; Equipment word bits 14..15 determing # parallel ports
9699 and ax, #0x3fff
9700 or ax, bx ; set number of parallel ports
9701 mov 0x410, ax
9703 ;; Serial setup
9704 SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
9705 SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
9706 xor bx, bx
9707 mov cl, #0x0a ; timeout value
9708 mov dx, #0x03f8 ; Serial I/O address, port 1
9709 call detect_serial
9710 mov dx, #0x02f8 ; Serial I/O address, port 2
9711 call detect_serial
9712 mov dx, #0x03e8 ; Serial I/O address, port 3
9713 call detect_serial
9714 mov dx, #0x02e8 ; Serial I/O address, port 4
9715 call detect_serial
9716 shl bx, #0x09
9717 mov ax, 0x410 ; Equipment word bits 9..11 determing # serial ports
9718 and ax, #0xf1ff
9719 or ax, bx ; set number of serial port
9720 mov 0x410, ax
9722 ;; CMOS RTC
9723 SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
9724 SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
9725 SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
9726 ;; BIOS DATA AREA 0x4CE ???
9727 call timer_tick_post
9729 ;; PS/2 mouse setup
9730 SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
9732 ;; IRQ13 (FPU exception) setup
9733 SET_INT_VECTOR(0x75, #0xF000, #int75_handler)
9735 ;; Video setup
9736 SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
9738 ;; PIC
9739 mov al, #0x11 ; send initialisation commands
9740 out 0x20, al
9741 out 0xa0, al
9742 mov al, #0x08
9743 out 0x21, al
9744 mov al, #0x70
9745 out 0xa1, al
9746 mov al, #0x04
9747 out 0x21, al
9748 mov al, #0x02
9749 out 0xa1, al
9750 mov al, #0x01
9751 out 0x21, al
9752 out 0xa1, al
9753 mov al, #0xb8
9754 out 0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6
9755 #if BX_USE_PS2_MOUSE
9756 mov al, #0x8f
9757 #else
9758 mov al, #0x9f
9759 #endif
9760 out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14
9762 #ifdef HVMASSIST
9763 call _copy_e820_table
9764 call smbios_init
9765 #endif
9767 call rom_scan
9769 call _print_bios_banner
9771 ;;
9772 ;; Floppy setup
9773 ;;
9774 call floppy_drive_post
9776 #if BX_USE_ATADRV
9778 ;;
9779 ;; Hard Drive setup
9780 ;;
9781 call hard_drive_post
9783 ;;
9784 ;; ATA/ATAPI driver setup
9785 ;;
9786 call _ata_init
9787 call _ata_detect
9788 ;;
9789 #else // BX_USE_ATADRV
9791 ;;
9792 ;; Hard Drive setup
9793 ;;
9794 call hard_drive_post
9796 #endif // BX_USE_ATADRV
9798 #if BX_ELTORITO_BOOT
9799 ;;
9800 ;; eltorito floppy/harddisk emulation from cd
9801 ;;
9802 call _cdemu_init
9803 ;;
9804 #endif // BX_ELTORITO_BOOT
9806 int #0x19
9807 //JMP_EP(0x0064) ; INT 19h location
9810 .org 0xe2c3 ; NMI Handler Entry Point
9811 nmi:
9812 ;; FIXME the NMI handler should not panic
9813 ;; but iret when called from int75 (fpu exception)
9814 call _nmi_handler_msg
9815 iret
9817 int75_handler:
9818 out 0xf0, al // clear irq13
9819 call eoi_both_pics // clear interrupt
9820 int 2 // legacy nmi call
9821 iret
9823 ;-------------------------------------------
9824 ;- INT 13h Fixed Disk Services Entry Point -
9825 ;-------------------------------------------
9826 .org 0xe3fe ; INT 13h Fixed Disk Services Entry Point
9827 int13_handler:
9828 //JMPL(int13_relocated)
9829 jmp int13_relocated
9831 .org 0xe401 ; Fixed Disk Parameter Table
9833 ;----------
9834 ;- INT19h -
9835 ;----------
9836 .org 0xe6f2 ; INT 19h Boot Load Service Entry Point
9837 int19_handler:
9839 jmp int19_relocated
9840 ;-------------------------------------------
9841 ;- System BIOS Configuration Data Table
9842 ;-------------------------------------------
9843 .org BIOS_CONFIG_TABLE
9844 db 0x08 ; Table size (bytes) -Lo
9845 db 0x00 ; Table size (bytes) -Hi
9846 db SYS_MODEL_ID
9847 db SYS_SUBMODEL_ID
9848 db BIOS_REVISION
9849 ; Feature byte 1
9850 ; b7: 1=DMA channel 3 used by hard disk
9851 ; b6: 1=2 interrupt controllers present
9852 ; b5: 1=RTC present
9853 ; b4: 1=BIOS calls int 15h/4Fh every key
9854 ; b3: 1=wait for extern event supported (Int 15h/41h)
9855 ; b2: 1=extended BIOS data area used
9856 ; b1: 0=AT or ESDI bus, 1=MicroChannel
9857 ; b0: 1=Dual bus (MicroChannel + ISA)
9858 db (0 << 7) | \
9859 (1 << 6) | \
9860 (1 << 5) | \
9861 (BX_CALL_INT15_4F << 4) | \
9862 (0 << 3) | \
9863 (BX_USE_EBDA << 2) | \
9864 (0 << 1) | \
9865 (0 << 0)
9866 ; Feature byte 2
9867 ; b7: 1=32-bit DMA supported
9868 ; b6: 1=int16h, function 9 supported
9869 ; b5: 1=int15h/C6h (get POS data) supported
9870 ; b4: 1=int15h/C7h (get mem map info) supported
9871 ; b3: 1=int15h/C8h (en/dis CPU) supported
9872 ; b2: 1=non-8042 kb controller
9873 ; b1: 1=data streaming supported
9874 ; b0: reserved
9875 db (0 << 7) | \
9876 (1 << 6) | \
9877 (0 << 5) | \
9878 (0 << 4) | \
9879 (0 << 3) | \
9880 (0 << 2) | \
9881 (0 << 1) | \
9882 (0 << 0)
9883 ; Feature byte 3
9884 ; b7: not used
9885 ; b6: reserved
9886 ; b5: reserved
9887 ; b4: POST supports ROM-to-RAM enable/disable
9888 ; b3: SCSI on system board
9889 ; b2: info panel installed
9890 ; b1: Initial Machine Load (IML) system - BIOS on disk
9891 ; b0: SCSI supported in IML
9892 db 0x00
9893 ; Feature byte 4
9894 ; b7: IBM private
9895 ; b6: EEPROM present
9896 ; b5-3: ABIOS presence (011 = not supported)
9897 ; b2: private
9898 ; b1: memory split above 16Mb supported
9899 ; b0: POSTEXT directly supported by POST
9900 db 0x00
9901 ; Feature byte 5 (IBM)
9902 ; b1: enhanced mouse
9903 ; b0: flash EPROM
9904 db 0x00
9908 .org 0xe729 ; Baud Rate Generator Table
9910 ;----------
9911 ;- INT14h -
9912 ;----------
9913 .org 0xe739 ; INT 14h Serial Communications Service Entry Point
9914 int14_handler:
9915 push ds
9916 pusha
9917 mov ax, #0x0000
9918 mov ds, ax
9919 call _int14_function
9920 popa
9921 pop ds
9922 iret
9925 ;----------------------------------------
9926 ;- INT 16h Keyboard Service Entry Point -
9927 ;----------------------------------------
9928 .org 0xe82e
9929 int16_handler:
9931 sti
9932 push ds
9933 pushf
9934 pusha
9936 cmp ah, #0x00
9937 je int16_F00
9938 cmp ah, #0x10
9939 je int16_F00
9941 mov bx, #0xf000
9942 mov ds, bx
9943 call _int16_function
9944 popa
9945 popf
9946 pop ds
9947 jz int16_zero_set
9949 int16_zero_clear:
9950 push bp
9951 mov bp, sp
9952 //SEG SS
9953 and BYTE [bp + 0x06], #0xbf
9954 pop bp
9955 iret
9957 int16_zero_set:
9958 push bp
9959 mov bp, sp
9960 //SEG SS
9961 or BYTE [bp + 0x06], #0x40
9962 pop bp
9963 iret
9965 int16_F00:
9966 mov bx, #0x0040
9967 mov ds, bx
9969 int16_wait_for_key:
9970 cli
9971 mov bx, 0x001a
9972 cmp bx, 0x001c
9973 jne int16_key_found
9974 sti
9975 nop
9976 #if 0
9977 /* no key yet, call int 15h, function AX=9002 */
9978 0x50, /* push AX */
9979 0xb8, 0x02, 0x90, /* mov AX, #0x9002 */
9980 0xcd, 0x15, /* int 15h */
9981 0x58, /* pop AX */
9982 0xeb, 0xea, /* jmp WAIT_FOR_KEY */
9983 #endif
9984 jmp int16_wait_for_key
9986 int16_key_found:
9987 mov bx, #0xf000
9988 mov ds, bx
9989 call _int16_function
9990 popa
9991 popf
9992 pop ds
9993 #if 0
9994 /* notify int16 complete w/ int 15h, function AX=9102 */
9995 0x50, /* push AX */
9996 0xb8, 0x02, 0x91, /* mov AX, #0x9102 */
9997 0xcd, 0x15, /* int 15h */
9998 0x58, /* pop AX */
9999 #endif
10000 iret
10004 ;-------------------------------------------------
10005 ;- INT09h : Keyboard Hardware Service Entry Point -
10006 ;-------------------------------------------------
10007 .org 0xe987
10008 int09_handler:
10009 cli
10010 push ax
10012 mov al, #0xAD ;;disable keyboard
10013 out #0x64, al
10015 mov al, #0x0B
10016 out #0x20, al
10017 in al, #0x20
10018 and al, #0x02
10019 jz int09_finish
10021 in al, #0x60 ;;read key from keyboard controller
10022 //test al, #0x80 ;;look for key release
10023 //jnz int09_process_key ;; dont pass releases to intercept?
10025 ;; check for extended key
10026 cmp al, #0xe0
10027 jne int09_call_int15_4f
10029 push ds
10030 xor ax, ax
10031 mov ds, ax
10032 mov al, BYTE [0x496] ;; mf2_state |= 0x01
10033 or al, #0x01
10034 mov BYTE [0x496], al
10035 pop ds
10037 in al, #0x60 ;;read another key from keyboard controller
10039 sti
10041 int09_call_int15_4f:
10042 push ds
10043 pusha
10044 #ifdef BX_CALL_INT15_4F
10045 mov ah, #0x4f ;; allow for keyboard intercept
10046 stc
10047 int #0x15
10048 jnc int09_done
10049 #endif
10052 //int09_process_key:
10053 mov bx, #0xf000
10054 mov ds, bx
10055 call _int09_function
10057 int09_done:
10058 popa
10059 pop ds
10060 cli
10061 call eoi_master_pic
10063 int09_finish:
10064 mov al, #0xAE ;;enable keyboard
10065 out #0x64, al
10066 pop ax
10067 iret
10072 ;----------------------------------------
10073 ;- INT 13h Diskette Service Entry Point -
10074 ;----------------------------------------
10075 .org 0xec59
10076 int13_diskette:
10077 jmp int13_noeltorito
10079 ;---------------------------------------------
10080 ;- INT 0Eh Diskette Hardware ISR Entry Point -
10081 ;---------------------------------------------
10082 .org 0xef57 ; INT 0Eh Diskette Hardware ISR Entry Point
10083 int0e_handler:
10084 push ax
10085 push dx
10086 mov dx, #0x03f4
10087 in al, dx
10088 and al, #0xc0
10089 cmp al, #0xc0
10090 je int0e_normal
10091 mov dx, #0x03f5
10092 mov al, #0x08 ; sense interrupt status
10093 out dx, al
10094 int0e_loop1:
10095 mov dx, #0x03f4
10096 in al, dx
10097 and al, #0xc0
10098 cmp al, #0xc0
10099 jne int0e_loop1
10100 int0e_loop2:
10101 mov dx, #0x03f5
10102 in al, dx
10103 mov dx, #0x03f4
10104 in al, dx
10105 and al, #0xc0
10106 cmp al, #0xc0
10107 je int0e_loop2
10108 int0e_normal:
10109 push ds
10110 mov ax, #0x0000 ;; segment 0000
10111 mov ds, ax
10112 call eoi_master_pic
10113 mov al, 0x043e
10114 or al, #0x80 ;; diskette interrupt has occurred
10115 mov 0x043e, al
10116 pop ds
10117 pop dx
10118 pop ax
10119 iret
10122 .org 0xefc7 ; Diskette Controller Parameter Table
10123 diskette_param_table:
10124 ;; Since no provisions are made for multiple drive types, most
10125 ;; values in this table are ignored. I set parameters for 1.44M
10126 ;; floppy here
10127 db 0xAF
10128 db 0x02 ;; head load time 0000001, DMA used
10129 db 0x25
10130 db 0x02
10131 db 18
10132 db 0x1B
10133 db 0xFF
10134 db 0x6C
10135 db 0xF6
10136 db 0x0F
10137 db 0x08
10140 ;----------------------------------------
10141 ;- INT17h : Printer Service Entry Point -
10142 ;----------------------------------------
10143 .org 0xefd2
10144 int17_handler:
10145 push ds
10146 pusha
10147 mov ax, #0x0000
10148 mov ds, ax
10149 call _int17_function
10150 popa
10151 pop ds
10152 iret
10154 diskette_param_table2:
10155 ;; New diskette parameter table adding 3 parameters from IBM
10156 ;; Since no provisions are made for multiple drive types, most
10157 ;; values in this table are ignored. I set parameters for 1.44M
10158 ;; floppy here
10159 db 0xAF
10160 db 0x02 ;; head load time 0000001, DMA used
10161 db 0x25
10162 db 0x02
10163 db 18
10164 db 0x1B
10165 db 0xFF
10166 db 0x6C
10167 db 0xF6
10168 db 0x0F
10169 db 0x08
10170 db 79 ;; maximum track
10171 db 0 ;; data transfer rate
10172 db 4 ;; drive type in cmos
10174 .org 0xf045 ; INT 10 Functions 0-Fh Entry Point
10175 HALT(__LINE__)
10176 iret
10178 ;----------
10179 ;- INT10h -
10180 ;----------
10181 .org 0xf065 ; INT 10h Video Support Service Entry Point
10182 int10_handler:
10183 ;; dont do anything, since the VGA BIOS handles int10h requests
10184 iret
10186 .org 0xf0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
10188 ;----------
10189 ;- INT12h -
10190 ;----------
10191 .org 0xf841 ; INT 12h Memory Size Service Entry Point
10192 ; ??? different for Pentium (machine check)?
10193 int12_handler:
10194 push ds
10195 mov ax, #0x0040
10196 mov ds, ax
10197 mov ax, 0x0013
10198 pop ds
10199 iret
10201 ;----------
10202 ;- INT11h -
10203 ;----------
10204 .org 0xf84d ; INT 11h Equipment List Service Entry Point
10205 int11_handler:
10206 push ds
10207 mov ax, #0x0040
10208 mov ds, ax
10209 mov ax, 0x0010
10210 pop ds
10211 iret
10213 ;----------
10214 ;- INT15h -
10215 ;----------
10216 .org 0xf859 ; INT 15h System Services Entry Point
10217 int15_handler:
10218 pushf
10219 #if BX_APM
10220 cmp ah, #0x53
10221 je apm_call
10222 #endif
10223 push ds
10224 push es
10225 cmp ah, #0x86
10226 je int15_handler32
10227 cmp ah, #0xE8
10228 je int15_handler32
10229 pusha
10230 #if BX_USE_PS2_MOUSE
10231 cmp ah, #0xC2
10232 je int15_handler_mouse
10233 #endif
10234 call _int15_function
10235 int15_handler_mouse_ret:
10236 popa
10237 int15_handler32_ret:
10238 pop es
10239 pop ds
10240 popf