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

Bochs x86 Emulator
bochs/bios/rombios.c

Version: ~ [ 2.3.5 ] ~ [ 2.3 ] ~

** Warning: Cannot open xref database.

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

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

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