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

Bochs x86 Emulator
bochs/bios/rombios.c

Version: ~ [ SVN-2014-01-05 ] ~ [ 2.6.2 ] ~

** Warning: Cannot open xref database.

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