~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Bochs x86 Emulator
bochs/bios/rombios.c

Version: ~ [ 2.3.5 ] ~ [ 2.3 ] ~

** Warning: Cannot open xref database.

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.