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

Bochs x86 Emulator
bochs/bios/rombios.c

Version: ~ [ 2.4 ] ~ [ 2.4.5 ] ~

** Warning: Cannot open xref database.

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