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