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