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