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