- mouse type 'none' added (no mouse connected)
[gplbios.git] / rombios.c
blob62d05decb9e8c83e841d95e1ba5801f5aecb60bd
1 /////////////////////////////////////////////////////////////////////////
2 // $Id$
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/
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.
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.
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
30 // ROM BIOS compatability entry points:
31 // ===================================
32 // $e05b ; POST Entry Point
33 // $e2c3 ; NMI Handler Entry Point
34 // $e3fe ; INT 13h Fixed Disk Services Entry Point
35 // $e401 ; Fixed Disk Parameter Table
36 // $e6f2 ; INT 19h Boot Load Service Entry Point
37 // $e6f5 ; Configuration Data Table
38 // $e729 ; Baud Rate Generator Table
39 // $e739 ; INT 14h Serial Communications Service Entry Point
40 // $e82e ; INT 16h Keyboard Service Entry Point
41 // $e987 ; INT 09h Keyboard Service Entry Point
42 // $ec59 ; INT 13h Diskette Service Entry Point
43 // $ef57 ; INT 0Eh Diskette Hardware ISR Entry Point
44 // $efc7 ; Diskette Controller Parameter Table
45 // $efd2 ; INT 17h Printer Service Entry Point
46 // $f045 ; INT 10 Functions 0-Fh Entry Point
47 // $f065 ; INT 10h Video Support Service Entry Point
48 // $f0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
49 // $f841 ; INT 12h Memory Size Service Entry Point
50 // $f84d ; INT 11h Equipment List Service Entry Point
51 // $f859 ; INT 15h System Services Entry Point
52 // $fa6e ; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
53 // $fe6e ; INT 1Ah Time-of-day Service Entry Point
54 // $fea5 ; INT 08h System Timer ISR Entry Point
55 // $fef3 ; Initial Interrupt Vector Offsets Loaded by POST
56 // $ff53 ; IRET Instruction for Dummy Interrupt Handler
57 // $ff54 ; INT 05h Print Screen Service Entry Point
58 // $fff0 ; Power-up Entry Point
59 // $fff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
60 // $fffe ; System Model ID
62 // NOTES for ATA/ATAPI driver (cbbochs@free.fr)
63 // Features
64 // - supports up to 4 ATA interfaces
65 // - device/geometry detection
66 // - 16bits/32bits device access
67 // - pchs/lba access
68 // - datain/dataout/packet command support
70 // NOTES for El-Torito Boot (cbbochs@free.fr)
71 // - CD-ROM booting is only available if ATA/ATAPI Driver is available
72 // - Current code is only able to boot mono-session cds
73 // - Current code can not boot and emulate a hard-disk
74 // the bios will panic otherwise
75 // - Current code also use memory in EBDA segement.
76 // - I used cmos byte 0x3D to store extended information on boot-device
77 // - Code has to be modified modified to handle multiple cdrom drives
78 // - Here are the cdrom boot failure codes:
79 // 1 : no atapi device found
80 // 2 : no atapi cdrom found
81 // 3 : can not read cd - BRVD
82 // 4 : cd is not eltorito (BRVD)
83 // 5 : cd is not eltorito (ISO TAG)
84 // 6 : cd is not eltorito (ELTORITO TAG)
85 // 7 : can not read cd - boot catalog
86 // 8 : boot catalog : bad header
87 // 9 : boot catalog : bad platform
88 // 10 : boot catalog : bad signature
89 // 11 : boot catalog : bootable flag not set
90 // 12 : can not read cd - boot image
92 // ATA driver
93 // - EBDA segment.
94 // I used memory starting at 0x121 in the segment
95 // - the translation policy is defined in cmos regs 0x39 & 0x3a
97 // TODO :
99 // int74
100 // - needs to be reworked. Uses direct [bp] offsets. (?)
102 // int13:
103 // - f04 (verify sectors) isn't complete (?)
104 // - f02/03/04 should set current cyl,etc in BDA (?)
105 // - rewrite int13_relocated & clean up int13 entry code
107 // NOTES:
108 // - NMI access (bit7 of addr written to 70h)
110 // ATA driver
111 // - should handle the "don't detect" bit (cmos regs 0x3b & 0x3c)
112 // - could send the multiple-sector read/write commands
114 // El-Torito
115 // - Emulate a Hard-disk (currently only diskette can be emulated) see "FIXME ElTorito Harddisk"
116 // - Implement remaining int13_cdemu functions (as defined by El-Torito specs)
117 // - cdrom drive is hardcoded to ide 0 device 1 in several places. see "FIXME ElTorito Hardcoded"
118 // - int13 Fix DL when emulating a cd. In that case DL is decremented before calling real int13.
119 // This is ok. But DL should be reincremented afterwards.
120 // - Fix all "FIXME ElTorito Various"
121 // - should be able to boot any cdrom instead of the first one
123 // BCC Bug: find a generic way to handle the bug of #asm after an "if" (fixed in 0.16.7)
125 #define DEBUG_ROMBIOS 0
127 #define DEBUG_ATA 0
128 #define DEBUG_INT13_HD 0
129 #define DEBUG_INT13_CD 0
130 #define DEBUG_INT13_ET 0
131 #define DEBUG_INT13_FL 0
132 #define DEBUG_INT15 0
133 #define DEBUG_INT16 0
134 #define DEBUG_INT1A 0
135 #define DEBUG_INT74 0
136 #define DEBUG_APM 0
138 #define BX_CPU 3
139 #define BX_USE_PS2_MOUSE 1
140 #define BX_CALL_INT15_4F 1
141 #define BX_USE_EBDA 1
142 #define BX_SUPPORT_FLOPPY 1
143 #define BX_FLOPPY_ON_CNT 37 // 2 seconds
144 #define BX_PCIBIOS 1
145 #define BX_APM 1
147 #define BX_USE_ATADRV 1
148 #define BX_ELTORITO_BOOT 1
150 #define BX_MAX_ATA_INTERFACES 4
151 #define BX_MAX_ATA_DEVICES (BX_MAX_ATA_INTERFACES*2)
153 /* model byte 0xFC = AT */
154 #define SYS_MODEL_ID 0xFC
155 #define SYS_SUBMODEL_ID 0x00
156 #define BIOS_REVISION 1
157 #define BIOS_CONFIG_TABLE 0xe6f5
159 // 1K of base memory used for Extended Bios Data Area (EBDA)
160 // EBDA is used for PS/2 mouse support, and IDE BIOS, etc.
161 #define EBDA_SEG 0x9FC0
162 #define EBDA_SIZE 1 // In KiB
163 #define BASE_MEM_IN_K (640 - EBDA_SIZE)
165 // Define the application NAME
166 #ifdef PLEX86
167 # define BX_APPNAME "Plex86"
168 #else
169 # define BX_APPNAME "Bochs"
170 #endif
172 // Sanity Checks
173 #if BX_USE_ATADRV && BX_CPU<3
174 # error The ATA/ATAPI Driver can only to be used with a 386+ cpu
175 #endif
176 #if BX_USE_ATADRV && !BX_USE_EBDA
177 # error ATA/ATAPI Driver can only be used if EBDA is available
178 #endif
179 #if BX_ELTORITO_BOOT && !BX_USE_ATADRV
180 # error El-Torito Boot can only be use if ATA/ATAPI Driver is available
181 #endif
182 #if BX_PCIBIOS && BX_CPU<3
183 # error PCI BIOS can only be used with 386+ cpu
184 #endif
187 #define PANIC_PORT 0x400
188 #define PANIC_PORT2 0x401
189 #define INFO_PORT 0x402
190 #define DEBUG_PORT 0x403
192 // #20 is dec 20
193 // #$20 is hex 20 = 32
194 // LDA #$20
195 // JSR $E820
196 // LDD .i,S
197 // JSR $C682
198 // mov al, #$20
200 // all hex literals should be prefixed with '0x'
201 // grep "#[0-9a-fA-F][0-9a-fA-F]" rombios.c
202 // no mov SEG-REG, #value, must mov register into seg-reg
203 // grep -i "mov[ ]*.s" rombios.c
205 // This is for compiling with gcc2 and gcc3
206 #define ASM_START #asm
207 #define ASM_END #endasm
209 ASM_START
210 .rom
212 .org 0x0000
214 #if BX_CPU >= 3
215 use16 386
216 #else
217 use16 286
218 #endif
220 MACRO HALT
221 ;; the HALT macro is called with the line number of the HALT call.
222 ;; The line number is then sent to the PANIC_PORT, causing Bochs/Plex
223 ;; to print a BX_PANIC message. This will normally halt the simulation
224 ;; with a message such as "BIOS panic at rombios.c, line 4091".
225 ;; However, users can choose to make panics non-fatal and continue.
226 mov dx,#PANIC_PORT
227 mov ax,#?1
228 out dx,ax
229 MEND
231 MACRO JMP_AP
232 db 0xea
233 dw ?2
234 dw ?1
235 MEND
237 MACRO SET_INT_VECTOR
238 mov ax, ?3
239 mov ?1*4, ax
240 mov ax, ?2
241 mov ?1*4+2, ax
242 MEND
244 ASM_END
246 typedef unsigned char Bit8u;
247 typedef unsigned short Bit16u;
248 typedef unsigned short bx_bool;
249 typedef unsigned long Bit32u;
251 #if BX_USE_ATADRV
253 void memsetb(seg,offset,value,count);
254 void memcpyb(dseg,doffset,sseg,soffset,count);
255 void memcpyd(dseg,doffset,sseg,soffset,count);
257 // memset of count bytes
258 void
259 memsetb(seg,offset,value,count)
260 Bit16u seg;
261 Bit16u offset;
262 Bit16u value;
263 Bit16u count;
265 ASM_START
266 push bp
267 mov bp, sp
269 push ax
270 push cx
271 push es
272 push di
274 mov cx, 10[bp] ; count
275 cmp cx, #0x00
276 je memsetb_end
277 mov ax, 4[bp] ; segment
278 mov es, ax
279 mov ax, 6[bp] ; offset
280 mov di, ax
281 mov al, 8[bp] ; value
284 stosb
286 memsetb_end:
287 pop di
288 pop es
289 pop cx
290 pop ax
292 pop bp
293 ASM_END
296 #if 0
297 // memcpy of count bytes
298 void
299 memcpyb(dseg,doffset,sseg,soffset,count)
300 Bit16u dseg;
301 Bit16u doffset;
302 Bit16u sseg;
303 Bit16u soffset;
304 Bit16u count;
306 ASM_START
307 push bp
308 mov bp, sp
310 push ax
311 push cx
312 push es
313 push di
314 push ds
315 push si
317 mov cx, 12[bp] ; count
318 cmp cx, #0x0000
319 je memcpyb_end
320 mov ax, 4[bp] ; dsegment
321 mov es, ax
322 mov ax, 6[bp] ; doffset
323 mov di, ax
324 mov ax, 8[bp] ; ssegment
325 mov ds, ax
326 mov ax, 10[bp] ; soffset
327 mov si, ax
330 movsb
332 memcpyb_end:
333 pop si
334 pop ds
335 pop di
336 pop es
337 pop cx
338 pop ax
340 pop bp
341 ASM_END
344 // memcpy of count dword
345 void
346 memcpyd(dseg,doffset,sseg,soffset,count)
347 Bit16u dseg;
348 Bit16u doffset;
349 Bit16u sseg;
350 Bit16u soffset;
351 Bit16u count;
353 ASM_START
354 push bp
355 mov bp, sp
357 push ax
358 push cx
359 push es
360 push di
361 push ds
362 push si
364 mov cx, 12[bp] ; count
365 cmp cx, #0x0000
366 je memcpyd_end
367 mov ax, 4[bp] ; dsegment
368 mov es, ax
369 mov ax, 6[bp] ; doffset
370 mov di, ax
371 mov ax, 8[bp] ; ssegment
372 mov ds, ax
373 mov ax, 10[bp] ; soffset
374 mov si, ax
377 movsd
379 memcpyd_end:
380 pop si
381 pop ds
382 pop di
383 pop es
384 pop cx
385 pop ax
387 pop bp
388 ASM_END
390 #endif
391 #endif //BX_USE_ATADRV
393 // read_dword and write_dword functions
394 static Bit32u read_dword();
395 static void write_dword();
397 Bit32u
398 read_dword(seg, offset)
399 Bit16u seg;
400 Bit16u offset;
402 ASM_START
403 push bp
404 mov bp, sp
406 push bx
407 push ds
408 mov ax, 4[bp] ; segment
409 mov ds, ax
410 mov bx, 6[bp] ; offset
411 mov ax, [bx]
412 inc bx
413 inc bx
414 mov dx, [bx]
415 ;; ax = return value (word)
416 ;; dx = return value (word)
417 pop ds
418 pop bx
420 pop bp
421 ASM_END
424 void
425 write_dword(seg, offset, data)
426 Bit16u seg;
427 Bit16u offset;
428 Bit32u data;
430 ASM_START
431 push bp
432 mov bp, sp
434 push ax
435 push bx
436 push ds
437 mov ax, 4[bp] ; segment
438 mov ds, ax
439 mov bx, 6[bp] ; offset
440 mov ax, 8[bp] ; data word
441 mov [bx], ax ; write data word
442 inc bx
443 inc bx
444 mov ax, 10[bp] ; data word
445 mov [bx], ax ; write data word
446 pop ds
447 pop bx
448 pop ax
450 pop bp
451 ASM_END
454 // Bit32u (unsigned long) and long helper functions
455 ASM_START
457 ;; and function
458 landl:
459 landul:
460 SEG SS
461 and ax,[di]
462 SEG SS
463 and bx,2[di]
466 ;; add function
467 laddl:
468 laddul:
469 SEG SS
470 add ax,[di]
471 SEG SS
472 adc bx,2[di]
475 ;; cmp function
476 lcmpl:
477 lcmpul:
478 and eax, #0x0000FFFF
479 shl ebx, #16
480 add eax, ebx
481 shr ebx, #16
482 SEG SS
483 cmp eax, dword ptr [di]
486 ;; sub function
487 lsubl:
488 lsubul:
489 SEG SS
490 sub ax,[di]
491 SEG SS
492 sbb bx,2[di]
495 ;; mul function
496 lmull:
497 lmulul:
498 and eax, #0x0000FFFF
499 shl ebx, #16
500 add eax, ebx
501 SEG SS
502 mul eax, dword ptr [di]
503 mov ebx, eax
504 shr ebx, #16
507 ;; dec function
508 ldecl:
509 ldecul:
510 SEG SS
511 dec dword ptr [bx]
514 ;; or function
515 lorl:
516 lorul:
517 SEG SS
518 or ax,[di]
519 SEG SS
520 or bx,2[di]
523 ;; inc function
524 lincl:
525 lincul:
526 SEG SS
527 inc dword ptr [bx]
530 ;; tst function
531 ltstl:
532 ltstul:
533 and eax, #0x0000FFFF
534 shl ebx, #16
535 add eax, ebx
536 shr ebx, #16
537 test eax, eax
540 ;; sr function
541 lsrul:
542 mov cx,di
543 jcxz lsr_exit
544 and eax, #0x0000FFFF
545 shl ebx, #16
546 add eax, ebx
547 lsr_loop:
548 shr eax, #1
549 loop lsr_loop
550 mov ebx, eax
551 shr ebx, #16
552 lsr_exit:
555 ;; sl function
556 lsll:
557 lslul:
558 mov cx,di
559 jcxz lsl_exit
560 and eax, #0x0000FFFF
561 shl ebx, #16
562 add eax, ebx
563 lsl_loop:
564 shl eax, #1
565 loop lsl_loop
566 mov ebx, eax
567 shr ebx, #16
568 lsl_exit:
571 idiv_:
573 idiv bx
576 idiv_u:
577 xor dx,dx
578 div bx
581 ldivul:
582 and eax, #0x0000FFFF
583 shl ebx, #16
584 add eax, ebx
585 xor edx, edx
586 SEG SS
587 mov bx, 2[di]
588 shl ebx, #16
589 SEG SS
590 mov bx, [di]
591 div ebx
592 mov ebx, eax
593 shr ebx, #16
596 ASM_END
598 // for access to RAM area which is used by interrupt vectors
599 // and BIOS Data Area
601 typedef struct {
602 unsigned char filler1[0x400];
603 unsigned char filler2[0x6c];
604 Bit16u ticks_low;
605 Bit16u ticks_high;
606 Bit8u midnight_flag;
607 } bios_data_t;
609 #define BiosData ((bios_data_t *) 0)
611 #if BX_USE_ATADRV
612 typedef struct {
613 Bit16u heads; // # heads
614 Bit16u cylinders; // # cylinders
615 Bit16u spt; // # sectors / track
616 } chs_t;
618 // DPTE definition
619 typedef struct {
620 Bit16u iobase1;
621 Bit16u iobase2;
622 Bit8u prefix;
623 Bit8u unused;
624 Bit8u irq;
625 Bit8u blkcount;
626 Bit8u dma;
627 Bit8u pio;
628 Bit16u options;
629 Bit16u reserved;
630 Bit8u revision;
631 Bit8u checksum;
632 } dpte_t;
634 typedef struct {
635 Bit8u iface; // ISA or PCI
636 Bit16u iobase1; // IO Base 1
637 Bit16u iobase2; // IO Base 2
638 Bit8u irq; // IRQ
639 } ata_channel_t;
641 typedef struct {
642 Bit8u type; // Detected type of ata (ata/atapi/none/unknown)
643 Bit8u device; // Detected type of attached devices (hd/cd/none)
644 Bit8u removable; // Removable device flag
645 Bit8u lock; // Locks for removable devices
646 // Bit8u lba_capable; // LBA capable flag - always yes for bochs devices
647 Bit8u mode; // transfert mode : PIO 16/32 bits - IRQ - ISADMA - PCIDMA
648 Bit16u blksize; // block size
650 Bit8u translation; // type of translation
651 chs_t lchs; // Logical CHS
652 chs_t pchs; // Physical CHS
654 Bit32u sectors; // Total sectors count
655 } ata_device_t;
657 typedef struct {
658 // ATA channels info
659 ata_channel_t channels[BX_MAX_ATA_INTERFACES];
661 // ATA devices info
662 ata_device_t devices[BX_MAX_ATA_DEVICES];
664 // map between (bios hd id - 0x80) and ata channels
665 Bit8u hdcount, hdidmap[BX_MAX_ATA_DEVICES];
667 // map between (bios cd id - 0xE0) and ata channels
668 Bit8u cdcount, cdidmap[BX_MAX_ATA_DEVICES];
670 // Buffer for DPTE table
671 dpte_t dpte;
673 // Count of transferred sectors and bytes
674 Bit16u trsfsectors;
675 Bit32u trsfbytes;
677 } ata_t;
679 #if BX_ELTORITO_BOOT
680 // ElTorito Device Emulation data
681 typedef struct {
682 Bit8u active;
683 Bit8u media;
684 Bit8u emulated_drive;
685 Bit8u controller_index;
686 Bit16u device_spec;
687 Bit32u ilba;
688 Bit16u buffer_segment;
689 Bit16u load_segment;
690 Bit16u sector_count;
692 // Virtual device
693 chs_t vdevice;
694 } cdemu_t;
695 #endif // BX_ELTORITO_BOOT
697 // for access to EBDA area
698 // The EBDA structure should conform to
699 // http://www.cybertrails.com/~fys/rombios.htm document
700 // I made the ata and cdemu structs begin at 0x121 in the EBDA seg
701 typedef struct {
702 unsigned char filler1[0x3D];
704 // FDPT - Can be splitted in data members if needed
705 unsigned char fdpt0[0x10];
706 unsigned char fdpt1[0x10];
708 unsigned char filler2[0xC4];
710 // ATA Driver data
711 ata_t ata;
713 #if BX_ELTORITO_BOOT
714 // El Torito Emulation data
715 cdemu_t cdemu;
716 #endif // BX_ELTORITO_BOOT
718 } ebda_data_t;
720 #define EbdaData ((ebda_data_t *) 0)
722 // for access to the int13ext structure
723 typedef struct {
724 Bit8u size;
725 Bit8u reserved;
726 Bit16u count;
727 Bit16u offset;
728 Bit16u segment;
729 Bit32u lba1;
730 Bit32u lba2;
731 } int13ext_t;
733 #define Int13Ext ((int13ext_t *) 0)
735 // Disk Physical Table definition
736 typedef struct {
737 Bit16u size;
738 Bit16u infos;
739 Bit32u cylinders;
740 Bit32u heads;
741 Bit32u spt;
742 Bit32u sector_count1;
743 Bit32u sector_count2;
744 Bit16u blksize;
745 Bit16u dpte_segment;
746 Bit16u dpte_offset;
747 Bit16u key;
748 Bit8u dpi_length;
749 Bit8u reserved1;
750 Bit16u reserved2;
751 Bit8u host_bus[4];
752 Bit8u iface_type[8];
753 Bit8u iface_path[8];
754 Bit8u device_path[8];
755 Bit8u reserved3;
756 Bit8u checksum;
757 } dpt_t;
759 #define Int13DPT ((dpt_t *) 0)
761 #endif // BX_USE_ATADRV
763 typedef struct {
764 union {
765 struct {
766 Bit16u di, si, bp, sp;
767 Bit16u bx, dx, cx, ax;
768 } r16;
769 struct {
770 Bit16u filler[4];
771 Bit8u bl, bh, dl, dh, cl, ch, al, ah;
772 } r8;
773 } u;
774 } pusha_regs_t;
776 typedef struct {
777 union {
778 struct {
779 Bit32u edi, esi, ebp, esp;
780 Bit32u ebx, edx, ecx, eax;
781 } r32;
782 struct {
783 Bit16u di, filler1, si, filler2, bp, filler3, sp, filler4;
784 Bit16u bx, filler5, dx, filler6, cx, filler7, ax, filler8;
785 } r16;
786 struct {
787 Bit32u filler[4];
788 Bit8u bl, bh;
789 Bit16u filler1;
790 Bit8u dl, dh;
791 Bit16u filler2;
792 Bit8u cl, ch;
793 Bit16u filler3;
794 Bit8u al, ah;
795 Bit16u filler4;
796 } r8;
797 } u;
798 } pushad_regs_t;
800 typedef struct {
801 union {
802 struct {
803 Bit16u flags;
804 } r16;
805 struct {
806 Bit8u flagsl;
807 Bit8u flagsh;
808 } r8;
809 } u;
810 } flags_t;
812 #define SetCF(x) x.u.r8.flagsl |= 0x01
813 #define SetZF(x) x.u.r8.flagsl |= 0x40
814 #define ClearCF(x) x.u.r8.flagsl &= 0xfe
815 #define ClearZF(x) x.u.r8.flagsl &= 0xbf
816 #define GetCF(x) (x.u.r8.flagsl & 0x01)
818 typedef struct {
819 Bit16u ip;
820 Bit16u cs;
821 flags_t flags;
822 } iret_addr_t;
826 static Bit8u inb();
827 static Bit8u inb_cmos();
828 static void outb();
829 static void outb_cmos();
830 static Bit16u inw();
831 static void outw();
832 static void init_rtc();
833 static bx_bool rtc_updating();
835 static Bit8u read_byte();
836 static Bit16u read_word();
837 static void write_byte();
838 static void write_word();
839 static void bios_printf();
841 static Bit8u inhibit_mouse_int_and_events();
842 static void enable_mouse_int_and_events();
843 static Bit8u send_to_mouse_ctrl();
844 static Bit8u get_mouse_data();
845 static void set_kbd_command_byte();
847 static void int09_function();
848 static void int13_harddisk();
849 static void int13_cdrom();
850 static void int13_cdemu();
851 static void int13_eltorito();
852 static void int13_diskette_function();
853 static void int14_function();
854 static void int15_function();
855 static void int16_function();
856 static void int17_function();
857 static Bit32u int19_function();
858 static void int1a_function();
859 static void int70_function();
860 static void int74_function();
861 //static Bit16u get_DS();
862 //static void set_DS();
863 static Bit16u get_SS();
864 static unsigned int enqueue_key();
865 static unsigned int dequeue_key();
866 static void get_hd_geometry();
867 static void set_diskette_ret_status();
868 static void set_diskette_current_cyl();
869 static void determine_floppy_media();
870 static bx_bool floppy_drive_exists();
871 static bx_bool floppy_drive_recal();
872 static bx_bool floppy_media_known();
873 static bx_bool floppy_media_sense();
874 static bx_bool set_enable_a20();
875 static void debugger_on();
876 static void debugger_off();
877 static void keyboard_init();
878 static void keyboard_panic();
879 static void shutdown_status_panic();
880 static void nmi_handler_msg();
882 static void print_bios_banner();
883 static void print_boot_device();
884 static void print_boot_failure();
885 static void print_cdromboot_failure();
887 # if BX_USE_ATADRV
889 // ATA / ATAPI driver
890 void ata_init();
891 void ata_detect();
892 void ata_reset();
894 Bit16u ata_cmd_non_data();
895 Bit16u ata_cmd_data_in();
896 Bit16u ata_cmd_data_out();
897 Bit16u ata_cmd_packet();
899 Bit16u atapi_get_sense();
900 Bit16u atapi_is_ready();
901 Bit16u atapi_is_cdrom();
903 #endif // BX_USE_ATADRV
905 #if BX_ELTORITO_BOOT
907 void cdemu_init();
908 Bit8u cdemu_isactive();
909 Bit8u cdemu_emulated_drive();
911 Bit16u cdrom_boot();
913 #endif // BX_ELTORITO_BOOT
915 static char bios_cvs_version_string[] = "$Revision$";
916 static char bios_date_string[] = "$Date$";
918 static char CVSID[] = "$Id$";
920 /* Offset to skip the CVS $Id: prefix */
921 #define bios_version_string (CVSID + 4)
923 #define BIOS_PRINTF_HALT 1
924 #define BIOS_PRINTF_SCREEN 2
925 #define BIOS_PRINTF_INFO 4
926 #define BIOS_PRINTF_DEBUG 8
927 #define BIOS_PRINTF_ALL (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO)
928 #define BIOS_PRINTF_DEBHALT (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO | BIOS_PRINTF_HALT)
930 #define printf(format, p...) bios_printf(BIOS_PRINTF_SCREEN, format, ##p)
932 // Defines the output macros.
933 // BX_DEBUG goes to INFO port until we can easily choose debug info on a
934 // per-device basis. Debug info are sent only in debug mode
935 #if DEBUG_ROMBIOS
936 # define BX_DEBUG(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
937 #else
938 # define BX_DEBUG(format, p...)
939 #endif
940 #define BX_INFO(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p)
941 #define BX_PANIC(format, p...) bios_printf(BIOS_PRINTF_DEBHALT, format, ##p)
943 #if DEBUG_ATA
944 # define BX_DEBUG_ATA(a...) BX_DEBUG(##a)
945 #else
946 # define BX_DEBUG_ATA(a...)
947 #endif
948 #if DEBUG_INT13_HD
949 # define BX_DEBUG_INT13_HD(a...) BX_DEBUG(##a)
950 #else
951 # define BX_DEBUG_INT13_HD(a...)
952 #endif
953 #if DEBUG_INT13_CD
954 # define BX_DEBUG_INT13_CD(a...) BX_DEBUG(##a)
955 #else
956 # define BX_DEBUG_INT13_CD(a...)
957 #endif
958 #if DEBUG_INT13_ET
959 # define BX_DEBUG_INT13_ET(a...) BX_DEBUG(##a)
960 #else
961 # define BX_DEBUG_INT13_ET(a...)
962 #endif
963 #if DEBUG_INT13_FL
964 # define BX_DEBUG_INT13_FL(a...) BX_DEBUG(##a)
965 #else
966 # define BX_DEBUG_INT13_FL(a...)
967 #endif
968 #if DEBUG_INT15
969 # define BX_DEBUG_INT15(a...) BX_DEBUG(##a)
970 #else
971 # define BX_DEBUG_INT15(a...)
972 #endif
973 #if DEBUG_INT16
974 # define BX_DEBUG_INT16(a...) BX_DEBUG(##a)
975 #else
976 # define BX_DEBUG_INT16(a...)
977 #endif
978 #if DEBUG_INT1A
979 # define BX_DEBUG_INT1A(a...) BX_DEBUG(##a)
980 #else
981 # define BX_DEBUG_INT1A(a...)
982 #endif
983 #if DEBUG_INT74
984 # define BX_DEBUG_INT74(a...) BX_DEBUG(##a)
985 #else
986 # define BX_DEBUG_INT74(a...)
987 #endif
989 #define SET_AL(val8) AX = ((AX & 0xff00) | (val8))
990 #define SET_BL(val8) BX = ((BX & 0xff00) | (val8))
991 #define SET_CL(val8) CX = ((CX & 0xff00) | (val8))
992 #define SET_DL(val8) DX = ((DX & 0xff00) | (val8))
993 #define SET_AH(val8) AX = ((AX & 0x00ff) | ((val8) << 8))
994 #define SET_BH(val8) BX = ((BX & 0x00ff) | ((val8) << 8))
995 #define SET_CH(val8) CX = ((CX & 0x00ff) | ((val8) << 8))
996 #define SET_DH(val8) DX = ((DX & 0x00ff) | ((val8) << 8))
998 #define GET_AL() ( AX & 0x00ff )
999 #define GET_BL() ( BX & 0x00ff )
1000 #define GET_CL() ( CX & 0x00ff )
1001 #define GET_DL() ( DX & 0x00ff )
1002 #define GET_AH() ( AX >> 8 )
1003 #define GET_BH() ( BX >> 8 )
1004 #define GET_CH() ( CX >> 8 )
1005 #define GET_DH() ( DX >> 8 )
1008 #define SET_CF() FLAGS |= 0x0001
1009 #define CLEAR_CF() FLAGS &= 0xfffe
1010 #define GET_CF() (FLAGS & 0x0001)
1012 #define SET_ZF() FLAGS |= 0x0040
1013 #define CLEAR_ZF() FLAGS &= 0xffbf
1014 #define GET_ZF() (FLAGS & 0x0040)
1016 #define UNSUPPORTED_FUNCTION 0x86
1018 #define none 0
1019 #define MAX_SCAN_CODE 0x53
1021 static struct {
1022 Bit16u normal;
1023 Bit16u shift;
1024 Bit16u control;
1025 Bit16u alt;
1026 Bit8u lock_flags;
1027 } scan_to_scanascii[MAX_SCAN_CODE + 1] = {
1028 { none, none, none, none, none },
1029 { 0x011b, 0x011b, 0x011b, 0x0100, none }, /* escape */
1030 { 0x0231, 0x0221, none, 0x7800, none }, /* 1! */
1031 { 0x0332, 0x0340, 0x0300, 0x7900, none }, /* 2@ */
1032 { 0x0433, 0x0423, none, 0x7a00, none }, /* 3# */
1033 { 0x0534, 0x0524, none, 0x7b00, none }, /* 4$ */
1034 { 0x0635, 0x0625, none, 0x7c00, none }, /* 5% */
1035 { 0x0736, 0x075e, 0x071e, 0x7d00, none }, /* 6^ */
1036 { 0x0837, 0x0826, none, 0x7e00, none }, /* 7& */
1037 { 0x0938, 0x092a, none, 0x7f00, none }, /* 8* */
1038 { 0x0a39, 0x0a28, none, 0x8000, none }, /* 9( */
1039 { 0x0b30, 0x0b29, none, 0x8100, none }, /* 0) */
1040 { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200, none }, /* -_ */
1041 { 0x0d3d, 0x0d2b, none, 0x8300, none }, /* =+ */
1042 { 0x0e08, 0x0e08, 0x0e7f, none, none }, /* backspace */
1043 { 0x0f09, 0x0f00, none, none, none }, /* tab */
1044 { 0x1071, 0x1051, 0x1011, 0x1000, 0x40 }, /* Q */
1045 { 0x1177, 0x1157, 0x1117, 0x1100, 0x40 }, /* W */
1046 { 0x1265, 0x1245, 0x1205, 0x1200, 0x40 }, /* E */
1047 { 0x1372, 0x1352, 0x1312, 0x1300, 0x40 }, /* R */
1048 { 0x1474, 0x1454, 0x1414, 0x1400, 0x40 }, /* T */
1049 { 0x1579, 0x1559, 0x1519, 0x1500, 0x40 }, /* Y */
1050 { 0x1675, 0x1655, 0x1615, 0x1600, 0x40 }, /* U */
1051 { 0x1769, 0x1749, 0x1709, 0x1700, 0x40 }, /* I */
1052 { 0x186f, 0x184f, 0x180f, 0x1800, 0x40 }, /* O */
1053 { 0x1970, 0x1950, 0x1910, 0x1900, 0x40 }, /* P */
1054 { 0x1a5b, 0x1a7b, 0x1a1b, none, none }, /* [{ */
1055 { 0x1b5d, 0x1b7d, 0x1b1d, none, none }, /* ]} */
1056 { 0x1c0d, 0x1c0d, 0x1c0a, none, none }, /* Enter */
1057 { none, none, none, none, none }, /* L Ctrl */
1058 { 0x1e61, 0x1e41, 0x1e01, 0x1e00, 0x40 }, /* A */
1059 { 0x1f73, 0x1f53, 0x1f13, 0x1f00, 0x40 }, /* S */
1060 { 0x2064, 0x2044, 0x2004, 0x2000, 0x40 }, /* D */
1061 { 0x2166, 0x2146, 0x2106, 0x2100, 0x40 }, /* F */
1062 { 0x2267, 0x2247, 0x2207, 0x2200, 0x40 }, /* G */
1063 { 0x2368, 0x2348, 0x2308, 0x2300, 0x40 }, /* H */
1064 { 0x246a, 0x244a, 0x240a, 0x2400, 0x40 }, /* J */
1065 { 0x256b, 0x254b, 0x250b, 0x2500, 0x40 }, /* K */
1066 { 0x266c, 0x264c, 0x260c, 0x2600, 0x40 }, /* L */
1067 { 0x273b, 0x273a, none, none, none }, /* ;: */
1068 { 0x2827, 0x2822, none, none, none }, /* '" */
1069 { 0x2960, 0x297e, none, none, none }, /* `~ */
1070 { none, none, none, none, none }, /* L shift */
1071 { 0x2b5c, 0x2b7c, 0x2b1c, none, none }, /* |\ */
1072 { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, 0x40 }, /* Z */
1073 { 0x2d78, 0x2d58, 0x2d18, 0x2d00, 0x40 }, /* X */
1074 { 0x2e63, 0x2e43, 0x2e03, 0x2e00, 0x40 }, /* C */
1075 { 0x2f76, 0x2f56, 0x2f16, 0x2f00, 0x40 }, /* V */
1076 { 0x3062, 0x3042, 0x3002, 0x3000, 0x40 }, /* B */
1077 { 0x316e, 0x314e, 0x310e, 0x3100, 0x40 }, /* N */
1078 { 0x326d, 0x324d, 0x320d, 0x3200, 0x40 }, /* M */
1079 { 0x332c, 0x333c, none, none, none }, /* ,< */
1080 { 0x342e, 0x343e, none, none, none }, /* .> */
1081 { 0x352f, 0x353f, none, none, none }, /* /? */
1082 { none, none, none, none, none }, /* R Shift */
1083 { 0x372a, 0x372a, none, none, none }, /* * */
1084 { none, none, none, none, none }, /* L Alt */
1085 { 0x3920, 0x3920, 0x3920, 0x3920, none }, /* space */
1086 { none, none, none, none, none }, /* caps lock */
1087 { 0x3b00, 0x5400, 0x5e00, 0x6800, none }, /* F1 */
1088 { 0x3c00, 0x5500, 0x5f00, 0x6900, none }, /* F2 */
1089 { 0x3d00, 0x5600, 0x6000, 0x6a00, none }, /* F3 */
1090 { 0x3e00, 0x5700, 0x6100, 0x6b00, none }, /* F4 */
1091 { 0x3f00, 0x5800, 0x6200, 0x6c00, none }, /* F5 */
1092 { 0x4000, 0x5900, 0x6300, 0x6d00, none }, /* F6 */
1093 { 0x4100, 0x5a00, 0x6400, 0x6e00, none }, /* F7 */
1094 { 0x4200, 0x5b00, 0x6500, 0x6f00, none }, /* F8 */
1095 { 0x4300, 0x5c00, 0x6600, 0x7000, none }, /* F9 */
1096 { 0x4400, 0x5d00, 0x6700, 0x7100, none }, /* F10 */
1097 { none, none, none, none, none }, /* Num Lock */
1098 { none, none, none, none, none }, /* Scroll Lock */
1099 { 0x4700, 0x4737, 0x7700, none, 0x20 }, /* 7 Home */
1100 { 0x4800, 0x4838, none, none, 0x20 }, /* 8 UP */
1101 { 0x4900, 0x4939, 0x8400, none, 0x20 }, /* 9 PgUp */
1102 { 0x4a2d, 0x4a2d, none, none, none }, /* - */
1103 { 0x4b00, 0x4b34, 0x7300, none, 0x20 }, /* 4 Left */
1104 { 0x4c00, 0x4c35, none, none, 0x20 }, /* 5 */
1105 { 0x4d00, 0x4d36, 0x7400, none, 0x20 }, /* 6 Right */
1106 { 0x4e2b, 0x4e2b, none, none, none }, /* + */
1107 { 0x4f00, 0x4f31, 0x7500, none, 0x20 }, /* 1 End */
1108 { 0x5000, 0x5032, none, none, 0x20 }, /* 2 Down */
1109 { 0x5100, 0x5133, 0x7600, none, 0x20 }, /* 3 PgDn */
1110 { 0x5200, 0x5230, none, none, 0x20 }, /* 0 Ins */
1111 { 0x5300, 0x532e, none, none, 0x20 } /* Del */
1114 Bit8u
1115 inb(port)
1116 Bit16u port;
1118 ASM_START
1119 push bp
1120 mov bp, sp
1122 push dx
1123 mov dx, 4[bp]
1124 in al, dx
1125 pop dx
1127 pop bp
1128 ASM_END
1131 #if BX_USE_ATADRV
1132 Bit16u
1133 inw(port)
1134 Bit16u port;
1136 ASM_START
1137 push bp
1138 mov bp, sp
1140 push dx
1141 mov dx, 4[bp]
1142 in ax, dx
1143 pop dx
1145 pop bp
1146 ASM_END
1148 #endif
1150 void
1151 outb(port, val)
1152 Bit16u port;
1153 Bit8u val;
1155 ASM_START
1156 push bp
1157 mov bp, sp
1159 push ax
1160 push dx
1161 mov dx, 4[bp]
1162 mov al, 6[bp]
1163 out dx, al
1164 pop dx
1165 pop ax
1167 pop bp
1168 ASM_END
1171 #if BX_USE_ATADRV
1172 void
1173 outw(port, val)
1174 Bit16u port;
1175 Bit16u val;
1177 ASM_START
1178 push bp
1179 mov bp, sp
1181 push ax
1182 push dx
1183 mov dx, 4[bp]
1184 mov ax, 6[bp]
1185 out dx, ax
1186 pop dx
1187 pop ax
1189 pop bp
1190 ASM_END
1192 #endif
1194 void
1195 outb_cmos(cmos_reg, val)
1196 Bit8u cmos_reg;
1197 Bit8u val;
1199 ASM_START
1200 push bp
1201 mov bp, sp
1203 mov al, 4[bp] ;; cmos_reg
1204 out 0x70, al
1205 mov al, 6[bp] ;; val
1206 out 0x71, al
1208 pop bp
1209 ASM_END
1212 Bit8u
1213 inb_cmos(cmos_reg)
1214 Bit8u cmos_reg;
1216 ASM_START
1217 push bp
1218 mov bp, sp
1220 mov al, 4[bp] ;; cmos_reg
1221 out 0x70, al
1222 in al, 0x71
1224 pop bp
1225 ASM_END
1228 void
1229 init_rtc()
1231 outb_cmos(0x0a, 0x26);
1232 outb_cmos(0x0b, 0x02);
1233 inb_cmos(0x0c);
1234 inb_cmos(0x0d);
1237 bx_bool
1238 rtc_updating()
1240 // This function checks to see if the update-in-progress bit
1241 // is set in CMOS Status Register A. If not, it returns 0.
1242 // If it is set, it tries to wait until there is a transition
1243 // to 0, and will return 0 if such a transition occurs. A 1
1244 // is returned only after timing out. The maximum period
1245 // that this bit should be set is constrained to 244useconds.
1246 // The count I use below guarantees coverage or more than
1247 // this time, with any reasonable IPS setting.
1249 Bit16u count;
1251 count = 25000;
1252 while (--count != 0) {
1253 if ( (inb_cmos(0x0a) & 0x80) == 0 )
1254 return(0);
1256 return(1); // update-in-progress never transitioned to 0
1260 Bit8u
1261 read_byte(seg, offset)
1262 Bit16u seg;
1263 Bit16u offset;
1265 ASM_START
1266 push bp
1267 mov bp, sp
1269 push bx
1270 push ds
1271 mov ax, 4[bp] ; segment
1272 mov ds, ax
1273 mov bx, 6[bp] ; offset
1274 mov al, [bx]
1275 ;; al = return value (byte)
1276 pop ds
1277 pop bx
1279 pop bp
1280 ASM_END
1283 Bit16u
1284 read_word(seg, offset)
1285 Bit16u seg;
1286 Bit16u offset;
1288 ASM_START
1289 push bp
1290 mov bp, sp
1292 push bx
1293 push ds
1294 mov ax, 4[bp] ; segment
1295 mov ds, ax
1296 mov bx, 6[bp] ; offset
1297 mov ax, [bx]
1298 ;; ax = return value (word)
1299 pop ds
1300 pop bx
1302 pop bp
1303 ASM_END
1306 void
1307 write_byte(seg, offset, data)
1308 Bit16u seg;
1309 Bit16u offset;
1310 Bit8u data;
1312 ASM_START
1313 push bp
1314 mov bp, sp
1316 push ax
1317 push bx
1318 push ds
1319 mov ax, 4[bp] ; segment
1320 mov ds, ax
1321 mov bx, 6[bp] ; offset
1322 mov al, 8[bp] ; data byte
1323 mov [bx], al ; write data byte
1324 pop ds
1325 pop bx
1326 pop ax
1328 pop bp
1329 ASM_END
1332 void
1333 write_word(seg, offset, data)
1334 Bit16u seg;
1335 Bit16u offset;
1336 Bit16u data;
1338 ASM_START
1339 push bp
1340 mov bp, sp
1342 push ax
1343 push bx
1344 push ds
1345 mov ax, 4[bp] ; segment
1346 mov ds, ax
1347 mov bx, 6[bp] ; offset
1348 mov ax, 8[bp] ; data word
1349 mov [bx], ax ; write data word
1350 pop ds
1351 pop bx
1352 pop ax
1354 pop bp
1355 ASM_END
1358 // Bit16u
1359 //get_DS()
1361 //ASM_START
1362 // mov ax, ds
1363 //ASM_END
1366 // void
1367 //set_DS(ds_selector)
1368 // Bit16u ds_selector;
1370 //ASM_START
1371 // push bp
1372 // mov bp, sp
1374 // push ax
1375 // mov ax, 4[bp] ; ds_selector
1376 // mov ds, ax
1377 // pop ax
1379 // pop bp
1380 //ASM_END
1383 Bit16u
1384 get_SS()
1386 ASM_START
1387 mov ax, ss
1388 ASM_END
1391 void
1392 wrch(c)
1393 Bit8u c;
1395 ASM_START
1396 push bp
1397 mov bp, sp
1399 push bx
1400 mov ah, #$0e
1401 mov al, 4[bp]
1402 xor bx,bx
1403 int #$10
1404 pop bx
1406 pop bp
1407 ASM_END
1410 void
1411 send(action, c)
1412 Bit16u action;
1413 Bit8u c;
1415 if (action & BIOS_PRINTF_DEBUG) outb(DEBUG_PORT, c);
1416 if (action & BIOS_PRINTF_INFO) outb(INFO_PORT, c);
1417 if (action & BIOS_PRINTF_SCREEN) {
1418 if (c == '\n') wrch('\r');
1419 wrch(c);
1423 void
1424 put_int(action, val, width, neg)
1425 Bit16u action;
1426 short val, width;
1427 bx_bool neg;
1429 short nval = val / 10;
1430 if (nval)
1431 put_int(action, nval, width - 1, neg);
1432 else {
1433 while (--width > 0) send(action, ' ');
1434 if (neg) send(action, '-');
1436 send(action, val - (nval * 10) + '0');
1439 void
1440 put_uint(action, val, width, neg)
1441 Bit16u action;
1442 unsigned short val;
1443 short width;
1444 bx_bool neg;
1446 unsigned short nval = val / 10;
1447 if (nval)
1448 put_uint(action, nval, width - 1, neg);
1449 else {
1450 while (--width > 0) send(action, ' ');
1451 if (neg) send(action, '-');
1453 send(action, val - (nval * 10) + '0');
1456 //--------------------------------------------------------------------------
1457 // bios_printf()
1458 // A compact variable argument printf function which prints its output via
1459 // an I/O port so that it can be logged by Bochs/Plex.
1460 // Currently, only %x is supported (or %02x, %04x, etc).
1462 // Supports %[format_width][format]
1463 // where format can be d,x,c,s
1464 //--------------------------------------------------------------------------
1465 void
1466 bios_printf(action, s)
1467 Bit16u action;
1468 Bit8u *s;
1470 Bit8u c, format_char;
1471 bx_bool in_format;
1472 short i;
1473 Bit16u *arg_ptr;
1474 Bit16u arg_seg, arg, nibble, shift_count, format_width;
1476 arg_ptr = &s;
1477 arg_seg = get_SS();
1479 in_format = 0;
1480 format_width = 0;
1482 if ((action & BIOS_PRINTF_DEBHALT) == BIOS_PRINTF_DEBHALT) {
1483 outb(PANIC_PORT2, 0x00);
1484 bios_printf (BIOS_PRINTF_SCREEN, "FATAL: ");
1487 while (c = read_byte(0xf000, s)) {
1488 if ( c == '%' ) {
1489 in_format = 1;
1490 format_width = 0;
1492 else if (in_format) {
1493 if ( (c>='0') && (c<='9') ) {
1494 format_width = (format_width * 10) + (c - '0');
1496 else {
1497 arg_ptr++; // increment to next arg
1498 arg = read_word(arg_seg, arg_ptr);
1499 if (c == 'x') {
1500 if (format_width == 0)
1501 format_width = 4;
1502 for (i=format_width-1; i>=0; i--) {
1503 nibble = (arg >> (4 * i)) & 0x000f;
1504 send (action, (nibble<=9)? (nibble+'0') : (nibble-10+'A'));
1507 else if (c == 'u') {
1508 put_uint(action, arg, format_width, 0);
1510 else if (c == 'd') {
1511 if (arg & 0x8000)
1512 put_int(action, -arg, format_width - 1, 1);
1513 else
1514 put_int(action, arg, format_width, 0);
1516 else if (c == 's') {
1517 bios_printf(action & (~BIOS_PRINTF_HALT), arg);
1519 else if (c == 'c') {
1520 send(action, arg);
1522 else
1523 BX_PANIC("bios_printf: unknown format\n");
1524 in_format = 0;
1527 else {
1528 send(action, c);
1530 s ++;
1533 if (action & BIOS_PRINTF_HALT) {
1534 // freeze in a busy loop.
1535 ASM_START
1537 halt2_loop:
1539 jmp halt2_loop
1540 ASM_END
1544 //--------------------------------------------------------------------------
1545 // keyboard_init
1546 //--------------------------------------------------------------------------
1547 // this file is based on LinuxBIOS implementation of keyboard.c
1548 // could convert to #asm to gain space
1549 void
1550 keyboard_init()
1552 Bit16u max;
1554 /* ------------------- Flush buffers ------------------------*/
1555 /* Wait until buffer is empty */
1556 max=0xffff;
1557 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
1559 /* flush incoming keys */
1560 max=0x2000;
1561 while (--max > 0) {
1562 outb(0x80, 0x00);
1563 if (inb(0x64) & 0x01) {
1564 inb(0x60);
1565 max = 0x2000;
1569 // Due to timer issues, and if the IPS setting is > 15000000,
1570 // the incoming keys might not be flushed here. That will
1571 // cause a panic a few lines below. See sourceforge bug report :
1572 // [ 642031 ] FATAL: Keyboard RESET error:993
1574 /* ------------------- controller side ----------------------*/
1575 /* send cmd = 0xAA, self test 8042 */
1576 outb(0x64, 0xaa);
1578 /* Wait until buffer is empty */
1579 max=0xffff;
1580 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
1581 if (max==0x0) keyboard_panic(00);
1583 /* Wait for data */
1584 max=0xffff;
1585 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x01);
1586 if (max==0x0) keyboard_panic(01);
1588 /* read self-test result, 0x55 should be returned from 0x60 */
1589 if ((inb(0x60) != 0x55)){
1590 keyboard_panic(991);
1593 /* send cmd = 0xAB, keyboard interface test */
1594 outb(0x64,0xab);
1596 /* Wait until buffer is empty */
1597 max=0xffff;
1598 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x10);
1599 if (max==0x0) keyboard_panic(10);
1601 /* Wait for data */
1602 max=0xffff;
1603 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x11);
1604 if (max==0x0) keyboard_panic(11);
1606 /* read keyboard interface test result, */
1607 /* 0x00 should be returned form 0x60 */
1608 if ((inb(0x60) != 0x00)) {
1609 keyboard_panic(992);
1612 /* Enable Keyboard clock */
1613 outb(0x64,0xae);
1614 outb(0x64,0xa8);
1616 /* ------------------- keyboard side ------------------------*/
1617 /* reset kerboard and self test (keyboard side) */
1618 outb(0x60, 0xff);
1620 /* Wait until buffer is empty */
1621 max=0xffff;
1622 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x20);
1623 if (max==0x0) keyboard_panic(20);
1625 /* Wait for data */
1626 max=0xffff;
1627 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x21);
1628 if (max==0x0) keyboard_panic(21);
1630 /* keyboard should return ACK */
1631 if ((inb(0x60) != 0xfa)) {
1632 keyboard_panic(993);
1635 /* Wait for data */
1636 max=0xffff;
1637 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x31);
1638 if (max==0x0) keyboard_panic(31);
1640 if ((inb(0x60) != 0xaa)) {
1641 keyboard_panic(994);
1644 /* Disable keyboard */
1645 outb(0x60, 0xf5);
1647 /* Wait until buffer is empty */
1648 max=0xffff;
1649 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x40);
1650 if (max==0x0) keyboard_panic(40);
1652 /* Wait for data */
1653 max=0xffff;
1654 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x41);
1655 if (max==0x0) keyboard_panic(41);
1657 /* keyboard should return ACK */
1658 if ((inb(0x60) != 0xfa)) {
1659 keyboard_panic(995);
1662 /* Write Keyboard Mode */
1663 outb(0x64, 0x60);
1665 /* Wait until buffer is empty */
1666 max=0xffff;
1667 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x50);
1668 if (max==0x0) keyboard_panic(50);
1670 /* send cmd: scan code convert, disable mouse, enable IRQ 1 */
1671 outb(0x60, 0x61);
1673 /* Wait until buffer is empty */
1674 max=0xffff;
1675 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x60);
1676 if (max==0x0) keyboard_panic(60);
1678 /* Enable keyboard */
1679 outb(0x60, 0xf4);
1681 /* Wait until buffer is empty */
1682 max=0xffff;
1683 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x70);
1684 if (max==0x0) keyboard_panic(70);
1686 /* Wait for data */
1687 max=0xffff;
1688 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x71);
1689 if (max==0x0) keyboard_panic(70);
1691 /* keyboard should return ACK */
1692 if ((inb(0x60) != 0xfa)) {
1693 keyboard_panic(996);
1696 outb(0x80, 0x77);
1699 //--------------------------------------------------------------------------
1700 // keyboard_panic
1701 //--------------------------------------------------------------------------
1702 void
1703 keyboard_panic(status)
1704 Bit16u status;
1706 // If you're getting a 993 keyboard panic here,
1707 // please see the comment in keyboard_init
1709 BX_PANIC("Keyboard error:%u\n",status);
1712 //--------------------------------------------------------------------------
1713 // shutdown_status_panic
1714 // called when the shutdown statsu is not implemented, displays the status
1715 //--------------------------------------------------------------------------
1716 void
1717 shutdown_status_panic(status)
1718 Bit16u status;
1720 BX_PANIC("Unimplemented shutdown status: %02x\n",(Bit8u)status);
1723 //--------------------------------------------------------------------------
1724 // print_bios_banner
1725 // displays a the bios version
1726 //--------------------------------------------------------------------------
1727 void
1728 print_bios_banner()
1730 printf(BX_APPNAME" BIOS, %d cpu%s, ", BX_SMP_PROCESSORS, BX_SMP_PROCESSORS>1?"s":"");
1731 printf("%s %s\n", bios_cvs_version_string, bios_date_string);
1732 printf("\n");
1735 //--------------------------------------------------------------------------
1736 // print_boot_device
1737 // displays the boot device
1738 //--------------------------------------------------------------------------
1740 static char drivetypes[][10]={"Floppy","Hard Disk","CD-Rom"};
1742 void
1743 print_boot_device(cdboot, drive)
1744 Bit8u cdboot; Bit16u drive;
1746 Bit8u i;
1748 // cdboot contains 0 if floppy/harddisk, 1 otherwise
1749 // drive contains real/emulated boot drive
1751 if(cdboot)i=2; // CD-Rom
1752 else if((drive&0x0080)==0x00)i=0; // Floppy
1753 else if((drive&0x0080)==0x80)i=1; // Hard drive
1754 else return;
1756 printf("Booting from %s...\n",drivetypes[i]);
1759 //--------------------------------------------------------------------------
1760 // print_boot_failure
1761 // displays the reason why boot failed
1762 //--------------------------------------------------------------------------
1763 void
1764 print_boot_failure(cdboot, drive, reason, lastdrive)
1765 Bit8u cdboot; Bit8u drive; Bit8u lastdrive;
1767 Bit16u drivenum = drive&0x7f;
1769 // cdboot: 1 if boot from cd, 0 otherwise
1770 // drive : drive number
1771 // reason: 0 signature check failed, 1 read error
1772 // lastdrive: 1 boot drive is the last one in boot sequence
1774 if (cdboot)
1775 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s failed\n",drivetypes[2]);
1776 else if (drive & 0x80)
1777 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[1],drivenum);
1778 else
1779 bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[0],drivenum);
1781 if (lastdrive==1) {
1782 if (reason==0)
1783 BX_PANIC("Not a bootable disk\n");
1784 else
1785 BX_PANIC("Could not read the boot disk\n");
1789 //--------------------------------------------------------------------------
1790 // print_cdromboot_failure
1791 // displays the reason why boot failed
1792 //--------------------------------------------------------------------------
1793 void
1794 print_cdromboot_failure( code )
1795 Bit16u code;
1797 bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "CDROM boot failure code : %04x\n",code);
1799 return;
1802 void
1803 nmi_handler_msg()
1805 BX_PANIC("NMI Handler called\n");
1808 void
1809 int18_panic_msg()
1811 BX_PANIC("INT18: BOOT FAILURE\n");
1814 void
1815 log_bios_start()
1817 BX_INFO("%s\n", bios_version_string);
1820 bx_bool
1821 set_enable_a20(val)
1822 bx_bool val;
1824 Bit8u oldval;
1826 // Use PS2 System Control port A to set A20 enable
1828 // get current setting first
1829 oldval = inb(0x92);
1831 // change A20 status
1832 if (val)
1833 outb(0x92, oldval | 0x02);
1834 else
1835 outb(0x92, oldval & 0xfd);
1837 return((oldval & 0x02) != 0);
1840 void
1841 debugger_on()
1843 outb(0xfedc, 0x01);
1846 void
1847 debugger_off()
1849 outb(0xfedc, 0x00);
1852 #if BX_USE_ATADRV
1854 // ---------------------------------------------------------------------------
1855 // Start of ATA/ATAPI Driver
1856 // ---------------------------------------------------------------------------
1858 // Global defines -- ATA register and register bits.
1859 // command block & control block regs
1860 #define ATA_CB_DATA 0 // data reg in/out pio_base_addr1+0
1861 #define ATA_CB_ERR 1 // error in pio_base_addr1+1
1862 #define ATA_CB_FR 1 // feature reg out pio_base_addr1+1
1863 #define ATA_CB_SC 2 // sector count in/out pio_base_addr1+2
1864 #define ATA_CB_SN 3 // sector number in/out pio_base_addr1+3
1865 #define ATA_CB_CL 4 // cylinder low in/out pio_base_addr1+4
1866 #define ATA_CB_CH 5 // cylinder high in/out pio_base_addr1+5
1867 #define ATA_CB_DH 6 // device head in/out pio_base_addr1+6
1868 #define ATA_CB_STAT 7 // primary status in pio_base_addr1+7
1869 #define ATA_CB_CMD 7 // command out pio_base_addr1+7
1870 #define ATA_CB_ASTAT 6 // alternate status in pio_base_addr2+6
1871 #define ATA_CB_DC 6 // device control out pio_base_addr2+6
1872 #define ATA_CB_DA 7 // device address in pio_base_addr2+7
1874 #define ATA_CB_ER_ICRC 0x80 // ATA Ultra DMA bad CRC
1875 #define ATA_CB_ER_BBK 0x80 // ATA bad block
1876 #define ATA_CB_ER_UNC 0x40 // ATA uncorrected error
1877 #define ATA_CB_ER_MC 0x20 // ATA media change
1878 #define ATA_CB_ER_IDNF 0x10 // ATA id not found
1879 #define ATA_CB_ER_MCR 0x08 // ATA media change request
1880 #define ATA_CB_ER_ABRT 0x04 // ATA command aborted
1881 #define ATA_CB_ER_NTK0 0x02 // ATA track 0 not found
1882 #define ATA_CB_ER_NDAM 0x01 // ATA address mark not found
1884 #define ATA_CB_ER_P_SNSKEY 0xf0 // ATAPI sense key (mask)
1885 #define ATA_CB_ER_P_MCR 0x08 // ATAPI Media Change Request
1886 #define ATA_CB_ER_P_ABRT 0x04 // ATAPI command abort
1887 #define ATA_CB_ER_P_EOM 0x02 // ATAPI End of Media
1888 #define ATA_CB_ER_P_ILI 0x01 // ATAPI Illegal Length Indication
1890 // ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC)
1891 #define ATA_CB_SC_P_TAG 0xf8 // ATAPI tag (mask)
1892 #define ATA_CB_SC_P_REL 0x04 // ATAPI release
1893 #define ATA_CB_SC_P_IO 0x02 // ATAPI I/O
1894 #define ATA_CB_SC_P_CD 0x01 // ATAPI C/D
1896 // bits 7-4 of the device/head (CB_DH) reg
1897 #define ATA_CB_DH_DEV0 0xa0 // select device 0
1898 #define ATA_CB_DH_DEV1 0xb0 // select device 1
1900 // status reg (CB_STAT and CB_ASTAT) bits
1901 #define ATA_CB_STAT_BSY 0x80 // busy
1902 #define ATA_CB_STAT_RDY 0x40 // ready
1903 #define ATA_CB_STAT_DF 0x20 // device fault
1904 #define ATA_CB_STAT_WFT 0x20 // write fault (old name)
1905 #define ATA_CB_STAT_SKC 0x10 // seek complete
1906 #define ATA_CB_STAT_SERV 0x10 // service
1907 #define ATA_CB_STAT_DRQ 0x08 // data request
1908 #define ATA_CB_STAT_CORR 0x04 // corrected
1909 #define ATA_CB_STAT_IDX 0x02 // index
1910 #define ATA_CB_STAT_ERR 0x01 // error (ATA)
1911 #define ATA_CB_STAT_CHK 0x01 // check (ATAPI)
1913 // device control reg (CB_DC) bits
1914 #define ATA_CB_DC_HD15 0x08 // bit should always be set to one
1915 #define ATA_CB_DC_SRST 0x04 // soft reset
1916 #define ATA_CB_DC_NIEN 0x02 // disable interrupts
1918 // Most mandtory and optional ATA commands (from ATA-3),
1919 #define ATA_CMD_CFA_ERASE_SECTORS 0xC0
1920 #define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03
1921 #define ATA_CMD_CFA_TRANSLATE_SECTOR 0x87
1922 #define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD
1923 #define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38
1924 #define ATA_CMD_CHECK_POWER_MODE1 0xE5
1925 #define ATA_CMD_CHECK_POWER_MODE2 0x98
1926 #define ATA_CMD_DEVICE_RESET 0x08
1927 #define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90
1928 #define ATA_CMD_FLUSH_CACHE 0xE7
1929 #define ATA_CMD_FORMAT_TRACK 0x50
1930 #define ATA_CMD_IDENTIFY_DEVICE 0xEC
1931 #define ATA_CMD_IDENTIFY_DEVICE_PACKET 0xA1
1932 #define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xA1
1933 #define ATA_CMD_IDLE1 0xE3
1934 #define ATA_CMD_IDLE2 0x97
1935 #define ATA_CMD_IDLE_IMMEDIATE1 0xE1
1936 #define ATA_CMD_IDLE_IMMEDIATE2 0x95
1937 #define ATA_CMD_INITIALIZE_DRIVE_PARAMETERS 0x91
1938 #define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
1939 #define ATA_CMD_NOP 0x00
1940 #define ATA_CMD_PACKET 0xA0
1941 #define ATA_CMD_READ_BUFFER 0xE4
1942 #define ATA_CMD_READ_DMA 0xC8
1943 #define ATA_CMD_READ_DMA_QUEUED 0xC7
1944 #define ATA_CMD_READ_MULTIPLE 0xC4
1945 #define ATA_CMD_READ_SECTORS 0x20
1946 #define ATA_CMD_READ_VERIFY_SECTORS 0x40
1947 #define ATA_CMD_RECALIBRATE 0x10
1948 #define ATA_CMD_SEEK 0x70
1949 #define ATA_CMD_SET_FEATURES 0xEF
1950 #define ATA_CMD_SET_MULTIPLE_MODE 0xC6
1951 #define ATA_CMD_SLEEP1 0xE6
1952 #define ATA_CMD_SLEEP2 0x99
1953 #define ATA_CMD_STANDBY1 0xE2
1954 #define ATA_CMD_STANDBY2 0x96
1955 #define ATA_CMD_STANDBY_IMMEDIATE1 0xE0
1956 #define ATA_CMD_STANDBY_IMMEDIATE2 0x94
1957 #define ATA_CMD_WRITE_BUFFER 0xE8
1958 #define ATA_CMD_WRITE_DMA 0xCA
1959 #define ATA_CMD_WRITE_DMA_QUEUED 0xCC
1960 #define ATA_CMD_WRITE_MULTIPLE 0xC5
1961 #define ATA_CMD_WRITE_SECTORS 0x30
1962 #define ATA_CMD_WRITE_VERIFY 0x3C
1964 #define ATA_IFACE_NONE 0x00
1965 #define ATA_IFACE_ISA 0x00
1966 #define ATA_IFACE_PCI 0x01
1968 #define ATA_TYPE_NONE 0x00
1969 #define ATA_TYPE_UNKNOWN 0x01
1970 #define ATA_TYPE_ATA 0x02
1971 #define ATA_TYPE_ATAPI 0x03
1973 #define ATA_DEVICE_NONE 0x00
1974 #define ATA_DEVICE_HD 0xFF
1975 #define ATA_DEVICE_CDROM 0x05
1977 #define ATA_MODE_NONE 0x00
1978 #define ATA_MODE_PIO16 0x00
1979 #define ATA_MODE_PIO32 0x01
1980 #define ATA_MODE_ISADMA 0x02
1981 #define ATA_MODE_PCIDMA 0x03
1982 #define ATA_MODE_USEIRQ 0x10
1984 #define ATA_TRANSLATION_NONE 0
1985 #define ATA_TRANSLATION_LBA 1
1986 #define ATA_TRANSLATION_LARGE 2
1987 #define ATA_TRANSLATION_RECHS 3
1989 #define ATA_DATA_NO 0x00
1990 #define ATA_DATA_IN 0x01
1991 #define ATA_DATA_OUT 0x02
1993 // ---------------------------------------------------------------------------
1994 // ATA/ATAPI driver : initialization
1995 // ---------------------------------------------------------------------------
1996 void ata_init( )
1998 Bit16u ebda_seg=read_word(0x0040,0x000E);
1999 Bit8u channel, device;
2001 // Channels info init.
2002 for (channel=0; channel<BX_MAX_ATA_INTERFACES; channel++) {
2003 write_byte(ebda_seg,&EbdaData->ata.channels[channel].iface,ATA_IFACE_NONE);
2004 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1,0x0);
2005 write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2,0x0);
2006 write_byte(ebda_seg,&EbdaData->ata.channels[channel].irq,0);
2009 // Devices info init.
2010 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2011 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
2012 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_NONE);
2013 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable,0);
2014 write_byte(ebda_seg,&EbdaData->ata.devices[device].lock,0);
2015 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode,ATA_MODE_NONE);
2016 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,0);
2017 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation,ATA_TRANSLATION_NONE);
2018 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads,0);
2019 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders,0);
2020 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt,0);
2021 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads,0);
2022 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders,0);
2023 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt,0);
2025 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors,0L);
2028 // hdidmap and cdidmap init.
2029 for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2030 write_byte(ebda_seg,&EbdaData->ata.hdidmap[device],BX_MAX_ATA_DEVICES);
2031 write_byte(ebda_seg,&EbdaData->ata.cdidmap[device],BX_MAX_ATA_DEVICES);
2034 write_byte(ebda_seg,&EbdaData->ata.hdcount,0);
2035 write_byte(ebda_seg,&EbdaData->ata.cdcount,0);
2038 // ---------------------------------------------------------------------------
2039 // ATA/ATAPI driver : device detection
2040 // ---------------------------------------------------------------------------
2042 void ata_detect( )
2044 Bit16u ebda_seg=read_word(0x0040,0x000E);
2045 Bit8u hdcount, cdcount, device, type;
2046 Bit8u buffer[0x0200];
2048 #if BX_MAX_ATA_INTERFACES > 0
2049 write_byte(ebda_seg,&EbdaData->ata.channels[0].iface,ATA_IFACE_ISA);
2050 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase1,0x1f0);
2051 write_word(ebda_seg,&EbdaData->ata.channels[0].iobase2,0x3f0);
2052 write_byte(ebda_seg,&EbdaData->ata.channels[0].irq,14);
2053 #endif
2054 #if BX_MAX_ATA_INTERFACES > 1
2055 write_byte(ebda_seg,&EbdaData->ata.channels[1].iface,ATA_IFACE_ISA);
2056 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase1,0x170);
2057 write_word(ebda_seg,&EbdaData->ata.channels[1].iobase2,0x370);
2058 write_byte(ebda_seg,&EbdaData->ata.channels[1].irq,15);
2059 #endif
2060 #if BX_MAX_ATA_INTERFACES > 2
2061 write_byte(ebda_seg,&EbdaData->ata.channels[2].iface,ATA_IFACE_ISA);
2062 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase1,0x1e8);
2063 write_word(ebda_seg,&EbdaData->ata.channels[2].iobase2,0x3e0);
2064 write_byte(ebda_seg,&EbdaData->ata.channels[2].irq,12);
2065 #endif
2066 #if BX_MAX_ATA_INTERFACES > 3
2067 write_byte(ebda_seg,&EbdaData->ata.channels[3].iface,ATA_IFACE_ISA);
2068 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase1,0x168);
2069 write_word(ebda_seg,&EbdaData->ata.channels[3].iobase2,0x360);
2070 write_byte(ebda_seg,&EbdaData->ata.channels[3].irq,11);
2071 #endif
2072 #if BX_MAX_ATA_INTERFACES > 4
2073 #error Please fill the ATA interface informations
2074 #endif
2076 // Device detection
2077 hdcount=cdcount=0;
2079 for(device=0; device<BX_MAX_ATA_DEVICES; device++) {
2080 Bit16u iobase1, iobase2;
2081 Bit8u channel, slave, shift;
2082 Bit8u sc, sn, cl, ch, st;
2084 channel = device / 2;
2085 slave = device % 2;
2087 iobase1 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1);
2088 iobase2 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2);
2090 // Disable interrupts
2091 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2093 // Look for device
2094 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2095 outb(iobase1+ATA_CB_SC, 0x55);
2096 outb(iobase1+ATA_CB_SN, 0xaa);
2097 outb(iobase1+ATA_CB_SC, 0xaa);
2098 outb(iobase1+ATA_CB_SN, 0x55);
2099 outb(iobase1+ATA_CB_SC, 0x55);
2100 outb(iobase1+ATA_CB_SN, 0xaa);
2102 // If we found something
2103 sc = inb(iobase1+ATA_CB_SC);
2104 sn = inb(iobase1+ATA_CB_SN);
2106 if ( (sc == 0x55) && (sn == 0xaa) ) {
2107 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_UNKNOWN);
2109 // reset the channel
2110 ata_reset (device);
2112 // check for ATA or ATAPI
2113 outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2114 sc = inb(iobase1+ATA_CB_SC);
2115 sn = inb(iobase1+ATA_CB_SN);
2116 if ( (sc==0x01) && (sn==0x01) ) {
2117 cl = inb(iobase1+ATA_CB_CL);
2118 ch = inb(iobase1+ATA_CB_CH);
2119 st = inb(iobase1+ATA_CB_STAT);
2121 if ( (cl==0x14) && (ch==0xeb) ) {
2122 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATAPI);
2124 else if ( (cl==0x00) && (ch==0x00) && (st!=0x00) ) {
2125 write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATA);
2130 type=read_byte(ebda_seg,&EbdaData->ata.devices[device].type);
2132 // Now we send a IDENTIFY command to ATA device
2133 if(type == ATA_TYPE_ATA) {
2134 Bit32u sectors;
2135 Bit16u cylinders, heads, spt, blksize;
2136 Bit8u translation, removable, mode;
2138 //Temporary values to do the transfer
2139 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2140 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2142 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE, 1, 0, 0, 0, 0L, get_SS(),buffer) !=0 )
2143 BX_PANIC("ata-detect: Failed to detect ATA device\n");
2145 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2146 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2147 blksize = read_word(get_SS(),buffer+10);
2149 cylinders = read_word(get_SS(),buffer+(1*2)); // word 1
2150 heads = read_word(get_SS(),buffer+(3*2)); // word 3
2151 spt = read_word(get_SS(),buffer+(6*2)); // word 6
2153 sectors = read_dword(get_SS(),buffer+(60*2)); // word 60 and word 61
2155 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2156 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2157 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2158 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2159 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads, heads);
2160 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders, cylinders);
2161 write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt, spt);
2162 write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors, sectors);
2163 BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel, slave,cylinders, heads, spt);
2165 translation = inb_cmos(0x39 + channel/2);
2166 for (shift=device%4; shift>0; shift--) translation >>= 2;
2167 translation &= 0x03;
2169 write_byte(ebda_seg,&EbdaData->ata.devices[device].translation, translation);
2171 switch (translation) {
2172 case ATA_TRANSLATION_NONE:
2173 BX_INFO("none");
2174 break;
2175 case ATA_TRANSLATION_LBA:
2176 BX_INFO("lba");
2177 break;
2178 case ATA_TRANSLATION_LARGE:
2179 BX_INFO("large");
2180 break;
2181 case ATA_TRANSLATION_RECHS:
2182 BX_INFO("r-echs");
2183 break;
2185 switch (translation) {
2186 case ATA_TRANSLATION_NONE:
2187 break;
2188 case ATA_TRANSLATION_LBA:
2189 spt = 63;
2190 sectors /= 63;
2191 heads = sectors / 1024;
2192 if (heads>128) heads = 255;
2193 else if (heads>64) heads = 128;
2194 else if (heads>32) heads = 64;
2195 else if (heads>16) heads = 32;
2196 else heads=16;
2197 cylinders = sectors / heads;
2198 break;
2199 case ATA_TRANSLATION_RECHS:
2200 // Take care not to overflow
2201 if (heads==16) {
2202 if(cylinders>61439) cylinders=61439;
2203 heads=15;
2204 cylinders = (Bit16u)((Bit32u)(cylinders)*16/15);
2206 // then go through the large bitshift process
2207 case ATA_TRANSLATION_LARGE:
2208 while(cylinders > 1024) {
2209 cylinders >>= 1;
2210 heads <<= 1;
2212 // If we max out the head count
2213 if (heads > 127) break;
2215 break;
2217 // clip to 1024 cylinders in lchs
2218 if (cylinders > 1024) cylinders=1024;
2219 BX_INFO(" LCHS=%d/%d/%d\n", cylinders, heads, spt);
2221 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, heads);
2222 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, cylinders);
2223 write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, spt);
2225 // fill hdidmap
2226 write_byte(ebda_seg,&EbdaData->ata.hdidmap[hdcount], device);
2227 hdcount++;
2230 // Now we send a IDENTIFY command to ATAPI device
2231 if(type == ATA_TYPE_ATAPI) {
2233 Bit8u type, removable, mode;
2234 Bit16u blksize;
2236 //Temporary values to do the transfer
2237 write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_CDROM);
2238 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2240 if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE_PACKET, 1, 0, 0, 0, 0L, get_SS(),buffer) != 0)
2241 BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
2243 type = read_byte(get_SS(),buffer+1) & 0x1f;
2244 removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2245 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2246 blksize = 2048;
2248 write_byte(ebda_seg,&EbdaData->ata.devices[device].device, type);
2249 write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2250 write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2251 write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2253 // fill cdidmap
2254 write_byte(ebda_seg,&EbdaData->ata.cdidmap[cdcount], device);
2255 cdcount++;
2259 Bit32u sizeinmb;
2260 Bit16u ataversion;
2261 Bit8u c, i, version, model[41];
2263 switch (type) {
2264 case ATA_TYPE_ATA:
2265 sizeinmb = read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors);
2266 sizeinmb >>= 11;
2267 case ATA_TYPE_ATAPI:
2268 // Read ATA/ATAPI version
2269 ataversion=((Bit16u)(read_byte(get_SS(),buffer+161))<<8)|read_byte(get_SS(),buffer+160);
2270 for(version=15;version>0;version--) {
2271 if((ataversion&(1<<version))!=0)
2272 break;
2275 // Read model name
2276 for(i=0;i<20;i++){
2277 write_byte(get_SS(),model+(i*2),read_byte(get_SS(),buffer+(i*2)+54+1));
2278 write_byte(get_SS(),model+(i*2)+1,read_byte(get_SS(),buffer+(i*2)+54));
2281 // Reformat
2282 write_byte(get_SS(),model+40,0x00);
2283 for(i=39;i>0;i--){
2284 if(read_byte(get_SS(),model+i)==0x20)
2285 write_byte(get_SS(),model+i,0x00);
2286 else break;
2288 break;
2291 switch (type) {
2292 case ATA_TYPE_ATA:
2293 printf("ata%d %s: ",channel,slave?" slave":"master");
2294 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2295 printf(" ATA-%d Hard-Disk (%d MBytes)\n",version,(Bit16u)sizeinmb);
2296 break;
2297 case ATA_TYPE_ATAPI:
2298 printf("ata%d %s: ",channel,slave?" slave":"master");
2299 i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2300 if(read_byte(ebda_seg,&EbdaData->ata.devices[device].device)==ATA_DEVICE_CDROM)
2301 printf(" ATAPI-%d CD-Rom/DVD-Rom\n",version);
2302 else
2303 printf(" ATAPI-%d Device\n",version);
2304 break;
2305 case ATA_TYPE_UNKNOWN:
2306 printf("ata%d %s: Unknown device\n",channel,slave?" slave":"master");
2307 break;
2312 // Store the devices counts
2313 write_byte(ebda_seg,&EbdaData->ata.hdcount, hdcount);
2314 write_byte(ebda_seg,&EbdaData->ata.cdcount, cdcount);
2315 write_byte(0x40,0x75, hdcount);
2317 printf("\n");
2319 // FIXME : should use bios=cmos|auto|disable bits
2320 // FIXME : should know about translation bits
2321 // FIXME : move hard_drive_post here
2325 // ---------------------------------------------------------------------------
2326 // ATA/ATAPI driver : software reset
2327 // ---------------------------------------------------------------------------
2328 // ATA-3
2329 // 8.2.1 Software reset - Device 0
2331 void ata_reset(device)
2332 Bit16u device;
2334 Bit16u ebda_seg=read_word(0x0040,0x000E);
2335 Bit16u iobase1, iobase2;
2336 Bit8u channel, slave, sn, sc;
2337 Bit16u max;
2339 channel = device / 2;
2340 slave = device % 2;
2342 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2343 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2345 // Reset
2347 // 8.2.1 (a) -- set SRST in DC
2348 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN | ATA_CB_DC_SRST);
2350 // 8.2.1 (b) -- wait for BSY
2351 max=0xff;
2352 while(--max>0) {
2353 Bit8u status = inb(iobase1+ATA_CB_STAT);
2354 if ((status & ATA_CB_STAT_BSY) != 0) break;
2357 // 8.2.1 (f) -- clear SRST
2358 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2360 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_NONE) {
2362 // 8.2.1 (g) -- check for sc==sn==0x01
2363 // select device
2364 outb(iobase1+ATA_CB_DH, slave?ATA_CB_DH_DEV1:ATA_CB_DH_DEV0);
2365 sc = inb(iobase1+ATA_CB_SC);
2366 sn = inb(iobase1+ATA_CB_SN);
2368 if ( (sc==0x01) && (sn==0x01) ) {
2370 // 8.2.1 (h) -- wait for not BSY
2371 max=0xff;
2372 while(--max>0) {
2373 Bit8u status = inb(iobase1+ATA_CB_STAT);
2374 if ((status & ATA_CB_STAT_BSY) == 0) break;
2379 // 8.2.1 (i) -- wait for DRDY
2380 max=0xfff;
2381 while(--max>0) {
2382 Bit8u status = inb(iobase1+ATA_CB_STAT);
2383 if ((status & ATA_CB_STAT_RDY) != 0) break;
2386 // Enable interrupts
2387 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2390 // ---------------------------------------------------------------------------
2391 // ATA/ATAPI driver : execute a non data command
2392 // ---------------------------------------------------------------------------
2394 Bit16u ata_cmd_non_data()
2395 {return 0;}
2397 // ---------------------------------------------------------------------------
2398 // ATA/ATAPI driver : execute a data-in command
2399 // ---------------------------------------------------------------------------
2400 // returns
2401 // 0 : no error
2402 // 1 : BUSY bit set
2403 // 2 : read error
2404 // 3 : expected DRQ=1
2405 // 4 : no sectors left to read/verify
2406 // 5 : more sectors to read/verify
2407 // 6 : no sectors left to write
2408 // 7 : more sectors to write
2409 Bit16u ata_cmd_data_in(device, command, count, cylinder, head, sector, lba, segment, offset)
2410 Bit16u device, command, count, cylinder, head, sector, segment, offset;
2411 Bit32u lba;
2413 Bit16u ebda_seg=read_word(0x0040,0x000E);
2414 Bit16u iobase1, iobase2, blksize;
2415 Bit8u channel, slave;
2416 Bit8u status, current, mode;
2418 channel = device / 2;
2419 slave = device % 2;
2421 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2422 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2423 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2424 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2425 if (mode == ATA_MODE_PIO32) blksize>>=2;
2426 else blksize>>=1;
2428 // sector will be 0 only on lba access. Convert to lba-chs
2429 if (sector == 0) {
2430 sector = (Bit16u) (lba & 0x000000ffL);
2431 lba >>= 8;
2432 cylinder = (Bit16u) (lba & 0x0000ffffL);
2433 lba >>= 16;
2434 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
2437 // Reset count of transferred data
2438 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2439 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2440 current = 0;
2442 status = inb(iobase1 + ATA_CB_STAT);
2443 if (status & ATA_CB_STAT_BSY) return 1;
2445 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2446 outb(iobase1 + ATA_CB_FR, 0x00);
2447 outb(iobase1 + ATA_CB_SC, count);
2448 outb(iobase1 + ATA_CB_SN, sector);
2449 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2450 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2451 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
2452 outb(iobase1 + ATA_CB_CMD, command);
2454 while (1) {
2455 status = inb(iobase1 + ATA_CB_STAT);
2456 if ( !(status & ATA_CB_STAT_BSY) ) break;
2459 if (status & ATA_CB_STAT_ERR) {
2460 BX_DEBUG_ATA("ata_cmd_data_in : read error\n");
2461 return 2;
2462 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2463 BX_DEBUG_ATA("ata_cmd_data_in : DRQ not set (status %02x)\n", (unsigned) status);
2464 return 3;
2467 // FIXME : move seg/off translation here
2469 ASM_START
2470 sti ;; enable higher priority interrupts
2471 ASM_END
2473 while (1) {
2475 ASM_START
2476 push bp
2477 mov bp, sp
2478 mov di, _ata_cmd_data_in.offset + 2[bp]
2479 mov ax, _ata_cmd_data_in.segment + 2[bp]
2480 mov cx, _ata_cmd_data_in.blksize + 2[bp]
2482 ;; adjust if there will be an overrun. 2K max sector size
2483 cmp di, #0xf800 ;;
2484 jbe ata_in_no_adjust
2486 ata_in_adjust:
2487 sub di, #0x0800 ;; sub 2 kbytes from offset
2488 add ax, #0x0080 ;; add 2 Kbytes to segment
2490 ata_in_no_adjust:
2491 mov es, ax ;; segment in es
2493 mov dx, _ata_cmd_data_in.iobase1 + 2[bp] ;; ATA data read port
2495 mov ah, _ata_cmd_data_in.mode + 2[bp]
2496 cmp ah, #ATA_MODE_PIO32
2497 je ata_in_32
2499 ata_in_16:
2501 insw ;; CX words transfered from port(DX) to ES:[DI]
2502 jmp ata_in_done
2504 ata_in_32:
2506 insd ;; CX dwords transfered from port(DX) to ES:[DI]
2508 ata_in_done:
2509 mov _ata_cmd_data_in.offset + 2[bp], di
2510 mov _ata_cmd_data_in.segment + 2[bp], es
2511 pop bp
2512 ASM_END
2514 current++;
2515 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
2516 count--;
2517 status = inb(iobase1 + ATA_CB_STAT);
2518 if (count == 0) {
2519 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2520 != ATA_CB_STAT_RDY ) {
2521 BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n", (unsigned) status);
2522 return 4;
2524 break;
2526 else {
2527 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2528 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
2529 BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n", (unsigned) status);
2530 return 5;
2532 continue;
2535 // Enable interrupts
2536 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2537 return 0;
2540 // ---------------------------------------------------------------------------
2541 // ATA/ATAPI driver : execute a data-out command
2542 // ---------------------------------------------------------------------------
2543 // returns
2544 // 0 : no error
2545 // 1 : BUSY bit set
2546 // 2 : read error
2547 // 3 : expected DRQ=1
2548 // 4 : no sectors left to read/verify
2549 // 5 : more sectors to read/verify
2550 // 6 : no sectors left to write
2551 // 7 : more sectors to write
2552 Bit16u ata_cmd_data_out(device, command, count, cylinder, head, sector, lba, segment, offset)
2553 Bit16u device, command, count, cylinder, head, sector, segment, offset;
2554 Bit32u lba;
2556 Bit16u ebda_seg=read_word(0x0040,0x000E);
2557 Bit16u iobase1, iobase2, blksize;
2558 Bit8u channel, slave;
2559 Bit8u status, current, mode;
2561 channel = device / 2;
2562 slave = device % 2;
2564 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2565 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2566 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2567 blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2568 if (mode == ATA_MODE_PIO32) blksize>>=2;
2569 else blksize>>=1;
2571 // sector will be 0 only on lba access. Convert to lba-chs
2572 if (sector == 0) {
2573 sector = (Bit16u) (lba & 0x000000ffL);
2574 lba >>= 8;
2575 cylinder = (Bit16u) (lba & 0x0000ffffL);
2576 lba >>= 16;
2577 head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
2580 // Reset count of transferred data
2581 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2582 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2583 current = 0;
2585 status = inb(iobase1 + ATA_CB_STAT);
2586 if (status & ATA_CB_STAT_BSY) return 1;
2588 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2589 outb(iobase1 + ATA_CB_FR, 0x00);
2590 outb(iobase1 + ATA_CB_SC, count);
2591 outb(iobase1 + ATA_CB_SN, sector);
2592 outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2593 outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2594 outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
2595 outb(iobase1 + ATA_CB_CMD, command);
2597 while (1) {
2598 status = inb(iobase1 + ATA_CB_STAT);
2599 if ( !(status & ATA_CB_STAT_BSY) ) break;
2602 if (status & ATA_CB_STAT_ERR) {
2603 BX_DEBUG_ATA("ata_cmd_data_out : read error\n");
2604 return 2;
2605 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2606 BX_DEBUG_ATA("ata_cmd_data_out : DRQ not set (status %02x)\n", (unsigned) status);
2607 return 3;
2610 // FIXME : move seg/off translation here
2612 ASM_START
2613 sti ;; enable higher priority interrupts
2614 ASM_END
2616 while (1) {
2618 ASM_START
2619 push bp
2620 mov bp, sp
2621 mov si, _ata_cmd_data_out.offset + 2[bp]
2622 mov ax, _ata_cmd_data_out.segment + 2[bp]
2623 mov cx, _ata_cmd_data_out.blksize + 2[bp]
2625 ;; adjust if there will be an overrun. 2K max sector size
2626 cmp si, #0xf800 ;;
2627 jbe ata_out_no_adjust
2629 ata_out_adjust:
2630 sub si, #0x0800 ;; sub 2 kbytes from offset
2631 add ax, #0x0080 ;; add 2 Kbytes to segment
2633 ata_out_no_adjust:
2634 mov es, ax ;; segment in es
2636 mov dx, _ata_cmd_data_out.iobase1 + 2[bp] ;; ATA data write port
2638 mov ah, _ata_cmd_data_out.mode + 2[bp]
2639 cmp ah, #ATA_MODE_PIO32
2640 je ata_out_32
2642 ata_out_16:
2643 seg ES
2645 outsw ;; CX words transfered from port(DX) to ES:[SI]
2646 jmp ata_out_done
2648 ata_out_32:
2649 seg ES
2651 outsd ;; CX dwords transfered from port(DX) to ES:[SI]
2653 ata_out_done:
2654 mov _ata_cmd_data_out.offset + 2[bp], si
2655 mov _ata_cmd_data_out.segment + 2[bp], es
2656 pop bp
2657 ASM_END
2659 current++;
2660 write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
2661 count--;
2662 status = inb(iobase1 + ATA_CB_STAT);
2663 if (count == 0) {
2664 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2665 != ATA_CB_STAT_RDY ) {
2666 BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n", (unsigned) status);
2667 return 6;
2669 break;
2671 else {
2672 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2673 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
2674 BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n", (unsigned) status);
2675 return 7;
2677 continue;
2680 // Enable interrupts
2681 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2682 return 0;
2685 // ---------------------------------------------------------------------------
2686 // ATA/ATAPI driver : execute a packet command
2687 // ---------------------------------------------------------------------------
2688 // returns
2689 // 0 : no error
2690 // 1 : error in parameters
2691 // 2 : BUSY bit set
2692 // 3 : error
2693 // 4 : not ready
2694 Bit16u ata_cmd_packet(device, cmdlen, cmdseg, cmdoff, header, length, inout, bufseg, bufoff)
2695 Bit8u cmdlen,inout;
2696 Bit16u device,cmdseg, cmdoff, bufseg, bufoff;
2697 Bit16u header;
2698 Bit32u length;
2700 Bit16u ebda_seg=read_word(0x0040,0x000E);
2701 Bit16u iobase1, iobase2;
2702 Bit16u lcount, lbefore, lafter, count;
2703 Bit8u channel, slave;
2704 Bit8u status, mode, lmode;
2705 Bit32u total, transfer;
2707 channel = device / 2;
2708 slave = device % 2;
2710 // Data out is not supported yet
2711 if (inout == ATA_DATA_OUT) {
2712 BX_INFO("ata_cmd_packet: DATA_OUT not supported yet");
2713 return 1;
2716 // The header length must be even
2717 if (header & 1) {
2718 BX_DEBUG_ATA("ata_cmd_packet : header must be even (%04x)\n",header);
2719 return 1;
2722 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2723 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2724 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2725 transfer= 0L;
2727 if (cmdlen < 12) cmdlen=12;
2728 if (cmdlen > 12) cmdlen=16;
2729 cmdlen>>=1;
2731 // Reset count of transferred data
2732 write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2733 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2735 status = inb(iobase1 + ATA_CB_STAT);
2736 if (status & ATA_CB_STAT_BSY) return 2;
2738 outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2739 // outb(iobase1 + ATA_CB_FR, 0x00);
2740 // outb(iobase1 + ATA_CB_SC, 0x00);
2741 // outb(iobase1 + ATA_CB_SN, 0x00);
2742 outb(iobase1 + ATA_CB_CL, 0xfff0 & 0x00ff);
2743 outb(iobase1 + ATA_CB_CH, 0xfff0 >> 8);
2744 outb(iobase1 + ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2745 outb(iobase1 + ATA_CB_CMD, ATA_CMD_PACKET);
2747 // Device should ok to receive command
2748 while (1) {
2749 status = inb(iobase1 + ATA_CB_STAT);
2750 if ( !(status & ATA_CB_STAT_BSY) ) break;
2753 if (status & ATA_CB_STAT_ERR) {
2754 BX_DEBUG_ATA("ata_cmd_packet : error, status is %02x\n",status);
2755 return 3;
2756 } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2757 BX_DEBUG_ATA("ata_cmd_packet : DRQ not set (status %02x)\n", (unsigned) status);
2758 return 4;
2761 // Normalize address
2762 cmdseg += (cmdoff / 16);
2763 cmdoff %= 16;
2765 // Send command to device
2766 ASM_START
2767 sti ;; enable higher priority interrupts
2769 push bp
2770 mov bp, sp
2772 mov si, _ata_cmd_packet.cmdoff + 2[bp]
2773 mov ax, _ata_cmd_packet.cmdseg + 2[bp]
2774 mov cx, _ata_cmd_packet.cmdlen + 2[bp]
2775 mov es, ax ;; segment in es
2777 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data write port
2779 seg ES
2781 outsw ;; CX words transfered from port(DX) to ES:[SI]
2783 pop bp
2784 ASM_END
2786 if (inout == ATA_DATA_NO) {
2787 status = inb(iobase1 + ATA_CB_STAT);
2789 else {
2790 while (1) {
2792 status = inb(iobase1 + ATA_CB_STAT);
2794 // Check if command completed
2795 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_DRQ) ) ==0 ) break;
2797 if (status & ATA_CB_STAT_ERR) {
2798 BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status);
2799 return 3;
2802 // Device must be ready to send data
2803 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2804 != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
2805 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", status);
2806 return 4;
2809 // Normalize address
2810 bufseg += (bufoff / 16);
2811 bufoff %= 16;
2813 // Get the byte count
2814 lcount = ((Bit16u)(inb(iobase1 + ATA_CB_CH))<<8)+inb(iobase1 + ATA_CB_CL);
2816 // adjust to read what we want
2817 if(header>lcount) {
2818 lbefore=lcount;
2819 header-=lcount;
2820 lcount=0;
2822 else {
2823 lbefore=header;
2824 header=0;
2825 lcount-=lbefore;
2828 if(lcount>length) {
2829 lafter=lcount-length;
2830 lcount=length;
2831 length=0;
2833 else {
2834 lafter=0;
2835 length-=lcount;
2838 // Save byte count
2839 count = lcount;
2841 BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore+lcount+lafter,lbefore,lcount,lafter);
2842 BX_DEBUG_ATA("to 0x%04x:0x%04x\n",bufseg,bufoff);
2844 // If counts not dividable by 4, use 16bits mode
2845 lmode = mode;
2846 if (lbefore & 0x03) lmode=ATA_MODE_PIO16;
2847 if (lcount & 0x03) lmode=ATA_MODE_PIO16;
2848 if (lafter & 0x03) lmode=ATA_MODE_PIO16;
2850 // adds an extra byte if count are odd. before is always even
2851 if (lcount & 0x01) {
2852 lcount+=1;
2853 if ((lafter > 0) && (lafter & 0x01)) {
2854 lafter-=1;
2858 if (lmode == ATA_MODE_PIO32) {
2859 lcount>>=2; lbefore>>=2; lafter>>=2;
2861 else {
2862 lcount>>=1; lbefore>>=1; lafter>>=1;
2865 ; // FIXME bcc bug
2867 ASM_START
2868 push bp
2869 mov bp, sp
2871 mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data read port
2873 mov cx, _ata_cmd_packet.lbefore + 2[bp]
2874 jcxz ata_packet_no_before
2876 mov ah, _ata_cmd_packet.lmode + 2[bp]
2877 cmp ah, #ATA_MODE_PIO32
2878 je ata_packet_in_before_32
2880 ata_packet_in_before_16:
2881 in ax, dx
2882 loop ata_packet_in_before_16
2883 jmp ata_packet_no_before
2885 ata_packet_in_before_32:
2886 in eax, dx
2887 loop ata_packet_in_before_32
2889 ata_packet_no_before:
2890 mov cx, _ata_cmd_packet.lcount + 2[bp]
2891 jcxz ata_packet_after
2893 mov di, _ata_cmd_packet.bufoff + 2[bp]
2894 mov ax, _ata_cmd_packet.bufseg + 2[bp]
2895 mov es, ax
2897 mov ah, _ata_cmd_packet.lmode + 2[bp]
2898 cmp ah, #ATA_MODE_PIO32
2899 je ata_packet_in_32
2901 ata_packet_in_16:
2903 insw ;; CX words transfered tp port(DX) to ES:[DI]
2904 jmp ata_packet_after
2906 ata_packet_in_32:
2908 insd ;; CX dwords transfered to port(DX) to ES:[DI]
2910 ata_packet_after:
2911 mov cx, _ata_cmd_packet.lafter + 2[bp]
2912 jcxz ata_packet_done
2914 mov ah, _ata_cmd_packet.lmode + 2[bp]
2915 cmp ah, #ATA_MODE_PIO32
2916 je ata_packet_in_after_32
2918 ata_packet_in_after_16:
2919 in ax, dx
2920 loop ata_packet_in_after_16
2921 jmp ata_packet_done
2923 ata_packet_in_after_32:
2924 in eax, dx
2925 loop ata_packet_in_after_32
2927 ata_packet_done:
2928 pop bp
2929 ASM_END
2931 // Compute new buffer address
2932 bufoff += count;
2934 // Save transferred bytes count
2935 transfer += count;
2936 write_dword(ebda_seg, &EbdaData->ata.trsfbytes,transfer);
2940 // Final check, device must be ready
2941 if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
2942 != ATA_CB_STAT_RDY ) {
2943 BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", (unsigned) status);
2944 return 4;
2947 // Enable interrupts
2948 outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2949 return 0;
2952 // ---------------------------------------------------------------------------
2953 // End of ATA/ATAPI Driver
2954 // ---------------------------------------------------------------------------
2956 // ---------------------------------------------------------------------------
2957 // Start of ATA/ATAPI generic functions
2958 // ---------------------------------------------------------------------------
2960 Bit16u
2961 atapi_get_sense(device)
2962 Bit16u device;
2964 Bit8u atacmd[12];
2965 Bit8u buffer[16];
2966 Bit8u i;
2968 memsetb(get_SS(),atacmd,0,12);
2970 // Request SENSE
2971 atacmd[0]=0x03;
2972 atacmd[4]=0x20;
2973 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 16L, ATA_DATA_IN, get_SS(), buffer) != 0)
2974 return 0x0002;
2976 if ((buffer[0] & 0x7e) == 0x70) {
2977 return (((Bit16u)buffer[2]&0x0f)*0x100)+buffer[12];
2980 return 0;
2983 Bit16u
2984 atapi_is_ready(device)
2985 Bit16u device;
2987 Bit8u atacmd[12];
2988 Bit8u buffer[];
2990 memsetb(get_SS(),atacmd,0,12);
2992 // Test Unit Ready
2993 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
2994 return 0x000f;
2996 if (atapi_get_sense(device) !=0 ) {
2997 memsetb(get_SS(),atacmd,0,12);
2999 // try to send Test Unit Ready again
3000 if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3001 return 0x000f;
3003 return atapi_get_sense(device);
3005 return 0;
3008 Bit16u
3009 atapi_is_cdrom(device)
3010 Bit8u device;
3012 Bit16u ebda_seg=read_word(0x0040,0x000E);
3014 if (device >= BX_MAX_ATA_DEVICES)
3015 return 0;
3017 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_ATAPI)
3018 return 0;
3020 if (read_byte(ebda_seg,&EbdaData->ata.devices[device].device) != ATA_DEVICE_CDROM)
3021 return 0;
3023 return 1;
3026 // ---------------------------------------------------------------------------
3027 // End of ATA/ATAPI generic functions
3028 // ---------------------------------------------------------------------------
3030 #endif // BX_USE_ATADRV
3032 #if BX_ELTORITO_BOOT
3034 // ---------------------------------------------------------------------------
3035 // Start of El-Torito boot functions
3036 // ---------------------------------------------------------------------------
3038 void
3039 cdemu_init()
3041 Bit16u ebda_seg=read_word(0x0040,0x000E);
3043 // the only important data is this one for now
3044 write_byte(ebda_seg,&EbdaData->cdemu.active,0x00);
3047 Bit8u
3048 cdemu_isactive()
3050 Bit16u ebda_seg=read_word(0x0040,0x000E);
3052 return(read_byte(ebda_seg,&EbdaData->cdemu.active));
3055 Bit8u
3056 cdemu_emulated_drive()
3058 Bit16u ebda_seg=read_word(0x0040,0x000E);
3060 return(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
3063 static char isotag[6]="CD001";
3064 static char eltorito[24]="EL TORITO SPECIFICATION";
3066 // Returns ah: emulated drive, al: error code
3068 Bit16u
3069 cdrom_boot()
3071 Bit16u ebda_seg=read_word(0x0040,0x000E);
3072 Bit8u atacmd[12], buffer[2048];
3073 Bit32u lba;
3074 Bit16u boot_segment, nbsectors, i, error;
3075 Bit8u device;
3077 // Find out the first cdrom
3078 for (device=0; device<BX_MAX_ATA_DEVICES;device++) {
3079 if (atapi_is_cdrom(device)) break;
3082 // if not found
3083 if(device >= BX_MAX_ATA_DEVICES) return 2;
3085 // Read the Boot Record Volume Descriptor
3086 memsetb(get_SS(),atacmd,0,12);
3087 atacmd[0]=0x28; // READ command
3088 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3089 atacmd[8]=(0x01 & 0x00ff); // Sectors
3090 atacmd[2]=(0x11 & 0xff000000) >> 24; // LBA
3091 atacmd[3]=(0x11 & 0x00ff0000) >> 16;
3092 atacmd[4]=(0x11 & 0x0000ff00) >> 8;
3093 atacmd[5]=(0x11 & 0x000000ff);
3094 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3095 return 3;
3097 // Validity checks
3098 if(buffer[0]!=0)return 4;
3099 for(i=0;i<5;i++){
3100 if(buffer[1+i]!=read_byte(0xf000,&isotag[i]))return 5;
3102 for(i=0;i<23;i++)
3103 if(buffer[7+i]!=read_byte(0xf000,&eltorito[i]))return 6;
3105 // ok, now we calculate the Boot catalog address
3106 lba=buffer[0x4A]*0x1000000+buffer[0x49]*0x10000+buffer[0x48]*0x100+buffer[0x47];
3108 // And we read the Boot Catalog
3109 memsetb(get_SS(),atacmd,0,12);
3110 atacmd[0]=0x28; // READ command
3111 atacmd[7]=(0x01 & 0xff00) >> 8; // Sectors
3112 atacmd[8]=(0x01 & 0x00ff); // Sectors
3113 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3114 atacmd[3]=(lba & 0x00ff0000) >> 16;
3115 atacmd[4]=(lba & 0x0000ff00) >> 8;
3116 atacmd[5]=(lba & 0x000000ff);
3117 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3118 return 7;
3120 // Validation entry
3121 if(buffer[0x00]!=0x01)return 8; // Header
3122 if(buffer[0x01]!=0x00)return 9; // Platform
3123 if(buffer[0x1E]!=0x55)return 10; // key 1
3124 if(buffer[0x1F]!=0xAA)return 10; // key 2
3126 // Initial/Default Entry
3127 if(buffer[0x20]!=0x88)return 11; // Bootable
3129 write_byte(ebda_seg,&EbdaData->cdemu.media,buffer[0x21]);
3130 if(buffer[0x21]==0){
3131 // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
3132 // Win2000 cd boot needs to know it booted from cd
3133 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0xE0);
3135 else if(buffer[0x21]<4)
3136 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x00);
3137 else
3138 write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x80);
3140 write_byte(ebda_seg,&EbdaData->cdemu.controller_index,device/2);
3141 write_byte(ebda_seg,&EbdaData->cdemu.device_spec,device%2);
3143 boot_segment=buffer[0x23]*0x100+buffer[0x22];
3144 if(boot_segment==0x0000)boot_segment=0x07C0;
3146 write_word(ebda_seg,&EbdaData->cdemu.load_segment,boot_segment);
3147 write_word(ebda_seg,&EbdaData->cdemu.buffer_segment,0x0000);
3149 nbsectors=buffer[0x27]*0x100+buffer[0x26];
3150 write_word(ebda_seg,&EbdaData->cdemu.sector_count,nbsectors);
3152 lba=buffer[0x2B]*0x1000000+buffer[0x2A]*0x10000+buffer[0x29]*0x100+buffer[0x28];
3153 write_dword(ebda_seg,&EbdaData->cdemu.ilba,lba);
3155 // And we read the image in memory
3156 memsetb(get_SS(),atacmd,0,12);
3157 atacmd[0]=0x28; // READ command
3158 atacmd[7]=((1+(nbsectors-1)/4) & 0xff00) >> 8; // Sectors
3159 atacmd[8]=((1+(nbsectors-1)/4) & 0x00ff); // Sectors
3160 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
3161 atacmd[3]=(lba & 0x00ff0000) >> 16;
3162 atacmd[4]=(lba & 0x0000ff00) >> 8;
3163 atacmd[5]=(lba & 0x000000ff);
3164 if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, nbsectors*512L, ATA_DATA_IN, boot_segment,0)) != 0)
3165 return 12;
3167 // Remember the media type
3168 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
3169 case 0x01: // 1.2M floppy
3170 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,15);
3171 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3172 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3173 break;
3174 case 0x02: // 1.44M floppy
3175 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,18);
3176 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3177 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3178 break;
3179 case 0x03: // 2.88M floppy
3180 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,36);
3181 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3182 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3183 break;
3184 case 0x04: // Harddrive
3185 write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,read_byte(boot_segment,446+6)&0x3f);
3186 write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,
3187 (read_byte(boot_segment,446+6)<<2) + read_byte(boot_segment,446+7) + 1);
3188 write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,read_byte(boot_segment,446+5) + 1);
3189 break;
3192 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0) {
3193 // Increase bios installed hardware number of devices
3194 if(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)==0x00)
3195 write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
3196 else
3197 write_byte(ebda_seg, &EbdaData->ata.hdcount, read_byte(ebda_seg, &EbdaData->ata.hdcount) + 1);
3201 // everything is ok, so from now on, the emulation is active
3202 if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0)
3203 write_byte(ebda_seg,&EbdaData->cdemu.active,0x01);
3205 // return the boot drive + no error
3206 return (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)*0x100)+0;
3209 // ---------------------------------------------------------------------------
3210 // End of El-Torito boot functions
3211 // ---------------------------------------------------------------------------
3212 #endif // BX_ELTORITO_BOOT
3214 void
3215 int14_function(regs, ds, iret_addr)
3216 pusha_regs_t regs; // regs pushed from PUSHA instruction
3217 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
3218 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
3220 Bit16u addr,timer,val16;
3221 Bit8u timeout;
3223 ASM_START
3225 ASM_END
3227 addr = read_word(0x0040, (regs.u.r16.dx << 1));
3228 timeout = read_byte(0x0040, 0x007C + regs.u.r16.dx);
3229 if ((regs.u.r16.dx < 4) && (addr > 0)) {
3230 switch (regs.u.r8.ah) {
3231 case 0:
3232 outb(addr+3, inb(addr+3) | 0x80);
3233 if (regs.u.r8.al & 0xE0 == 0) {
3234 outb(addr, 0x17);
3235 outb(addr+1, 0x04);
3236 } else {
3237 val16 = 0x600 >> ((regs.u.r8.al & 0xE0) >> 5);
3238 outb(addr, val16 & 0xFF);
3239 outb(addr+1, val16 >> 8);
3241 outb(addr+3, regs.u.r8.al & 0x1F);
3242 regs.u.r8.ah = inb(addr+5);
3243 regs.u.r8.al = inb(addr+6);
3244 ClearCF(iret_addr.flags);
3245 break;
3246 case 1:
3247 timer = read_word(0x0040, 0x006C);
3248 while (((inb(addr+5) & 0x60) != 0x60) && (timeout)) {
3249 val16 = read_word(0x0040, 0x006C);
3250 if (val16 != timer) {
3251 timer = val16;
3252 timeout--;
3255 if (timeout) outb(addr, regs.u.r8.al);
3256 regs.u.r8.ah = inb(addr+5);
3257 if (!timeout) regs.u.r8.ah |= 0x80;
3258 ClearCF(iret_addr.flags);
3259 break;
3260 case 2:
3261 timer = read_word(0x0040, 0x006C);
3262 while (((inb(addr+5) & 0x01) == 0) && (timeout)) {
3263 val16 = read_word(0x0040, 0x006C);
3264 if (val16 != timer) {
3265 timer = val16;
3266 timeout--;
3269 if (timeout) {
3270 regs.u.r8.ah = 0;
3271 regs.u.r8.al = inb(addr);
3272 } else {
3273 regs.u.r8.ah = inb(addr+5);
3275 ClearCF(iret_addr.flags);
3276 break;
3277 case 3:
3278 regs.u.r8.ah = inb(addr+5);
3279 regs.u.r8.al = inb(addr+6);
3280 ClearCF(iret_addr.flags);
3281 break;
3282 default:
3283 SetCF(iret_addr.flags); // Unsupported
3285 } else {
3286 SetCF(iret_addr.flags); // Unsupported
3290 void
3291 int15_function(regs, ES, DS, FLAGS)
3292 pusha_regs_t regs; // REGS pushed via pusha
3293 Bit16u ES, DS, FLAGS;
3295 Bit16u ebda_seg=read_word(0x0040,0x000E);
3296 bx_bool prev_a20_enable;
3297 Bit16u base15_00;
3298 Bit8u base23_16;
3299 Bit16u ss;
3300 Bit16u CX,DX;
3302 Bit16u bRegister;
3303 Bit8u irqDisable;
3305 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
3307 switch (regs.u.r8.ah) {
3308 case 0x24: /* A20 Control */
3309 switch (regs.u.r8.al) {
3310 case 0x00:
3311 set_enable_a20(0);
3312 CLEAR_CF();
3313 regs.u.r8.ah = 0;
3314 break;
3315 case 0x01:
3316 set_enable_a20(1);
3317 CLEAR_CF();
3318 regs.u.r8.ah = 0;
3319 break;
3320 case 0x02:
3321 regs.u.r8.al = (inb(0x92) >> 1) & 0x01;
3322 CLEAR_CF();
3323 regs.u.r8.ah = 0;
3324 break;
3325 case 0x03:
3326 CLEAR_CF();
3327 regs.u.r8.ah = 0;
3328 regs.u.r16.bx = 3;
3329 break;
3330 default:
3331 BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs.u.r8.al);
3332 SET_CF();
3333 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3335 break;
3337 case 0x41:
3338 SET_CF();
3339 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3340 break;
3342 case 0x4f:
3343 /* keyboard intercept */
3344 #if BX_CPU < 2
3345 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3346 #else
3347 // nop
3348 #endif
3349 SET_CF();
3350 break;
3352 case 0x52: // removable media eject
3353 CLEAR_CF();
3354 regs.u.r8.ah = 0; // "ok ejection may proceed"
3355 break;
3357 case 0x83: {
3358 if( regs.u.r8.al == 0 ) {
3359 // Set Interval requested.
3360 if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
3361 // Interval not already set.
3362 write_byte( 0x40, 0xA0, 1 ); // Set status byte.
3363 write_word( 0x40, 0x98, ES ); // Byte location, segment
3364 write_word( 0x40, 0x9A, regs.u.r16.bx ); // Byte location, offset
3365 write_word( 0x40, 0x9C, regs.u.r16.dx ); // Low word, delay
3366 write_word( 0x40, 0x9E, regs.u.r16.cx ); // High word, delay.
3367 CLEAR_CF( );
3368 irqDisable = inb( 0xA1 );
3369 outb( 0xA1, irqDisable & 0xFE );
3370 bRegister = inb_cmos( 0xB ); // Unmask IRQ8 so INT70 will get through.
3371 outb_cmos( 0xB, bRegister | 0x40 ); // Turn on the Periodic Interrupt timer
3372 } else {
3373 // Interval already set.
3374 BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
3375 SET_CF();
3376 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3378 } else if( regs.u.r8.al == 1 ) {
3379 // Clear Interval requested
3380 write_byte( 0x40, 0xA0, 0 ); // Clear status byte
3381 CLEAR_CF( );
3382 bRegister = inb_cmos( 0xB );
3383 outb_cmos( 0xB, bRegister & ~0x40 ); // Turn off the Periodic Interrupt timer
3384 } else {
3385 BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
3386 SET_CF();
3387 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3388 regs.u.r8.al--;
3391 break;
3394 case 0x87:
3395 #if BX_CPU < 3
3396 # error "Int15 function 87h not supported on < 80386"
3397 #endif
3398 // +++ should probably have descriptor checks
3399 // +++ should have exception handlers
3401 // turn off interrupts
3402 ASM_START
3404 ASM_END
3406 prev_a20_enable = set_enable_a20(1); // enable A20 line
3408 // 128K max of transfer on 386+ ???
3409 // source == destination ???
3411 // ES:SI points to descriptor table
3412 // offset use initially comments
3413 // ==============================================
3414 // 00..07 Unused zeros Null descriptor
3415 // 08..0f GDT zeros filled in by BIOS
3416 // 10..17 source ssssssss source of data
3417 // 18..1f dest dddddddd destination of data
3418 // 20..27 CS zeros filled in by BIOS
3419 // 28..2f SS zeros filled in by BIOS
3421 //es:si
3422 //eeee0
3423 //0ssss
3424 //-----
3426 // check for access rights of source & dest here
3428 // Initialize GDT descriptor
3429 base15_00 = (ES << 4) + regs.u.r16.si;
3430 base23_16 = ES >> 12;
3431 if (base15_00 < (ES<<4))
3432 base23_16++;
3433 write_word(ES, regs.u.r16.si+0x08+0, 47); // limit 15:00 = 6 * 8bytes/descriptor
3434 write_word(ES, regs.u.r16.si+0x08+2, base15_00);// base 15:00
3435 write_byte(ES, regs.u.r16.si+0x08+4, base23_16);// base 23:16
3436 write_byte(ES, regs.u.r16.si+0x08+5, 0x93); // access
3437 write_word(ES, regs.u.r16.si+0x08+6, 0x0000); // base 31:24/reserved/limit 19:16
3439 // Initialize CS descriptor
3440 write_word(ES, regs.u.r16.si+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
3441 write_word(ES, regs.u.r16.si+0x20+2, 0x0000);// base 15:00
3442 write_byte(ES, regs.u.r16.si+0x20+4, 0x000f);// base 23:16
3443 write_byte(ES, regs.u.r16.si+0x20+5, 0x9b); // access
3444 write_word(ES, regs.u.r16.si+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
3446 // Initialize SS descriptor
3447 ss = get_SS();
3448 base15_00 = ss << 4;
3449 base23_16 = ss >> 12;
3450 write_word(ES, regs.u.r16.si+0x28+0, 0xffff); // limit 15:00 = normal 64K limit
3451 write_word(ES, regs.u.r16.si+0x28+2, base15_00);// base 15:00
3452 write_byte(ES, regs.u.r16.si+0x28+4, base23_16);// base 23:16
3453 write_byte(ES, regs.u.r16.si+0x28+5, 0x93); // access
3454 write_word(ES, regs.u.r16.si+0x28+6, 0x0000); // base 31:24/reserved/limit 19:16
3456 CX = regs.u.r16.cx;
3457 ASM_START
3458 // Compile generates locals offset info relative to SP.
3459 // Get CX (word count) from stack.
3460 mov bx, sp
3461 SEG SS
3462 mov cx, _int15_function.CX [bx]
3464 // since we need to set SS:SP, save them to the BDA
3465 // for future restore
3466 push eax
3467 xor eax, eax
3468 mov ds, ax
3469 mov 0x0469, ss
3470 mov 0x0467, sp
3472 SEG ES
3473 lgdt [si + 0x08]
3474 SEG CS
3475 lidt [pmode_IDT_info]
3476 ;; perhaps do something with IDT here
3478 ;; set PE bit in CR0
3479 mov eax, cr0
3480 or al, #0x01
3481 mov cr0, eax
3482 ;; far jump to flush CPU queue after transition to protected mode
3483 JMP_AP(0x0020, protected_mode)
3485 protected_mode:
3486 ;; GDT points to valid descriptor table, now load SS, DS, ES
3487 mov ax, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
3488 mov ss, ax
3489 mov ax, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
3490 mov ds, ax
3491 mov ax, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
3492 mov es, ax
3493 xor si, si
3494 xor di, di
3497 movsw ;; move CX words from DS:SI to ES:DI
3499 ;; make sure DS and ES limits are 64KB
3500 mov ax, #0x28
3501 mov ds, ax
3502 mov es, ax
3504 ;; reset PG bit in CR0 ???
3505 mov eax, cr0
3506 and al, #0xFE
3507 mov cr0, eax
3509 ;; far jump to flush CPU queue after transition to real mode
3510 JMP_AP(0xf000, real_mode)
3512 real_mode:
3513 ;; restore IDT to normal real-mode defaults
3514 SEG CS
3515 lidt [rmode_IDT_info]
3517 // restore SS:SP from the BDA
3518 xor ax, ax
3519 mov ds, ax
3520 mov ss, 0x0469
3521 mov sp, 0x0467
3522 pop eax
3523 ASM_END
3525 set_enable_a20(prev_a20_enable);
3527 // turn back on interrupts
3528 ASM_START
3530 ASM_END
3532 regs.u.r8.ah = 0;
3533 CLEAR_CF();
3534 break;
3537 case 0x88: /* extended memory size */
3538 #if BX_CPU < 2
3539 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3540 SET_CF();
3541 #else
3542 /* ??? change this back later... */
3543 /* number of 1K blocks of extended memory, subtract off 1st 1Meg */
3544 // AX = bx_mem.get_memory_in_k() - 1024;
3545 regs.u.r8.al = inb_cmos(0x30);
3546 regs.u.r8.ah = inb_cmos(0x31);
3547 CLEAR_CF();
3548 #endif
3549 break;
3551 case 0x90:
3552 /* Device busy interrupt. Called by Int 16h when no key available */
3553 break;
3555 case 0x91:
3556 /* Interrupt complete. Called by Int 16h when key becomes available */
3557 break;
3559 case 0xbf:
3560 BX_INFO("*** int 15h function AH=bf not yet supported!\n");
3561 SET_CF();
3562 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3563 break;
3565 case 0xC0:
3566 #if 0
3567 SET_CF();
3568 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3569 break;
3570 #endif
3571 CLEAR_CF();
3572 regs.u.r8.ah = 0;
3573 regs.u.r16.bx = BIOS_CONFIG_TABLE;
3574 ES = 0xF000;
3575 break;
3577 case 0xc1:
3578 ES = ebda_seg;
3579 CLEAR_CF();
3580 break;
3582 case 0xd8:
3583 bios_printf(BIOS_PRINTF_DEBUG, "EISA BIOS not present\n");
3584 SET_CF();
3585 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3586 break;
3588 default:
3589 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
3590 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
3591 SET_CF();
3592 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3593 break;
3597 #if BX_USE_PS2_MOUSE
3598 void
3599 int15_function_mouse(regs, ES, DS, FLAGS)
3600 pusha_regs_t regs; // REGS pushed via pusha
3601 Bit16u ES, DS, FLAGS;
3603 Bit16u ebda_seg=read_word(0x0040,0x000E);
3604 Bit8u mouse_flags_1, mouse_flags_2;
3605 Bit16u mouse_driver_seg;
3606 Bit16u mouse_driver_offset;
3607 Bit8u response, prev_command_byte;
3608 bx_bool prev_a20_enable;
3609 Bit8u ret, mouse_data1, mouse_data2, mouse_data3;
3610 Bit8u comm_byte, mf2_state;
3612 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
3614 switch (regs.u.r8.ah) {
3615 case 0xC2:
3616 // Return Codes status in AH
3617 // =========================
3618 // 00: success
3619 // 01: invalid subfunction (AL > 7)
3620 // 02: invalid input value (out of allowable range)
3621 // 03: interface error
3622 // 04: resend command received from mouse controller,
3623 // device driver should attempt command again
3624 // 05: cannot enable mouse, since no far call has been installed
3625 // 80/86: mouse service not implemented
3627 switch (regs.u.r8.al) {
3628 case 0: // Disable/Enable Mouse
3629 BX_DEBUG_INT15("case 0:\n");
3630 switch (regs.u.r8.bh) {
3631 case 0: // Disable Mouse
3632 BX_DEBUG_INT15("case 0: disable mouse\n");
3633 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3634 ret = send_to_mouse_ctrl(0xF5); // disable mouse command
3635 if (ret == 0) {
3636 ret = get_mouse_data(&mouse_data1);
3637 if ( (ret == 0) || (mouse_data1 == 0xFA) ) {
3638 CLEAR_CF();
3639 regs.u.r8.ah = 0;
3640 return;
3644 // error
3645 SET_CF();
3646 regs.u.r8.ah = ret;
3647 return;
3648 break;
3650 case 1: // Enable Mouse
3651 BX_DEBUG_INT15("case 1: enable mouse\n");
3652 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
3653 if ( (mouse_flags_2 & 0x80) == 0 ) {
3654 BX_DEBUG_INT15("INT 15h C2 Enable Mouse, no far call handler\n");
3655 SET_CF(); // error
3656 regs.u.r8.ah = 5; // no far call installed
3657 return;
3659 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3660 ret = send_to_mouse_ctrl(0xF4); // enable mouse command
3661 if (ret == 0) {
3662 ret = get_mouse_data(&mouse_data1);
3663 if ( (ret == 0) && (mouse_data1 == 0xFA) ) {
3664 enable_mouse_int_and_events(); // turn IRQ12 and packet generation on
3665 CLEAR_CF();
3666 regs.u.r8.ah = 0;
3667 return;
3670 SET_CF();
3671 regs.u.r8.ah = ret;
3672 return;
3674 default: // invalid subfunction
3675 BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs.u.r8.bh);
3676 SET_CF(); // error
3677 regs.u.r8.ah = 1; // invalid subfunction
3678 return;
3680 break;
3682 case 1: // Reset Mouse
3683 case 5: // Initialize Mouse
3684 BX_DEBUG_INT15("case 1 or 5:\n");
3685 if (regs.u.r8.al == 5) {
3686 if (regs.u.r8.bh != 3)
3687 BX_PANIC("INT 15h C2 AL=5, BH=%02x\n", (unsigned) regs.u.r8.bh);
3688 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
3689 mouse_flags_2 = (mouse_flags_2 & 0x00) | regs.u.r8.bh;
3690 mouse_flags_1 = 0x00;
3691 write_byte(ebda_seg, 0x0026, mouse_flags_1);
3692 write_byte(ebda_seg, 0x0027, mouse_flags_2);
3695 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3696 ret = send_to_mouse_ctrl(0xFF); // reset mouse command
3697 if (ret == 0) {
3698 ret = get_mouse_data(&mouse_data3);
3699 // if no mouse attached, it will return RESEND
3700 if (mouse_data3 == 0xfe) {
3701 SET_CF();
3702 return;
3704 if (mouse_data3 != 0xfa)
3705 BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3);
3706 if ( ret == 0 ) {
3707 ret = get_mouse_data(&mouse_data1);
3708 if ( ret == 0 ) {
3709 ret = get_mouse_data(&mouse_data2);
3710 if ( ret == 0 ) {
3711 // turn IRQ12 and packet generation on
3712 enable_mouse_int_and_events();
3713 CLEAR_CF();
3714 regs.u.r8.ah = 0;
3715 regs.u.r8.bl = mouse_data1;
3716 regs.u.r8.bh = mouse_data2;
3717 return;
3723 // error
3724 SET_CF();
3725 regs.u.r8.ah = ret;
3726 return;
3728 case 2: // Set Sample Rate
3729 BX_DEBUG_INT15("case 2:\n");
3730 switch (regs.u.r8.bh) {
3731 case 0: mouse_data1 = 10; break; // 10 reports/sec
3732 case 1: mouse_data1 = 20; break; // 20 reports/sec
3733 case 2: mouse_data1 = 40; break; // 40 reports/sec
3734 case 3: mouse_data1 = 60; break; // 60 reports/sec
3735 case 4: mouse_data1 = 80; break; // 80 reports/sec
3736 case 5: mouse_data1 = 100; break; // 100 reports/sec (default)
3737 case 6: mouse_data1 = 200; break; // 200 reports/sec
3738 default: mouse_data1 = 0;
3740 if (mouse_data1 > 0) {
3741 ret = send_to_mouse_ctrl(0xF3); // set sample rate command
3742 if (ret == 0) {
3743 ret = get_mouse_data(&mouse_data2);
3744 ret = send_to_mouse_ctrl(mouse_data1);
3745 ret = get_mouse_data(&mouse_data2);
3746 CLEAR_CF();
3747 regs.u.r8.ah = 0;
3748 } else {
3749 // error
3750 SET_CF();
3751 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3753 } else {
3754 // error
3755 SET_CF();
3756 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3758 break;
3760 case 3: // Set Resolution
3761 BX_DEBUG_INT15("case 3:\n");
3762 // BX:
3763 // 0 = 25 dpi, 1 count per millimeter
3764 // 1 = 50 dpi, 2 counts per millimeter
3765 // 2 = 100 dpi, 4 counts per millimeter
3766 // 3 = 200 dpi, 8 counts per millimeter
3767 CLEAR_CF();
3768 regs.u.r8.ah = 0;
3769 break;
3771 case 4: // Get Device ID
3772 BX_DEBUG_INT15("case 4:\n");
3773 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3774 ret = send_to_mouse_ctrl(0xF2); // get mouse ID command
3775 if (ret == 0) {
3776 ret = get_mouse_data(&mouse_data1);
3777 ret = get_mouse_data(&mouse_data2);
3778 CLEAR_CF();
3779 regs.u.r8.ah = 0;
3780 regs.u.r8.bh = mouse_data2;
3781 } else {
3782 // error
3783 SET_CF();
3784 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3786 break;
3788 case 6: // Return Status & Set Scaling Factor...
3789 BX_DEBUG_INT15("case 6:\n");
3790 switch (regs.u.r8.bh) {
3791 case 0: // Return Status
3792 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3793 ret = send_to_mouse_ctrl(0xE9); // get mouse info command
3794 if (ret == 0) {
3795 ret = get_mouse_data(&mouse_data1);
3796 if (mouse_data1 != 0xfa)
3797 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
3798 if (ret == 0) {
3799 ret = get_mouse_data(&mouse_data1);
3800 if ( ret == 0 ) {
3801 ret = get_mouse_data(&mouse_data2);
3802 if ( ret == 0 ) {
3803 ret = get_mouse_data(&mouse_data3);
3804 if ( ret == 0 ) {
3805 CLEAR_CF();
3806 regs.u.r8.ah = 0;
3807 regs.u.r8.bl = mouse_data1;
3808 regs.u.r8.cl = mouse_data2;
3809 regs.u.r8.dl = mouse_data3;
3810 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
3811 return;
3818 // error
3819 SET_CF();
3820 regs.u.r8.ah = ret;
3821 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
3822 return;
3824 case 1: // Set Scaling Factor to 1:1
3825 CLEAR_CF();
3826 regs.u.r8.ah = 0;
3827 break;
3829 default:
3830 BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs.u.r8.bh);
3832 break;
3834 case 7: // Set Mouse Handler Address
3835 BX_DEBUG_INT15("case 7:\n");
3836 mouse_driver_seg = ES;
3837 mouse_driver_offset = regs.u.r16.bx;
3838 write_word(ebda_seg, 0x0022, mouse_driver_offset);
3839 write_word(ebda_seg, 0x0024, mouse_driver_seg);
3840 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
3841 if (mouse_driver_offset == 0 && mouse_driver_seg == 0) {
3842 /* remove handler */
3843 if ( (mouse_flags_2 & 0x80) != 0 ) {
3844 mouse_flags_2 &= ~0x80;
3845 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3848 else {
3849 /* install handler */
3850 mouse_flags_2 |= 0x80;
3852 write_byte(ebda_seg, 0x0027, mouse_flags_2);
3853 CLEAR_CF();
3854 regs.u.r8.ah = 0;
3855 break;
3857 default:
3858 BX_DEBUG_INT15("case default:\n");
3859 regs.u.r8.ah = 1; // invalid function
3860 SET_CF();
3862 break;
3864 default:
3865 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
3866 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
3867 SET_CF();
3868 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3869 break;
3872 #endif
3874 void
3875 int15_function32(regs, ES, DS, FLAGS)
3876 pushad_regs_t regs; // REGS pushed via pushad
3877 Bit16u ES, DS, FLAGS;
3879 Bit32u extended_memory_size=0; // 64bits long
3880 Bit16u CX,DX;
3882 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
3884 switch (regs.u.r8.ah) {
3885 case 0x86:
3886 // Wait for CX:DX microseconds. currently using the
3887 // refresh request port 0x61 bit4, toggling every 15usec
3889 CX = regs.u.r16.cx;
3890 DX = regs.u.r16.dx;
3892 ASM_START
3895 ;; Get the count in eax
3896 mov bx, sp
3897 SEG SS
3898 mov ax, _int15_function.CX [bx]
3899 shl eax, #16
3900 SEG SS
3901 mov ax, _int15_function.DX [bx]
3903 ;; convert to numbers of 15usec ticks
3904 mov ebx, #15
3905 xor edx, edx
3906 div eax, ebx
3907 mov ecx, eax
3909 ;; wait for ecx number of refresh requests
3910 in al, #0x61
3911 and al,#0x10
3912 mov ah, al
3914 or ecx, ecx
3915 je int1586_tick_end
3916 int1586_tick:
3917 in al, #0x61
3918 and al,#0x10
3919 cmp al, ah
3920 je int1586_tick
3921 mov ah, al
3922 dec ecx
3923 jnz int1586_tick
3924 int1586_tick_end:
3925 ASM_END
3927 break;
3929 case 0xe8:
3930 switch(regs.u.r8.al)
3932 case 0x20: // coded by osmaker aka K.J.
3933 if(regs.u.r32.edx == 0x534D4150)
3935 switch(regs.u.r16.bx)
3937 case 0:
3938 write_word(ES, regs.u.r16.di, 0x00);
3939 write_word(ES, regs.u.r16.di+2, 0x00);
3940 write_word(ES, regs.u.r16.di+4, 0x00);
3941 write_word(ES, regs.u.r16.di+6, 0x00);
3943 write_word(ES, regs.u.r16.di+8, 0xFC00);
3944 write_word(ES, regs.u.r16.di+10, 0x0009);
3945 write_word(ES, regs.u.r16.di+12, 0x0000);
3946 write_word(ES, regs.u.r16.di+14, 0x0000);
3948 write_word(ES, regs.u.r16.di+16, 0x1);
3949 write_word(ES, regs.u.r16.di+18, 0x0);
3951 regs.u.r32.ebx = 1;
3952 regs.u.r32.eax = 0x534D4150;
3953 regs.u.r32.ecx = 0x14;
3954 CLEAR_CF();
3955 return;
3956 break;
3957 case 1:
3958 extended_memory_size = inb_cmos(0x35);
3959 extended_memory_size <<= 8;
3960 extended_memory_size |= inb_cmos(0x34);
3961 extended_memory_size *= 64;
3962 if(extended_memory_size > 0x3bc000) // greater than EFF00000???
3964 extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
3966 extended_memory_size *= 1024;
3967 extended_memory_size += 15728640; // make up for the 16mb of memory that is chopped off
3969 if(extended_memory_size <= 15728640)
3971 extended_memory_size = inb_cmos(0x31);
3972 extended_memory_size <<= 8;
3973 extended_memory_size |= inb_cmos(0x30);
3974 extended_memory_size *= 1024;
3977 write_word(ES, regs.u.r16.di, 0x0000);
3978 write_word(ES, regs.u.r16.di+2, 0x0010);
3979 write_word(ES, regs.u.r16.di+4, 0x0000);
3980 write_word(ES, regs.u.r16.di+6, 0x0000);
3982 write_word(ES, regs.u.r16.di+8, extended_memory_size);
3983 extended_memory_size >>= 16;
3984 write_word(ES, regs.u.r16.di+10, extended_memory_size);
3985 extended_memory_size >>= 16;
3986 write_word(ES, regs.u.r16.di+12, extended_memory_size);
3987 extended_memory_size >>= 16;
3988 write_word(ES, regs.u.r16.di+14, extended_memory_size);
3990 write_word(ES, regs.u.r16.di+16, 0x1);
3991 write_word(ES, regs.u.r16.di+18, 0x0);
3993 regs.u.r32.ebx = 0;
3994 regs.u.r32.eax = 0x534D4150;
3995 regs.u.r32.ecx = 0x14;
3996 CLEAR_CF();
3997 return;
3998 break;
3999 default: /* AX=E820, DX=534D4150, BX unrecognized */
4000 goto int15_unimplemented;
4001 break;
4003 } else {
4004 // if DX != 0x534D4150)
4005 goto int15_unimplemented;
4007 break;
4009 case 0x01:
4010 // do we have any reason to fail here ?
4011 CLEAR_CF();
4013 // my real system sets ax and bx to 0
4014 // this is confirmed by Ralph Brown list
4015 // but syslinux v1.48 is known to behave
4016 // strangely if ax is set to 0
4017 // regs.u.r16.ax = 0;
4018 // regs.u.r16.bx = 0;
4020 // Get the amount of extended memory (above 1M)
4021 regs.u.r8.cl = inb_cmos(0x30);
4022 regs.u.r8.ch = inb_cmos(0x31);
4024 // limit to 15M
4025 if(regs.u.r16.cx > 0x3c00)
4027 regs.u.r16.cx = 0x3c00;
4030 // Get the amount of extended memory above 16M in 64k blocs
4031 regs.u.r8.dl = inb_cmos(0x34);
4032 regs.u.r8.dh = inb_cmos(0x35);
4034 // Set configured memory equal to extended memory
4035 regs.u.r16.ax = regs.u.r16.cx;
4036 regs.u.r16.bx = regs.u.r16.dx;
4037 break;
4038 default: /* AH=0xE8?? but not implemented */
4039 goto int15_unimplemented;
4041 break;
4042 int15_unimplemented:
4043 // fall into the default
4044 default:
4045 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4046 (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4047 SET_CF();
4048 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4049 break;
4053 void
4054 int16_function(DI, SI, BP, SP, BX, DX, CX, AX, FLAGS)
4055 Bit16u DI, SI, BP, SP, BX, DX, CX, AX, FLAGS;
4057 Bit8u scan_code, ascii_code, shift_flags, count;
4058 Bit16u kbd_code, max;
4060 BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX, BX, CX, DX);
4062 switch (GET_AH()) {
4063 case 0x00: /* read keyboard input */
4065 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4066 BX_PANIC("KBD: int16h: out of keyboard input\n");
4068 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4069 else if (ascii_code == 0xE0) ascii_code = 0;
4070 AX = (scan_code << 8) | ascii_code;
4071 break;
4073 case 0x01: /* check keyboard status */
4074 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4075 SET_ZF();
4076 return;
4078 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4079 else if (ascii_code == 0xE0) ascii_code = 0;
4080 AX = (scan_code << 8) | ascii_code;
4081 CLEAR_ZF();
4082 break;
4084 case 0x02: /* get shift flag status */
4085 shift_flags = read_byte(0x0040, 0x17);
4086 SET_AL(shift_flags);
4087 break;
4089 case 0x05: /* store key-stroke into buffer */
4090 if ( !enqueue_key(GET_CH(), GET_CL()) ) {
4091 SET_AL(1);
4093 else {
4094 SET_AL(0);
4096 break;
4098 case 0x09: /* GET KEYBOARD FUNCTIONALITY */
4099 // bit Bochs Description
4100 // 7 0 reserved
4101 // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
4102 // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
4103 // 4 1 INT 16/AH=0Ah supported
4104 // 3 0 INT 16/AX=0306h supported
4105 // 2 0 INT 16/AX=0305h supported
4106 // 1 0 INT 16/AX=0304h supported
4107 // 0 0 INT 16/AX=0300h supported
4109 SET_AL(0x30);
4110 break;
4112 case 0x0A: /* GET KEYBOARD ID */
4113 count = 2;
4114 kbd_code = 0x0;
4115 outb(0x60, 0xf2);
4116 /* Wait for data */
4117 max=0xffff;
4118 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4119 if (max>0x0) {
4120 if ((inb(0x60) == 0xfa)) {
4121 do {
4122 max=0xffff;
4123 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4124 if (max>0x0) {
4125 kbd_code >>= 8;
4126 kbd_code |= (inb(0x60) << 8);
4128 } while (--count>0);
4131 BX=kbd_code;
4132 break;
4134 case 0x10: /* read MF-II keyboard input */
4136 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4137 BX_PANIC("KBD: int16h: out of keyboard input\n");
4139 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4140 AX = (scan_code << 8) | ascii_code;
4141 break;
4143 case 0x11: /* check MF-II keyboard status */
4144 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4145 SET_ZF();
4146 return;
4148 if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4149 AX = (scan_code << 8) | ascii_code;
4150 CLEAR_ZF();
4151 break;
4153 case 0x12: /* get extended keyboard status */
4154 shift_flags = read_byte(0x0040, 0x17);
4155 SET_AL(shift_flags);
4156 shift_flags = read_byte(0x0040, 0x18);
4157 SET_AH(shift_flags);
4158 BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX);
4159 break;
4161 case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
4162 SET_AH(0x80); // function int16 ah=0x10-0x12 supported
4163 break;
4165 case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
4166 // don't change AH : function int16 ah=0x20-0x22 NOT supported
4167 break;
4169 default:
4170 BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
4174 unsigned int
4175 dequeue_key(scan_code, ascii_code, incr)
4176 Bit8u *scan_code;
4177 Bit8u *ascii_code;
4178 unsigned int incr;
4180 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail;
4181 Bit16u ss;
4182 Bit8u acode, scode;
4184 #if BX_CPU < 2
4185 buffer_start = 0x001E;
4186 buffer_end = 0x003E;
4187 #else
4188 buffer_start = read_word(0x0040, 0x0080);
4189 buffer_end = read_word(0x0040, 0x0082);
4190 #endif
4192 buffer_head = read_word(0x0040, 0x001a);
4193 buffer_tail = read_word(0x0040, 0x001c);
4195 if (buffer_head != buffer_tail) {
4196 ss = get_SS();
4197 acode = read_byte(0x0040, buffer_head);
4198 scode = read_byte(0x0040, buffer_head+1);
4199 write_byte(ss, ascii_code, acode);
4200 write_byte(ss, scan_code, scode);
4202 if (incr) {
4203 buffer_head += 2;
4204 if (buffer_head >= buffer_end)
4205 buffer_head = buffer_start;
4206 write_word(0x0040, 0x001a, buffer_head);
4208 return(1);
4210 else {
4211 return(0);
4215 static char panic_msg_keyb_buffer_full[] = "%s: keyboard input buffer full\n";
4217 Bit8u
4218 inhibit_mouse_int_and_events()
4220 Bit8u command_byte, prev_command_byte;
4222 // Turn off IRQ generation and aux data line
4223 if ( inb(0x64) & 0x02 )
4224 BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
4225 outb(0x64, 0x20); // get command byte
4226 while ( (inb(0x64) & 0x01) != 0x01 );
4227 prev_command_byte = inb(0x60);
4228 command_byte = prev_command_byte;
4229 //while ( (inb(0x64) & 0x02) );
4230 if ( inb(0x64) & 0x02 )
4231 BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
4232 command_byte &= 0xfd; // turn off IRQ 12 generation
4233 command_byte |= 0x20; // disable mouse serial clock line
4234 outb(0x64, 0x60); // write command byte
4235 outb(0x60, command_byte);
4236 return(prev_command_byte);
4239 void
4240 enable_mouse_int_and_events()
4242 Bit8u command_byte;
4244 // Turn on IRQ generation and aux data line
4245 if ( inb(0x64) & 0x02 )
4246 BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
4247 outb(0x64, 0x20); // get command byte
4248 while ( (inb(0x64) & 0x01) != 0x01 );
4249 command_byte = inb(0x60);
4250 //while ( (inb(0x64) & 0x02) );
4251 if ( inb(0x64) & 0x02 )
4252 BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
4253 command_byte |= 0x02; // turn on IRQ 12 generation
4254 command_byte &= 0xdf; // enable mouse serial clock line
4255 outb(0x64, 0x60); // write command byte
4256 outb(0x60, command_byte);
4259 Bit8u
4260 send_to_mouse_ctrl(sendbyte)
4261 Bit8u sendbyte;
4263 Bit8u response;
4265 // wait for chance to write to ctrl
4266 if ( inb(0x64) & 0x02 )
4267 BX_PANIC(panic_msg_keyb_buffer_full,"sendmouse");
4268 outb(0x64, 0xD4);
4269 outb(0x60, sendbyte);
4270 return(0);
4274 Bit8u
4275 get_mouse_data(data)
4276 Bit8u *data;
4278 Bit8u response;
4279 Bit16u ss;
4281 while ( (inb(0x64) & 0x21) != 0x21 ) {
4284 response = inb(0x60);
4286 ss = get_SS();
4287 write_byte(ss, data, response);
4288 return(0);
4291 void
4292 set_kbd_command_byte(command_byte)
4293 Bit8u command_byte;
4295 if ( inb(0x64) & 0x02 )
4296 BX_PANIC(panic_msg_keyb_buffer_full,"setkbdcomm");
4297 outb(0x64, 0xD4);
4299 outb(0x64, 0x60); // write command byte
4300 outb(0x60, command_byte);
4303 void
4304 int09_function(DI, SI, BP, SP, BX, DX, CX, AX)
4305 Bit16u DI, SI, BP, SP, BX, DX, CX, AX;
4307 Bit8u scancode, asciicode, shift_flags;
4308 Bit8u mf2_flags, mf2_state, led_flags;
4311 // DS has been set to F000 before call
4315 scancode = GET_AL();
4317 if (scancode == 0) {
4318 BX_INFO("KBD: int09 handler: AL=0\n");
4319 return;
4323 shift_flags = read_byte(0x0040, 0x17);
4324 mf2_flags = read_byte(0x0040, 0x18);
4325 mf2_state = read_byte(0x0040, 0x96);
4326 led_flags = read_byte(0x0040, 0x97);
4327 asciicode = 0;
4329 switch (scancode) {
4330 case 0x3a: /* Caps Lock press */
4331 shift_flags ^= 0x40;
4332 write_byte(0x0040, 0x17, shift_flags);
4333 mf2_flags |= 0x40;
4334 write_byte(0x0040, 0x18, mf2_flags);
4335 led_flags ^= 0x04;
4336 write_byte(0x0040, 0x97, led_flags);
4337 break;
4338 case 0xba: /* Caps Lock release */
4339 mf2_flags &= ~0x40;
4340 write_byte(0x0040, 0x18, mf2_flags);
4341 break;
4343 case 0x2a: /* L Shift press */
4344 /*shift_flags &= ~0x40;*/
4345 shift_flags |= 0x02;
4346 write_byte(0x0040, 0x17, shift_flags);
4347 led_flags &= ~0x04;
4348 write_byte(0x0040, 0x97, led_flags);
4349 break;
4350 case 0xaa: /* L Shift release */
4351 shift_flags &= ~0x02;
4352 write_byte(0x0040, 0x17, shift_flags);
4353 break;
4355 case 0x36: /* R Shift press */
4356 /*shift_flags &= ~0x40;*/
4357 shift_flags |= 0x01;
4358 write_byte(0x0040, 0x17, shift_flags);
4359 led_flags &= ~0x04;
4360 write_byte(0x0040, 0x97, led_flags);
4361 break;
4362 case 0xb6: /* R Shift release */
4363 shift_flags &= ~0x01;
4364 write_byte(0x0040, 0x17, shift_flags);
4365 break;
4367 case 0x1d: /* Ctrl press */
4368 shift_flags |= 0x04;
4369 write_byte(0x0040, 0x17, shift_flags);
4370 if (mf2_state & 0x01) {
4371 mf2_flags |= 0x04;
4372 } else {
4373 mf2_flags |= 0x01;
4375 write_byte(0x0040, 0x18, mf2_flags);
4376 break;
4377 case 0x9d: /* Ctrl release */
4378 shift_flags &= ~0x04;
4379 write_byte(0x0040, 0x17, shift_flags);
4380 if (mf2_state & 0x01) {
4381 mf2_flags &= ~0x04;
4382 } else {
4383 mf2_flags &= ~0x01;
4385 write_byte(0x0040, 0x18, mf2_flags);
4386 break;
4388 case 0x38: /* Alt press */
4389 shift_flags |= 0x08;
4390 write_byte(0x0040, 0x17, shift_flags);
4391 if (mf2_state & 0x01) {
4392 mf2_flags |= 0x08;
4393 } else {
4394 mf2_flags |= 0x02;
4396 write_byte(0x0040, 0x18, mf2_flags);
4397 break;
4398 case 0xb8: /* Alt release */
4399 shift_flags &= ~0x08;
4400 write_byte(0x0040, 0x17, shift_flags);
4401 if (mf2_state & 0x01) {
4402 mf2_flags &= ~0x08;
4403 } else {
4404 mf2_flags &= ~0x02;
4406 write_byte(0x0040, 0x18, mf2_flags);
4407 break;
4409 case 0x45: /* Num Lock press */
4410 if ((mf2_state & 0x01) == 0) {
4411 mf2_flags |= 0x20;
4412 write_byte(0x0040, 0x18, mf2_flags);
4413 shift_flags ^= 0x20;
4414 led_flags ^= 0x02;
4415 write_byte(0x0040, 0x17, shift_flags);
4416 write_byte(0x0040, 0x97, led_flags);
4418 break;
4419 case 0xc5: /* Num Lock release */
4420 if ((mf2_state & 0x01) == 0) {
4421 mf2_flags &= ~0x20;
4422 write_byte(0x0040, 0x18, mf2_flags);
4424 break;
4426 case 0x46: /* Scroll Lock press */
4427 mf2_flags |= 0x10;
4428 write_byte(0x0040, 0x18, mf2_flags);
4429 shift_flags ^= 0x10;
4430 led_flags ^= 0x01;
4431 write_byte(0x0040, 0x17, shift_flags);
4432 write_byte(0x0040, 0x97, led_flags);
4433 break;
4435 case 0xc6: /* Scroll Lock release */
4436 mf2_flags &= ~0x10;
4437 write_byte(0x0040, 0x18, mf2_flags);
4438 break;
4440 default:
4441 if (scancode & 0x80) return; /* toss key releases ... */
4442 if (scancode > MAX_SCAN_CODE) {
4443 BX_INFO("KBD: int09h_handler(): unknown scancode read!");
4444 return;
4446 if (shift_flags & 0x08) { /* ALT */
4447 asciicode = scan_to_scanascii[scancode].alt;
4448 scancode = scan_to_scanascii[scancode].alt >> 8;
4450 else if (shift_flags & 0x04) { /* CONTROL */
4451 asciicode = scan_to_scanascii[scancode].control;
4452 scancode = scan_to_scanascii[scancode].control >> 8;
4454 else if (shift_flags & 0x03) { /* LSHIFT + RSHIFT */
4455 /* check if lock state should be ignored
4456 * because a SHIFT key are pressed */
4458 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
4459 asciicode = scan_to_scanascii[scancode].normal;
4460 scancode = scan_to_scanascii[scancode].normal >> 8;
4462 else {
4463 asciicode = scan_to_scanascii[scancode].shift;
4464 scancode = scan_to_scanascii[scancode].shift >> 8;
4467 else {
4468 /* check if lock is on */
4469 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
4470 asciicode = scan_to_scanascii[scancode].shift;
4471 scancode = scan_to_scanascii[scancode].shift >> 8;
4473 else {
4474 asciicode = scan_to_scanascii[scancode].normal;
4475 scancode = scan_to_scanascii[scancode].normal >> 8;
4478 if (scancode==0 && asciicode==0) {
4479 BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?");
4481 enqueue_key(scancode, asciicode);
4482 break;
4484 mf2_state &= ~0x01;
4487 unsigned int
4488 enqueue_key(scan_code, ascii_code)
4489 Bit8u scan_code, ascii_code;
4491 Bit16u buffer_start, buffer_end, buffer_head, buffer_tail, temp_tail;
4493 //BX_INFO("KBD: enqueue_key() called scan:%02x, ascii:%02x\n",
4494 // scan_code, ascii_code);
4496 #if BX_CPU < 2
4497 buffer_start = 0x001E;
4498 buffer_end = 0x003E;
4499 #else
4500 buffer_start = read_word(0x0040, 0x0080);
4501 buffer_end = read_word(0x0040, 0x0082);
4502 #endif
4504 buffer_head = read_word(0x0040, 0x001A);
4505 buffer_tail = read_word(0x0040, 0x001C);
4507 temp_tail = buffer_tail;
4508 buffer_tail += 2;
4509 if (buffer_tail >= buffer_end)
4510 buffer_tail = buffer_start;
4512 if (buffer_tail == buffer_head) {
4513 return(0);
4516 write_byte(0x0040, temp_tail, ascii_code);
4517 write_byte(0x0040, temp_tail+1, scan_code);
4518 write_word(0x0040, 0x001C, buffer_tail);
4519 return(1);
4523 void
4524 int74_function(make_farcall, Z, Y, X, status)
4525 Bit16u make_farcall, Z, Y, X, status;
4527 Bit16u ebda_seg=read_word(0x0040,0x000E);
4528 Bit8u in_byte, index, package_count;
4529 Bit8u mouse_flags_1, mouse_flags_2;
4531 BX_DEBUG_INT74("entering int74_function\n");
4532 make_farcall = 0;
4534 in_byte = inb(0x64);
4535 if ( (in_byte & 0x21) != 0x21 ) {
4536 return;
4538 in_byte = inb(0x60);
4539 BX_DEBUG_INT74("int74: read byte %02x\n", in_byte);
4541 mouse_flags_1 = read_byte(ebda_seg, 0x0026);
4542 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4544 if ( (mouse_flags_2 & 0x80) != 0x80 ) {
4545 // BX_PANIC("int74_function:\n");
4546 return;
4549 package_count = mouse_flags_2 & 0x07;
4550 index = mouse_flags_1 & 0x07;
4551 write_byte(ebda_seg, 0x28 + index, in_byte);
4553 if ( (index+1) >= package_count ) {
4554 BX_DEBUG_INT74("int74_function: make_farcall=1\n");
4555 status = read_byte(ebda_seg, 0x0028 + 0);
4556 X = read_byte(ebda_seg, 0x0028 + 1);
4557 Y = read_byte(ebda_seg, 0x0028 + 2);
4558 Z = 0;
4559 mouse_flags_1 = 0;
4560 // check if far call handler installed
4561 if (mouse_flags_2 & 0x80)
4562 make_farcall = 1;
4564 else {
4565 mouse_flags_1++;
4567 write_byte(ebda_seg, 0x0026, mouse_flags_1);
4570 #define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
4572 #if BX_USE_ATADRV
4574 void
4575 int13_harddisk(DI, SI, BP, SP, BX, DX, CX, AX, DS, ES, FLAGS)
4576 Bit16u DI, SI, BP, SP, BX, DX, CX, AX, DS, ES, FLAGS;
4578 Bit32u lba;
4579 Bit16u ebda_seg=read_word(0x0040,0x000E);
4580 Bit16u cylinder, head, sector;
4581 Bit16u segment, offset;
4582 Bit16u npc, nph, npspt, nlc, nlh, nlspt;
4583 Bit16u size, count;
4584 Bit8u device, status;
4586 BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
4588 write_byte(0x0040, 0x008e, 0); // clear completion flag
4590 // basic check : device has to be defined
4591 if ( (GET_DL() < 0x80) || (GET_DL() >= 0x80 + BX_MAX_ATA_DEVICES) ) {
4592 BX_INFO("int13_harddisk: function %02x, DL out of range %02x\n", GET_AH(), GET_DL());
4593 goto int13_fail;
4596 // Get the ata channel
4597 device=read_byte(ebda_seg,&EbdaData->ata.hdidmap[GET_DL()-0x80]);
4599 // basic check : device has to be valid
4600 if (device >= BX_MAX_ATA_DEVICES) {
4601 BX_INFO("int13_harddisk: function %02x, unmapped device for DL=%02x\n", GET_AH(), GET_DL());
4602 goto int13_fail;
4605 switch (GET_AH()) {
4607 case 0x00: /* disk controller reset */
4608 ata_reset (device);
4609 goto int13_success;
4610 break;
4612 case 0x01: /* read disk status */
4613 status = read_byte(0x0040, 0x0074);
4614 SET_AH(status);
4615 SET_DISK_RET_STATUS(0);
4616 /* set CF if error status read */
4617 if (status) goto int13_fail_nostatus;
4618 else goto int13_success_noah;
4619 break;
4621 case 0x02: // read disk sectors
4622 case 0x03: // write disk sectors
4623 case 0x04: // verify disk sectors
4625 count = GET_AL();
4626 cylinder = GET_CH();
4627 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
4628 sector = (GET_CL() & 0x3f);
4629 head = GET_DH();
4631 segment = ES;
4632 offset = BX;
4634 if ( (count > 128) || (count == 0) ) {
4635 BX_INFO("int13_harddisk: function %02x, count out of range!\n",GET_AH());
4636 goto int13_fail;
4639 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
4640 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
4641 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
4643 // sanity check on cyl heads, sec
4644 if( (cylinder >= nlc) || (head >= nlh) || (sector > nlspt )) {
4645 BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder, head, sector);
4646 goto int13_fail;
4649 // FIXME verify
4650 if ( GET_AH() == 0x04 ) goto int13_success;
4652 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
4653 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
4655 // if needed, translate lchs to lba, and execute command
4656 if ( (nph != nlh) || (npspt != nlspt)) {
4657 lba = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
4658 sector = 0; // this forces the command to be lba
4661 if ( GET_AH() == 0x02 )
4662 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, cylinder, head, sector, lba, segment, offset);
4663 else
4664 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, cylinder, head, sector, lba, segment, offset);
4666 // Set nb of sector transferred
4667 SET_AL(read_word(ebda_seg, &EbdaData->ata.trsfsectors));
4669 if (status != 0) {
4670 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
4671 SET_AH(0x0c);
4672 goto int13_fail_noah;
4675 goto int13_success;
4676 break;
4678 case 0x05: /* format disk track */
4679 BX_INFO("format disk track called\n");
4680 goto int13_success;
4681 return;
4682 break;
4684 case 0x08: /* read disk drive parameters */
4686 // Get logical geometry from table
4687 nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
4688 nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
4689 nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
4690 count = read_byte(ebda_seg, &EbdaData->ata.hdcount);
4692 nlc = nlc - 2; /* 0 based , last sector not used */
4693 SET_AL(0);
4694 SET_CH(nlc & 0xff);
4695 SET_CL(((nlc >> 2) & 0xc0) | (nlspt & 0x3f));
4696 SET_DH(nlh - 1);
4697 SET_DL(count); /* FIXME returns 0, 1, or n hard drives */
4699 // FIXME should set ES & DI
4701 goto int13_success;
4702 break;
4704 case 0x10: /* check drive ready */
4705 // should look at 40:8E also???
4707 // Read the status from controller
4708 status = inb(read_word(ebda_seg, &EbdaData->ata.channels[device/2].iobase1) + ATA_CB_STAT);
4709 if ( (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY ) {
4710 goto int13_success;
4712 else {
4713 SET_AH(0xAA);
4714 goto int13_fail_noah;
4716 break;
4718 case 0x15: /* read disk drive size */
4720 // Get physical geometry from table
4721 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
4722 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
4723 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
4725 // Compute sector count seen by int13
4726 lba = (Bit32u)(npc - 1) * (Bit32u)nph * (Bit32u)npspt;
4727 CX = lba >> 16;
4728 DX = lba & 0xffff;
4730 SET_AH(3); // hard disk accessible
4731 goto int13_success_noah;
4732 break;
4734 case 0x41: // IBM/MS installation check
4735 BX=0xaa55; // install check
4736 SET_AH(0x30); // EDD 3.0
4737 CX=0x0007; // ext disk access and edd, removable supported
4738 goto int13_success_noah;
4739 break;
4741 case 0x42: // IBM/MS extended read
4742 case 0x43: // IBM/MS extended write
4743 case 0x44: // IBM/MS verify
4744 case 0x47: // IBM/MS extended seek
4746 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
4747 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
4748 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
4750 // Can't use 64 bits lba
4751 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
4752 if (lba != 0L) {
4753 BX_PANIC("int13_harddisk: function %02x. Can't use 64bits lba\n",GET_AH());
4754 goto int13_fail;
4757 // Get 32 bits lba and check
4758 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
4759 if (lba >= read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors) ) {
4760 BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
4761 goto int13_fail;
4764 // If verify or seek
4765 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
4766 goto int13_success;
4768 // Execute the command
4769 if ( GET_AH() == 0x42 )
4770 status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba, segment, offset);
4771 else
4772 status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
4774 count=read_word(ebda_seg, &EbdaData->ata.trsfsectors);
4775 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
4777 if (status != 0) {
4778 BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
4779 SET_AH(0x0c);
4780 goto int13_fail_noah;
4783 goto int13_success;
4784 break;
4786 case 0x45: // IBM/MS lock/unlock drive
4787 case 0x49: // IBM/MS extended media change
4788 goto int13_success; // Always success for HD
4789 break;
4791 case 0x46: // IBM/MS eject media
4792 SET_AH(0xb2); // Volume Not Removable
4793 goto int13_fail_noah; // Always fail for HD
4794 break;
4796 case 0x48: // IBM/MS get drive parameters
4797 size=read_word(DS,SI+(Bit16u)&Int13DPT->size);
4799 // Buffer is too small
4800 if(size < 0x1a)
4801 goto int13_fail;
4803 // EDD 1.x
4804 if(size >= 0x1a) {
4805 Bit16u blksize;
4807 npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
4808 nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
4809 npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
4810 lba = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors);
4811 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
4813 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
4814 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x02); // geometry is valid
4815 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, (Bit32u)npc);
4816 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, (Bit32u)nph);
4817 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, (Bit32u)npspt);
4818 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, lba); // FIXME should be Bit64
4819 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0L);
4820 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
4823 // EDD 2.x
4824 if(size >= 0x1e) {
4825 Bit8u channel, dev, irq, mode, checksum, i, translation;
4826 Bit16u iobase1, iobase2, options;
4828 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
4830 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
4831 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
4833 // Fill in dpte
4834 channel = device / 2;
4835 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
4836 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
4837 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
4838 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
4839 translation = read_byte(ebda_seg, &EbdaData->ata.devices[device].translation);
4841 options = (translation==ATA_TRANSLATION_NONE?0:1<<3); // chs translation
4842 options |= (1<<4); // lba translation
4843 options |= (mode==ATA_MODE_PIO32?1:0<<7);
4844 options |= (translation==ATA_TRANSLATION_LBA?1:0<<9);
4845 options |= (translation==ATA_TRANSLATION_RECHS?3:0<<9);
4847 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
4848 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
4849 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
4850 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
4851 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
4852 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
4853 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
4854 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
4855 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
4856 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
4857 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
4859 checksum=0;
4860 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
4861 checksum = ~checksum;
4862 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
4865 // EDD 3.x
4866 if(size >= 0x42) {
4867 Bit8u channel, iface, checksum, i;
4868 Bit16u iobase1;
4870 channel = device / 2;
4871 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
4872 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
4874 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
4875 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
4876 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
4877 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
4878 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
4880 if (iface==ATA_IFACE_ISA) {
4881 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
4882 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
4883 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
4884 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
4886 else {
4887 // FIXME PCI
4889 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
4890 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
4891 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
4892 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
4894 if (iface==ATA_IFACE_ISA) {
4895 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
4896 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
4897 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
4899 else {
4900 // FIXME PCI
4902 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
4903 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
4904 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
4905 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
4907 checksum=0;
4908 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
4909 checksum = ~checksum;
4910 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
4913 goto int13_success;
4914 break;
4916 case 0x4e: // // IBM/MS set hardware configuration
4917 // DMA, prefetch, PIO maximum not supported
4918 switch (GET_AL()) {
4919 case 0x01:
4920 case 0x03:
4921 case 0x04:
4922 case 0x06:
4923 goto int13_success;
4924 break;
4925 default :
4926 goto int13_fail;
4928 break;
4930 case 0x09: /* initialize drive parameters */
4931 case 0x0c: /* seek to specified cylinder */
4932 case 0x0d: /* alternate disk reset */
4933 case 0x11: /* recalibrate */
4934 case 0x14: /* controller internal diagnostic */
4935 BX_INFO("int13h_harddisk function %02xh unimplemented, returns success\n", GET_AH());
4936 goto int13_success;
4937 break;
4939 case 0x0a: /* read disk sectors with ECC */
4940 case 0x0b: /* write disk sectors with ECC */
4941 case 0x18: // set media type for format
4942 case 0x50: // IBM/MS send packet command
4943 default:
4944 BX_INFO("int13_harddisk function %02xh unsupported, returns fail\n", GET_AH());
4945 goto int13_fail;
4946 break;
4949 int13_fail:
4950 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
4951 int13_fail_noah:
4952 SET_DISK_RET_STATUS(GET_AH());
4953 int13_fail_nostatus:
4954 SET_CF(); // error occurred
4955 return;
4957 int13_success:
4958 SET_AH(0x00); // no error
4959 int13_success_noah:
4960 SET_DISK_RET_STATUS(0x00);
4961 CLEAR_CF(); // no error
4962 return;
4965 // ---------------------------------------------------------------------------
4966 // Start of int13 for cdrom
4967 // ---------------------------------------------------------------------------
4969 void
4970 int13_cdrom(DI, DIH, SI, SIH, BP, BPH, SP, SPH, BX, BXH, DX, DXH, CX, CXH, AX, AXH,
4971 DS, ES, FLAGS)
4972 Bit16u DI, DIH, SI, SIH, BP, BPH, SP, SPH, BX, BXH, DX, DXH, CX, CXH, AX, AXH,
4973 DS, ES, FLAGS;
4975 Bit16u ebda_seg=read_word(0x0040,0x000E);
4976 Bit8u device, status, locks;
4977 Bit8u atacmd[12];
4978 Bit32u lba;
4979 Bit16u count, segment, offset, i, size;
4981 BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
4982 // BX_DEBUG_INT13_CD("int13_cdrom: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
4984 SET_DISK_RET_STATUS(0x00);
4986 /* basic check : device should be 0xE0+ */
4987 if( (GET_DL() < 0xE0) || (GET_DL() >= 0xE0+BX_MAX_ATA_DEVICES) ) {
4988 BX_INFO("int13_cdrom: function %02x, DL out of range %02x\n", GET_AH(), GET_DL());
4989 goto int13_fail;
4992 // Get the ata channel
4993 device=read_byte(ebda_seg,&EbdaData->ata.cdidmap[GET_DL()-0xE0]);
4995 /* basic check : device has to be valid */
4996 if (device >= BX_MAX_ATA_DEVICES) {
4997 BX_INFO("int13_cdrom: function %02x, unmapped device for DL=%02x\n", GET_AH(), GET_DL());
4998 goto int13_fail;
5001 switch (GET_AH()) {
5003 // all those functions return SUCCESS
5004 case 0x00: /* disk controller reset */
5005 case 0x09: /* initialize drive parameters */
5006 case 0x0c: /* seek to specified cylinder */
5007 case 0x0d: /* alternate disk reset */
5008 case 0x10: /* check drive ready */
5009 case 0x11: /* recalibrate */
5010 case 0x14: /* controller internal diagnostic */
5011 case 0x16: /* detect disk change */
5012 goto int13_success;
5013 break;
5015 // all those functions return disk write-protected
5016 case 0x03: /* write disk sectors */
5017 case 0x05: /* format disk track */
5018 case 0x43: // IBM/MS extended write
5019 SET_AH(0x03);
5020 goto int13_fail_noah;
5021 break;
5023 case 0x01: /* read disk status */
5024 status = read_byte(0x0040, 0x0074);
5025 SET_AH(status);
5026 SET_DISK_RET_STATUS(0);
5028 /* set CF if error status read */
5029 if (status) goto int13_fail_nostatus;
5030 else goto int13_success_noah;
5031 break;
5033 case 0x15: /* read disk drive size */
5034 SET_AH(0x02);
5035 goto int13_fail_noah;
5036 break;
5038 case 0x41: // IBM/MS installation check
5039 BX=0xaa55; // install check
5040 SET_AH(0x30); // EDD 2.1
5041 CX=0x0007; // ext disk access, removable and edd
5042 goto int13_success_noah;
5043 break;
5045 case 0x42: // IBM/MS extended read
5046 case 0x44: // IBM/MS verify sectors
5047 case 0x47: // IBM/MS extended seek
5049 count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5050 segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5051 offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5053 // Can't use 64 bits lba
5054 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5055 if (lba != 0L) {
5056 BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
5057 goto int13_fail;
5060 // Get 32 bits lba
5061 lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5063 // If verify or seek
5064 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5065 goto int13_success;
5067 memsetb(get_SS(),atacmd,0,12);
5068 atacmd[0]=0x28; // READ command
5069 atacmd[7]=(count & 0xff00) >> 8; // Sectors
5070 atacmd[8]=(count & 0x00ff); // Sectors
5071 atacmd[2]=(lba & 0xff000000) >> 24; // LBA
5072 atacmd[3]=(lba & 0x00ff0000) >> 16;
5073 atacmd[4]=(lba & 0x0000ff00) >> 8;
5074 atacmd[5]=(lba & 0x000000ff);
5075 status = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, count*2048L, ATA_DATA_IN, segment,offset);
5077 count = (Bit16u)(read_dword(ebda_seg, &EbdaData->ata.trsfbytes) >> 11);
5078 write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5080 if (status != 0) {
5081 BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status);
5082 SET_AH(0x0c);
5083 goto int13_fail_noah;
5086 goto int13_success;
5087 break;
5089 case 0x45: // IBM/MS lock/unlock drive
5090 if (GET_AL() > 2) goto int13_fail;
5092 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
5094 switch (GET_AL()) {
5095 case 0 : // lock
5096 if (locks == 0xff) {
5097 SET_AH(0xb4);
5098 SET_AL(1);
5099 goto int13_fail_noah;
5101 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, ++locks);
5102 SET_AL(1);
5103 break;
5104 case 1 : // unlock
5105 if (locks == 0x00) {
5106 SET_AH(0xb0);
5107 SET_AL(0);
5108 goto int13_fail_noah;
5110 write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, --locks);
5111 SET_AL(locks==0?0:1);
5112 break;
5113 case 2 : // status
5114 SET_AL(locks==0?0:1);
5115 break;
5117 goto int13_success;
5118 break;
5120 case 0x46: // IBM/MS eject media
5121 locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
5123 if (locks != 0) {
5124 SET_AH(0xb1); // media locked
5125 goto int13_fail_noah;
5127 // FIXME should handle 0x31 no media in device
5128 // FIXME should handle 0xb5 valid request failed
5130 // Call removable media eject
5131 ASM_START
5132 push bp
5133 mov bp, sp
5135 mov ah, #0x52
5136 int 15
5137 mov _int13_cdrom.status + 2[bp], ah
5138 jnc int13_cdrom_rme_end
5139 mov _int13_cdrom.status, #1
5140 int13_cdrom_rme_end:
5141 pop bp
5142 ASM_END
5144 if (status != 0) {
5145 SET_AH(0xb1); // media locked
5146 goto int13_fail_noah;
5149 goto int13_success;
5150 break;
5152 case 0x48: // IBM/MS get drive parameters
5153 size = read_word(DS,SI+(Bit16u)&Int13Ext->size);
5155 // Buffer is too small
5156 if(size < 0x1a)
5157 goto int13_fail;
5159 // EDD 1.x
5160 if(size >= 0x1a) {
5161 Bit16u cylinders, heads, spt, blksize;
5163 blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5165 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5166 write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x74); // removable, media change, lockable, max values
5167 write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, 0xffffffff);
5168 write_dword(DS, SI+(Bit16u)&Int13DPT->heads, 0xffffffff);
5169 write_dword(DS, SI+(Bit16u)&Int13DPT->spt, 0xffffffff);
5170 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, 0xffffffff); // FIXME should be Bit64
5171 write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0xffffffff);
5172 write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
5175 // EDD 2.x
5176 if(size >= 0x1e) {
5177 Bit8u channel, dev, irq, mode, checksum, i;
5178 Bit16u iobase1, iobase2, options;
5180 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5182 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
5183 write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
5185 // Fill in dpte
5186 channel = device / 2;
5187 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5188 iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5189 irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5190 mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5192 // FIXME atapi device
5193 options = (1<<4); // lba translation
5194 options |= (1<<5); // removable device
5195 options |= (1<<6); // atapi device
5196 options |= (mode==ATA_MODE_PIO32?1:0<<7);
5198 write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5199 write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5200 write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5201 write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5202 write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5203 write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5204 write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5205 write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5206 write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5207 write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5208 write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5210 checksum=0;
5211 for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5212 checksum = ~checksum;
5213 write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5216 // EDD 3.x
5217 if(size >= 0x42) {
5218 Bit8u channel, iface, checksum, i;
5219 Bit16u iobase1;
5221 channel = device / 2;
5222 iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5223 iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5225 write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5226 write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5227 write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5228 write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5229 write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5231 if (iface==ATA_IFACE_ISA) {
5232 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5233 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5234 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5235 write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5237 else {
5238 // FIXME PCI
5240 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5241 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5242 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5243 write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5245 if (iface==ATA_IFACE_ISA) {
5246 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5247 write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5248 write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5250 else {
5251 // FIXME PCI
5253 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5254 write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5255 write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5256 write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5258 checksum=0;
5259 for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5260 checksum = ~checksum;
5261 write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5264 goto int13_success;
5265 break;
5267 case 0x49: // IBM/MS extended media change
5268 // always send changed ??
5269 SET_AH(06);
5270 goto int13_fail_nostatus;
5271 break;
5273 case 0x4e: // // IBM/MS set hardware configuration
5274 // DMA, prefetch, PIO maximum not supported
5275 switch (GET_AL()) {
5276 case 0x01:
5277 case 0x03:
5278 case 0x04:
5279 case 0x06:
5280 goto int13_success;
5281 break;
5282 default :
5283 goto int13_fail;
5285 break;
5287 // all those functions return unimplemented
5288 case 0x02: /* read sectors */
5289 case 0x04: /* verify sectors */
5290 case 0x08: /* read disk drive parameters */
5291 case 0x0a: /* read disk sectors with ECC */
5292 case 0x0b: /* write disk sectors with ECC */
5293 case 0x18: /* set media type for format */
5294 case 0x50: // ? - send packet command
5295 default:
5296 BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
5297 goto int13_fail;
5298 break;
5301 int13_fail:
5302 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5303 int13_fail_noah:
5304 SET_DISK_RET_STATUS(GET_AH());
5305 int13_fail_nostatus:
5306 SET_CF(); // error occurred
5307 return;
5309 int13_success:
5310 SET_AH(0x00); // no error
5311 int13_success_noah:
5312 SET_DISK_RET_STATUS(0x00);
5313 CLEAR_CF(); // no error
5314 return;
5317 // ---------------------------------------------------------------------------
5318 // End of int13 for cdrom
5319 // ---------------------------------------------------------------------------
5321 #if BX_ELTORITO_BOOT
5322 // ---------------------------------------------------------------------------
5323 // Start of int13 for eltorito functions
5324 // ---------------------------------------------------------------------------
5326 void
5327 int13_eltorito(DI, SI, BP, SP, BX, DX, CX, AX, DS, ES, FLAGS)
5328 Bit16u DI, SI, BP, SP, BX, DX, CX, AX, DS, ES, FLAGS;
5330 Bit16u ebda_seg=read_word(0x0040,0x000E);
5332 BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5333 // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
5335 switch (GET_AH()) {
5337 // FIXME ElTorito Various. Should be implemented
5338 case 0x4a: // ElTorito - Initiate disk emu
5339 case 0x4c: // ElTorito - Initiate disk emu and boot
5340 case 0x4d: // ElTorito - Return Boot catalog
5341 BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX);
5342 goto int13_fail;
5343 break;
5345 case 0x4b: // ElTorito - Terminate disk emu
5346 // FIXME ElTorito Hardcoded
5347 write_byte(DS,SI+0x00,0x13);
5348 write_byte(DS,SI+0x01,read_byte(ebda_seg,&EbdaData->cdemu.media));
5349 write_byte(DS,SI+0x02,read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
5350 write_byte(DS,SI+0x03,read_byte(ebda_seg,&EbdaData->cdemu.controller_index));
5351 write_dword(DS,SI+0x04,read_dword(ebda_seg,&EbdaData->cdemu.ilba));
5352 write_word(DS,SI+0x08,read_word(ebda_seg,&EbdaData->cdemu.device_spec));
5353 write_word(DS,SI+0x0a,read_word(ebda_seg,&EbdaData->cdemu.buffer_segment));
5354 write_word(DS,SI+0x0c,read_word(ebda_seg,&EbdaData->cdemu.load_segment));
5355 write_word(DS,SI+0x0e,read_word(ebda_seg,&EbdaData->cdemu.sector_count));
5356 write_byte(DS,SI+0x10,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.cylinders));
5357 write_byte(DS,SI+0x11,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.spt));
5358 write_byte(DS,SI+0x12,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.heads));
5360 // If we have to terminate emulation
5361 if(GET_AL() == 0x00) {
5362 // FIXME ElTorito Various. Should be handled accordingly to spec
5363 write_byte(ebda_seg,&EbdaData->cdemu.active, 0x00); // bye bye
5366 goto int13_success;
5367 break;
5369 default:
5370 BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
5371 goto int13_fail;
5372 break;
5375 int13_fail:
5376 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5377 SET_DISK_RET_STATUS(GET_AH());
5378 SET_CF(); // error occurred
5379 return;
5381 int13_success:
5382 SET_AH(0x00); // no error
5383 SET_DISK_RET_STATUS(0x00);
5384 CLEAR_CF(); // no error
5385 return;
5388 // ---------------------------------------------------------------------------
5389 // End of int13 for eltorito functions
5390 // ---------------------------------------------------------------------------
5392 // ---------------------------------------------------------------------------
5393 // Start of int13 when emulating a device from the cd
5394 // ---------------------------------------------------------------------------
5396 void
5397 int13_cdemu(DI, SI, BP, SP, BX, DX, CX, AX, ES, FLAGS)
5398 Bit16u DI, SI, BP, SP, BX, DX, CX, AX, ES, FLAGS;
5400 Bit16u ebda_seg=read_word(0x0040,0x000E);
5401 Bit8u device, status;
5402 Bit16u vheads, vspt, vcylinders;
5403 Bit16u head, sector, cylinder, nbsectors;
5404 Bit32u vlba, ilba, slba, elba;
5405 Bit16u before, segment, offset;
5406 Bit8u atacmd[12];
5408 BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5409 //BX_DEBUG_INT13_ET("int13_cdemu: SS=%04x ES=%04x DI=%04x SI=%04x\n", get_SS(), ES, DI, SI);
5411 /* at this point, we are emulating a floppy/harddisk */
5413 // Recompute the device number
5414 device = read_byte(ebda_seg,&EbdaData->cdemu.controller_index) * 2;
5415 device += read_byte(ebda_seg,&EbdaData->cdemu.device_spec);
5417 SET_DISK_RET_STATUS(0x00);
5419 /* basic checks : emulation should be active, dl should equal the emulated drive */
5420 if( (read_byte(ebda_seg,&EbdaData->cdemu.active) ==0 )
5421 || (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive ) != GET_DL())) {
5422 BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
5423 goto int13_fail;
5426 switch (GET_AH()) {
5428 // all those functions return SUCCESS
5429 case 0x00: /* disk controller reset */
5430 case 0x09: /* initialize drive parameters */
5431 case 0x0c: /* seek to specified cylinder */
5432 case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
5433 case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
5434 case 0x11: /* recalibrate */
5435 case 0x14: /* controller internal diagnostic */
5436 case 0x16: /* detect disk change */
5437 goto int13_success;
5438 break;
5440 // all those functions return disk write-protected
5441 case 0x03: /* write disk sectors */
5442 case 0x05: /* format disk track */
5443 SET_AH(0x03);
5444 goto int13_fail_noah;
5445 break;
5447 case 0x01: /* read disk status */
5448 status=read_byte(0x0040, 0x0074);
5449 SET_AH(status);
5450 SET_DISK_RET_STATUS(0);
5452 /* set CF if error status read */
5453 if (status) goto int13_fail_nostatus;
5454 else goto int13_success_noah;
5455 break;
5457 case 0x02: // read disk sectors
5458 case 0x04: // verify disk sectors
5459 vspt = read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
5460 vcylinders = read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders);
5461 vheads = read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads);
5463 ilba = read_dword(ebda_seg,&EbdaData->cdemu.ilba);
5465 sector = GET_CL() & 0x003f;
5466 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
5467 head = GET_DH();
5468 nbsectors = GET_AL();
5469 segment = ES;
5470 offset = BX;
5472 // no sector to read ?
5473 if(nbsectors==0) goto int13_success;
5475 // sanity checks sco openserver needs this!
5476 if ((sector > vspt)
5477 || (cylinder >= vcylinders)
5478 || (head >= vheads)) {
5479 goto int13_fail;
5482 // After controls, verify do nothing
5483 if (GET_AH() == 0x04) goto int13_success;
5485 segment = ES+(BX / 16);
5486 offset = BX % 16;
5488 // calculate the virtual lba inside the image
5489 vlba=((((Bit32u)cylinder*(Bit32u)vheads)+(Bit32u)head)*(Bit32u)vspt)+((Bit32u)(sector-1));
5491 // In advance so we don't loose the count
5492 SET_AL(nbsectors);
5494 // start lba on cd
5495 slba = (Bit32u)vlba/4;
5496 before= (Bit16u)vlba%4;
5498 // end lba on cd
5499 elba = (Bit32u)(vlba+nbsectors-1)/4;
5501 memsetb(get_SS(),atacmd,0,12);
5502 atacmd[0]=0x28; // READ command
5503 atacmd[7]=((Bit16u)(elba-slba+1) & 0xff00) >> 8; // Sectors
5504 atacmd[8]=((Bit16u)(elba-slba+1) & 0x00ff); // Sectors
5505 atacmd[2]=(ilba+slba & 0xff000000) >> 24; // LBA
5506 atacmd[3]=(ilba+slba & 0x00ff0000) >> 16;
5507 atacmd[4]=(ilba+slba & 0x0000ff00) >> 8;
5508 atacmd[5]=(ilba+slba & 0x000000ff);
5509 if((status = ata_cmd_packet(device, 12, get_SS(), atacmd, before*512, nbsectors*512L, ATA_DATA_IN, segment,offset)) != 0) {
5510 BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status);
5511 SET_AH(0x02);
5512 SET_AL(0);
5513 goto int13_fail_noah;
5516 goto int13_success;
5517 break;
5519 case 0x08: /* read disk drive parameters */
5520 vspt=read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
5521 vcylinders=read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders) - 1;
5522 vheads=read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads) - 1;
5524 SET_AL( 0x00 );
5525 SET_BL( 0x00 );
5526 SET_CH( vcylinders & 0xff );
5527 SET_CL((( vcylinders >> 2) & 0xc0) | ( vspt & 0x3f ));
5528 SET_DH( vheads );
5529 SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2
5530 // FIXME ElTorito Harddisk. should send the HD count
5532 switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
5533 case 0x01: SET_BL( 0x02 ); break;
5534 case 0x02: SET_BL( 0x04 ); break;
5535 case 0x03: SET_BL( 0x06 ); break;
5538 DI = read_word(0x00, 0x1e*4); // INT vector 0x1E
5539 ES = read_word(0x00, 0x1e*4+2);
5540 goto int13_success;
5541 break;
5543 case 0x15: /* read disk drive size */
5544 // FIXME ElTorito Harddisk. What geometry to send ?
5545 SET_AH(0x03);
5546 goto int13_success_noah;
5547 break;
5549 // all those functions return unimplemented
5550 case 0x0a: /* read disk sectors with ECC */
5551 case 0x0b: /* write disk sectors with ECC */
5552 case 0x18: /* set media type for format */
5553 case 0x41: // IBM/MS installation check
5554 // FIXME ElTorito Harddisk. Darwin would like to use EDD
5555 case 0x42: // IBM/MS extended read
5556 case 0x43: // IBM/MS extended write
5557 case 0x44: // IBM/MS verify sectors
5558 case 0x45: // IBM/MS lock/unlock drive
5559 case 0x46: // IBM/MS eject media
5560 case 0x47: // IBM/MS extended seek
5561 case 0x48: // IBM/MS get drive parameters
5562 case 0x49: // IBM/MS extended media change
5563 case 0x4e: // ? - set hardware configuration
5564 case 0x50: // ? - send packet command
5565 default:
5566 BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
5567 goto int13_fail;
5568 break;
5571 int13_fail:
5572 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5573 int13_fail_noah:
5574 SET_DISK_RET_STATUS(GET_AH());
5575 int13_fail_nostatus:
5576 SET_CF(); // error occurred
5577 return;
5579 int13_success:
5580 SET_AH(0x00); // no error
5581 int13_success_noah:
5582 SET_DISK_RET_STATUS(0x00);
5583 CLEAR_CF(); // no error
5584 return;
5587 // ---------------------------------------------------------------------------
5588 // End of int13 when emulating a device from the cd
5589 // ---------------------------------------------------------------------------
5591 #endif // BX_ELTORITO_BOOT
5593 #else //BX_USE_ATADRV
5595 void
5596 outLBA(cylinder,hd_heads,head,hd_sectors,sector,dl)
5597 Bit16u cylinder;
5598 Bit16u hd_heads;
5599 Bit16u head;
5600 Bit16u hd_sectors;
5601 Bit16u sector;
5602 Bit16u dl;
5604 ASM_START
5605 push bp
5606 mov bp, sp
5607 push eax
5608 push ebx
5609 push edx
5610 xor eax,eax
5611 mov ax,4[bp] // cylinder
5612 xor ebx,ebx
5613 mov bl,6[bp] // hd_heads
5614 imul ebx
5616 mov bl,8[bp] // head
5617 add eax,ebx
5618 mov bl,10[bp] // hd_sectors
5619 imul ebx
5620 mov bl,12[bp] // sector
5621 add eax,ebx
5623 dec eax
5624 mov dx,#0x1f3
5625 out dx,al
5626 mov dx,#0x1f4
5627 mov al,ah
5628 out dx,al
5629 shr eax,#16
5630 mov dx,#0x1f5
5631 out dx,al
5632 and ah,#0xf
5633 mov bl,14[bp] // dl
5634 and bl,#1
5635 shl bl,#4
5636 or ah,bl
5637 or ah,#0xe0
5638 mov al,ah
5639 mov dx,#0x01f6
5640 out dx,al
5641 pop edx
5642 pop ebx
5643 pop eax
5644 pop bp
5645 ASM_END
5648 void
5649 int13_harddisk(DI, SI, BP, SP, BX, DX, CX, AX, DS, ES, FLAGS)
5650 Bit16u DI, SI, BP, SP, BX, DX, CX, AX, DS, ES, FLAGS;
5652 Bit8u drive, num_sectors, sector, head, status, mod;
5653 Bit8u drive_map;
5654 Bit8u n_drives;
5655 Bit16u cyl_mod, ax;
5656 Bit16u max_cylinder, cylinder, total_sectors;
5657 Bit16u hd_cylinders;
5658 Bit8u hd_heads, hd_sectors;
5659 Bit16u val16;
5660 Bit8u sector_count;
5661 unsigned int i;
5662 Bit16u tempbx;
5663 Bit16u dpsize;
5665 Bit16u count, segment, offset;
5666 Bit32u lba;
5667 Bit16u error;
5669 BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5671 write_byte(0x0040, 0x008e, 0); // clear completion flag
5673 /* at this point, DL is >= 0x80 to be passed from the floppy int13h
5674 handler code */
5675 /* check how many disks first (cmos reg 0x12), return an error if
5676 drive not present */
5677 drive_map = inb_cmos(0x12);
5678 drive_map = (((drive_map & 0xf0)==0) ? 0 : 1) |
5679 (((drive_map & 0x0f)==0) ? 0 : 2);
5680 n_drives = (drive_map==0) ? 0 :
5681 ((drive_map==3) ? 2 : 1);
5683 if (!(drive_map & (1<<(GET_DL()&0x7f)))) { /* allow 0, 1, or 2 disks */
5684 SET_AH(0x01);
5685 SET_DISK_RET_STATUS(0x01);
5686 SET_CF(); /* error occurred */
5687 return;
5690 switch (GET_AH()) {
5692 case 0x00: /* disk controller reset */
5693 BX_DEBUG_INT13_HD("int13_f00\n");
5695 SET_AH(0);
5696 SET_DISK_RET_STATUS(0);
5697 set_diskette_ret_status(0);
5698 set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
5699 set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
5700 CLEAR_CF(); /* successful */
5701 return;
5702 break;
5704 case 0x01: /* read disk status */
5705 BX_DEBUG_INT13_HD("int13_f01\n");
5706 status = read_byte(0x0040, 0x0074);
5707 SET_AH(status);
5708 SET_DISK_RET_STATUS(0);
5709 /* set CF if error status read */
5710 if (status) SET_CF();
5711 else CLEAR_CF();
5712 return;
5713 break;
5715 case 0x04: // verify disk sectors
5716 case 0x02: // read disk sectors
5717 drive = GET_DL();
5718 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
5720 num_sectors = GET_AL();
5721 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
5722 sector = (GET_CL() & 0x3f);
5723 head = GET_DH();
5726 if (hd_cylinders > 1024) {
5727 if (hd_cylinders <= 2048) {
5728 cylinder <<= 1;
5730 else if (hd_cylinders <= 4096) {
5731 cylinder <<= 2;
5733 else if (hd_cylinders <= 8192) {
5734 cylinder <<= 3;
5736 else { // hd_cylinders <= 16384
5737 cylinder <<= 4;
5740 ax = head / hd_heads;
5741 cyl_mod = ax & 0xff;
5742 head = ax >> 8;
5743 cylinder |= cyl_mod;
5746 if ( (cylinder >= hd_cylinders) ||
5747 (sector > hd_sectors) ||
5748 (head >= hd_heads) ) {
5749 SET_AH(1);
5750 SET_DISK_RET_STATUS(1);
5751 SET_CF(); /* error occurred */
5752 return;
5755 if ( (num_sectors > 128) || (num_sectors == 0) )
5756 BX_PANIC("int13_harddisk(): num_sectors out of range!\n");
5758 if (head > 15)
5759 BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
5761 if ( GET_AH() == 0x04 ) {
5762 SET_AH(0);
5763 SET_DISK_RET_STATUS(0);
5764 CLEAR_CF();
5765 return;
5768 status = inb(0x1f7);
5769 if (status & 0x80) {
5770 BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
5772 outb(0x01f2, num_sectors);
5773 /* activate LBA? (tomv) */
5774 if (hd_heads > 16) {
5775 BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder, head, sector);
5776 outLBA(cylinder,hd_heads,head,hd_sectors,sector,drive);
5778 else {
5779 outb(0x01f3, sector);
5780 outb(0x01f4, cylinder & 0x00ff);
5781 outb(0x01f5, cylinder >> 8);
5782 outb(0x01f6, 0xa0 | ((drive & 0x01)<<4) | (head & 0x0f));
5784 outb(0x01f7, 0x20);
5786 while (1) {
5787 status = inb(0x1f7);
5788 if ( !(status & 0x80) ) break;
5791 if (status & 0x01) {
5792 BX_PANIC("hard drive BIOS:(read/verify) read error\n");
5793 } else if ( !(status & 0x08) ) {
5794 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
5795 BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
5798 sector_count = 0;
5799 tempbx = BX;
5801 ASM_START
5802 sti ;; enable higher priority interrupts
5803 ASM_END
5805 while (1) {
5806 ASM_START
5807 ;; store temp bx in real DI register
5808 push bp
5809 mov bp, sp
5810 mov di, _int13_harddisk.tempbx + 2 [bp]
5811 pop bp
5813 ;; adjust if there will be an overrun
5814 cmp di, #0xfe00
5815 jbe i13_f02_no_adjust
5816 i13_f02_adjust:
5817 sub di, #0x0200 ; sub 512 bytes from offset
5818 mov ax, es
5819 add ax, #0x0020 ; add 512 to segment
5820 mov es, ax
5822 i13_f02_no_adjust:
5823 mov cx, #0x0100 ;; counter (256 words = 512b)
5824 mov dx, #0x01f0 ;; AT data read port
5827 insw ;; CX words transfered from port(DX) to ES:[DI]
5829 i13_f02_done:
5830 ;; store real DI register back to temp bx
5831 push bp
5832 mov bp, sp
5833 mov _int13_harddisk.tempbx + 2 [bp], di
5834 pop bp
5835 ASM_END
5837 sector_count++;
5838 num_sectors--;
5839 if (num_sectors == 0) {
5840 status = inb(0x1f7);
5841 if ( (status & 0xc9) != 0x40 )
5842 BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status);
5843 break;
5845 else {
5846 status = inb(0x1f7);
5847 if ( (status & 0xc9) != 0x48 )
5848 BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status);
5849 continue;
5853 SET_AH(0);
5854 SET_DISK_RET_STATUS(0);
5855 SET_AL(sector_count);
5856 CLEAR_CF(); /* successful */
5857 return;
5858 break;
5861 case 0x03: /* write disk sectors */
5862 BX_DEBUG_INT13_HD("int13_f03\n");
5863 drive = GET_DL ();
5864 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
5866 num_sectors = GET_AL();
5867 cylinder = GET_CH();
5868 cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
5869 sector = (GET_CL() & 0x3f);
5870 head = GET_DH();
5872 if (hd_cylinders > 1024) {
5873 if (hd_cylinders <= 2048) {
5874 cylinder <<= 1;
5876 else if (hd_cylinders <= 4096) {
5877 cylinder <<= 2;
5879 else if (hd_cylinders <= 8192) {
5880 cylinder <<= 3;
5882 else { // hd_cylinders <= 16384
5883 cylinder <<= 4;
5886 ax = head / hd_heads;
5887 cyl_mod = ax & 0xff;
5888 head = ax >> 8;
5889 cylinder |= cyl_mod;
5892 if ( (cylinder >= hd_cylinders) ||
5893 (sector > hd_sectors) ||
5894 (head >= hd_heads) ) {
5895 SET_AH( 1);
5896 SET_DISK_RET_STATUS(1);
5897 SET_CF(); /* error occurred */
5898 return;
5901 if ( (num_sectors > 128) || (num_sectors == 0) )
5902 BX_PANIC("int13_harddisk(): num_sectors out of range!\n");
5904 if (head > 15)
5905 BX_PANIC("hard drive BIOS:(read) head > 15\n");
5907 status = inb(0x1f7);
5908 if (status & 0x80) {
5909 BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
5911 // should check for Drive Ready Bit also in status reg
5912 outb(0x01f2, num_sectors);
5914 /* activate LBA? (tomv) */
5915 if (hd_heads > 16) {
5916 BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder, head, sector);
5917 outLBA(cylinder,hd_heads,head,hd_sectors,sector,GET_DL());
5919 else {
5920 outb(0x01f3, sector);
5921 outb(0x01f4, cylinder & 0x00ff);
5922 outb(0x01f5, cylinder >> 8);
5923 outb(0x01f6, 0xa0 | ((GET_DL() & 0x01)<<4) | (head & 0x0f));
5925 outb(0x01f7, 0x30);
5927 // wait for busy bit to turn off after seeking
5928 while (1) {
5929 status = inb(0x1f7);
5930 if ( !(status & 0x80) ) break;
5933 if ( !(status & 0x08) ) {
5934 BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
5935 BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
5938 sector_count = 0;
5939 tempbx = BX;
5941 ASM_START
5942 sti ;; enable higher priority interrupts
5943 ASM_END
5945 while (1) {
5946 ASM_START
5947 ;; store temp bx in real SI register
5948 push bp
5949 mov bp, sp
5950 mov si, _int13_harddisk.tempbx + 2 [bp]
5951 pop bp
5953 ;; adjust if there will be an overrun
5954 cmp si, #0xfe00
5955 jbe i13_f03_no_adjust
5956 i13_f03_adjust:
5957 sub si, #0x0200 ; sub 512 bytes from offset
5958 mov ax, es
5959 add ax, #0x0020 ; add 512 to segment
5960 mov es, ax
5962 i13_f03_no_adjust:
5963 mov cx, #0x0100 ;; counter (256 words = 512b)
5964 mov dx, #0x01f0 ;; AT data read port
5966 seg ES
5968 outsw ;; CX words tranfered from ES:[SI] to port(DX)
5970 ;; store real SI register back to temp bx
5971 push bp
5972 mov bp, sp
5973 mov _int13_harddisk.tempbx + 2 [bp], si
5974 pop bp
5975 ASM_END
5977 sector_count++;
5978 num_sectors--;
5979 if (num_sectors == 0) {
5980 status = inb(0x1f7);
5981 if ( (status & 0xe9) != 0x40 )
5982 BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status);
5983 break;
5985 else {
5986 status = inb(0x1f7);
5987 if ( (status & 0xc9) != 0x48 )
5988 BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status);
5989 continue;
5993 SET_AH(0);
5994 SET_DISK_RET_STATUS(0);
5995 SET_AL(sector_count);
5996 CLEAR_CF(); /* successful */
5997 return;
5998 break;
6000 case 0x05: /* format disk track */
6001 BX_DEBUG_INT13_HD("int13_f05\n");
6002 BX_PANIC("format disk track called\n");
6003 /* nop */
6004 SET_AH(0);
6005 SET_DISK_RET_STATUS(0);
6006 CLEAR_CF(); /* successful */
6007 return;
6008 break;
6010 case 0x08: /* read disk drive parameters */
6011 BX_DEBUG_INT13_HD("int13_f08\n");
6013 drive = GET_DL ();
6014 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6016 // translate CHS
6018 if (hd_cylinders <= 1024) {
6019 // hd_cylinders >>= 0;
6020 // hd_heads <<= 0;
6022 else if (hd_cylinders <= 2048) {
6023 hd_cylinders >>= 1;
6024 hd_heads <<= 1;
6026 else if (hd_cylinders <= 4096) {
6027 hd_cylinders >>= 2;
6028 hd_heads <<= 2;
6030 else if (hd_cylinders <= 8192) {
6031 hd_cylinders >>= 3;
6032 hd_heads <<= 3;
6034 else { // hd_cylinders <= 16384
6035 hd_cylinders >>= 4;
6036 hd_heads <<= 4;
6039 max_cylinder = hd_cylinders - 2; /* 0 based */
6040 SET_AL(0);
6041 SET_CH(max_cylinder & 0xff);
6042 SET_CL(((max_cylinder >> 2) & 0xc0) | (hd_sectors & 0x3f));
6043 SET_DH(hd_heads - 1);
6044 SET_DL(n_drives); /* returns 0, 1, or 2 hard drives */
6045 SET_AH(0);
6046 SET_DISK_RET_STATUS(0);
6047 CLEAR_CF(); /* successful */
6049 return;
6050 break;
6052 case 0x09: /* initialize drive parameters */
6053 BX_DEBUG_INT13_HD("int13_f09\n");
6054 SET_AH(0);
6055 SET_DISK_RET_STATUS(0);
6056 CLEAR_CF(); /* successful */
6057 return;
6058 break;
6060 case 0x0a: /* read disk sectors with ECC */
6061 BX_DEBUG_INT13_HD("int13_f0a\n");
6062 case 0x0b: /* write disk sectors with ECC */
6063 BX_DEBUG_INT13_HD("int13_f0b\n");
6064 BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
6065 return;
6066 break;
6068 case 0x0c: /* seek to specified cylinder */
6069 BX_DEBUG_INT13_HD("int13_f0c\n");
6070 BX_INFO("int13h function 0ch (seek) not implemented!\n");
6071 SET_AH(0);
6072 SET_DISK_RET_STATUS(0);
6073 CLEAR_CF(); /* successful */
6074 return;
6075 break;
6077 case 0x0d: /* alternate disk reset */
6078 BX_DEBUG_INT13_HD("int13_f0d\n");
6079 SET_AH(0);
6080 SET_DISK_RET_STATUS(0);
6081 CLEAR_CF(); /* successful */
6082 return;
6083 break;
6085 case 0x10: /* check drive ready */
6086 BX_DEBUG_INT13_HD("int13_f10\n");
6087 //SET_AH(0);
6088 //SET_DISK_RET_STATUS(0);
6089 //CLEAR_CF(); /* successful */
6090 //return;
6091 //break;
6093 // should look at 40:8E also???
6094 status = inb(0x01f7);
6095 if ( (status & 0xc0) == 0x40 ) {
6096 SET_AH(0);
6097 SET_DISK_RET_STATUS(0);
6098 CLEAR_CF(); // drive ready
6099 return;
6101 else {
6102 SET_AH(0xAA);
6103 SET_DISK_RET_STATUS(0xAA);
6104 SET_CF(); // not ready
6105 return;
6107 break;
6109 case 0x11: /* recalibrate */
6110 BX_DEBUG_INT13_HD("int13_f11\n");
6111 SET_AH(0);
6112 SET_DISK_RET_STATUS(0);
6113 CLEAR_CF(); /* successful */
6114 return;
6115 break;
6117 case 0x14: /* controller internal diagnostic */
6118 BX_DEBUG_INT13_HD("int13_f14\n");
6119 SET_AH(0);
6120 SET_DISK_RET_STATUS(0);
6121 CLEAR_CF(); /* successful */
6122 SET_AL(0);
6123 return;
6124 break;
6126 case 0x15: /* read disk drive size */
6127 drive = GET_DL();
6128 get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6129 ASM_START
6130 push bp
6131 mov bp, sp
6132 mov al, _int13_harddisk.hd_heads + 2 [bp]
6133 mov ah, _int13_harddisk.hd_sectors + 2 [bp]
6134 mul al, ah ;; ax = heads * sectors
6135 mov bx, _int13_harddisk.hd_cylinders + 2 [bp]
6136 dec bx ;; use (cylinders - 1) ???
6137 mul ax, bx ;; dx:ax = (cylinders -1) * (heads * sectors)
6138 ;; now we need to move the 32bit result dx:ax to what the
6139 ;; BIOS wants which is cx:dx.
6140 ;; and then into CX:DX on the stack
6141 mov _int13_harddisk.CX + 2 [bp], dx
6142 mov _int13_harddisk.DX + 2 [bp], ax
6143 pop bp
6144 ASM_END
6145 SET_AH(3); // hard disk accessible
6146 SET_DISK_RET_STATUS(0); // ??? should this be 0
6147 CLEAR_CF(); // successful
6148 return;
6149 break;
6151 case 0x18: // set media type for format
6152 case 0x41: // IBM/MS
6153 case 0x42: // IBM/MS
6154 case 0x43: // IBM/MS
6155 case 0x44: // IBM/MS
6156 case 0x45: // IBM/MS lock/unlock drive
6157 case 0x46: // IBM/MS eject media
6158 case 0x47: // IBM/MS extended seek
6159 case 0x49: // IBM/MS extended media change
6160 case 0x50: // IBM/MS send packet command
6161 default:
6162 BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
6164 SET_AH(1); // code=invalid function in AH or invalid parameter
6165 SET_DISK_RET_STATUS(1);
6166 SET_CF(); /* unsuccessful */
6167 return;
6168 break;
6172 static char panic_msg_reg12h[] = "HD%d cmos reg 12h not type F";
6173 static char panic_msg_reg19h[] = "HD%d cmos reg %02xh not user definable type 47";
6175 void
6176 get_hd_geometry(drive, hd_cylinders, hd_heads, hd_sectors)
6177 Bit8u drive;
6178 Bit16u *hd_cylinders;
6179 Bit8u *hd_heads;
6180 Bit8u *hd_sectors;
6182 Bit8u hd_type;
6183 Bit16u ss;
6184 Bit16u cylinders;
6185 Bit8u iobase;
6187 ss = get_SS();
6188 if (drive == 0x80) {
6189 hd_type = inb_cmos(0x12) & 0xf0;
6190 if (hd_type != 0xf0)
6191 BX_INFO(panic_msg_reg12h,0);
6192 hd_type = inb_cmos(0x19); // HD0: extended type
6193 if (hd_type != 47)
6194 BX_INFO(panic_msg_reg19h,0,0x19);
6195 iobase = 0x1b;
6196 } else {
6197 hd_type = inb_cmos(0x12) & 0x0f;
6198 if (hd_type != 0x0f)
6199 BX_INFO(panic_msg_reg12h,1);
6200 hd_type = inb_cmos(0x1a); // HD0: extended type
6201 if (hd_type != 47)
6202 BX_INFO(panic_msg_reg19h,0,0x1a);
6203 iobase = 0x24;
6206 // cylinders
6207 cylinders = inb_cmos(iobase) | (inb_cmos(iobase+1) << 8);
6208 write_word(ss, hd_cylinders, cylinders);
6210 // heads
6211 write_byte(ss, hd_heads, inb_cmos(iobase+2));
6213 // sectors per track
6214 write_byte(ss, hd_sectors, inb_cmos(iobase+8));
6217 #endif //else BX_USE_ATADRV
6220 //////////////////////
6221 // FLOPPY functions //
6222 //////////////////////
6224 bx_bool
6225 floppy_media_known(drive)
6226 Bit16u drive;
6228 Bit8u val8;
6229 Bit16u media_state_offset;
6231 val8 = read_byte(0x0040, 0x003e); // diskette recal status
6232 if (drive)
6233 val8 >>= 1;
6234 val8 &= 0x01;
6235 if (val8 == 0)
6236 return(0);
6238 media_state_offset = 0x0090;
6239 if (drive)
6240 media_state_offset += 1;
6242 val8 = read_byte(0x0040, media_state_offset);
6243 val8 = (val8 >> 4) & 0x01;
6244 if (val8 == 0)
6245 return(0);
6247 // check pass, return KNOWN
6248 return(1);
6251 bx_bool
6252 floppy_media_sense(drive)
6253 Bit16u drive;
6255 bx_bool retval;
6256 Bit16u media_state_offset;
6257 Bit8u drive_type, config_data, media_state;
6259 if (floppy_drive_recal(drive) == 0) {
6260 return(0);
6263 // for now cheat and get drive type from CMOS,
6264 // assume media is same as drive type
6266 // ** config_data **
6267 // Bitfields for diskette media control:
6268 // Bit(s) Description (Table M0028)
6269 // 7-6 last data rate set by controller
6270 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6271 // 5-4 last diskette drive step rate selected
6272 // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
6273 // 3-2 {data rate at start of operation}
6274 // 1-0 reserved
6276 // ** media_state **
6277 // Bitfields for diskette drive media state:
6278 // Bit(s) Description (Table M0030)
6279 // 7-6 data rate
6280 // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6281 // 5 double stepping required (e.g. 360kB in 1.2MB)
6282 // 4 media type established
6283 // 3 drive capable of supporting 4MB media
6284 // 2-0 on exit from BIOS, contains
6285 // 000 trying 360kB in 360kB
6286 // 001 trying 360kB in 1.2MB
6287 // 010 trying 1.2MB in 1.2MB
6288 // 011 360kB in 360kB established
6289 // 100 360kB in 1.2MB established
6290 // 101 1.2MB in 1.2MB established
6291 // 110 reserved
6292 // 111 all other formats/drives
6294 drive_type = inb_cmos(0x10);
6295 if (drive == 0)
6296 drive_type >>= 4;
6297 else
6298 drive_type &= 0x0f;
6299 if ( drive_type == 1 ) {
6300 // 360K 5.25" drive
6301 config_data = 0x00; // 0000 0000
6302 media_state = 0x25; // 0010 0101
6303 retval = 1;
6305 else if ( drive_type == 2 ) {
6306 // 1.2 MB 5.25" drive
6307 config_data = 0x00; // 0000 0000
6308 media_state = 0x25; // 0010 0101 // need double stepping??? (bit 5)
6309 retval = 1;
6311 else if ( drive_type == 3 ) {
6312 // 720K 3.5" drive
6313 config_data = 0x00; // 0000 0000 ???
6314 media_state = 0x17; // 0001 0111
6315 retval = 1;
6317 else if ( drive_type == 4 ) {
6318 // 1.44 MB 3.5" drive
6319 config_data = 0x00; // 0000 0000
6320 media_state = 0x17; // 0001 0111
6321 retval = 1;
6323 else if ( drive_type == 5 ) {
6324 // 2.88 MB 3.5" drive
6325 config_data = 0xCC; // 1100 1100
6326 media_state = 0xD7; // 1101 0111
6327 retval = 1;
6330 // Extended floppy size uses special cmos setting
6331 else if ( drive_type == 6 ) {
6332 // 160k 5.25" drive
6333 config_data = 0x00; // 0000 0000
6334 media_state = 0x27; // 0010 0111
6335 retval = 1;
6337 else if ( drive_type == 7 ) {
6338 // 180k 5.25" drive
6339 config_data = 0x00; // 0000 0000
6340 media_state = 0x27; // 0010 0111
6341 retval = 1;
6343 else if ( drive_type == 8 ) {
6344 // 320k 5.25" drive
6345 config_data = 0x00; // 0000 0000
6346 media_state = 0x27; // 0010 0111
6347 retval = 1;
6350 else {
6351 // not recognized
6352 config_data = 0x00; // 0000 0000
6353 media_state = 0x00; // 0000 0000
6354 retval = 0;
6357 if (drive == 0)
6358 media_state_offset = 0x90;
6359 else
6360 media_state_offset = 0x91;
6361 write_byte(0x0040, 0x008B, config_data);
6362 write_byte(0x0040, media_state_offset, media_state);
6364 return(retval);
6367 bx_bool
6368 floppy_drive_recal(drive)
6369 Bit16u drive;
6371 Bit8u val8, dor;
6372 Bit16u curr_cyl_offset;
6374 // set 40:3e bit 7 to 0
6375 val8 = read_byte(0x0000, 0x043e);
6376 val8 &= 0x7f;
6377 write_byte(0x0000, 0x043e, val8);
6379 // turn on motor of selected drive, DMA & int enabled, normal operation
6380 if (drive)
6381 dor = 0x20;
6382 else
6383 dor = 0x10;
6384 dor |= 0x0c;
6385 dor |= drive;
6386 outb(0x03f2, dor);
6388 // reset the disk motor timeout value of INT 08
6389 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
6391 // check port 3f4 for drive readiness
6392 val8 = inb(0x3f4);
6393 if ( (val8 & 0xf0) != 0x80 )
6394 BX_PANIC("floppy recal:f07: ctrl not ready\n");
6396 // send Recalibrate command (2 bytes) to controller
6397 outb(0x03f5, 0x07); // 07: Recalibrate
6398 outb(0x03f5, drive); // 0=drive0, 1=drive1
6400 // turn on interrupts
6401 ASM_START
6403 ASM_END
6405 // wait on 40:3e bit 7 to become 1
6406 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6407 while ( val8 == 0 ) {
6408 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6411 val8 = 0; // separate asm from while() loop
6412 // turn off interrupts
6413 ASM_START
6415 ASM_END
6417 // set 40:3e bit 7 to 0, and calibrated bit
6418 val8 = read_byte(0x0000, 0x043e);
6419 val8 &= 0x7f;
6420 if (drive) {
6421 val8 |= 0x02; // Drive 1 calibrated
6422 curr_cyl_offset = 0x0095;
6424 else {
6425 val8 |= 0x01; // Drive 0 calibrated
6426 curr_cyl_offset = 0x0094;
6428 write_byte(0x0040, 0x003e, val8);
6429 write_byte(0x0040, curr_cyl_offset, 0); // current cylinder is 0
6431 return(1);
6436 bx_bool
6437 floppy_drive_exists(drive)
6438 Bit16u drive;
6440 Bit8u drive_type;
6442 // check CMOS to see if drive exists
6443 drive_type = inb_cmos(0x10);
6444 if (drive == 0)
6445 drive_type >>= 4;
6446 else
6447 drive_type &= 0x0f;
6448 if ( drive_type == 0 )
6449 return(0);
6450 else
6451 return(1);
6454 #if BX_SUPPORT_FLOPPY
6455 void
6456 int13_diskette_function(DI, SI, BP, SP, BX, DX, CX, AX, ES, FLAGS)
6457 Bit16u DI, SI, BP, SP, BX, DX, CX, AX, ES, FLAGS;
6459 Bit8u drive, num_sectors, track, sector, head, status;
6460 Bit16u base_address, base_count, base_es;
6461 Bit8u page, mode_register, val8, dor;
6462 Bit8u return_status[7];
6463 Bit8u drive_type, num_floppies, ah;
6464 Bit16u es, last_addr;
6466 BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6467 // BX_DEBUG_INT13_FL("int13_diskette: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), get_DS(), ES, DI, SI);
6469 ah = GET_AH();
6471 switch ( ah ) {
6472 case 0x00: // diskette controller reset
6473 BX_DEBUG_INT13_FL("floppy f00\n");
6474 drive = GET_DL();
6475 if (drive > 1) {
6476 SET_AH(1); // invalid param
6477 set_diskette_ret_status(1);
6478 SET_CF();
6479 return;
6481 drive_type = inb_cmos(0x10);
6483 if (drive == 0)
6484 drive_type >>= 4;
6485 else
6486 drive_type &= 0x0f;
6487 if (drive_type == 0) {
6488 SET_AH(0x80); // drive not responding
6489 set_diskette_ret_status(0x80);
6490 SET_CF();
6491 return;
6493 SET_AH(0);
6494 set_diskette_ret_status(0);
6495 CLEAR_CF(); // successful
6496 set_diskette_current_cyl(drive, 0); // current cylinder
6497 return;
6499 case 0x01: // Read Diskette Status
6500 CLEAR_CF();
6501 val8 = read_byte(0x0000, 0x0441);
6502 SET_AH(val8);
6503 if (val8) {
6504 SET_CF();
6506 return;
6508 case 0x02: // Read Diskette Sectors
6509 case 0x03: // Write Diskette Sectors
6510 case 0x04: // Verify Diskette Sectors
6511 num_sectors = GET_AL();
6512 track = GET_CH();
6513 sector = GET_CL();
6514 head = GET_DH();
6515 drive = GET_DL();
6517 if ( (drive > 1) || (head > 1) ||
6518 (num_sectors == 0) || (num_sectors > 72) ) {
6519 BX_INFO("floppy: drive>1 || head>1 ...\n");
6520 SET_AH(1);
6521 set_diskette_ret_status(1);
6522 SET_AL(0); // no sectors read
6523 SET_CF(); // error occurred
6524 return;
6527 // see if drive exists
6528 if (floppy_drive_exists(drive) == 0) {
6529 SET_AH(0x80); // not responding
6530 set_diskette_ret_status(0x80);
6531 SET_AL(0); // no sectors read
6532 SET_CF(); // error occurred
6533 return;
6536 // see if media in drive, and type is known
6537 if (floppy_media_known(drive) == 0) {
6538 if (floppy_media_sense(drive) == 0) {
6539 SET_AH(0x0C); // Media type not found
6540 set_diskette_ret_status(0x0C);
6541 SET_AL(0); // no sectors read
6542 SET_CF(); // error occurred
6543 return;
6547 if (ah == 0x02) {
6548 // Read Diskette Sectors
6550 //-----------------------------------
6551 // set up DMA controller for transfer
6552 //-----------------------------------
6554 // es:bx = pointer to where to place information from diskette
6555 // port 04: DMA-1 base and current address, channel 2
6556 // port 05: DMA-1 base and current count, channel 2
6557 page = (ES >> 12); // upper 4 bits
6558 base_es = (ES << 4); // lower 16bits contributed by ES
6559 base_address = base_es + BX; // lower 16 bits of address
6560 // contributed by ES:BX
6561 if ( base_address < base_es ) {
6562 // in case of carry, adjust page by 1
6563 page++;
6565 base_count = (num_sectors * 512) - 1;
6567 // check for 64K boundary overrun
6568 last_addr = base_address + base_count;
6569 if (last_addr < base_address) {
6570 SET_AH(0x09);
6571 set_diskette_ret_status(0x09);
6572 SET_AL(0); // no sectors read
6573 SET_CF(); // error occurred
6574 return;
6577 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
6578 outb(0x000a, 0x06);
6580 BX_DEBUG_INT13_FL("clear flip-flop\n");
6581 outb(0x000c, 0x00); // clear flip-flop
6582 outb(0x0004, base_address);
6583 outb(0x0004, base_address>>8);
6584 BX_DEBUG_INT13_FL("clear flip-flop\n");
6585 outb(0x000c, 0x00); // clear flip-flop
6586 outb(0x0005, base_count);
6587 outb(0x0005, base_count>>8);
6589 // port 0b: DMA-1 Mode Register
6590 mode_register = 0x46; // single mode, increment, autoinit disable,
6591 // transfer type=write, channel 2
6592 BX_DEBUG_INT13_FL("setting mode register\n");
6593 outb(0x000b, mode_register);
6595 BX_DEBUG_INT13_FL("setting page register\n");
6596 // port 81: DMA-1 Page Register, channel 2
6597 outb(0x0081, page);
6599 BX_DEBUG_INT13_FL("unmask chan 2\n");
6600 outb(0x000a, 0x02); // unmask channel 2
6602 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
6603 outb(0x000a, 0x02);
6605 //--------------------------------------
6606 // set up floppy controller for transfer
6607 //--------------------------------------
6609 // set 40:3e bit 7 to 0
6610 val8 = read_byte(0x0000, 0x043e);
6611 val8 &= 0x7f;
6612 write_byte(0x0000, 0x043e, val8);
6614 // turn on motor of selected drive, DMA & int enabled, normal operation
6615 if (drive)
6616 dor = 0x20;
6617 else
6618 dor = 0x10;
6619 dor |= 0x0c;
6620 dor |= drive;
6621 outb(0x03f2, dor);
6623 // reset the disk motor timeout value of INT 08
6624 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
6626 // check port 3f4 for drive readiness
6627 val8 = inb(0x3f4);
6628 if ( (val8 & 0xf0) != 0x80 )
6629 BX_PANIC("int13_diskette:f02: ctrl not ready\n");
6631 // send read-normal-data command (9 bytes) to controller
6632 outb(0x03f5, 0xe6); // e6: read normal data
6633 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
6634 outb(0x03f5, track);
6635 outb(0x03f5, head);
6636 outb(0x03f5, sector);
6637 outb(0x03f5, 2); // 512 byte sector size
6638 outb(0x03f5, 0); // last sector number possible on track
6639 outb(0x03f5, 0); // Gap length
6640 outb(0x03f5, 0xff); // Gap length
6642 // turn on interrupts
6643 ASM_START
6645 ASM_END
6647 // wait on 40:3e bit 7 to become 1
6648 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6649 while ( val8 == 0 ) {
6650 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6653 val8 = 0; // separate asm from while() loop
6654 // turn off interrupts
6655 ASM_START
6657 ASM_END
6659 // set 40:3e bit 7 to 0
6660 val8 = read_byte(0x0000, 0x043e);
6661 val8 &= 0x7f;
6662 write_byte(0x0000, 0x043e, val8);
6664 // check port 3f4 for accessibility to status bytes
6665 val8 = inb(0x3f4);
6666 if ( (val8 & 0xc0) != 0xc0 )
6667 BX_PANIC("int13_diskette: ctrl not ready\n");
6669 // read 7 return status bytes from controller
6670 // using loop index broken, have to unroll...
6671 return_status[0] = inb(0x3f5);
6672 return_status[1] = inb(0x3f5);
6673 return_status[2] = inb(0x3f5);
6674 return_status[3] = inb(0x3f5);
6675 return_status[4] = inb(0x3f5);
6676 return_status[5] = inb(0x3f5);
6677 return_status[6] = inb(0x3f5);
6678 // record in BIOS Data Area
6679 write_byte(0x0040, 0x0042, return_status[0]);
6680 write_byte(0x0040, 0x0043, return_status[1]);
6681 write_byte(0x0040, 0x0044, return_status[2]);
6682 write_byte(0x0040, 0x0045, return_status[3]);
6683 write_byte(0x0040, 0x0046, return_status[4]);
6684 write_byte(0x0040, 0x0047, return_status[5]);
6685 write_byte(0x0040, 0x0048, return_status[6]);
6687 if ( (return_status[0] & 0xc0) != 0 ) {
6688 SET_AH(0x20);
6689 set_diskette_ret_status(0x20);
6690 SET_AL(0); // no sectors read
6691 SET_CF(); // error occurred
6692 return;
6695 // ??? should track be new val from return_status[3] ?
6696 set_diskette_current_cyl(drive, track);
6697 // AL = number of sectors read (same value as passed)
6698 SET_AH(0x00); // success
6699 CLEAR_CF(); // success
6700 return;
6702 else if (ah == 0x03) {
6703 // Write Diskette Sectors
6705 //-----------------------------------
6706 // set up DMA controller for transfer
6707 //-----------------------------------
6709 // es:bx = pointer to where to place information from diskette
6710 // port 04: DMA-1 base and current address, channel 2
6711 // port 05: DMA-1 base and current count, channel 2
6712 page = (ES >> 12); // upper 4 bits
6713 base_es = (ES << 4); // lower 16bits contributed by ES
6714 base_address = base_es + BX; // lower 16 bits of address
6715 // contributed by ES:BX
6716 if ( base_address < base_es ) {
6717 // in case of carry, adjust page by 1
6718 page++;
6720 base_count = (num_sectors * 512) - 1;
6722 // check for 64K boundary overrun
6723 last_addr = base_address + base_count;
6724 if (last_addr < base_address) {
6725 SET_AH(0x09);
6726 set_diskette_ret_status(0x09);
6727 SET_AL(0); // no sectors read
6728 SET_CF(); // error occurred
6729 return;
6732 BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
6733 outb(0x000a, 0x06);
6735 outb(0x000c, 0x00); // clear flip-flop
6736 outb(0x0004, base_address);
6737 outb(0x0004, base_address>>8);
6738 outb(0x000c, 0x00); // clear flip-flop
6739 outb(0x0005, base_count);
6740 outb(0x0005, base_count>>8);
6742 // port 0b: DMA-1 Mode Register
6743 mode_register = 0x4a; // single mode, increment, autoinit disable,
6744 // transfer type=read, channel 2
6745 outb(0x000b, mode_register);
6747 // port 81: DMA-1 Page Register, channel 2
6748 outb(0x0081, page);
6750 BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
6751 outb(0x000a, 0x02);
6753 //--------------------------------------
6754 // set up floppy controller for transfer
6755 //--------------------------------------
6757 // set 40:3e bit 7 to 0
6758 val8 = read_byte(0x0000, 0x043e);
6759 val8 &= 0x7f;
6760 write_byte(0x0000, 0x043e, val8);
6762 // turn on motor of selected drive, DMA & int enabled, normal operation
6763 if (drive)
6764 dor = 0x20;
6765 else
6766 dor = 0x10;
6767 dor |= 0x0c;
6768 dor |= drive;
6769 outb(0x03f2, dor);
6771 // reset the disk motor timeout value of INT 08
6772 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
6774 // check port 3f4 for drive readiness
6775 val8 = inb(0x3f4);
6776 if ( (val8 & 0xf0) != 0x80 )
6777 BX_PANIC("int13_diskette:f03: ctrl not ready\n");
6779 // send read-normal-data command (9 bytes) to controller
6780 outb(0x03f5, 0xc5); // c5: write normal data
6781 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
6782 outb(0x03f5, track);
6783 outb(0x03f5, head);
6784 outb(0x03f5, sector);
6785 outb(0x03f5, 2); // 512 byte sector size
6786 outb(0x03f5, 0); // last sector number possible on track
6787 outb(0x03f5, 0); // Gap length
6788 outb(0x03f5, 0xff); // Gap length
6790 // turn on interrupts
6791 ASM_START
6793 ASM_END
6795 // wait on 40:3e bit 7 to become 1
6796 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6797 while ( val8 == 0 ) {
6798 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6801 val8 = 0; // separate asm from while() loop
6802 // turn off interrupts
6803 ASM_START
6805 ASM_END
6807 // set 40:3e bit 7 to 0
6808 val8 = read_byte(0x0000, 0x043e);
6809 val8 &= 0x7f;
6810 write_byte(0x0000, 0x043e, val8);
6812 // check port 3f4 for accessibility to status bytes
6813 val8 = inb(0x3f4);
6814 if ( (val8 & 0xc0) != 0xc0 )
6815 BX_PANIC("int13_diskette: ctrl not ready\n");
6817 // read 7 return status bytes from controller
6818 // using loop index broken, have to unroll...
6819 return_status[0] = inb(0x3f5);
6820 return_status[1] = inb(0x3f5);
6821 return_status[2] = inb(0x3f5);
6822 return_status[3] = inb(0x3f5);
6823 return_status[4] = inb(0x3f5);
6824 return_status[5] = inb(0x3f5);
6825 return_status[6] = inb(0x3f5);
6826 // record in BIOS Data Area
6827 write_byte(0x0040, 0x0042, return_status[0]);
6828 write_byte(0x0040, 0x0043, return_status[1]);
6829 write_byte(0x0040, 0x0044, return_status[2]);
6830 write_byte(0x0040, 0x0045, return_status[3]);
6831 write_byte(0x0040, 0x0046, return_status[4]);
6832 write_byte(0x0040, 0x0047, return_status[5]);
6833 write_byte(0x0040, 0x0048, return_status[6]);
6835 if ( (return_status[0] & 0xc0) != 0 ) {
6836 if ( (return_status[1] & 0x02) != 0 ) {
6837 // diskette not writable.
6838 // AH=status code=0x03 (tried to write on write-protected disk)
6839 // AL=number of sectors written=0
6840 AX = 0x0300;
6841 SET_CF();
6842 return;
6843 } else {
6844 BX_PANIC("int13_diskette_function: read error\n");
6848 // ??? should track be new val from return_status[3] ?
6849 set_diskette_current_cyl(drive, track);
6850 // AL = number of sectors read (same value as passed)
6851 SET_AH(0x00); // success
6852 CLEAR_CF(); // success
6853 return;
6855 else { // if (ah == 0x04)
6856 // Verify Diskette Sectors
6858 // ??? should track be new val from return_status[3] ?
6859 set_diskette_current_cyl(drive, track);
6860 // AL = number of sectors verified (same value as passed)
6861 CLEAR_CF(); // success
6862 SET_AH(0x00); // success
6863 return;
6867 case 0x05: // format diskette track
6868 BX_DEBUG_INT13_FL("floppy f05\n");
6870 num_sectors = GET_AL();
6871 track = GET_CH();
6872 head = GET_DH();
6873 drive = GET_DL();
6875 if ((drive > 1) || (head > 1) || (track > 79) ||
6876 (num_sectors == 0) || (num_sectors > 18)) {
6877 SET_AH(1);
6878 set_diskette_ret_status(1);
6879 SET_CF(); // error occurred
6882 // see if drive exists
6883 if (floppy_drive_exists(drive) == 0) {
6884 SET_AH(0x80); // drive not responding
6885 set_diskette_ret_status(0x80);
6886 SET_CF(); // error occurred
6887 return;
6890 // see if media in drive, and type is known
6891 if (floppy_media_known(drive) == 0) {
6892 if (floppy_media_sense(drive) == 0) {
6893 SET_AH(0x0C); // Media type not found
6894 set_diskette_ret_status(0x0C);
6895 SET_AL(0); // no sectors read
6896 SET_CF(); // error occurred
6897 return;
6901 // set up DMA controller for transfer
6902 page = (ES >> 12); // upper 4 bits
6903 base_es = (ES << 4); // lower 16bits contributed by ES
6904 base_address = base_es + BX; // lower 16 bits of address
6905 // contributed by ES:BX
6906 if ( base_address < base_es ) {
6907 // in case of carry, adjust page by 1
6908 page++;
6910 base_count = (num_sectors * 4) - 1;
6912 // check for 64K boundary overrun
6913 last_addr = base_address + base_count;
6914 if (last_addr < base_address) {
6915 SET_AH(0x09);
6916 set_diskette_ret_status(0x09);
6917 SET_AL(0); // no sectors read
6918 SET_CF(); // error occurred
6919 return;
6922 outb(0x000a, 0x06);
6923 outb(0x000c, 0x00); // clear flip-flop
6924 outb(0x0004, base_address);
6925 outb(0x0004, base_address>>8);
6926 outb(0x000c, 0x00); // clear flip-flop
6927 outb(0x0005, base_count);
6928 outb(0x0005, base_count>>8);
6929 mode_register = 0x4a; // single mode, increment, autoinit disable,
6930 // transfer type=read, channel 2
6931 outb(0x000b, mode_register);
6932 // port 81: DMA-1 Page Register, channel 2
6933 outb(0x0081, page);
6934 outb(0x000a, 0x02);
6936 // set up floppy controller for transfer
6937 val8 = read_byte(0x0000, 0x043e);
6938 val8 &= 0x7f;
6939 write_byte(0x0000, 0x043e, val8);
6940 // turn on motor of selected drive, DMA & int enabled, normal operation
6941 if (drive)
6942 dor = 0x20;
6943 else
6944 dor = 0x10;
6945 dor |= 0x0c;
6946 dor |= drive;
6947 outb(0x03f2, dor);
6949 // reset the disk motor timeout value of INT 08
6950 write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
6952 // check port 3f4 for drive readiness
6953 val8 = inb(0x3f4);
6954 if ( (val8 & 0xf0) != 0x80 )
6955 BX_PANIC("int13_diskette:f05: ctrl not ready\n");
6957 // send read-normal-data command (6 bytes) to controller
6958 outb(0x03f5, 0x4d); // 4d: format track
6959 outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
6960 outb(0x03f5, 2); // 512 byte sector size
6961 outb(0x03f5, num_sectors); // number of sectors per track
6962 outb(0x03f5, 0); // Gap length
6963 outb(0x03f5, 0xf6); // Fill byte
6964 // turn on interrupts
6965 ASM_START
6967 ASM_END
6968 // wait on 40:3e bit 7 to become 1
6969 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6970 while ( val8 == 0 ) {
6971 val8 = (read_byte(0x0000, 0x043e) & 0x80);
6973 val8 = 0; // separate asm from while() loop
6974 // turn off interrupts
6975 ASM_START
6977 ASM_END
6978 // set 40:3e bit 7 to 0
6979 val8 = read_byte(0x0000, 0x043e);
6980 val8 &= 0x7f;
6981 write_byte(0x0000, 0x043e, val8);
6982 // check port 3f4 for accessibility to status bytes
6983 val8 = inb(0x3f4);
6984 if ( (val8 & 0xc0) != 0xc0 )
6985 BX_PANIC("int13_diskette: ctrl not ready\n");
6987 // read 7 return status bytes from controller
6988 // using loop index broken, have to unroll...
6989 return_status[0] = inb(0x3f5);
6990 return_status[1] = inb(0x3f5);
6991 return_status[2] = inb(0x3f5);
6992 return_status[3] = inb(0x3f5);
6993 return_status[4] = inb(0x3f5);
6994 return_status[5] = inb(0x3f5);
6995 return_status[6] = inb(0x3f5);
6996 // record in BIOS Data Area
6997 write_byte(0x0040, 0x0042, return_status[0]);
6998 write_byte(0x0040, 0x0043, return_status[1]);
6999 write_byte(0x0040, 0x0044, return_status[2]);
7000 write_byte(0x0040, 0x0045, return_status[3]);
7001 write_byte(0x0040, 0x0046, return_status[4]);
7002 write_byte(0x0040, 0x0047, return_status[5]);
7003 write_byte(0x0040, 0x0048, return_status[6]);
7005 if ( (return_status[0] & 0xc0) != 0 ) {
7006 if ( (return_status[1] & 0x02) != 0 ) {
7007 // diskette not writable.
7008 // AH=status code=0x03 (tried to write on write-protected disk)
7009 // AL=number of sectors written=0
7010 AX = 0x0300;
7011 SET_CF();
7012 return;
7013 } else {
7014 BX_PANIC("int13_diskette_function: write error\n");
7018 SET_AH(0);
7019 set_diskette_ret_status(0);
7020 set_diskette_current_cyl(drive, 0);
7021 CLEAR_CF(); // successful
7022 return;
7025 case 0x08: // read diskette drive parameters
7026 BX_DEBUG_INT13_FL("floppy f08\n");
7027 drive = GET_DL();
7029 if (drive > 1) {
7030 AX = 0;
7031 BX = 0;
7032 CX = 0;
7033 DX = 0;
7034 ES = 0;
7035 DI = 0;
7036 SET_DL(num_floppies);
7037 SET_CF();
7038 return;
7041 drive_type = inb_cmos(0x10);
7042 num_floppies = 0;
7043 if (drive_type & 0xf0)
7044 num_floppies++;
7045 if (drive_type & 0x0f)
7046 num_floppies++;
7048 if (drive == 0)
7049 drive_type >>= 4;
7050 else
7051 drive_type &= 0x0f;
7053 SET_BH(0);
7054 SET_BL(drive_type);
7055 SET_AH(0);
7056 SET_AL(0);
7057 SET_DL(num_floppies);
7059 switch (drive_type) {
7060 case 0: // none
7061 CX = 0;
7062 SET_DH(0); // max head #
7063 break;
7065 case 1: // 360KB, 5.25"
7066 CX = 0x2709; // 40 tracks, 9 sectors
7067 SET_DH(1); // max head #
7068 break;
7070 case 2: // 1.2MB, 5.25"
7071 CX = 0x4f0f; // 80 tracks, 15 sectors
7072 SET_DH(1); // max head #
7073 break;
7075 case 3: // 720KB, 3.5"
7076 CX = 0x4f09; // 80 tracks, 9 sectors
7077 SET_DH(1); // max head #
7078 break;
7080 case 4: // 1.44MB, 3.5"
7081 CX = 0x4f12; // 80 tracks, 18 sectors
7082 SET_DH(1); // max head #
7083 break;
7085 case 5: // 2.88MB, 3.5"
7086 CX = 0x4f24; // 80 tracks, 36 sectors
7087 SET_DH(1); // max head #
7088 break;
7090 case 6: // 160k, 5.25"
7091 CX = 0x2708; // 40 tracks, 8 sectors
7092 SET_DH(0); // max head #
7093 break;
7095 case 7: // 180k, 5.25"
7096 CX = 0x2709; // 40 tracks, 9 sectors
7097 SET_DH(0); // max head #
7098 break;
7100 case 8: // 320k, 5.25"
7101 CX = 0x2708; // 40 tracks, 8 sectors
7102 SET_DH(1); // max head #
7103 break;
7105 default: // ?
7106 BX_PANIC("floppy: int13: bad floppy type\n");
7109 /* set es & di to point to 11 byte diskette param table in ROM */
7110 DI = read_word(0x00, 0x1e*4); // INT vector 0x1E
7111 ES = read_word(0x00, 0x1e*4+2);
7112 CLEAR_CF(); // success
7113 /* disk status not changed upon success */
7114 return;
7117 case 0x15: // read diskette drive type
7118 BX_DEBUG_INT13_FL("floppy f15\n");
7119 drive = GET_DL();
7120 if (drive > 1) {
7121 SET_AH(0); // only 2 drives supported
7122 // set_diskette_ret_status here ???
7123 SET_CF();
7124 return;
7126 drive_type = inb_cmos(0x10);
7128 if (drive == 0)
7129 drive_type >>= 4;
7130 else
7131 drive_type &= 0x0f;
7132 CLEAR_CF(); // successful, not present
7133 if (drive_type==0) {
7134 SET_AH(0); // drive not present
7136 else {
7137 SET_AH(1); // drive present, does not support change line
7140 #if BX_ELTORITO_BOOT
7141 // This is mandatory. Otherwise Win98 does not boot
7142 if ((cdemu_isactive() != 00) && (cdemu_emulated_drive() == drive))
7143 DX+=0x0001;
7144 #endif
7145 return;
7147 case 0x16: // get diskette change line status
7148 BX_DEBUG_INT13_FL("floppy f16\n");
7149 drive = GET_DL();
7150 if (drive > 1) {
7151 SET_AH(0x01); // invalid drive
7152 set_diskette_ret_status(0x01);
7153 SET_CF();
7154 return;
7157 SET_AH(0x06); // change line not supported
7158 set_diskette_ret_status(0x06);
7159 SET_CF();
7160 return;
7162 case 0x17: // set diskette type for format(old)
7163 BX_DEBUG_INT13_FL("floppy f17\n");
7164 /* not used for 1.44M floppies */
7165 SET_AH(0x01); // not supported
7166 set_diskette_ret_status(1); /* not supported */
7167 SET_CF();
7168 return;
7170 case 0x18: // set diskette type for format(new)
7171 BX_DEBUG_INT13_FL("floppy f18\n");
7172 SET_AH(0x01); // do later
7173 set_diskette_ret_status(1);
7174 SET_CF();
7175 return;
7177 default:
7178 BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
7180 // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
7181 SET_AH(0x01); // ???
7182 set_diskette_ret_status(1);
7183 SET_CF();
7184 return;
7185 // }
7188 #else // #if BX_SUPPORT_FLOPPY
7189 void
7190 int13_diskette_function(DI, SI, BP, SP, BX, DX, CX, AX, ES, FLAGS)
7191 Bit16u DI, SI, BP, SP, BX, DX, CX, AX, ES, FLAGS;
7193 Bit8u val8;
7195 switch ( GET_AH() ) {
7197 case 0x01: // Read Diskette Status
7198 CLEAR_CF();
7199 val8 = read_byte(0x0000, 0x0441);
7200 SET_AH(val8);
7201 if (val8) {
7202 SET_CF();
7204 return;
7206 default:
7207 SET_CF();
7208 write_byte(0x0000, 0x0441, 0x01);
7209 SET_AH(0x01);
7212 #endif // #if BX_SUPPORT_FLOPPY
7214 void
7215 set_diskette_ret_status(value)
7216 Bit8u value;
7218 write_byte(0x0040, 0x0041, value);
7221 void
7222 set_diskette_current_cyl(drive, cyl)
7223 Bit8u drive;
7224 Bit8u cyl;
7226 if (drive > 1)
7227 BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
7228 write_byte(0x0040, 0x0094+drive, cyl);
7231 void
7232 determine_floppy_media(drive)
7233 Bit16u drive;
7235 #if 0
7236 Bit8u val8, DOR, ctrl_info;
7238 ctrl_info = read_byte(0x0040, 0x008F);
7239 if (drive==1)
7240 ctrl_info >>= 4;
7241 else
7242 ctrl_info &= 0x0f;
7244 #if 0
7245 if (drive == 0) {
7246 DOR = 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
7248 else {
7249 DOR = 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
7251 #endif
7253 if ( (ctrl_info & 0x04) != 0x04 ) {
7254 // Drive not determined means no drive exists, done.
7255 return;
7258 #if 0
7259 // check Main Status Register for readiness
7260 val8 = inb(0x03f4) & 0x80; // Main Status Register
7261 if (val8 != 0x80)
7262 BX_PANIC("d_f_m: MRQ bit not set\n");
7264 // change line
7266 // existing BDA values
7268 // turn on drive motor
7269 outb(0x03f2, DOR); // Digital Output Register
7271 #endif
7272 BX_PANIC("d_f_m: OK so far\n");
7273 #endif
7276 void
7277 int17_function(regs, ds, iret_addr)
7278 pusha_regs_t regs; // regs pushed from PUSHA instruction
7279 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
7280 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
7282 Bit16u addr,timeout;
7283 Bit8u val8;
7285 ASM_START
7287 ASM_END
7289 addr = read_word(0x0040, (regs.u.r16.dx << 1) + 8);
7290 if ((regs.u.r8.ah < 3) && (regs.u.r16.dx < 3) && (addr > 0)) {
7291 timeout = read_byte(0x0040, 0x0078 + regs.u.r16.dx) << 8;
7292 if (regs.u.r8.ah == 0) {
7293 outb(addr, regs.u.r8.al);
7294 val8 = inb(addr+2);
7295 outb(addr+2, val8 | 0x01); // send strobe
7296 ASM_START
7298 ASM_END
7299 outb(addr+2, val8 & ~0x01);
7300 while (((inb(addr+1) & 0x40) == 0x40) && (timeout)) {
7301 timeout--;
7304 if (regs.u.r8.ah == 1) {
7305 val8 = inb(addr+2);
7306 outb(addr+2, val8 & ~0x04); // send init
7307 ASM_START
7309 ASM_END
7310 outb(addr+2, val8 | 0x04);
7312 regs.u.r8.ah = inb(addr+1);
7313 val8 = (~regs.u.r8.ah & 0x48);
7314 regs.u.r8.ah &= 0xB7;
7315 regs.u.r8.ah |= val8;
7316 if (!timeout) regs.u.r8.ah |= 0x01;
7317 ClearCF(iret_addr.flags);
7318 } else {
7319 SetCF(iret_addr.flags); // Unsupported
7323 // returns bootsegment in ax, drive in bl
7324 Bit32u
7325 int19_function(bseqnr)
7326 Bit8u bseqnr;
7328 Bit16u ebda_seg=read_word(0x0040,0x000E);
7329 Bit16u bootseq;
7330 Bit8u bootdrv;
7331 Bit8u bootcd;
7332 Bit8u bootchk;
7333 Bit16u bootseg;
7334 Bit16u status;
7335 Bit8u lastdrive=0;
7337 // if BX_ELTORITO_BOOT is not defined, old behavior
7338 // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL
7339 // in preparation for the intial INT 13h (0=floppy A:, 0x80=C:)
7340 // 0: system boot sequence, first drive C: then A:
7341 // 1: system boot sequence, first drive A: then C:
7342 // else BX_ELTORITO_BOOT is defined
7343 // CMOS regs 0x3D and 0x38 contain the boot sequence:
7344 // CMOS reg 0x3D & 0x0f : 1st boot device
7345 // CMOS reg 0x3D & 0xf0 : 2nd boot device
7346 // CMOS reg 0x38 & 0xf0 : 3rd boot device
7347 // boot device codes:
7348 // 0x00 : not defined
7349 // 0x01 : first floppy
7350 // 0x02 : first harddrive
7351 // 0x03 : first cdrom
7352 // else : boot failure
7354 // Get the boot sequence
7355 #if BX_ELTORITO_BOOT
7356 bootseq=inb_cmos(0x3d);
7357 bootseq|=((inb_cmos(0x38) & 0xf0) << 4);
7359 if (bseqnr==2) bootseq >>= 4;
7360 if (bseqnr==3) bootseq >>= 8;
7361 if (bootseq<0x10) lastdrive = 1;
7362 bootdrv=0x00; bootcd=0;
7363 switch(bootseq & 0x0f) {
7364 case 0x01: bootdrv=0x00; bootcd=0; break;
7365 case 0x02: bootdrv=0x80; bootcd=0; break;
7366 case 0x03: bootdrv=0x00; bootcd=1; break;
7367 default: return 0x00000000;
7369 #else
7370 bootseq=inb_cmos(0x2d);
7372 if (bseqnr==2) {
7373 bootseq ^= 0x20;
7374 lastdrive = 1;
7376 bootdrv=0x00; bootcd=0;
7377 if((bootseq&0x20)==0) bootdrv=0x80;
7378 #endif // BX_ELTORITO_BOOT
7380 #if BX_ELTORITO_BOOT
7381 // We have to boot from cd
7382 if (bootcd != 0) {
7383 status = cdrom_boot();
7385 // If failure
7386 if ( (status & 0x00ff) !=0 ) {
7387 print_cdromboot_failure(status);
7388 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
7389 return 0x00000000;
7392 bootseg = read_word(ebda_seg,&EbdaData->cdemu.load_segment);
7393 bootdrv = (Bit8u)(status>>8);
7396 #endif // BX_ELTORITO_BOOT
7398 // We have to boot from harddisk or floppy
7399 if (bootcd == 0) {
7400 bootseg=0x07c0;
7402 ASM_START
7403 push bp
7404 mov bp, sp
7406 mov ax, #0x0000
7407 mov _int19_function.status + 2[bp], ax
7408 mov dl, _int19_function.bootdrv + 2[bp]
7409 mov ax, _int19_function.bootseg + 2[bp]
7410 mov es, ax ;; segment
7411 mov bx, #0x0000 ;; offset
7412 mov ah, #0x02 ;; function 2, read diskette sector
7413 mov al, #0x01 ;; read 1 sector
7414 mov ch, #0x00 ;; track 0
7415 mov cl, #0x01 ;; sector 1
7416 mov dh, #0x00 ;; head 0
7417 int #0x13 ;; read sector
7418 jnc int19_load_done
7419 mov ax, #0x0001
7420 mov _int19_function.status + 2[bp], ax
7422 int19_load_done:
7423 pop bp
7424 ASM_END
7426 if (status != 0) {
7427 print_boot_failure(bootcd, bootdrv, 1, lastdrive);
7428 return 0x00000000;
7432 // check signature if instructed by cmos reg 0x38, only for floppy
7433 // bootchk = 1 : signature check disabled
7434 // bootchk = 0 : signature check enabled
7435 if (bootdrv != 0) bootchk = 0;
7436 else bootchk = inb_cmos(0x38) & 0x01;
7438 #if BX_ELTORITO_BOOT
7439 // if boot from cd, no signature check
7440 if (bootcd != 0)
7441 bootchk = 1;
7442 #endif // BX_ELTORITO_BOOT
7444 if (bootchk == 0) {
7445 if (read_word(bootseg,0x1fe) != 0xaa55) {
7446 print_boot_failure(bootcd, bootdrv, 0, lastdrive);
7447 return 0x00000000;
7451 #if BX_ELTORITO_BOOT
7452 // Print out the boot string
7453 print_boot_device(bootcd, bootdrv);
7454 #else // BX_ELTORITO_BOOT
7455 print_boot_device(0, bootdrv);
7456 #endif // BX_ELTORITO_BOOT
7458 // return the boot segment
7459 return (((Bit32u)bootdrv) << 16) + bootseg;
7462 void
7463 int1a_function(regs, ds, iret_addr)
7464 pusha_regs_t regs; // regs pushed from PUSHA instruction
7465 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
7466 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
7468 Bit8u val8;
7470 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);
7472 ASM_START
7474 ASM_END
7476 switch (regs.u.r8.ah) {
7477 case 0: // get current clock count
7478 ASM_START
7480 ASM_END
7481 regs.u.r16.cx = BiosData->ticks_high;
7482 regs.u.r16.dx = BiosData->ticks_low;
7483 regs.u.r8.al = BiosData->midnight_flag;
7484 BiosData->midnight_flag = 0; // reset flag
7485 ASM_START
7487 ASM_END
7488 // AH already 0
7489 ClearCF(iret_addr.flags); // OK
7490 break;
7492 case 1: // Set Current Clock Count
7493 ASM_START
7495 ASM_END
7496 BiosData->ticks_high = regs.u.r16.cx;
7497 BiosData->ticks_low = regs.u.r16.dx;
7498 BiosData->midnight_flag = 0; // reset flag
7499 ASM_START
7501 ASM_END
7502 regs.u.r8.ah = 0;
7503 ClearCF(iret_addr.flags); // OK
7504 break;
7507 case 2: // Read CMOS Time
7508 if (rtc_updating()) {
7509 SetCF(iret_addr.flags);
7510 break;
7513 regs.u.r8.dh = inb_cmos(0x00); // Seconds
7514 regs.u.r8.cl = inb_cmos(0x02); // Minutes
7515 regs.u.r8.ch = inb_cmos(0x04); // Hours
7516 regs.u.r8.dl = inb_cmos(0x0b) & 0x01; // Stat Reg B
7517 regs.u.r8.ah = 0;
7518 regs.u.r8.al = regs.u.r8.ch;
7519 ClearCF(iret_addr.flags); // OK
7520 break;
7522 case 3: // Set CMOS Time
7523 // Using a debugger, I notice the following masking/setting
7524 // of bits in Status Register B, by setting Reg B to
7525 // a few values and getting its value after INT 1A was called.
7527 // try#1 try#2 try#3
7528 // before 1111 1101 0111 1101 0000 0000
7529 // after 0110 0010 0110 0010 0000 0010
7531 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7532 // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
7533 if (rtc_updating()) {
7534 init_rtc();
7535 // fall through as if an update were not in progress
7537 outb_cmos(0x00, regs.u.r8.dh); // Seconds
7538 outb_cmos(0x02, regs.u.r8.cl); // Minutes
7539 outb_cmos(0x04, regs.u.r8.ch); // Hours
7540 // Set Daylight Savings time enabled bit to requested value
7541 val8 = (inb_cmos(0x0b) & 0x60) | 0x02 | (regs.u.r8.dl & 0x01);
7542 // (reg B already selected)
7543 outb_cmos(0x0b, val8);
7544 regs.u.r8.ah = 0;
7545 regs.u.r8.al = val8; // val last written to Reg B
7546 ClearCF(iret_addr.flags); // OK
7547 break;
7549 case 4: // Read CMOS Date
7550 regs.u.r8.ah = 0;
7551 if (rtc_updating()) {
7552 SetCF(iret_addr.flags);
7553 break;
7555 regs.u.r8.cl = inb_cmos(0x09); // Year
7556 regs.u.r8.dh = inb_cmos(0x08); // Month
7557 regs.u.r8.dl = inb_cmos(0x07); // Day of Month
7558 regs.u.r8.ch = inb_cmos(0x32); // Century
7559 regs.u.r8.al = regs.u.r8.ch;
7560 ClearCF(iret_addr.flags); // OK
7561 break;
7563 case 5: // Set CMOS Date
7564 // Using a debugger, I notice the following masking/setting
7565 // of bits in Status Register B, by setting Reg B to
7566 // a few values and getting its value after INT 1A was called.
7568 // try#1 try#2 try#3 try#4
7569 // before 1111 1101 0111 1101 0000 0010 0000 0000
7570 // after 0110 1101 0111 1101 0000 0010 0000 0000
7572 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7573 // My assumption: RegB = (RegB & 01111111b)
7574 if (rtc_updating()) {
7575 init_rtc();
7576 SetCF(iret_addr.flags);
7577 break;
7579 outb_cmos(0x09, regs.u.r8.cl); // Year
7580 outb_cmos(0x08, regs.u.r8.dh); // Month
7581 outb_cmos(0x07, regs.u.r8.dl); // Day of Month
7582 outb_cmos(0x32, regs.u.r8.ch); // Century
7583 val8 = inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
7584 outb_cmos(0x0b, val8);
7585 regs.u.r8.ah = 0;
7586 regs.u.r8.al = val8; // AL = val last written to Reg B
7587 ClearCF(iret_addr.flags); // OK
7588 break;
7590 case 6: // Set Alarm Time in CMOS
7591 // Using a debugger, I notice the following masking/setting
7592 // of bits in Status Register B, by setting Reg B to
7593 // a few values and getting its value after INT 1A was called.
7595 // try#1 try#2 try#3
7596 // before 1101 1111 0101 1111 0000 0000
7597 // after 0110 1111 0111 1111 0010 0000
7599 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7600 // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
7601 val8 = inb_cmos(0x0b); // Get Status Reg B
7602 regs.u.r16.ax = 0;
7603 if (val8 & 0x20) {
7604 // Alarm interrupt enabled already
7605 SetCF(iret_addr.flags); // Error: alarm in use
7606 break;
7608 if (rtc_updating()) {
7609 init_rtc();
7610 // fall through as if an update were not in progress
7612 outb_cmos(0x01, regs.u.r8.dh); // Seconds alarm
7613 outb_cmos(0x03, regs.u.r8.cl); // Minutes alarm
7614 outb_cmos(0x05, regs.u.r8.ch); // Hours alarm
7615 outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
7616 // enable Status Reg B alarm bit, clear halt clock bit
7617 outb_cmos(0x0b, (val8 & 0x7f) | 0x20);
7618 ClearCF(iret_addr.flags); // OK
7619 break;
7621 case 7: // Turn off Alarm
7622 // Using a debugger, I notice the following masking/setting
7623 // of bits in Status Register B, by setting Reg B to
7624 // a few values and getting its value after INT 1A was called.
7626 // try#1 try#2 try#3 try#4
7627 // before 1111 1101 0111 1101 0010 0000 0010 0010
7628 // after 0100 0101 0101 0101 0000 0000 0000 0010
7630 // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7631 // My assumption: RegB = (RegB & 01010111b)
7632 val8 = inb_cmos(0x0b); // Get Status Reg B
7633 // clear clock-halt bit, disable alarm bit
7634 outb_cmos(0x0b, val8 & 0x57); // disable alarm bit
7635 regs.u.r8.ah = 0;
7636 regs.u.r8.al = val8; // val last written to Reg B
7637 ClearCF(iret_addr.flags); // OK
7638 break;
7639 #if BX_PCIBIOS
7640 case 0xb1:
7641 // real mode PCI BIOS functions now handled in assembler code
7642 // this C code handles the error code for information only
7643 if (regs.u.r8.al == 0xff) {
7644 BX_INFO("PCI BIOS: PCI not present\n");
7645 } else if (regs.u.r8.al == 0x81) {
7646 BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs.u.r8.al);
7647 } else if (regs.u.r8.al == 0x83) {
7648 BX_INFO("bad PCI vendor ID %04x\n", regs.u.r16.dx);
7649 } else if (regs.u.r8.al == 0x86) {
7650 BX_INFO("PCI device %04x:%04x not found\n", regs.u.r16.dx, regs.u.r16.cx);
7652 regs.u.r8.ah = regs.u.r8.al;
7653 SetCF(iret_addr.flags);
7654 break;
7655 #endif
7657 default:
7658 SetCF(iret_addr.flags); // Unsupported
7662 void
7663 int70_function(regs, ds, iret_addr)
7664 pusha_regs_t regs; // regs pushed from PUSHA instruction
7665 Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
7666 iret_addr_t iret_addr; // CS,IP,Flags pushed from original INT call
7668 // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
7669 Bit8u registerB = 0, registerC = 0;
7671 // Check which modes are enabled and have occurred.
7672 registerB = inb_cmos( 0xB );
7673 registerC = inb_cmos( 0xC );
7675 if( ( registerB & 0x60 ) != 0 ) {
7676 if( ( registerC & 0x20 ) != 0 ) {
7677 // Handle Alarm Interrupt.
7678 ASM_START
7680 int #0x4a
7682 ASM_END
7684 if( ( registerC & 0x40 ) != 0 ) {
7685 // Handle Periodic Interrupt.
7687 if( read_byte( 0x40, 0xA0 ) != 0 ) {
7688 // Wait Interval (Int 15, AH=83) active.
7689 Bit32u time, toggle;
7691 time = read_dword( 0x40, 0x9C ); // Time left in microseconds.
7692 if( time < 0x3D1 ) {
7693 // Done waiting.
7694 Bit16u segment, offset;
7696 offset = read_word( 0x40, 0x98 );
7697 segment = read_word( 0x40, 0x9A );
7698 write_byte( 0x40, 0xA0, 0 ); // Turn of status byte.
7699 outb_cmos( 0xB, registerB & 0x37 ); // Clear the Periodic Interrupt.
7700 write_byte( segment, offset, 0x80 ); // Write to specified flag byte.
7701 } else {
7702 // Continue waiting.
7703 time -= 0x3D1;
7704 write_dword( 0x40, 0x9C, time );
7710 ASM_START
7711 call eoi_both_pics
7712 ASM_END
7716 ASM_START
7717 ;------------------------------------------
7718 ;- INT74h : PS/2 mouse hardware interrupt -
7719 ;------------------------------------------
7720 int74_handler:
7722 pusha
7723 push ds ;; save DS
7724 push #0x00 ;; placeholder for status
7725 push #0x00 ;; placeholder for X
7726 push #0x00 ;; placeholder for Y
7727 push #0x00 ;; placeholder for Z
7728 push #0x00 ;; placeholder for make_far_call boolean
7729 call _int74_function
7730 pop cx ;; remove make_far_call from stack
7731 jcxz int74_done
7733 ;; make far call to EBDA:0022
7734 push #0x00
7735 pop ds
7736 push 0x040E ;; push 0000:040E (opcodes 0xff, 0x36, 0x0E, 0x04)
7737 pop ds
7738 //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
7739 call far ptr[0x22]
7740 int74_done:
7742 call eoi_both_pics
7743 add sp, #8 ;; pop status, x, y, z
7745 pop ds ;; restore DS
7746 popa
7747 iret
7750 ;; This will perform an IRET, but will retain value of current CF
7751 ;; by altering flags on stack. Better than RETF #02.
7752 iret_modify_cf:
7753 jc carry_set
7754 push bp
7755 mov bp, sp
7756 and BYTE [bp + 0x06], #0xfe
7757 pop bp
7758 iret
7759 carry_set:
7760 push bp
7761 mov bp, sp
7762 or BYTE [bp + 0x06], #0x01
7763 pop bp
7764 iret
7767 ;----------------------
7768 ;- INT13h (relocated) -
7769 ;----------------------
7771 ; int13_relocated is a little bit messed up since I played with it
7772 ; I have to rewrite it:
7773 ; - call a function that detect which function to call
7774 ; - make all called C function get the same parameters list
7776 int13_relocated:
7778 #if BX_ELTORITO_BOOT
7779 ;; check for an eltorito function
7780 cmp ah,#0x4a
7781 jb int13_not_eltorito
7782 cmp ah,#0x4d
7783 ja int13_not_eltorito
7784 jmp int13_eltorito
7786 int13_not_eltorito:
7787 push ax
7788 push bx
7789 push cx
7790 push dx
7792 ;; check if emulation active
7793 call _cdemu_isactive
7794 cmp al,#0x00
7795 je int13_cdemu_inactive
7797 ;; check if access to the emulated drive
7798 call _cdemu_emulated_drive
7799 pop dx
7800 push dx
7801 cmp al,dl ;; int13 on emulated drive
7802 je int13_cdemu
7804 ;; otherwise
7805 and dl,#0xE0 ;; mask to get device class, including cdroms
7806 cmp al,dl ;; al is 0x00 or 0x80
7807 jne int13_cdemu_inactive ;; inactive for device class
7809 int13_cdemu_active:
7810 pop dx
7811 pop cx
7812 pop bx
7813 pop ax
7814 dec dl ;; real drive is dl - 1
7815 jmp int13_legacy
7817 int13_cdemu_inactive:
7818 pop dx
7819 pop cx
7820 pop bx
7821 pop ax
7823 int13_legacy:
7825 #endif // BX_ELTORITO_BOOT
7827 pushf
7828 test dl, #0x80
7829 jz int13_floppy
7831 #if BX_USE_ATADRV
7833 int13_disk_or_cdrom:
7834 cmp dl, #0xE0
7835 jae int13_cdrom
7837 #endif
7839 int13_disk:
7840 ;; pushf already done
7841 push es
7842 push ds
7843 push ss
7844 pop ds
7845 pusha
7846 call _int13_harddisk
7847 popa
7848 pop ds
7849 pop es
7850 popf
7851 // JMPL(iret_modify_cf)
7852 jmp iret_modify_cf
7854 int13_floppy:
7855 popf
7856 // JMPL(int13_diskette)
7857 jmp int13_diskette
7860 #if BX_USE_ATADRV
7861 int13_cdrom:
7862 ;; pushf already done
7863 ;; popf
7864 ;; pushf
7865 push es
7866 push ds
7867 push ss
7868 pop ds
7869 // ebx is modified: BSD 5.2.1 boot loader problem, so we save all
7870 // the 32 bit registers. It should be done in all the bios or no 32
7871 // bit register should be used without saving it first.
7872 pushad
7873 call _int13_cdrom
7874 popad
7875 pop ds
7876 pop es
7877 popf
7879 // JMPL(iret_modify_cf)
7880 jmp iret_modify_cf
7881 #endif
7883 #if BX_ELTORITO_BOOT
7884 int13_cdemu:
7885 pop dx
7886 pop cx
7887 pop bx
7888 pop ax
7890 push ds
7891 push ss
7892 pop ds
7894 pushf
7895 push es
7896 pusha
7897 call _int13_cdemu
7898 popa
7899 pop es
7900 popf
7902 pop ds
7903 jmp iret_modify_cf
7905 int13_eltorito:
7907 pushf
7908 push es
7909 push ds
7910 push ss
7911 pop ds
7912 pusha
7913 call _int13_eltorito
7914 popa
7915 pop ds
7916 pop es
7917 popf
7919 jmp iret_modify_cf
7920 #endif
7923 ;----------
7924 ;- INT18h -
7925 ;----------
7926 int18_handler: ;; Boot Failure routing
7927 call _int18_panic_msg
7929 iret
7931 ;----------
7932 ;- INT19h -
7933 ;----------
7934 int19_relocated: ;; Boot function, relocated
7936 ;; int19 was beginning to be really complex, so now it
7937 ;; just calls an C function, that does the work
7938 ;; it returns in BL the boot drive, and in AX the boot segment
7939 ;; the boot segment will be 0x0000 if something has failed
7941 push bp
7942 mov bp, sp
7944 ;; drop ds
7945 xor ax, ax
7946 mov ds, ax
7948 ;; 1st boot device
7949 mov ax, #0x0001
7950 push ax
7951 call _int19_function
7952 inc sp
7953 inc sp
7954 ;; bl contains the boot drive
7955 ;; ax contains the boot segment or 0 if failure
7957 test ax, ax ;; if ax is 0 try next boot device
7958 jnz boot_setup
7960 ;; 2nd boot device
7961 mov ax, #0x0002
7962 push ax
7963 call _int19_function
7964 inc sp
7965 inc sp
7966 test ax, ax ;; if ax is 0 try next boot device
7967 jnz boot_setup
7969 ;; 3rd boot device
7970 mov ax, #0x0003
7971 push ax
7972 call _int19_function
7973 inc sp
7974 inc sp
7975 test ax, ax ;; if ax is 0 call int18
7976 jz int18_handler
7978 boot_setup:
7979 mov dl, bl ;; set drive so guest os find it
7980 shl eax, #0x04 ;; convert seg to ip
7981 mov 2[bp], ax ;; set ip
7983 shr eax, #0x04 ;; get cs back
7984 and ax, #0xF000 ;; remove what went in ip
7985 mov 4[bp], ax ;; set cs
7986 xor ax, ax
7987 mov es, ax ;; set es to zero fixes [ 549815 ]
7988 mov [bp], ax ;; set bp to zero
7989 mov ax, #0xaa55 ;; set ok flag
7991 pop bp
7992 iret ;; Beam me up Scotty
7994 ;----------
7995 ;- INT1Ch -
7996 ;----------
7997 int1c_handler: ;; User Timer Tick
7998 iret
8001 ;----------------------
8002 ;- POST: Floppy Drive -
8003 ;----------------------
8004 floppy_drive_post:
8005 mov ax, #0x0000
8006 mov ds, ax
8008 mov al, #0x00
8009 mov 0x043e, al ;; drive 0 & 1 uncalibrated, no interrupt has occurred
8011 mov 0x043f, al ;; diskette motor status: read op, drive0, motors off
8013 mov 0x0440, al ;; diskette motor timeout counter: not active
8014 mov 0x0441, al ;; diskette controller status return code
8016 mov 0x0442, al ;; disk & diskette controller status register 0
8017 mov 0x0443, al ;; diskette controller status register 1
8018 mov 0x0444, al ;; diskette controller status register 2
8019 mov 0x0445, al ;; diskette controller cylinder number
8020 mov 0x0446, al ;; diskette controller head number
8021 mov 0x0447, al ;; diskette controller sector number
8022 mov 0x0448, al ;; diskette controller bytes written
8024 mov 0x048b, al ;; diskette configuration data
8026 ;; -----------------------------------------------------------------
8027 ;; (048F) diskette controller information
8029 mov al, #0x10 ;; get CMOS diskette drive type
8030 out 0x70, AL
8031 in AL, 0x71
8032 mov ah, al ;; save byte to AH
8034 look_drive0:
8035 shr al, #4 ;; look at top 4 bits for drive 0
8036 jz f0_missing ;; jump if no drive0
8037 mov bl, #0x07 ;; drive0 determined, multi-rate, has changed line
8038 jmp look_drive1
8039 f0_missing:
8040 mov bl, #0x00 ;; no drive0
8042 look_drive1:
8043 mov al, ah ;; restore from AH
8044 and al, #0x0f ;; look at bottom 4 bits for drive 1
8045 jz f1_missing ;; jump if no drive1
8046 or bl, #0x70 ;; drive1 determined, multi-rate, has changed line
8047 f1_missing:
8048 ;; leave high bits in BL zerod
8049 mov 0x048f, bl ;; put new val in BDA (diskette controller information)
8050 ;; -----------------------------------------------------------------
8052 mov al, #0x00
8053 mov 0x0490, al ;; diskette 0 media state
8054 mov 0x0491, al ;; diskette 1 media state
8056 ;; diskette 0,1 operational starting state
8057 ;; drive type has not been determined,
8058 ;; has no changed detection line
8059 mov 0x0492, al
8060 mov 0x0493, al
8062 mov 0x0494, al ;; diskette 0 current cylinder
8063 mov 0x0495, al ;; diskette 1 current cylinder
8065 mov al, #0x02
8066 out #0x0a, al ;; clear DMA-1 channel 2 mask bit
8068 SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
8069 SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
8070 SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
8075 ;--------------------
8076 ;- POST: HARD DRIVE -
8077 ;--------------------
8078 ; relocated here because the primary POST area isnt big enough.
8079 hard_drive_post:
8080 // IRQ 14 = INT 76h
8081 // INT 76h calls INT 15h function ax=9100
8083 mov al, #0x0a ; 0000 1010 = reserved, disable IRQ 14
8084 mov dx, #0x03f6
8085 out dx, al
8087 mov ax, #0x0000
8088 mov ds, ax
8089 mov 0x0474, al /* hard disk status of last operation */
8090 mov 0x0477, al /* hard disk port offset (XT only ???) */
8091 mov 0x048c, al /* hard disk status register */
8092 mov 0x048d, al /* hard disk error register */
8093 mov 0x048e, al /* hard disk task complete flag */
8094 mov al, #0x01
8095 mov 0x0475, al /* hard disk number attached */
8096 mov al, #0xc0
8097 mov 0x0476, al /* hard disk control byte */
8098 SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
8099 SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
8100 ;; INT 41h: hard disk 0 configuration pointer
8101 ;; INT 46h: hard disk 1 configuration pointer
8102 SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D)
8103 SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D)
8105 ;; move disk geometry data from CMOS to EBDA disk parameter table(s)
8106 mov al, #0x12
8107 out #0x70, al
8108 in al, #0x71
8109 and al, #0xf0
8110 cmp al, #0xf0
8111 je post_d0_extended
8112 jmp check_for_hd1
8113 post_d0_extended:
8114 mov al, #0x19
8115 out #0x70, al
8116 in al, #0x71
8117 cmp al, #47 ;; decimal 47 - user definable
8118 je post_d0_type47
8119 HALT(__LINE__)
8120 post_d0_type47:
8121 ;; CMOS purpose param table offset
8122 ;; 1b cylinders low 0
8123 ;; 1c cylinders high 1
8124 ;; 1d heads 2
8125 ;; 1e write pre-comp low 5
8126 ;; 1f write pre-comp high 6
8127 ;; 20 retries/bad map/heads>8 8
8128 ;; 21 landing zone low C
8129 ;; 22 landing zone high D
8130 ;; 23 sectors/track E
8132 mov ax, #EBDA_SEG
8133 mov ds, ax
8135 ;;; Filling EBDA table for hard disk 0.
8136 mov al, #0x1f
8137 out #0x70, al
8138 in al, #0x71
8139 mov ah, al
8140 mov al, #0x1e
8141 out #0x70, al
8142 in al, #0x71
8143 mov (0x003d + 0x05), ax ;; write precomp word
8145 mov al, #0x20
8146 out #0x70, al
8147 in al, #0x71
8148 mov (0x003d + 0x08), al ;; drive control byte
8150 mov al, #0x22
8151 out #0x70, al
8152 in al, #0x71
8153 mov ah, al
8154 mov al, #0x21
8155 out #0x70, al
8156 in al, #0x71
8157 mov (0x003d + 0x0C), ax ;; landing zone word
8159 mov al, #0x1c ;; get cylinders word in AX
8160 out #0x70, al
8161 in al, #0x71 ;; high byte
8162 mov ah, al
8163 mov al, #0x1b
8164 out #0x70, al
8165 in al, #0x71 ;; low byte
8166 mov bx, ax ;; BX = cylinders
8168 mov al, #0x1d
8169 out #0x70, al
8170 in al, #0x71
8171 mov cl, al ;; CL = heads
8173 mov al, #0x23
8174 out #0x70, al
8175 in al, #0x71
8176 mov dl, al ;; DL = sectors
8178 cmp bx, #1024
8179 jnbe hd0_post_logical_chs ;; if cylinders > 1024, use translated style CHS
8181 hd0_post_physical_chs:
8182 ;; no logical CHS mapping used, just physical CHS
8183 ;; use Standard Fixed Disk Parameter Table (FDPT)
8184 mov (0x003d + 0x00), bx ;; number of physical cylinders
8185 mov (0x003d + 0x02), cl ;; number of physical heads
8186 mov (0x003d + 0x0E), dl ;; number of physical sectors
8187 jmp check_for_hd1
8189 hd0_post_logical_chs:
8190 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
8191 mov (0x003d + 0x09), bx ;; number of physical cylinders
8192 mov (0x003d + 0x0b), cl ;; number of physical heads
8193 mov (0x003d + 0x04), dl ;; number of physical sectors
8194 mov (0x003d + 0x0e), dl ;; number of logical sectors (same)
8195 mov al, #0xa0
8196 mov (0x003d + 0x03), al ;; A0h signature, indicates translated table
8198 cmp bx, #2048
8199 jnbe hd0_post_above_2048
8200 ;; 1024 < c <= 2048 cylinders
8201 shr bx, #0x01
8202 shl cl, #0x01
8203 jmp hd0_post_store_logical
8205 hd0_post_above_2048:
8206 cmp bx, #4096
8207 jnbe hd0_post_above_4096
8208 ;; 2048 < c <= 4096 cylinders
8209 shr bx, #0x02
8210 shl cl, #0x02
8211 jmp hd0_post_store_logical
8213 hd0_post_above_4096:
8214 cmp bx, #8192
8215 jnbe hd0_post_above_8192
8216 ;; 4096 < c <= 8192 cylinders
8217 shr bx, #0x03
8218 shl cl, #0x03
8219 jmp hd0_post_store_logical
8221 hd0_post_above_8192:
8222 ;; 8192 < c <= 16384 cylinders
8223 shr bx, #0x04
8224 shl cl, #0x04
8226 hd0_post_store_logical:
8227 mov (0x003d + 0x00), bx ;; number of physical cylinders
8228 mov (0x003d + 0x02), cl ;; number of physical heads
8229 ;; checksum
8230 mov cl, #0x0f ;; repeat count
8231 mov si, #0x003d ;; offset to disk0 FDPT
8232 mov al, #0x00 ;; sum
8233 hd0_post_checksum_loop:
8234 add al, [si]
8235 inc si
8236 dec cl
8237 jnz hd0_post_checksum_loop
8238 not al ;; now take 2s complement
8239 inc al
8240 mov [si], al
8241 ;;; Done filling EBDA table for hard disk 0.
8244 check_for_hd1:
8245 ;; is there really a second hard disk? if not, return now
8246 mov al, #0x12
8247 out #0x70, al
8248 in al, #0x71
8249 and al, #0x0f
8250 jnz post_d1_exists
8252 post_d1_exists:
8253 ;; check that the hd type is really 0x0f.
8254 cmp al, #0x0f
8255 jz post_d1_extended
8256 HALT(__LINE__)
8257 post_d1_extended:
8258 ;; check that the extended type is 47 - user definable
8259 mov al, #0x1a
8260 out #0x70, al
8261 in al, #0x71
8262 cmp al, #47 ;; decimal 47 - user definable
8263 je post_d1_type47
8264 HALT(__LINE__)
8265 post_d1_type47:
8266 ;; Table for disk1.
8267 ;; CMOS purpose param table offset
8268 ;; 0x24 cylinders low 0
8269 ;; 0x25 cylinders high 1
8270 ;; 0x26 heads 2
8271 ;; 0x27 write pre-comp low 5
8272 ;; 0x28 write pre-comp high 6
8273 ;; 0x29 heads>8 8
8274 ;; 0x2a landing zone low C
8275 ;; 0x2b landing zone high D
8276 ;; 0x2c sectors/track E
8277 ;;; Fill EBDA table for hard disk 1.
8278 mov ax, #EBDA_SEG
8279 mov ds, ax
8280 mov al, #0x28
8281 out #0x70, al
8282 in al, #0x71
8283 mov ah, al
8284 mov al, #0x27
8285 out #0x70, al
8286 in al, #0x71
8287 mov (0x004d + 0x05), ax ;; write precomp word
8289 mov al, #0x29
8290 out #0x70, al
8291 in al, #0x71
8292 mov (0x004d + 0x08), al ;; drive control byte
8294 mov al, #0x2b
8295 out #0x70, al
8296 in al, #0x71
8297 mov ah, al
8298 mov al, #0x2a
8299 out #0x70, al
8300 in al, #0x71
8301 mov (0x004d + 0x0C), ax ;; landing zone word
8303 mov al, #0x25 ;; get cylinders word in AX
8304 out #0x70, al
8305 in al, #0x71 ;; high byte
8306 mov ah, al
8307 mov al, #0x24
8308 out #0x70, al
8309 in al, #0x71 ;; low byte
8310 mov bx, ax ;; BX = cylinders
8312 mov al, #0x26
8313 out #0x70, al
8314 in al, #0x71
8315 mov cl, al ;; CL = heads
8317 mov al, #0x2c
8318 out #0x70, al
8319 in al, #0x71
8320 mov dl, al ;; DL = sectors
8322 cmp bx, #1024
8323 jnbe hd1_post_logical_chs ;; if cylinders > 1024, use translated style CHS
8325 hd1_post_physical_chs:
8326 ;; no logical CHS mapping used, just physical CHS
8327 ;; use Standard Fixed Disk Parameter Table (FDPT)
8328 mov (0x004d + 0x00), bx ;; number of physical cylinders
8329 mov (0x004d + 0x02), cl ;; number of physical heads
8330 mov (0x004d + 0x0E), dl ;; number of physical sectors
8333 hd1_post_logical_chs:
8334 ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
8335 mov (0x004d + 0x09), bx ;; number of physical cylinders
8336 mov (0x004d + 0x0b), cl ;; number of physical heads
8337 mov (0x004d + 0x04), dl ;; number of physical sectors
8338 mov (0x004d + 0x0e), dl ;; number of logical sectors (same)
8339 mov al, #0xa0
8340 mov (0x004d + 0x03), al ;; A0h signature, indicates translated table
8342 cmp bx, #2048
8343 jnbe hd1_post_above_2048
8344 ;; 1024 < c <= 2048 cylinders
8345 shr bx, #0x01
8346 shl cl, #0x01
8347 jmp hd1_post_store_logical
8349 hd1_post_above_2048:
8350 cmp bx, #4096
8351 jnbe hd1_post_above_4096
8352 ;; 2048 < c <= 4096 cylinders
8353 shr bx, #0x02
8354 shl cl, #0x02
8355 jmp hd1_post_store_logical
8357 hd1_post_above_4096:
8358 cmp bx, #8192
8359 jnbe hd1_post_above_8192
8360 ;; 4096 < c <= 8192 cylinders
8361 shr bx, #0x03
8362 shl cl, #0x03
8363 jmp hd1_post_store_logical
8365 hd1_post_above_8192:
8366 ;; 8192 < c <= 16384 cylinders
8367 shr bx, #0x04
8368 shl cl, #0x04
8370 hd1_post_store_logical:
8371 mov (0x004d + 0x00), bx ;; number of physical cylinders
8372 mov (0x004d + 0x02), cl ;; number of physical heads
8373 ;; checksum
8374 mov cl, #0x0f ;; repeat count
8375 mov si, #0x004d ;; offset to disk0 FDPT
8376 mov al, #0x00 ;; sum
8377 hd1_post_checksum_loop:
8378 add al, [si]
8379 inc si
8380 dec cl
8381 jnz hd1_post_checksum_loop
8382 not al ;; now take 2s complement
8383 inc al
8384 mov [si], al
8385 ;;; Done filling EBDA table for hard disk 1.
8389 ;--------------------
8390 ;- POST: EBDA segment
8391 ;--------------------
8392 ; relocated here because the primary POST area isnt big enough.
8393 ebda_post:
8394 #if BX_USE_EBDA
8395 mov ax, #EBDA_SEG
8396 mov ds, ax
8397 mov byte ptr [0x0], #EBDA_SIZE
8398 #endif
8399 xor ax, ax ; mov EBDA seg into 40E
8400 mov ds, ax
8401 mov word ptr [0x40E], #EBDA_SEG
8402 ret;;
8404 ;--------------------
8405 ;- POST: EOI + jmp via [0x40:67)
8406 ;--------------------
8407 ; relocated here because the primary POST area isnt big enough.
8408 eoi_jmp_post:
8409 call eoi_both_pics
8411 xor ax, ax
8412 mov ds, ax
8414 jmp far ptr [0x467]
8417 ;--------------------
8418 eoi_both_pics:
8419 mov al, #0x20
8420 out #0xA0, al ;; slave PIC EOI
8421 eoi_master_pic:
8422 mov al, #0x20
8423 out #0x20, al ;; master PIC EOI
8426 ;--------------------
8427 BcdToBin:
8428 ;; in: AL in BCD format
8429 ;; out: AL in binary format, AH will always be 0
8430 ;; trashes BX
8431 mov bl, al
8432 and bl, #0x0f ;; bl has low digit
8433 shr al, #4 ;; al has high digit
8434 mov bh, #10
8435 mul al, bh ;; multiply high digit by 10 (result in AX)
8436 add al, bl ;; then add low digit
8439 ;--------------------
8440 timer_tick_post:
8441 ;; Setup the Timer Ticks Count (0x46C:dword) and
8442 ;; Timer Ticks Roller Flag (0x470:byte)
8443 ;; The Timer Ticks Count needs to be set according to
8444 ;; the current CMOS time, as if ticks have been occurring
8445 ;; at 18.2hz since midnight up to this point. Calculating
8446 ;; this is a little complicated. Here are the factors I gather
8447 ;; regarding this. 14,318,180 hz was the original clock speed,
8448 ;; chosen so it could be divided by either 3 to drive the 5Mhz CPU
8449 ;; at the time, or 4 to drive the CGA video adapter. The div3
8450 ;; source was divided again by 4 to feed a 1.193Mhz signal to
8451 ;; the timer. With a maximum 16bit timer count, this is again
8452 ;; divided down by 65536 to 18.2hz.
8454 ;; 14,318,180 Hz clock
8455 ;; /3 = 4,772,726 Hz fed to orginal 5Mhz CPU
8456 ;; /4 = 1,193,181 Hz fed to timer
8457 ;; /65536 (maximum timer count) = 18.20650736 ticks/second
8458 ;; 1 second = 18.20650736 ticks
8459 ;; 1 minute = 1092.390442 ticks
8460 ;; 1 hour = 65543.42651 ticks
8462 ;; Given the values in the CMOS clock, one could calculate
8463 ;; the number of ticks by the following:
8464 ;; ticks = (BcdToBin(seconds) * 18.206507) +
8465 ;; (BcdToBin(minutes) * 1092.3904)
8466 ;; (BcdToBin(hours) * 65543.427)
8467 ;; To get a little more accuracy, since Im using integer
8468 ;; arithmatic, I use:
8469 ;; ticks = (BcdToBin(seconds) * 18206507) / 1000000 +
8470 ;; (BcdToBin(minutes) * 10923904) / 10000 +
8471 ;; (BcdToBin(hours) * 65543427) / 1000
8473 ;; assuming DS=0000
8475 ;; get CMOS seconds
8476 xor eax, eax ;; clear EAX
8477 mov al, #0x00
8478 out #0x70, al
8479 in al, #0x71 ;; AL has CMOS seconds in BCD
8480 call BcdToBin ;; EAX now has seconds in binary
8481 mov edx, #18206507
8482 mul eax, edx
8483 mov ebx, #1000000
8484 xor edx, edx
8485 div eax, ebx
8486 mov ecx, eax ;; ECX will accumulate total ticks
8488 ;; get CMOS minutes
8489 xor eax, eax ;; clear EAX
8490 mov al, #0x02
8491 out #0x70, al
8492 in al, #0x71 ;; AL has CMOS minutes in BCD
8493 call BcdToBin ;; EAX now has minutes in binary
8494 mov edx, #10923904
8495 mul eax, edx
8496 mov ebx, #10000
8497 xor edx, edx
8498 div eax, ebx
8499 add ecx, eax ;; add to total ticks
8501 ;; get CMOS hours
8502 xor eax, eax ;; clear EAX
8503 mov al, #0x04
8504 out #0x70, al
8505 in al, #0x71 ;; AL has CMOS hours in BCD
8506 call BcdToBin ;; EAX now has hours in binary
8507 mov edx, #65543427
8508 mul eax, edx
8509 mov ebx, #1000
8510 xor edx, edx
8511 div eax, ebx
8512 add ecx, eax ;; add to total ticks
8514 mov 0x46C, ecx ;; Timer Ticks Count
8515 xor al, al
8516 mov 0x470, al ;; Timer Ticks Rollover Flag
8519 ;--------------------
8520 int76_handler:
8521 ;; record completion in BIOS task complete flag
8522 push ax
8523 push ds
8524 mov ax, #0x0040
8525 mov ds, ax
8526 mov 0x008E, #0xff
8527 call eoi_both_pics
8528 pop ds
8529 pop ax
8530 iret
8533 ;--------------------
8534 #if BX_APM
8535 use32 386
8536 #define APM_PROT32
8537 #include "apmbios.S"
8538 use16 386
8540 #define APM_REAL
8541 #include "apmbios.S"
8543 #endif
8545 ;--------------------
8546 #if BX_PCIBIOS
8547 use32 386
8548 .align 16
8549 bios32_structure:
8550 db 0x5f, 0x33, 0x32, 0x5f ;; "_32_" signature
8551 dw bios32_entry_point, 0xf ;; 32 bit physical address
8552 db 0 ;; revision level
8553 ;; length in paragraphs and checksum stored in a word to prevent errors
8554 dw (~(((bios32_entry_point >> 8) + (bios32_entry_point & 0xff) + 0x32) \
8555 & 0xff) << 8) + 0x01
8556 db 0,0,0,0,0 ;; reserved
8558 .align 16
8559 bios32_entry_point:
8560 pushf
8561 cmp eax, #0x49435024
8562 jne unknown_service
8563 mov eax, #0x80000000
8564 mov dx, #0x0cf8
8565 out dx, eax
8566 mov dx, #0x0cfc
8567 in eax, dx
8568 cmp eax, #0x12378086
8569 jne unknown_service
8570 mov ebx, #0x000f0000
8571 mov ecx, #0
8572 mov edx, #pcibios_protected
8573 xor al, al
8574 jmp bios32_end
8575 unknown_service:
8576 mov al, #0x80
8577 bios32_end:
8578 popf
8579 retf
8581 .align 16
8582 pcibios_protected:
8583 pushf
8585 cmp al, #0x01 ;; installation check
8586 jne pci_pro_f02
8587 mov bx, #0x0210
8588 mov cx, #0
8589 mov edx, #0x20494350
8590 mov al, #0x01
8591 jmp pci_pro_ok
8592 pci_pro_f02: ;; find pci device
8593 cmp al, #0x02
8594 jne pci_pro_f08
8595 shl ecx, #16
8596 or ecx, edx
8597 mov bx, #0x0000
8598 mov di, #0x00
8599 pci_pro_devloop:
8600 call pci_pro_select_reg
8601 mov dx, #0x0cfc
8602 in eax, dx
8603 cmp eax, ecx
8604 jne pci_pro_nextdev
8605 cmp si, #0
8606 je pci_pro_ok
8607 dec si
8608 pci_pro_nextdev:
8609 inc bx
8610 cmp bx, #0x0100
8611 jne pci_pro_devloop
8612 mov ah, #0x86
8613 jmp pci_pro_fail
8614 pci_pro_f08: ;; read configuration byte
8615 cmp al, #0x08
8616 jne pci_pro_f09
8617 call pci_pro_select_reg
8618 push edx
8619 mov dx, di
8620 and dx, #0x03
8621 add dx, #0x0cfc
8622 in al, dx
8623 pop edx
8624 mov cl, al
8625 jmp pci_pro_ok
8626 pci_pro_f09: ;; read configuration word
8627 cmp al, #0x09
8628 jne pci_pro_f0a
8629 call pci_pro_select_reg
8630 push edx
8631 mov dx, di
8632 and dx, #0x02
8633 add dx, #0x0cfc
8634 in ax, dx
8635 pop edx
8636 mov cx, ax
8637 jmp pci_pro_ok
8638 pci_pro_f0a: ;; read configuration dword
8639 cmp al, #0x0a
8640 jne pci_pro_f0b
8641 call pci_pro_select_reg
8642 push edx
8643 mov dx, #0x0cfc
8644 in eax, dx
8645 pop edx
8646 mov ecx, eax
8647 jmp pci_pro_ok
8648 pci_pro_f0b: ;; write configuration byte
8649 cmp al, #0x0b
8650 jne pci_pro_f0c
8651 call pci_pro_select_reg
8652 push edx
8653 mov dx, di
8654 and dx, #0x03
8655 add dx, #0x0cfc
8656 mov al, cl
8657 out dx, al
8658 pop edx
8659 jmp pci_pro_ok
8660 pci_pro_f0c: ;; write configuration word
8661 cmp al, #0x0c
8662 jne pci_pro_f0d
8663 call pci_pro_select_reg
8664 push edx
8665 mov dx, di
8666 and dx, #0x02
8667 add dx, #0x0cfc
8668 mov ax, cx
8669 out dx, ax
8670 pop edx
8671 jmp pci_pro_ok
8672 pci_pro_f0d: ;; write configuration dword
8673 cmp al, #0x0d
8674 jne pci_pro_unknown
8675 call pci_pro_select_reg
8676 push edx
8677 mov dx, #0x0cfc
8678 mov eax, ecx
8679 out dx, eax
8680 pop edx
8681 jmp pci_pro_ok
8682 pci_pro_unknown:
8683 mov ah, #0x81
8684 pci_pro_fail:
8686 popf
8688 retf
8689 pci_pro_ok:
8690 xor ah, ah
8692 popf
8694 retf
8696 pci_pro_select_reg:
8697 push edx
8698 mov eax, #0x800000
8699 mov ax, bx
8700 shl eax, #8
8701 and di, #0xff
8702 or ax, di
8703 and al, #0xfc
8704 mov dx, #0x0cf8
8705 out dx, eax
8706 pop edx
8709 use16 386
8711 pcibios_real:
8712 push eax
8713 push dx
8714 mov eax, #0x80000000
8715 mov dx, #0x0cf8
8716 out dx, eax
8717 mov dx, #0x0cfc
8718 in eax, dx
8719 cmp eax, #0x12378086
8720 je pci_present
8721 pop dx
8722 pop eax
8723 mov ah, #0xff
8726 pci_present:
8727 pop dx
8728 pop eax
8729 cmp al, #0x01 ;; installation check
8730 jne pci_real_f02
8731 mov ax, #0x0001
8732 mov bx, #0x0210
8733 mov cx, #0
8734 mov edx, #0x20494350
8735 mov edi, #pcibios_protected
8736 or edi, #0xf0000
8739 pci_real_f02: ;; find pci device
8740 cmp al, #0x02
8741 jne pci_real_f08
8742 shl ecx, #16
8743 or ecx, edx
8744 mov bx, #0x0000
8745 mov di, #0x00
8746 pci_real_devloop:
8747 call pci_real_select_reg
8748 mov dx, #0x0cfc
8749 in eax, dx
8750 cmp eax, ecx
8751 jne pci_real_nextdev
8752 cmp si, #0
8753 je pci_real_ok
8754 dec si
8755 pci_real_nextdev:
8756 inc bx
8757 cmp bx, #0x0100
8758 jne pci_real_devloop
8759 mov dx, cx
8760 shr ecx, #16
8761 mov ah, #0x86
8762 jmp pci_real_fail
8763 pci_real_f08: ;; read configuration byte
8764 cmp al, #0x08
8765 jne pci_real_f09
8766 call pci_real_select_reg
8767 push dx
8768 mov dx, di
8769 and dx, #0x03
8770 add dx, #0x0cfc
8771 in al, dx
8772 pop dx
8773 mov cl, al
8774 jmp pci_real_ok
8775 pci_real_f09: ;; read configuration word
8776 cmp al, #0x09
8777 jne pci_real_f0a
8778 call pci_real_select_reg
8779 push dx
8780 mov dx, di
8781 and dx, #0x02
8782 add dx, #0x0cfc
8783 in ax, dx
8784 pop dx
8785 mov cx, ax
8786 jmp pci_real_ok
8787 pci_real_f0a: ;; read configuration dword
8788 cmp al, #0x0a
8789 jne pci_real_f0b
8790 call pci_real_select_reg
8791 push dx
8792 mov dx, #0x0cfc
8793 in eax, dx
8794 pop dx
8795 mov ecx, eax
8796 jmp pci_real_ok
8797 pci_real_f0b: ;; write configuration byte
8798 cmp al, #0x0b
8799 jne pci_real_f0c
8800 call pci_real_select_reg
8801 push dx
8802 mov dx, di
8803 and dx, #0x03
8804 add dx, #0x0cfc
8805 mov al, cl
8806 out dx, al
8807 pop dx
8808 jmp pci_real_ok
8809 pci_real_f0c: ;; write configuration word
8810 cmp al, #0x0c
8811 jne pci_real_f0d
8812 call pci_real_select_reg
8813 push dx
8814 mov dx, di
8815 and dx, #0x02
8816 add dx, #0x0cfc
8817 mov ax, cx
8818 out dx, ax
8819 pop dx
8820 jmp pci_real_ok
8821 pci_real_f0d: ;; write configuration dword
8822 cmp al, #0x0d
8823 jne pci_real_unknown
8824 call pci_real_select_reg
8825 push dx
8826 mov dx, #0x0cfc
8827 mov eax, ecx
8828 out dx, eax
8829 pop dx
8830 jmp pci_real_ok
8831 pci_real_unknown:
8832 mov ah, #0x81
8833 pci_real_fail:
8836 pci_real_ok:
8837 xor ah, ah
8841 pci_real_select_reg:
8842 push dx
8843 mov eax, #0x800000
8844 mov ax, bx
8845 shl eax, #8
8846 and di, #0xff
8847 or ax, di
8848 and al, #0xfc
8849 mov dx, #0x0cf8
8850 out dx, eax
8851 pop dx
8854 .align 16
8855 pci_routing_table_structure:
8856 db 0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature
8857 db 0, 1 ;; version
8858 dw 32 + (6 * 16) ;; table size
8859 db 0 ;; PCI interrupt router bus
8860 db 0x08 ;; PCI interrupt router DevFunc
8861 dw 0x0000 ;; PCI exclusive IRQs
8862 dw 0x8086 ;; compatible PCI interrupt router vendor ID
8863 dw 0x7000 ;; compatible PCI interrupt router device ID
8864 dw 0,0 ;; Miniport data
8865 db 0,0,0,0,0,0,0,0,0,0,0 ;; reserved
8866 db 0x07 ;; checksum
8867 ;; first slot entry PCI-to-ISA (embedded)
8868 db 0 ;; pci bus number
8869 db 0x08 ;; pci device number (bit 7-3)
8870 db 0x60 ;; link value INTA#: pointer into PCI2ISA config space
8871 dw 0xdef8 ;; IRQ bitmap INTA#
8872 db 0x61 ;; link value INTB#
8873 dw 0xdef8 ;; IRQ bitmap INTB#
8874 db 0x62 ;; link value INTC#
8875 dw 0xdef8 ;; IRQ bitmap INTC#
8876 db 0x63 ;; link value INTD#
8877 dw 0xdef8 ;; IRQ bitmap INTD#
8878 db 0 ;; physical slot (0 = embedded)
8879 db 0 ;; reserved
8880 ;; second slot entry: 1st PCI slot
8881 db 0 ;; pci bus number
8882 db 0x10 ;; pci device number (bit 7-3)
8883 db 0x61 ;; link value INTA#
8884 dw 0xdef8 ;; IRQ bitmap INTA#
8885 db 0x62 ;; link value INTB#
8886 dw 0xdef8 ;; IRQ bitmap INTB#
8887 db 0x63 ;; link value INTC#
8888 dw 0xdef8 ;; IRQ bitmap INTC#
8889 db 0x60 ;; link value INTD#
8890 dw 0xdef8 ;; IRQ bitmap INTD#
8891 db 1 ;; physical slot (0 = embedded)
8892 db 0 ;; reserved
8893 ;; third slot entry: 2nd PCI slot
8894 db 0 ;; pci bus number
8895 db 0x18 ;; pci device number (bit 7-3)
8896 db 0x62 ;; link value INTA#
8897 dw 0xdef8 ;; IRQ bitmap INTA#
8898 db 0x63 ;; link value INTB#
8899 dw 0xdef8 ;; IRQ bitmap INTB#
8900 db 0x60 ;; link value INTC#
8901 dw 0xdef8 ;; IRQ bitmap INTC#
8902 db 0x61 ;; link value INTD#
8903 dw 0xdef8 ;; IRQ bitmap INTD#
8904 db 2 ;; physical slot (0 = embedded)
8905 db 0 ;; reserved
8906 ;; 4th slot entry: 3rd PCI slot
8907 db 0 ;; pci bus number
8908 db 0x20 ;; pci device number (bit 7-3)
8909 db 0x63 ;; link value INTA#
8910 dw 0xdef8 ;; IRQ bitmap INTA#
8911 db 0x60 ;; link value INTB#
8912 dw 0xdef8 ;; IRQ bitmap INTB#
8913 db 0x61 ;; link value INTC#
8914 dw 0xdef8 ;; IRQ bitmap INTC#
8915 db 0x62 ;; link value INTD#
8916 dw 0xdef8 ;; IRQ bitmap INTD#
8917 db 3 ;; physical slot (0 = embedded)
8918 db 0 ;; reserved
8919 ;; 5th slot entry: 4rd PCI slot
8920 db 0 ;; pci bus number
8921 db 0x28 ;; pci device number (bit 7-3)
8922 db 0x60 ;; link value INTA#
8923 dw 0xdef8 ;; IRQ bitmap INTA#
8924 db 0x61 ;; link value INTB#
8925 dw 0xdef8 ;; IRQ bitmap INTB#
8926 db 0x62 ;; link value INTC#
8927 dw 0xdef8 ;; IRQ bitmap INTC#
8928 db 0x63 ;; link value INTD#
8929 dw 0xdef8 ;; IRQ bitmap INTD#
8930 db 4 ;; physical slot (0 = embedded)
8931 db 0 ;; reserved
8932 ;; 6th slot entry: 5rd PCI slot
8933 db 0 ;; pci bus number
8934 db 0x30 ;; pci device number (bit 7-3)
8935 db 0x61 ;; link value INTA#
8936 dw 0xdef8 ;; IRQ bitmap INTA#
8937 db 0x62 ;; link value INTB#
8938 dw 0xdef8 ;; IRQ bitmap INTB#
8939 db 0x63 ;; link value INTC#
8940 dw 0xdef8 ;; IRQ bitmap INTC#
8941 db 0x60 ;; link value INTD#
8942 dw 0xdef8 ;; IRQ bitmap INTD#
8943 db 5 ;; physical slot (0 = embedded)
8944 db 0 ;; reserved
8946 pci_irq_list:
8947 db 11, 10, 9, 5;
8949 pcibios_init_sel_reg:
8950 push eax
8951 mov eax, #0x800000
8952 mov ax, bx
8953 shl eax, #8
8954 and dl, #0xfc
8955 or al, dl
8956 mov dx, #0x0cf8
8957 out dx, eax
8958 pop eax
8961 pcibios_init_set_elcr:
8962 push ax
8963 push cx
8964 mov dx, #0x04d0
8965 test al, #0x08
8966 jz is_master_pic
8967 inc dx
8968 and al, #0x07
8969 is_master_pic:
8970 mov cl, al
8971 mov bl, #0x01
8972 shl bl, cl
8973 in al, dx
8974 or al, bl
8975 out dx, al
8976 pop cx
8977 pop ax
8980 pcibios_init:
8981 push ds
8982 push bp
8983 mov ax, #0xf000
8984 mov ds, ax
8985 mov dx, #0x04d0 ;; reset ELCR1 + ELCR2
8986 mov al, #0x00
8987 out dx, al
8988 inc dx
8989 out dx, al
8990 mov si, #pci_routing_table_structure
8991 mov bh, [si+8]
8992 mov bl, [si+9]
8993 mov dl, #0x00
8994 call pcibios_init_sel_reg
8995 mov dx, #0x0cfc
8996 in eax, dx
8997 cmp eax, [si+12] ;; check irq router
8998 jne pci_init_end
8999 mov dl, [si+34]
9000 call pcibios_init_sel_reg
9001 push bx ;; save irq router bus + devfunc
9002 mov dx, #0x0cfc
9003 mov ax, #0x8080
9004 out dx, ax ;; reset PIRQ route control
9005 inc dx
9006 inc dx
9007 out dx, ax
9008 mov ax, [si+6]
9009 sub ax, #0x20
9010 shr ax, #4
9011 mov cx, ax
9012 add si, #0x20 ;; set pointer to 1st entry
9013 mov bp, sp
9014 mov ax, #pci_irq_list
9015 push ax
9016 xor ax, ax
9017 push ax
9018 pci_init_loop1:
9019 mov bh, [si]
9020 mov bl, [si+1]
9021 pci_init_loop2:
9022 mov dl, #0x00
9023 call pcibios_init_sel_reg
9024 mov dx, #0x0cfc
9025 in ax, dx
9026 cmp ax, #0xffff
9027 jnz pci_test_int_pin
9028 test bl, #0x07
9029 jz next_pir_entry
9030 jmp next_pci_func
9031 pci_test_int_pin:
9032 mov dl, #0x3c
9033 call pcibios_init_sel_reg
9034 mov dx, #0x0cfd
9035 in al, dx
9036 and al, #0x07
9037 jz next_pci_func
9038 dec al ;; determine pirq reg
9039 mov dl, #0x03
9040 mul al, dl
9041 add al, #0x02
9042 xor ah, ah
9043 mov bx, ax
9044 mov al, [si+bx]
9045 mov dl, al
9046 mov bx, [bp]
9047 call pcibios_init_sel_reg
9048 mov dx, #0x0cfc
9049 and al, #0x03
9050 add dl, al
9051 in al, dx
9052 cmp al, #0x80
9053 jb pirq_found
9054 mov bx, [bp-2] ;; pci irq list pointer
9055 mov al, [bx]
9056 out dx, al
9057 inc bx
9058 mov [bp-2], bx
9059 call pcibios_init_set_elcr
9060 pirq_found:
9061 mov bh, [si]
9062 mov bl, [si+1]
9063 add bl, [bp-3] ;; pci function number
9064 mov dl, #0x3c
9065 call pcibios_init_sel_reg
9066 mov dx, #0x0cfc
9067 out dx, al
9068 next_pci_func:
9069 inc byte ptr[bp-3]
9070 inc bl
9071 test bl, #0x07
9072 jnz pci_init_loop2
9073 next_pir_entry:
9074 add si, #0x10
9075 mov byte ptr[bp-3], #0x00
9076 loop pci_init_loop1
9077 mov sp, bp
9078 pop bx
9079 pci_init_end:
9080 pop bp
9081 pop ds
9083 #endif // BX_PCIBIOS
9085 detect_parport:
9086 push dx
9087 add dx, #2
9088 in al, dx
9089 and al, #0xdf ; clear input mode
9090 out dx, al
9091 pop dx
9092 mov al, #0xaa
9093 out dx, al
9094 in al, dx
9095 cmp al, #0xaa
9096 jne no_parport
9097 push bx
9098 shl bx, #1
9099 mov [bx+0x408], dx ; Parallel I/O address
9100 pop bx
9101 mov [bx+0x478], cl ; Parallel printer timeout
9102 inc bx
9103 no_parport:
9106 detect_serial:
9107 push dx
9108 inc dx
9109 mov al, #0x02
9110 out dx, al
9111 in al, dx
9112 cmp al, #0x02
9113 jne no_serial
9114 inc dx
9115 in al, dx
9116 cmp al, #0x02
9117 jne no_serial
9118 dec dx
9119 xor al, al
9120 out dx, al
9121 pop dx
9122 push bx
9123 shl bx, #1
9124 mov [bx+0x400], dx ; Serial I/O address
9125 pop bx
9126 mov [bx+0x47c], cl ; Serial timeout
9127 inc bx
9129 no_serial:
9130 pop dx
9133 rom_checksum:
9134 push ax
9135 push bx
9136 push cx
9137 xor ax, ax
9138 xor bx, bx
9139 xor cx, cx
9140 mov ch, [2]
9141 shl cx, #1
9142 checksum_loop:
9143 add al, [bx]
9144 inc bx
9145 loop checksum_loop
9146 and al, #0xff
9147 pop cx
9148 pop bx
9149 pop ax
9152 rom_scan:
9153 ;; Scan for existence of valid expansion ROMS.
9154 ;; Video ROM: from 0xC0000..0xC7FFF in 2k increments
9155 ;; General ROM: from 0xC8000..0xDFFFF in 2k increments
9156 ;; System ROM: only 0xE0000
9158 ;; Header:
9159 ;; Offset Value
9160 ;; 0 0x55
9161 ;; 1 0xAA
9162 ;; 2 ROM length in 512-byte blocks
9163 ;; 3 ROM initialization entry point (FAR CALL)
9165 mov cx, #0xc000
9166 rom_scan_loop:
9167 mov ds, cx
9168 mov ax, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
9169 cmp [0], #0xAA55 ;; look for signature
9170 jne rom_scan_increment
9171 call rom_checksum
9172 jnz rom_scan_increment
9173 mov al, [2] ;; change increment to ROM length in 512-byte blocks
9175 ;; We want our increment in 512-byte quantities, rounded to
9176 ;; the nearest 2k quantity, since we only scan at 2k intervals.
9177 test al, #0x03
9178 jz block_count_rounded
9179 and al, #0xfc ;; needs rounding up
9180 add al, #0x04
9181 block_count_rounded:
9183 xor bx, bx ;; Restore DS back to 0000:
9184 mov ds, bx
9185 push ax ;; Save AX
9186 ;; Push addr of ROM entry point
9187 push cx ;; Push seg
9188 push #0x0003 ;; Push offset
9189 mov bp, sp ;; Call ROM init routine using seg:off on stack
9190 db 0xff ;; call_far ss:[bp+0]
9191 db 0x5e
9192 db 0
9193 cli ;; In case expansion ROM BIOS turns IF on
9194 add sp, #2 ;; Pop offset value
9195 pop cx ;; Pop seg value (restore CX)
9196 pop ax ;; Restore AX
9197 rom_scan_increment:
9198 shl ax, #5 ;; convert 512-bytes blocks to 16-byte increments
9199 ;; because the segment selector is shifted left 4 bits.
9200 add cx, ax
9201 cmp cx, #0xe000
9202 jbe rom_scan_loop
9204 xor ax, ax ;; Restore DS back to 0000:
9205 mov ds, ax
9208 ;; for 'C' strings and other data, insert them here with
9209 ;; a the following hack:
9210 ;; DATA_SEG_DEFS_HERE
9213 ;--------
9214 ;- POST -
9215 ;--------
9216 .org 0xe05b ; POST Entry Point
9217 post:
9219 xor ax, ax
9221 ;; first reset the DMA controllers
9222 out 0x0d,al
9223 out 0xda,al
9225 ;; then initialize the DMA controllers
9226 mov al, #0xC0
9227 out 0xD6, al ; cascade mode of channel 4 enabled
9228 mov al, #0x00
9229 out 0xD4, al ; unmask channel 4
9231 ;; Examine CMOS shutdown status.
9232 mov AL, #0x0f
9233 out 0x70, AL
9234 in AL, 0x71
9236 ;; backup status
9237 mov bl, al
9239 ;; Reset CMOS shutdown status.
9240 mov AL, #0x0f
9241 out 0x70, AL ; select CMOS register Fh
9242 mov AL, #0x00
9243 out 0x71, AL ; set shutdown action to normal
9245 ;; Examine CMOS shutdown status.
9246 mov al, bl
9248 ;; 0x00, 0x09, 0x0D+ = normal startup
9249 cmp AL, #0x00
9250 jz normal_post
9251 cmp AL, #0x0d
9252 jae normal_post
9253 cmp AL, #0x09
9254 je normal_post
9256 ;; 0x05 = eoi + jmp via [0x40:0x67] jump
9257 cmp al, #0x05
9258 je eoi_jmp_post
9260 ;; Examine CMOS shutdown status.
9261 ;; 0x01,0x02,0x03,0x04,0x06,0x07,0x08, 0x0a, 0x0b, 0x0c = Unimplemented shutdown status.
9262 push bx
9263 call _shutdown_status_panic
9265 #if 0
9266 HALT(__LINE__)
9268 ;#if 0
9269 ; 0xb0, 0x20, /* mov al, #0x20 */
9270 ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */
9271 ;#endif
9273 pop es
9274 pop ds
9275 popa
9276 iret
9277 #endif
9279 normal_post:
9280 ; case 0: normal startup
9283 mov ax, #0xfffe
9284 mov sp, ax
9285 mov ax, #0x0000
9286 mov ds, ax
9287 mov ss, ax
9289 ;; zero out BIOS data area (40:00..40:ff)
9290 mov es, ax
9291 mov cx, #0x0080 ;; 128 words
9292 mov di, #0x0400
9295 stosw
9297 call _log_bios_start
9299 ;; set all interrupts to default handler
9300 mov bx, #0x0000 ;; offset index
9301 mov cx, #0x0100 ;; counter (256 interrupts)
9302 mov ax, #dummy_iret_handler
9303 mov dx, #0xF000
9305 post_default_ints:
9306 mov [bx], ax
9307 inc bx
9308 inc bx
9309 mov [bx], dx
9310 inc bx
9311 inc bx
9312 loop post_default_ints
9314 ;; set vector 0x79 to zero
9315 ;; this is used by 'gardian angel' protection system
9316 SET_INT_VECTOR(0x79, #0, #0)
9318 ;; base memory in K 40:13 (word)
9319 mov ax, #BASE_MEM_IN_K
9320 mov 0x0413, ax
9323 ;; Manufacturing Test 40:12
9324 ;; zerod out above
9326 ;; Warm Boot Flag 0040:0072
9327 ;; value of 1234h = skip memory checks
9328 ;; zerod out above
9331 ;; Printer Services vector
9332 SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
9334 ;; Bootstrap failure vector
9335 SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
9337 ;; Bootstrap Loader vector
9338 SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
9340 ;; User Timer Tick vector
9341 SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
9343 ;; Memory Size Check vector
9344 SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
9346 ;; Equipment Configuration Check vector
9347 SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
9349 ;; System Services
9350 SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
9352 ;; EBDA setup
9353 call ebda_post
9355 ;; PIT setup
9356 SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
9357 ;; int 1C already points at dummy_iret_handler (above)
9358 mov al, #0x34 ; timer0: binary count, 16bit count, mode 2
9359 out 0x43, al
9360 mov al, #0x00 ; maximum count of 0000H = 18.2Hz
9361 out 0x40, al
9362 out 0x40, al
9364 ;; Keyboard
9365 SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
9366 SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
9368 xor ax, ax
9369 mov ds, ax
9370 mov 0x0417, al /* keyboard shift flags, set 1 */
9371 mov 0x0418, al /* keyboard shift flags, set 2 */
9372 mov 0x0419, al /* keyboard alt-numpad work area */
9373 mov 0x0471, al /* keyboard ctrl-break flag */
9374 mov 0x0497, al /* keyboard status flags 4 */
9375 mov al, #0x10
9376 mov 0x0496, al /* keyboard status flags 3 */
9379 /* keyboard head of buffer pointer */
9380 mov bx, #0x001E
9381 mov 0x041A, bx
9383 /* keyboard end of buffer pointer */
9384 mov 0x041C, bx
9386 /* keyboard pointer to start of buffer */
9387 mov bx, #0x001E
9388 mov 0x0480, bx
9390 /* keyboard pointer to end of buffer */
9391 mov bx, #0x003E
9392 mov 0x0482, bx
9394 /* init the keyboard */
9395 call _keyboard_init
9397 ;; mov CMOS Equipment Byte to BDA Equipment Word
9398 mov ax, 0x0410
9399 mov al, #0x14
9400 out 0x70, al
9401 in al, 0x71
9402 mov 0x0410, ax
9405 ;; Parallel setup
9406 SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
9407 xor ax, ax
9408 mov ds, ax
9409 xor bx, bx
9410 mov cl, #0x14 ; timeout value
9411 mov dx, #0x378 ; Parallel I/O address, port 1
9412 call detect_parport
9413 mov dx, #0x278 ; Parallel I/O address, port 2
9414 call detect_parport
9415 shl bx, #0x0e
9416 mov ax, 0x410 ; Equipment word bits 14..15 determing # parallel ports
9417 and ax, #0x3fff
9418 or ax, bx ; set number of parallel ports
9419 mov 0x410, ax
9421 ;; Serial setup
9422 SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
9423 SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
9424 xor bx, bx
9425 mov cl, #0x0a ; timeout value
9426 mov dx, #0x03f8 ; Serial I/O address, port 1
9427 call detect_serial
9428 mov dx, #0x02f8 ; Serial I/O address, port 2
9429 call detect_serial
9430 mov dx, #0x03e8 ; Serial I/O address, port 3
9431 call detect_serial
9432 mov dx, #0x02e8 ; Serial I/O address, port 4
9433 call detect_serial
9434 shl bx, #0x09
9435 mov ax, 0x410 ; Equipment word bits 9..11 determing # serial ports
9436 and ax, #0xf1ff
9437 or ax, bx ; set number of serial port
9438 mov 0x410, ax
9440 ;; CMOS RTC
9441 SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
9442 SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
9443 SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
9444 ;; BIOS DATA AREA 0x4CE ???
9445 call timer_tick_post
9447 ;; PS/2 mouse setup
9448 SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
9450 ;; IRQ13 (FPU exception) setup
9451 SET_INT_VECTOR(0x75, #0xF000, #int75_handler)
9453 ;; Video setup
9454 SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
9456 ;; PIC
9457 mov al, #0x11 ; send initialisation commands
9458 out 0x20, al
9459 out 0xa0, al
9460 mov al, #0x08
9461 out 0x21, al
9462 mov al, #0x70
9463 out 0xa1, al
9464 mov al, #0x04
9465 out 0x21, al
9466 mov al, #0x02
9467 out 0xa1, al
9468 mov al, #0x01
9469 out 0x21, al
9470 out 0xa1, al
9471 mov al, #0xb8
9472 out 0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6
9473 #if BX_USE_PS2_MOUSE
9474 mov al, #0x8f
9475 #else
9476 mov al, #0x9f
9477 #endif
9478 out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14
9480 call pcibios_init
9482 call rom_scan
9484 call _print_bios_banner
9487 ;; Floppy setup
9489 call floppy_drive_post
9491 #if BX_USE_ATADRV
9494 ;; Hard Drive setup
9496 call hard_drive_post
9499 ;; ATA/ATAPI driver setup
9501 call _ata_init
9502 call _ata_detect
9504 #else // BX_USE_ATADRV
9507 ;; Hard Drive setup
9509 call hard_drive_post
9511 #endif // BX_USE_ATADRV
9513 #if BX_ELTORITO_BOOT
9515 ;; eltorito floppy/harddisk emulation from cd
9517 call _cdemu_init
9519 #endif // BX_ELTORITO_BOOT
9521 int #0x19
9522 //JMP_EP(0x0064) ; INT 19h location
9525 .org 0xe2c3 ; NMI Handler Entry Point
9526 nmi:
9527 ;; FIXME the NMI handler should not panic
9528 ;; but iret when called from int75 (fpu exception)
9529 call _nmi_handler_msg
9530 iret
9532 int75_handler:
9533 out 0xf0, al // clear irq13
9534 call eoi_both_pics // clear interrupt
9535 int 2 // legacy nmi call
9536 iret
9538 ;-------------------------------------------
9539 ;- INT 13h Fixed Disk Services Entry Point -
9540 ;-------------------------------------------
9541 .org 0xe3fe ; INT 13h Fixed Disk Services Entry Point
9542 int13_handler:
9543 //JMPL(int13_relocated)
9544 jmp int13_relocated
9546 .org 0xe401 ; Fixed Disk Parameter Table
9548 ;----------
9549 ;- INT19h -
9550 ;----------
9551 .org 0xe6f2 ; INT 19h Boot Load Service Entry Point
9552 int19_handler:
9554 jmp int19_relocated
9555 ;-------------------------------------------
9556 ;- System BIOS Configuration Data Table
9557 ;-------------------------------------------
9558 .org BIOS_CONFIG_TABLE
9559 db 0x08 ; Table size (bytes) -Lo
9560 db 0x00 ; Table size (bytes) -Hi
9561 db SYS_MODEL_ID
9562 db SYS_SUBMODEL_ID
9563 db BIOS_REVISION
9564 ; Feature byte 1
9565 ; b7: 1=DMA channel 3 used by hard disk
9566 ; b6: 1=2 interrupt controllers present
9567 ; b5: 1=RTC present
9568 ; b4: 1=BIOS calls int 15h/4Fh every key
9569 ; b3: 1=wait for extern event supported (Int 15h/41h)
9570 ; b2: 1=extended BIOS data area used
9571 ; b1: 0=AT or ESDI bus, 1=MicroChannel
9572 ; b0: 1=Dual bus (MicroChannel + ISA)
9573 db (0 << 7) | \
9574 (1 << 6) | \
9575 (1 << 5) | \
9576 (BX_CALL_INT15_4F << 4) | \
9577 (0 << 3) | \
9578 (BX_USE_EBDA << 2) | \
9579 (0 << 1) | \
9580 (0 << 0)
9581 ; Feature byte 2
9582 ; b7: 1=32-bit DMA supported
9583 ; b6: 1=int16h, function 9 supported
9584 ; b5: 1=int15h/C6h (get POS data) supported
9585 ; b4: 1=int15h/C7h (get mem map info) supported
9586 ; b3: 1=int15h/C8h (en/dis CPU) supported
9587 ; b2: 1=non-8042 kb controller
9588 ; b1: 1=data streaming supported
9589 ; b0: reserved
9590 db (0 << 7) | \
9591 (1 << 6) | \
9592 (0 << 5) | \
9593 (0 << 4) | \
9594 (0 << 3) | \
9595 (0 << 2) | \
9596 (0 << 1) | \
9597 (0 << 0)
9598 ; Feature byte 3
9599 ; b7: not used
9600 ; b6: reserved
9601 ; b5: reserved
9602 ; b4: POST supports ROM-to-RAM enable/disable
9603 ; b3: SCSI on system board
9604 ; b2: info panel installed
9605 ; b1: Initial Machine Load (IML) system - BIOS on disk
9606 ; b0: SCSI supported in IML
9607 db 0x00
9608 ; Feature byte 4
9609 ; b7: IBM private
9610 ; b6: EEPROM present
9611 ; b5-3: ABIOS presence (011 = not supported)
9612 ; b2: private
9613 ; b1: memory split above 16Mb supported
9614 ; b0: POSTEXT directly supported by POST
9615 db 0x00
9616 ; Feature byte 5 (IBM)
9617 ; b1: enhanced mouse
9618 ; b0: flash EPROM
9619 db 0x00
9623 .org 0xe729 ; Baud Rate Generator Table
9625 ;----------
9626 ;- INT14h -
9627 ;----------
9628 .org 0xe739 ; INT 14h Serial Communications Service Entry Point
9629 int14_handler:
9630 push ds
9631 pusha
9632 mov ax, #0x0000
9633 mov ds, ax
9634 call _int14_function
9635 popa
9636 pop ds
9637 iret
9640 ;----------------------------------------
9641 ;- INT 16h Keyboard Service Entry Point -
9642 ;----------------------------------------
9643 .org 0xe82e
9644 int16_handler:
9647 push ds
9648 pushf
9649 pusha
9651 cmp ah, #0x00
9652 je int16_F00
9653 cmp ah, #0x10
9654 je int16_F00
9656 mov bx, #0xf000
9657 mov ds, bx
9658 call _int16_function
9659 popa
9660 popf
9661 pop ds
9662 jz int16_zero_set
9664 int16_zero_clear:
9665 push bp
9666 mov bp, sp
9667 //SEG SS
9668 and BYTE [bp + 0x06], #0xbf
9669 pop bp
9670 iret
9672 int16_zero_set:
9673 push bp
9674 mov bp, sp
9675 //SEG SS
9676 or BYTE [bp + 0x06], #0x40
9677 pop bp
9678 iret
9680 int16_F00:
9681 mov bx, #0x0040
9682 mov ds, bx
9684 int16_wait_for_key:
9686 mov bx, 0x001a
9687 cmp bx, 0x001c
9688 jne int16_key_found
9691 #if 0
9692 /* no key yet, call int 15h, function AX=9002 */
9693 0x50, /* push AX */
9694 0xb8, 0x02, 0x90, /* mov AX, #0x9002 */
9695 0xcd, 0x15, /* int 15h */
9696 0x58, /* pop AX */
9697 0xeb, 0xea, /* jmp WAIT_FOR_KEY */
9698 #endif
9699 jmp int16_wait_for_key
9701 int16_key_found:
9702 mov bx, #0xf000
9703 mov ds, bx
9704 call _int16_function
9705 popa
9706 popf
9707 pop ds
9708 #if 0
9709 /* notify int16 complete w/ int 15h, function AX=9102 */
9710 0x50, /* push AX */
9711 0xb8, 0x02, 0x91, /* mov AX, #0x9102 */
9712 0xcd, 0x15, /* int 15h */
9713 0x58, /* pop AX */
9714 #endif
9715 iret
9719 ;-------------------------------------------------
9720 ;- INT09h : Keyboard Hardware Service Entry Point -
9721 ;-------------------------------------------------
9722 .org 0xe987
9723 int09_handler:
9725 push ax
9727 mov al, #0xAD ;;disable keyboard
9728 out #0x64, al
9730 mov al, #0x0B
9731 out #0x20, al
9732 in al, #0x20
9733 and al, #0x02
9734 jz int09_finish
9736 in al, #0x60 ;;read key from keyboard controller
9737 //test al, #0x80 ;;look for key release
9738 //jnz int09_process_key ;; dont pass releases to intercept?
9740 ;; check for extended key
9741 cmp al, #0xe0
9742 jne int09_call_int15_4f
9744 push ds
9745 xor ax, ax
9746 mov ds, ax
9747 mov al, BYTE [0x496] ;; mf2_state |= 0x01
9748 or al, #0x01
9749 mov BYTE [0x496], al
9750 pop ds
9752 in al, #0x60 ;;read another key from keyboard controller
9756 int09_call_int15_4f:
9757 push ds
9758 pusha
9759 #ifdef BX_CALL_INT15_4F
9760 mov ah, #0x4f ;; allow for keyboard intercept
9762 int #0x15
9763 jnc int09_done
9764 #endif
9767 //int09_process_key:
9768 mov bx, #0xf000
9769 mov ds, bx
9770 call _int09_function
9772 int09_done:
9773 popa
9774 pop ds
9776 call eoi_master_pic
9778 int09_finish:
9779 mov al, #0xAE ;;enable keyboard
9780 out #0x64, al
9781 pop ax
9782 iret
9787 ;----------------------------------------
9788 ;- INT 13h Diskette Service Entry Point -
9789 ;----------------------------------------
9790 .org 0xec59
9791 int13_diskette:
9792 pushf
9793 push es
9794 pusha
9795 call _int13_diskette_function
9796 popa
9797 pop es
9798 popf
9799 //JMPL(iret_modify_cf)
9800 jmp iret_modify_cf
9802 #if 0
9803 pushf
9804 cmp ah, #0x01
9805 je i13d_f01
9807 ;; pushf already done
9808 push es
9809 pusha
9810 call _int13_diskette_function
9811 popa
9812 pop es
9813 popf
9814 //JMPL(iret_modify_cf)
9815 jmp iret_modify_cf
9816 i13d_f01:
9817 popf
9818 push ds
9819 push bx
9820 mov bx, #0x0000
9821 mov ds, bx
9822 mov ah, 0x0441
9823 pop bx
9824 pop ds
9826 ;; ??? dont know if this service changes the return status
9827 //JMPL(iret_modify_cf)
9828 jmp iret_modify_cf
9829 #endif
9833 ;---------------------------------------------
9834 ;- INT 0Eh Diskette Hardware ISR Entry Point -
9835 ;---------------------------------------------
9836 .org 0xef57 ; INT 0Eh Diskette Hardware ISR Entry Point
9837 int0e_handler:
9838 push ax
9839 push dx
9840 mov dx, #0x03f4
9841 in al, dx
9842 and al, #0xc0
9843 cmp al, #0xc0
9844 je int0e_normal
9845 mov dx, #0x03f5
9846 mov al, #0x08 ; sense interrupt status
9847 out dx, al
9848 int0e_loop1:
9849 mov dx, #0x03f4
9850 in al, dx
9851 and al, #0xc0
9852 cmp al, #0xc0
9853 jne int0e_loop1
9854 int0e_loop2:
9855 mov dx, #0x03f5
9856 in al, dx
9857 mov dx, #0x03f4
9858 in al, dx
9859 and al, #0xc0
9860 cmp al, #0xc0
9861 je int0e_loop2
9862 int0e_normal:
9863 push ds
9864 mov ax, #0x0000 ;; segment 0000
9865 mov ds, ax
9866 call eoi_master_pic
9867 mov al, 0x043e
9868 or al, #0x80 ;; diskette interrupt has occurred
9869 mov 0x043e, al
9870 pop ds
9871 pop dx
9872 pop ax
9873 iret
9876 .org 0xefc7 ; Diskette Controller Parameter Table
9877 diskette_param_table:
9878 ;; Since no provisions are made for multiple drive types, most
9879 ;; values in this table are ignored. I set parameters for 1.44M
9880 ;; floppy here
9881 db 0xAF
9882 db 0x02 ;; head load time 0000001, DMA used
9883 db 0x25
9884 db 0x02
9885 db 18
9886 db 0x1B
9887 db 0xFF
9888 db 0x6C
9889 db 0xF6
9890 db 0x0F
9891 db 0x08
9894 ;----------------------------------------
9895 ;- INT17h : Printer Service Entry Point -
9896 ;----------------------------------------
9897 .org 0xefd2
9898 int17_handler:
9899 push ds
9900 pusha
9901 mov ax, #0x0000
9902 mov ds, ax
9903 call _int17_function
9904 popa
9905 pop ds
9906 iret
9908 diskette_param_table2:
9909 ;; New diskette parameter table adding 3 parameters from IBM
9910 ;; Since no provisions are made for multiple drive types, most
9911 ;; values in this table are ignored. I set parameters for 1.44M
9912 ;; floppy here
9913 db 0xAF
9914 db 0x02 ;; head load time 0000001, DMA used
9915 db 0x25
9916 db 0x02
9917 db 18
9918 db 0x1B
9919 db 0xFF
9920 db 0x6C
9921 db 0xF6
9922 db 0x0F
9923 db 0x08
9924 db 79 ;; maximum track
9925 db 0 ;; data transfer rate
9926 db 4 ;; drive type in cmos
9928 .org 0xf045 ; INT 10 Functions 0-Fh Entry Point
9929 HALT(__LINE__)
9930 iret
9932 ;----------
9933 ;- INT10h -
9934 ;----------
9935 .org 0xf065 ; INT 10h Video Support Service Entry Point
9936 int10_handler:
9937 ;; dont do anything, since the VGA BIOS handles int10h requests
9938 iret
9940 .org 0xf0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
9942 ;----------
9943 ;- INT12h -
9944 ;----------
9945 .org 0xf841 ; INT 12h Memory Size Service Entry Point
9946 ; ??? different for Pentium (machine check)?
9947 int12_handler:
9948 push ds
9949 mov ax, #0x0040
9950 mov ds, ax
9951 mov ax, 0x0013
9952 pop ds
9953 iret
9955 ;----------
9956 ;- INT11h -
9957 ;----------
9958 .org 0xf84d ; INT 11h Equipment List Service Entry Point
9959 int11_handler:
9960 push ds
9961 mov ax, #0x0040
9962 mov ds, ax
9963 mov ax, 0x0010
9964 pop ds
9965 iret
9967 ;----------
9968 ;- INT15h -
9969 ;----------
9970 .org 0xf859 ; INT 15h System Services Entry Point
9971 int15_handler:
9972 pushf
9973 #if BX_APM
9974 cmp ah, #0x53
9975 je apm_call
9976 #endif
9977 push ds
9978 push es
9979 cmp ah, #0x86
9980 je int15_handler32
9981 cmp ah, #0xE8
9982 je int15_handler32
9983 pusha
9984 #if BX_USE_PS2_MOUSE
9985 cmp ah, #0xC2
9986 je int15_handler_mouse
9987 #endif
9988 call _int15_function
9989 int15_handler_mouse_ret:
9990 popa
9991 int15_handler32_ret:
9992 pop es
9993 pop ds
9994 popf
9995 jmp iret_modify_cf
9996 #if BX_APM
9997 apm_call:
9998 jmp _apmreal_entry
9999 #endif
10001 #if BX_USE_PS2_MOUSE
10002 int15_handler_mouse:
10003 call _int15_function_mouse
10004 jmp int15_handler_mouse_ret
10005 #endif
10007 int15_handler32:
10008 pushad
10009 call _int15_function32
10010 popad
10011 jmp int15_handler32_ret
10013 ;; Protected mode IDT descriptor
10015 ;; I just make the limit 0, so the machine will shutdown
10016 ;; if an exception occurs during protected mode memory
10017 ;; transfers.
10019 ;; Set base to f0000 to correspond to beginning of BIOS,
10020 ;; in case I actually define an IDT later
10021 ;; Set limit to 0
10023 pmode_IDT_info:
10024 dw 0x0000 ;; limit 15:00
10025 dw 0x0000 ;; base 15:00
10026 db 0x0f ;; base 23:16
10028 ;; Real mode IDT descriptor
10030 ;; Set to typical real-mode values.
10031 ;; base = 000000
10032 ;; limit = 03ff
10034 rmode_IDT_info:
10035 dw 0x03ff ;; limit 15:00
10036 dw 0x0000 ;; base 15:00
10037 db 0x00 ;; base 23:16
10040 ;----------
10041 ;- INT1Ah -
10042 ;----------
10043 .org 0xfe6e ; INT 1Ah Time-of-day Service Entry Point
10044 int1a_handler:
10045 #if BX_PCIBIOS
10046 cmp ah, #0xb1
10047 jne int1a_normal
10048 call pcibios_real
10049 jc pcibios_error
10050 push ax
10051 mov ax, ss
10052 push ds
10053 mov ds, ax
10054 push bp
10055 mov bp, sp
10056 lahf
10057 mov [bp+10], ah
10058 pop bp
10059 pop ds
10060 pop ax
10061 iret
10062 pcibios_error:
10063 mov al, ah
10064 mov ah, #0xb1
10065 int1a_normal:
10066 #endif
10067 push ds
10068 pusha
10069 xor ax, ax
10070 mov ds, ax
10071 call _int1a_function
10072 popa
10073 pop ds
10074 iret
10077 ;; int70h: IRQ8 - CMOS RTC
10079 int70_handler:
10080 push ds
10081 pusha
10082 xor ax, ax
10083 mov ds, ax
10084 call _int70_function
10085 popa
10086 pop ds
10087 iret
10089 ;---------
10090 ;- INT08 -
10091 ;---------
10092 .org 0xfea5 ; INT 08h System Timer ISR Entry Point
10093 int08_handler:
10095 push eax
10096 push ds
10097 xor ax, ax
10098 mov ds, ax
10100 ;; time to turn off drive(s)?
10101 mov al,0x0440
10102 or al,al
10103 jz int08_floppy_off
10104 dec al
10105 mov 0x0440,al
10106 jnz int08_floppy_off
10107 ;; turn motor(s) off
10108 push dx
10109 mov dx,#0x03f2
10110 in al,dx
10111 and al,#0xcf
10112 out dx,al
10113 pop dx
10114 int08_floppy_off:
10116 mov eax, 0x046c ;; get ticks dword
10117 inc eax
10119 ;; compare eax to one days worth of timer ticks at 18.2 hz
10120 cmp eax, #0x001800B0
10121 jb int08_store_ticks
10122 ;; there has been a midnight rollover at this point
10123 xor eax, eax ;; zero out counter
10124 inc BYTE 0x0470 ;; increment rollover flag
10126 int08_store_ticks:
10127 mov 0x046c, eax ;; store new ticks dword
10128 ;; chain to user timer tick INT #0x1c
10129 //pushf
10130 //;; call_ep [ds:loc]
10131 //CALL_EP( 0x1c << 2 )
10132 int #0x1c
10134 call eoi_master_pic
10135 pop ds
10136 pop eax
10137 iret
10139 .org 0xfef3 ; Initial Interrupt Vector Offsets Loaded by POST
10142 .org 0xff00
10143 .ascii "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team."
10145 ;------------------------------------------------
10146 ;- IRET Instruction for Dummy Interrupt Handler -
10147 ;------------------------------------------------
10148 .org 0xff53 ; IRET Instruction for Dummy Interrupt Handler
10149 dummy_iret_handler:
10150 iret
10152 .org 0xff54 ; INT 05h Print Screen Service Entry Point
10153 HALT(__LINE__)
10154 iret
10156 .org 0xfff0 ; Power-up Entry Point
10157 jmp 0xf000:post;
10159 .org 0xfff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
10160 .ascii "06/23/99"
10162 .org 0xfffe ; System Model ID
10163 db SYS_MODEL_ID
10164 db 0x00 ; filler
10166 .org 0xfa6e ;; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
10167 ASM_END
10169 * This font comes from the fntcol16.zip package (c) by Joseph Gil
10170 * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
10171 * This font is public domain
10173 static Bit8u vgafont8[128*8]=
10175 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10176 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
10177 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
10178 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
10179 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
10180 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
10181 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
10182 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
10183 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
10184 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
10185 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
10186 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
10187 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
10188 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
10189 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
10190 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
10191 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
10192 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
10193 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
10194 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
10195 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
10196 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
10197 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
10198 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
10199 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
10200 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
10201 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
10202 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
10203 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
10204 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
10205 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
10206 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
10207 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10208 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
10209 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
10210 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
10211 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
10212 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
10213 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
10214 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
10215 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
10216 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
10217 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
10218 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
10219 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
10220 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
10221 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
10222 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
10223 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
10224 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
10225 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
10226 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
10227 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
10228 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
10229 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
10230 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
10231 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
10232 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
10233 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
10234 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
10235 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
10236 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
10237 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
10238 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
10239 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
10240 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
10241 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
10242 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
10243 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
10244 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
10245 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
10246 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
10247 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
10248 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10249 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
10250 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
10251 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
10252 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
10253 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
10254 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
10255 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
10256 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
10257 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
10258 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
10259 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10260 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
10261 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
10262 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
10263 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
10264 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
10265 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
10266 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
10267 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
10268 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
10269 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
10270 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
10271 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
10272 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
10273 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
10274 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
10275 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
10276 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
10277 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
10278 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
10279 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
10280 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
10281 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
10282 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
10283 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10284 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
10285 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
10286 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
10287 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
10288 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
10289 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
10290 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
10291 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
10292 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
10293 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
10294 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
10295 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
10296 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
10297 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
10298 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
10299 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
10300 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
10301 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10302 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
10305 ASM_START
10306 .org 0xd000
10307 // bcc-generated data will be placed here
10309 // For documentation of this config structure, look on developer.intel.com and
10310 // search for multiprocessor specification. Note that when you change anything
10311 // you must update the checksum (a pain!). It would be better to construct this
10312 // with C structures, or at least fill in the checksum automatically.
10314 // Maybe this structs could be moved elsewhere than d000
10316 #if (BX_SMP_PROCESSORS==1)
10317 // no structure necessary.
10318 #elif (BX_SMP_PROCESSORS==2)
10319 // define the Intel MP Configuration Structure for 2 processors at
10320 // APIC ID 0,1. I/O APIC at ID=2.
10321 .align 16
10322 mp_config_table:
10323 db 0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature
10324 dw (mp_config_end-mp_config_table) ;; table length
10325 db 4 ;; spec rev
10326 db 0x65 ;; checksum
10327 .ascii "BOCHSCPU" ;; OEM id = "BOCHSCPU"
10328 db 0x30, 0x2e, 0x31, 0x20 ;; vendor id = "0.1 "
10329 db 0x20, 0x20, 0x20, 0x20
10330 db 0x20, 0x20, 0x20, 0x20
10331 dw 0,0 ;; oem table ptr
10332 dw 0 ;; oem table size
10333 dw 20 ;; entry count
10334 dw 0x0000, 0xfee0 ;; memory mapped address of local APIC
10335 dw 0 ;; extended table length
10336 db 0 ;; extended table checksum
10337 db 0 ;; reserved
10338 mp_config_proc0:
10339 db 0 ;; entry type=processor
10340 db 0 ;; local APIC id
10341 db 0x11 ;; local APIC version number
10342 db 3 ;; cpu flags: enabled
10343 db 0,6,0,0 ;; cpu signature
10344 dw 0x201,0 ;; feature flags
10345 dw 0,0 ;; reserved
10346 dw 0,0 ;; reserved
10347 mp_config_proc1:
10348 db 0 ;; entry type=processor
10349 db 1 ;; local APIC id
10350 db 0x11 ;; local APIC version number
10351 db 1 ;; cpu flags: enabled
10352 db 0,6,0,0 ;; cpu signature
10353 dw 0x201,0 ;; feature flags
10354 dw 0,0 ;; reserved
10355 dw 0,0 ;; reserved
10356 mp_config_isa_bus:
10357 db 1 ;; entry type=bus
10358 db 0 ;; bus ID
10359 db 0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type="ISA "
10360 mp_config_ioapic:
10361 db 2 ;; entry type=I/O APIC
10362 db 2 ;; apic id=2. linux will set.
10363 db 0x11 ;; I/O APIC version number
10364 db 1 ;; flags=1=enabled
10365 dw 0x0000, 0xfec0 ;; memory mapped address of I/O APIC
10366 mp_config_irqs:
10367 db 3 ;; entry type=I/O interrupt
10368 db 0 ;; interrupt type=vectored interrupt
10369 db 0,0 ;; flags po=0, el=0 (linux uses as default)
10370 db 0 ;; source bus ID is ISA
10371 db 0 ;; source bus IRQ
10372 db 2 ;; destination I/O APIC ID
10373 db 0 ;; destination I/O APIC interrrupt in
10374 ;; repeat pattern for interrupts 0-15
10375 db 3,0,0,0,0,1,2,1
10376 db 3,0,0,0,0,2,2,2
10377 db 3,0,0,0,0,3,2,3
10378 db 3,0,0,0,0,4,2,4
10379 db 3,0,0,0,0,5,2,5
10380 db 3,0,0,0,0,6,2,6
10381 db 3,0,0,0,0,7,2,7
10382 db 3,0,0,0,0,8,2,8
10383 db 3,0,0,0,0,9,2,9
10384 db 3,0,0,0,0,10,2,10
10385 db 3,0,0,0,0,11,2,11
10386 db 3,0,0,0,0,12,2,12
10387 db 3,0,0,0,0,13,2,13
10388 db 3,0,0,0,0,14,2,14
10389 db 3,0,0,0,0,15,2,15
10390 #elif (BX_SMP_PROCESSORS==4)
10391 // define the Intel MP Configuration Structure for 4 processors at
10392 // APIC ID 0,1,2,3. I/O APIC at ID=4.
10393 .align 16
10394 mp_config_table:
10395 db 0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature
10396 dw (mp_config_end-mp_config_table) ;; table length
10397 db 4 ;; spec rev
10398 db 0xdd ;; checksum
10399 .ascii "BOCHSCPU" ;; OEM id = "BOCHSCPU"
10400 db 0x30, 0x2e, 0x31, 0x20 ;; vendor id = "0.1 "
10401 db 0x20, 0x20, 0x20, 0x20
10402 db 0x20, 0x20, 0x20, 0x20
10403 dw 0,0 ;; oem table ptr
10404 dw 0 ;; oem table size
10405 dw 22 ;; entry count
10406 dw 0x0000, 0xfee0 ;; memory mapped address of local APIC
10407 dw 0 ;; extended table length
10408 db 0 ;; extended table checksum
10409 db 0 ;; reserved
10410 mp_config_proc0:
10411 db 0 ;; entry type=processor
10412 db 0 ;; local APIC id
10413 db 0x11 ;; local APIC version number
10414 db 1 ;; cpu flags: enabled
10415 db 0,6,0,0 ;; cpu signature
10416 dw 0x201,0 ;; feature flags
10417 dw 0,0 ;; reserved
10418 dw 0,0 ;; reserved
10419 mp_config_proc1:
10420 db 0 ;; entry type=processor
10421 db 1 ;; local APIC id
10422 db 0x11 ;; local APIC version number
10423 db 1 ;; cpu flags: enabled
10424 db 0,6,0,0 ;; cpu signature
10425 dw 0x201,0 ;; feature flags
10426 dw 0,0 ;; reserved
10427 dw 0,0 ;; reserved
10428 mp_config_proc2:
10429 db 0 ;; entry type=processor
10430 db 2 ;; local APIC id
10431 db 0x11 ;; local APIC version number
10432 db 3 ;; cpu flags: enabled, bootstrap processor
10433 db 0,6,0,0 ;; cpu signature
10434 dw 0x201,0 ;; feature flags
10435 dw 0,0 ;; reserved
10436 dw 0,0 ;; reserved
10437 mp_config_proc3:
10438 db 0 ;; entry type=processor
10439 db 3 ;; local APIC id
10440 db 0x11 ;; local APIC version number
10441 db 1 ;; cpu flags: enabled
10442 db 0,6,0,0 ;; cpu signature
10443 dw 0x201,0 ;; feature flags
10444 dw 0,0 ;; reserved
10445 dw 0,0 ;; reserved
10446 mp_config_isa_bus:
10447 db 1 ;; entry type=bus
10448 db 0 ;; bus ID
10449 db 0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type="ISA "
10450 mp_config_ioapic:
10451 db 2 ;; entry type=I/O APIC
10452 db 4 ;; apic id=2. linux will set.
10453 db 0x11 ;; I/O APIC version number
10454 db 1 ;; flags=1=enabled
10455 dw 0x0000, 0xfec0 ;; memory mapped address of I/O APIC
10456 mp_config_irqs:
10457 db 3 ;; entry type=I/O interrupt
10458 db 0 ;; interrupt type=vectored interrupt
10459 db 0,0 ;; flags po=0, el=0 (linux uses as default)
10460 db 0 ;; source bus ID is ISA
10461 db 0 ;; source bus IRQ
10462 db 4 ;; destination I/O APIC ID
10463 db 0 ;; destination I/O APIC interrrupt in
10464 ;; repeat pattern for interrupts 0-15
10465 db 3,0,0,0,0,1,4,1
10466 db 3,0,0,0,0,2,4,2
10467 db 3,0,0,0,0,3,4,3
10468 db 3,0,0,0,0,4,4,4
10469 db 3,0,0,0,0,5,4,5
10470 db 3,0,0,0,0,6,4,6
10471 db 3,0,0,0,0,7,4,7
10472 db 3,0,0,0,0,8,4,8
10473 db 3,0,0,0,0,9,4,9
10474 db 3,0,0,0,0,10,4,10
10475 db 3,0,0,0,0,11,4,11
10476 db 3,0,0,0,0,12,4,12
10477 db 3,0,0,0,0,13,4,13
10478 db 3,0,0,0,0,14,4,14
10479 db 3,0,0,0,0,15,4,15
10480 #elif (BX_SMP_PROCESSORS==8)
10481 // define the Intel MP Configuration Structure for 8 processors at
10482 // APIC ID 0,1,2,3,4,5,6,7. I/O APIC at ID=8.
10483 .align 16
10484 mp_config_table:
10485 db 0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature
10486 dw (mp_config_end-mp_config_table) ;; table length
10487 db 4 ;; spec rev
10488 db 0xc3 ;; checksum
10489 .ascii "BOCHSCPU" ;; OEM id = "BOCHSCPU"
10490 db 0x30, 0x2e, 0x31, 0x20 ;; vendor id = "0.1 "
10491 db 0x20, 0x20, 0x20, 0x20
10492 db 0x20, 0x20, 0x20, 0x20
10493 dw 0,0 ;; oem table ptr
10494 dw 0 ;; oem table size
10495 dw 26 ;; entry count
10496 dw 0x0000, 0xfee0 ;; memory mapped address of local APIC
10497 dw 0 ;; extended table length
10498 db 0 ;; extended table checksum
10499 db 0 ;; reserved
10500 mp_config_proc0:
10501 db 0 ;; entry type=processor
10502 db 0 ;; local APIC id
10503 db 0x11 ;; local APIC version number
10504 db 3 ;; cpu flags: bootstrap cpu
10505 db 0,6,0,0 ;; cpu signature
10506 dw 0x201,0 ;; feature flags
10507 dw 0,0 ;; reserved
10508 dw 0,0 ;; reserved
10509 mp_config_proc1:
10510 db 0 ;; entry type=processor
10511 db 1 ;; local APIC id
10512 db 0x11 ;; local APIC version number
10513 db 1 ;; cpu flags: enabled
10514 db 0,6,0,0 ;; cpu signature
10515 dw 0x201,0 ;; feature flags
10516 dw 0,0 ;; reserved
10517 dw 0,0 ;; reserved
10518 mp_config_proc2:
10519 db 0 ;; entry type=processor
10520 db 2 ;; local APIC id
10521 db 0x11 ;; local APIC version number
10522 db 1 ;; cpu flags: enabled
10523 db 0,6,0,0 ;; cpu signature
10524 dw 0x201,0 ;; feature flags
10525 dw 0,0 ;; reserved
10526 dw 0,0 ;; reserved
10527 mp_config_proc3:
10528 db 0 ;; entry type=processor
10529 db 3 ;; local APIC id
10530 db 0x11 ;; local APIC version number
10531 db 1 ;; cpu flags: enabled
10532 db 0,6,0,0 ;; cpu signature
10533 dw 0x201,0 ;; feature flags
10534 dw 0,0 ;; reserved
10535 dw 0,0 ;; reserved
10536 mp_config_proc4:
10537 db 0 ;; entry type=processor
10538 db 4 ;; local APIC id
10539 db 0x11 ;; local APIC version number
10540 db 1 ;; cpu flags: enabled
10541 db 0,6,0,0 ;; cpu signature
10542 dw 0x201,0 ;; feature flags
10543 dw 0,0 ;; reserved
10544 dw 0,0 ;; reserved
10545 mp_config_proc5:
10546 db 0 ;; entry type=processor
10547 db 5 ;; local APIC id
10548 db 0x11 ;; local APIC version number
10549 db 1 ;; cpu flags: enabled
10550 db 0,6,0,0 ;; cpu signature
10551 dw 0x201,0 ;; feature flags
10552 dw 0,0 ;; reserved
10553 dw 0,0 ;; reserved
10554 mp_config_proc6:
10555 db 0 ;; entry type=processor
10556 db 6 ;; local APIC id
10557 db 0x11 ;; local APIC version number
10558 db 1 ;; cpu flags: enabled
10559 db 0,6,0,0 ;; cpu signature
10560 dw 0x201,0 ;; feature flags
10561 dw 0,0 ;; reserved
10562 dw 0,0 ;; reserved
10563 mp_config_proc7:
10564 db 0 ;; entry type=processor
10565 db 7 ;; local APIC id
10566 db 0x11 ;; local APIC version number
10567 db 1 ;; cpu flags: enabled
10568 db 0,6,0,0 ;; cpu signature
10569 dw 0x201,0 ;; feature flags
10570 dw 0,0 ;; reserved
10571 dw 0,0 ;; reserved
10572 mp_config_isa_bus:
10573 db 1 ;; entry type=bus
10574 db 0 ;; bus ID
10575 db 0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type="ISA "
10576 mp_config_ioapic:
10577 db 2 ;; entry type=I/O APIC
10578 db 8 ;; apic id=8
10579 db 0x11 ;; I/O APIC version number
10580 db 1 ;; flags=1=enabled
10581 dw 0x0000, 0xfec0 ;; memory mapped address of I/O APIC
10582 mp_config_irqs:
10583 db 3 ;; entry type=I/O interrupt
10584 db 0 ;; interrupt type=vectored interrupt
10585 db 0,0 ;; flags po=0, el=0 (linux uses as default)
10586 db 0 ;; source bus ID is ISA
10587 db 0 ;; source bus IRQ
10588 db 8 ;; destination I/O APIC ID
10589 db 0 ;; destination I/O APIC interrrupt in
10590 ;; repeat pattern for interrupts 0-15
10591 db 3,0,0,0,0,1,8,1
10592 db 3,0,0,0,0,2,8,2
10593 db 3,0,0,0,0,3,8,3
10594 db 3,0,0,0,0,4,8,4
10595 db 3,0,0,0,0,5,8,5
10596 db 3,0,0,0,0,6,8,6
10597 db 3,0,0,0,0,7,8,7
10598 db 3,0,0,0,0,8,8,8
10599 db 3,0,0,0,0,9,8,9
10600 db 3,0,0,0,0,10,8,10
10601 db 3,0,0,0,0,11,8,11
10602 db 3,0,0,0,0,12,8,12
10603 db 3,0,0,0,0,13,8,13
10604 db 3,0,0,0,0,14,8,14
10605 db 3,0,0,0,0,15,8,15
10606 #else
10607 # error Sorry, rombios only has configurations for 1, 2, 4 or 8 processors.
10608 #endif // if (BX_SMP_PROCESSORS==...)
10610 mp_config_end: // this label used to find length of mp structure
10611 db 0
10613 #if (BX_SMP_PROCESSORS>1)
10614 .align 16
10615 mp_floating_pointer_structure:
10616 db 0x5f, 0x4d, 0x50, 0x5f ; "_MP_" signature
10617 dw mp_config_table, 0xf ;; pointer to MP configuration table
10618 db 1 ;; length of this struct in 16-bit byte chunks
10619 db 4 ;; MP spec revision
10620 db 0xc1 ;; checksum
10621 db 0 ;; MP feature byte 1. value 0 means look at the config table
10622 db 0,0,0,0 ;; MP feature bytes 2-5.
10623 #endif
10625 ASM_END