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