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