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

Bochs x86 Emulator
bochs/bios/rombios.c

Version: ~ [ 2.4 ] ~ [ 2.4.5 ] ~

** Warning: Cannot open xref database.

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

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

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