1 /* 2 * COPYRIGHT: GPL - See COPYING in the top level directory 3 * PROJECT: ReactOS Virtual DOS Machine 4 * FILE: subsystems/mvdm/ntvdm/bios/bios32/bios32.c 5 * PURPOSE: VDM 32-bit BIOS 6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org> 7 * Hermes Belusca-Maito (hermes.belusca@sfr.fr) 8 */ 9 10 /* INCLUDES *******************************************************************/ 11 12 #include "ntvdm.h" 13 14 /* BIOS Version number and Copyright */ 15 #include <reactos/buildno.h> 16 #include <reactos/version.h> 17 18 #define NDEBUG 19 #include <debug.h> 20 21 #include "emulator.h" 22 #include "cpu/cpu.h" // for EMULATOR_FLAG_CF 23 #include "cpu/bop.h" 24 #include "int32.h" 25 #include <isvbop.h> 26 27 #include <bios/bios.h> 28 #include <bios/rom.h> 29 #include "bios32.h" 30 #include "bios32p.h" 31 #include "dskbios32.h" 32 #include "kbdbios32.h" 33 #include "vidbios32.h" 34 #include "moubios32.h" 35 36 #include "memory.h" 37 #include "io.h" 38 #include "hardware/cmos.h" 39 #include "hardware/pic.h" 40 #include "hardware/pit.h" 41 #include "hardware/ps2.h" 42 43 /* PRIVATE VARIABLES **********************************************************/ 44 45 CALLBACK16 BiosContext; 46 47 /* 48 49 Bochs BIOS, see rombios.h 50 ========================= 51 52 // model byte 0xFC = AT 53 #define SYS_MODEL_ID 0xFC 54 #define SYS_SUBMODEL_ID 0x00 55 #define BIOS_REVISION 1 56 #define BIOS_CONFIG_TABLE 0xe6f5 57 58 #ifndef BIOS_BUILD_DATE 59 # define BIOS_BUILD_DATE "06/23/99" 60 #endif 61 62 // 1K of base memory used for Extended Bios Data Area (EBDA) 63 // EBDA is used for PS/2 mouse support, and IDE BIOS, etc. 64 #define EBDA_SEG 0x9FC0 65 #define EBDA_SIZE 1 // In KiB 66 #define BASE_MEM_IN_K (640 - EBDA_SIZE) 67 68 69 See rombios.c 70 ============= 71 72 ROM BIOS compatibility entry points: 73 =================================== 74 $e05b ; POST Entry Point 75 $e2c3 ; NMI Handler Entry Point 76 $e3fe ; INT 13h Fixed Disk Services Entry Point 77 $e401 ; Fixed Disk Parameter Table 78 $e6f2 ; INT 19h Boot Load Service Entry Point 79 $e6f5 ; Configuration Data Table 80 $e729 ; Baud Rate Generator Table 81 $e739 ; INT 14h Serial Communications Service Entry Point 82 $e82e ; INT 16h Keyboard Service Entry Point 83 $e987 ; INT 09h Keyboard Service Entry Point 84 $ec59 ; INT 13h Diskette Service Entry Point 85 $ef57 ; INT 0Eh Diskette Hardware ISR Entry Point 86 $efc7 ; Diskette Controller Parameter Table 87 $efd2 ; INT 17h Printer Service Entry Point 88 $f045 ; INT 10 Functions 0-Fh Entry Point 89 $f065 ; INT 10h Video Support Service Entry Point 90 $f0a4 ; MDA/CGA Video Parameter Table (INT 1Dh) 91 $f841 ; INT 12h Memory Size Service Entry Point 92 $f84d ; INT 11h Equipment List Service Entry Point 93 $f859 ; INT 15h System Services Entry Point 94 $fa6e ; Character Font for 320x200 & 640x200 Graphics (lower 128 characters) 95 $fe6e ; INT 1Ah Time-of-day Service Entry Point 96 $fea5 ; INT 08h System Timer ISR Entry Point 97 $fef3 ; Initial Interrupt Vector Offsets Loaded by POST 98 $ff53 ; IRET Instruction for Dummy Interrupt Handler 99 $ff54 ; INT 05h Print Screen Service Entry Point 100 $fff0 ; Power-up Entry Point 101 $fff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY 102 $fffe ; System Model ID 103 104 */ 105 106 /* 107 * See Ralf Brown: http://www.ctyme.com/intr/rb-1594.htm#Table515 108 * for more information. 109 */ 110 #define BIOS_MODEL 0xFC // PC-AT 111 #define BIOS_SUBMODEL 0x01 // AT models 319,339 8 MHz, Enh Keyb, 3.5" 112 #define BIOS_REVISION 0x00 113 // FIXME: Find a nice PS/2 486 + 487 BIOS combination! 114 115 static const BIOS_CONFIG_TABLE BiosConfigTable = 116 { 117 sizeof(BIOS_CONFIG_TABLE) - sizeof(((BIOS_CONFIG_TABLE*)0)->Length), // Length: Number of bytes following 118 119 BIOS_MODEL, // BIOS Model 120 BIOS_SUBMODEL, // BIOS Sub-Model 121 BIOS_REVISION, // BIOS Revision 122 123 // Feature bytes 124 { 125 0x78, // At the moment we don't have any Extended BIOS Area; see http://www.ctyme.com/intr/rb-1594.htm#Table510 126 0x00, // We don't support anything from here; see http://www.ctyme.com/intr/rb-1594.htm#Table511 127 0x10, // Bit 4: POST supports ROM-to-RAM enable/disable 128 0x00, 129 0x00 130 } 131 }; 132 133 134 /* 135 * WARNING! For compatibility purposes the string "IBM" should be at F000:E00E . 136 * Some programs otherwise look for "COPR. IBM" at F000:E008 . 137 */ 138 static const CHAR BiosCopyright[] = "0000000 NTVDM IBM COMPATIBLE 486 BIOS COPYRIGHT (C) ReactOS Team 1996-"COPYRIGHT_YEAR; 139 static const CHAR BiosVersion[] = "ReactOS NTVDM 32-bit BIOS Version "KERNEL_VERSION_STR"\0" 140 "BIOS32 Version "KERNEL_VERSION_STR" (Build "KERNEL_VERSION_BUILD_STR")"; 141 static const CHAR BiosDate[] = "06/17/13"; 142 143 C_ASSERT(sizeof(BiosCopyright)-1 <= 0x5B); // Ensures that we won't overflow on the POST Code starting at F000:E05B 144 C_ASSERT(sizeof(BiosDate)-1 == 0x08); 145 146 /* 16-bit bootstrap code at F000:FFF0 */ 147 static const BYTE Bootstrap[] = 148 { 149 0xEA, // jmp far ptr 150 0x5B, 0xE0, 0x00, 0xF0, // F000:E05B 151 }; 152 153 /* 154 * POST code at F000:E05B. All the POST is done in 32 bit 155 * and only at the end it calls the bootstrap interrupt. 156 */ 157 static const BYTE PostCode[] = 158 { 159 LOBYTE(EMULATOR_BOP), HIBYTE(EMULATOR_BOP), BOP_RESET, // Call BIOS POST 160 0xCD, BIOS_BOOTSTRAP_LOADER, // INT 0x19 161 0xCD, BIOS_ROM_BASIC, // INT 0x18 162 LOBYTE(EMULATOR_BOP), HIBYTE(EMULATOR_BOP), BOP_UNSIMULATE 163 }; 164 165 166 /* PRIVATE FUNCTIONS **********************************************************/ 167 168 static VOID BiosCharPrint(CHAR Character) 169 { 170 /* Save AX and BX */ 171 USHORT AX = getAX(); 172 USHORT BX = getBX(); 173 174 /* 175 * Set the parameters: 176 * AL contains the character to print, 177 * BL contains the character attribute, 178 * BH contains the video page to use. 179 */ 180 setAL(Character); 181 setBL(DEFAULT_ATTRIBUTE); 182 setBH(Bda->VideoPage); 183 184 /* Call the BIOS INT 10h, AH=0Eh "Teletype Output" */ 185 setAH(0x0E); 186 Int32Call(&BiosContext, BIOS_VIDEO_INTERRUPT); 187 188 /* Restore AX and BX */ 189 setBX(BX); 190 setAX(AX); 191 } 192 193 static VOID WINAPI BiosException(LPWORD Stack) 194 { 195 /* Get the exception number and call the emulator API */ 196 BYTE ExceptionNumber = LOBYTE(Stack[STACK_INT_NUM]); 197 EmulatorException(ExceptionNumber, Stack); 198 } 199 200 VOID WINAPI BiosEquipmentService(LPWORD Stack) 201 { 202 /* Return the equipment list */ 203 setAX(Bda->EquipmentList); 204 } 205 206 VOID WINAPI BiosGetMemorySize(LPWORD Stack) 207 { 208 /* Return the conventional memory size in kB, typically 640 kB */ 209 setAX(Bda->MemorySize); 210 } 211 212 static VOID WINAPI BiosMiscService(LPWORD Stack) 213 { 214 switch (getAH()) 215 { 216 /* OS Hooks for Multitasking */ 217 case 0x80: // Device Open 218 case 0x81: // Device Close 219 case 0x82: // Program Termination 220 case 0x90: // Device Busy 221 case 0x91: // Device POST 222 { 223 /* Return success by default */ 224 setAH(0x00); 225 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; 226 break; 227 } 228 229 /* Wait on External Event */ 230 case 0x41: 231 { 232 BYTE Value; 233 BOOLEAN Return; 234 static DWORD StartingCount; 235 236 /* Check if this is the first time this BOP occurred */ 237 if (!getCF()) 238 { 239 /* Set the starting count */ 240 StartingCount = Bda->TickCounter; 241 } 242 243 if (getBL() != 0 && (Bda->TickCounter - StartingCount) >= getBL()) 244 { 245 /* Timeout expired */ 246 setCF(0); 247 break; 248 } 249 250 if (getAL() & (1 << 4)) 251 { 252 /* Read from the I/O port */ 253 Value = IOReadB(getDX()); 254 } 255 else 256 { 257 /* Read from the memory */ 258 Value = *(LPBYTE)SEG_OFF_TO_PTR(getES(), getDI()); 259 } 260 261 switch (getAL() & 7) 262 { 263 /* Any external event */ 264 case 0: 265 { 266 /* Return if this is not the first time the BOP occurred */ 267 Return = getCF(); 268 break; 269 } 270 271 /* Compare and return if equal */ 272 case 1: 273 { 274 Return = Value == getBH(); 275 break; 276 } 277 278 /* Compare and return if not equal */ 279 case 2: 280 { 281 Return = Value != getBH(); 282 break; 283 } 284 285 /* Test and return if not zero */ 286 case 3: 287 { 288 Return = (Value & getBH()) != 0; 289 break; 290 } 291 292 /* Test and return if zero */ 293 case 4: 294 { 295 Return = (Value & getBH()) == 0; 296 break; 297 } 298 299 default: 300 { 301 DPRINT1("INT 15h, AH = 41h - Unknown condition type: %u\n", getAL() & 7); 302 Return = TRUE; 303 break; 304 } 305 } 306 307 /* Repeat the BOP if we shouldn't return */ 308 setCF(!Return); 309 break; 310 } 311 312 /* Keyboard intercept */ 313 case 0x4F: 314 { 315 /* CF should be set but let's just set it again just in case */ 316 /* Do not modify AL (the hardware scan code), but set CF to continue processing */ 317 // setCF(1); 318 Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; 319 break; 320 } 321 322 /* Wait */ 323 case 0x86: 324 { 325 /* 326 * Interval in microseconds in CX:DX 327 * See Ralf Brown: http://www.ctyme.com/intr/rb-1525.htm 328 * for more information. 329 */ 330 331 static ULONG CompletionTime = 0; 332 333 /* Check if we're already looping */ 334 if (getCF()) 335 { 336 if (GetTickCount() >= CompletionTime) 337 { 338 /* Stop looping */ 339 setCF(0); 340 341 /* Clear the CF on the stack too */ 342 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; 343 } 344 } 345 else 346 { 347 /* Set the CF on the stack */ 348 Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; 349 350 /* Set the completion time and start looping */ 351 CompletionTime = GetTickCount() + (MAKELONG(getDX(), getCX()) / 1000); 352 setCF(1); 353 } 354 355 break; 356 } 357 358 /* Copy Extended Memory */ 359 case 0x87: 360 { 361 DWORD Count = (DWORD)getCX() * 2; 362 PFAST486_GDT_ENTRY Gdt = (PFAST486_GDT_ENTRY)SEG_OFF_TO_PTR(getES(), getSI()); 363 DWORD SourceBase = Gdt[2].Base + (Gdt[2].BaseMid << 16) + (Gdt[2].BaseHigh << 24); 364 DWORD SourceLimit = Gdt[2].Limit + (Gdt[2].LimitHigh << 16); 365 DWORD DestBase = Gdt[3].Base + (Gdt[3].BaseMid << 16) + (Gdt[3].BaseHigh << 24); 366 DWORD DestLimit = Gdt[3].Limit + (Gdt[3].LimitHigh << 16); 367 368 /* Check for flags */ 369 if (Gdt[2].Granularity) SourceLimit = (SourceLimit << 12) | 0xFFF; 370 if (Gdt[3].Granularity) DestLimit = (DestLimit << 12) | 0xFFF; 371 372 if ((Count > SourceLimit) || (Count > DestLimit)) 373 { 374 setAX(0x80); 375 Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; 376 break; 377 } 378 379 /* Copy */ 380 RtlMoveMemory((PVOID)((ULONG_PTR)BaseAddress + DestBase), 381 (PVOID)((ULONG_PTR)BaseAddress + SourceBase), 382 Count); 383 384 setAX(ERROR_SUCCESS); 385 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; 386 break; 387 } 388 389 /* Get Extended Memory Size */ 390 case 0x88: 391 { 392 UCHAR Low, High; 393 394 /* 395 * Return the (usable) extended memory (after 1 MB) 396 * size in kB from CMOS. 397 */ 398 IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_ACTUAL_EXT_MEMORY_LOW | CMOS_DISABLE_NMI); 399 Low = IOReadB(CMOS_DATA_PORT); 400 IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_ACTUAL_EXT_MEMORY_HIGH | CMOS_DISABLE_NMI); 401 High = IOReadB(CMOS_DATA_PORT); 402 setAX(MAKEWORD(Low, High)); 403 404 /* Clear CF */ 405 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; 406 break; 407 } 408 409 /* Switch to Protected Mode */ 410 case 0x89: 411 { 412 DPRINT1("BIOS INT 15h, AH=89h \"Switch to Protected Mode\" is UNIMPLEMENTED"); 413 414 Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; 415 goto Default; 416 } 417 418 /* Get Configuration */ 419 case 0xC0: 420 { 421 /* Return the BIOS ROM Configuration Table address in ES:BX */ 422 // The BCT is found at F000:E6F5 for 100% compatible BIOSes. 423 setES(BIOS_SEGMENT); 424 setBX(0xE6F5); 425 426 /* Call successful; clear CF */ 427 setAH(0x00); 428 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; 429 break; 430 } 431 432 /* Return Extended-Bios Data-Area Segment Address (PS) */ 433 case 0xC1: 434 { 435 /* We do not support EBDA yet */ 436 UNIMPLEMENTED; 437 Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; 438 goto Default; 439 } 440 441 /* Pointing Device BIOS Interface (PS) */ 442 case 0xC2: 443 { 444 // FIXME: Reenable this call when we understand why 445 // our included mouse driver doesn't correctly reeanble 446 // mouse reporting! 447 // BiosMousePs2Interface(Stack); 448 // break; 449 goto Default; 450 } 451 452 /* Get CPU Type and Mask Revision */ 453 case 0xC9: 454 { 455 /* 456 * We can see this function as a CPUID replacement. 457 * See Ralf Brown: http://www.ctyme.com/intr/rb-1613.htm 458 * for more information. 459 */ 460 461 /* 462 * Fast486 is a 486DX with FPU included, 463 * but old enough to not support CPUID. 464 */ 465 setCX(0x0400); 466 467 /* Call successful; clear CF */ 468 setAH(0x00); 469 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; 470 break; 471 } 472 473 /* Get System Memory Map */ 474 case 0xE8: 475 { 476 if (getAL() == 0x01) 477 { 478 /* The amount of memory between 1M and 16M, in kilobytes */ 479 ULONG Above1M = (min(MAX_ADDRESS, 0x01000000) - 0x00100000) >> 10; 480 481 /* The amount of memory above 16M, in 64K blocks */ 482 ULONG Above16M = (MAX_ADDRESS > 0x01000000) ? ((MAX_ADDRESS - 0x01000000) >> 16) : 0; 483 484 setAX(Above1M); 485 setBX(Above16M); 486 setCX(Above1M); 487 setDX(Above16M); 488 489 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; 490 } 491 else if (getAL() == 0x20 && getEDX() == 'SMAP') 492 { 493 ULONG Offset = getEBX(); 494 ULONG Length; 495 ULONG BytesWritten = 0; 496 BOOLEAN Hooked; 497 PBIOS_MEMORY_MAP Map = (PBIOS_MEMORY_MAP)SEG_OFF_TO_PTR(getES(), getDI()); 498 499 /* Assume the buffer won't be large enough */ 500 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; 501 502 while (BytesWritten < getECX() && (ULONG_PTR)Map < (MAX_ADDRESS - sizeof(BIOS_MEMORY_MAP))) 503 { 504 /* Let's ask our memory controller */ 505 if (!MemQueryMemoryZone(Offset, &Length, &Hooked)) 506 { 507 /* No more memory blocks */ 508 Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; 509 break; 510 } 511 512 Map->BaseAddress = (ULONGLONG)Offset; 513 Map->Length = (ULONGLONG)Length; 514 Map->Type = Hooked ? BIOS_MEMORY_RESERVED : BIOS_MEMORY_AVAILABLE; 515 516 /* Go to the next record */ 517 Map++; 518 Offset += Length; 519 BytesWritten += sizeof(BIOS_MEMORY_MAP); 520 } 521 522 setEAX('SMAP'); 523 setEBX(Offset); 524 setECX(BytesWritten); 525 } 526 else 527 { 528 DPRINT1("BIOS Function INT 15h, AH = 0xE8 - unexpected AL = %02X, EDX = %08X\n", 529 getAL(), getEDX()); 530 } 531 532 break; 533 } 534 535 default: Default: 536 { 537 DPRINT1("BIOS Function INT 15h, AH = 0x%02X NOT IMPLEMENTED\n", 538 getAH()); 539 540 /* 541 * The original signification of the error code 0x86 is that 542 * no PC Cassette is present. The CF is also set in this case. 543 * To keep backward compatibility, newer BIOSes use this value 544 * to indicate an unimplemented call in INT 15h. 545 */ 546 setAH(0x86); 547 Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; 548 } 549 } 550 } 551 552 static VOID WINAPI BiosRomBasic(LPWORD Stack) 553 { 554 PrintMessageAnsi(BiosCharPrint, "FATAL: INT18: BOOT FAILURE."); 555 556 /* ROM Basic is unsupported, display a message to the user */ 557 DisplayMessage(L"NTVDM doesn't support ROM Basic. The VDM is closing."); 558 559 /* Stop the VDM */ 560 EmulatorTerminate(); 561 } 562 563 564 extern VOID DosBootsectorInitialize(VOID); 565 extern VOID WINAPI BiosDiskService(LPWORD Stack); 566 567 static VOID WINAPI BiosBootstrapLoader(LPWORD Stack) 568 { 569 USHORT BootOrder; 570 571 USHORT AX, BX, CX, DX, ES; 572 AX = getAX(); 573 BX = getBX(); 574 CX = getCX(); 575 DX = getDX(); 576 ES = getES(); 577 578 /* 579 * Read the boot sequence order from the CMOS, old behaviour AMI-style. 580 * 581 * For more information, see: 582 * http://www.virtualbox.org/svn/vbox/trunk/src/VBox/Devices/PC/BIOS/orgs.asm 583 * http://www.virtualbox.org/svn/vbox/trunk/src/VBox/Devices/PC/BIOS/boot.c 584 * http://bochs.sourceforge.net/cgi-bin/lxr/source/iodev/cmos.cc 585 * https://web.archive.org/web/20111209041013/http://www-ivs.cs.uni-magdeburg.de/~zbrog/asm/cmos.html 586 * http://www.bioscentral.com/misc/cmosmap.htm 587 */ 588 IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_SYSOP); 589 BootOrder = (IOReadB(CMOS_DATA_PORT) & 0x20) >> 5; 590 591 /* 592 * BootOrder = 593 * 0: Hard Disk, then Floppy Disk 594 * 1: Floppy Disk, then Hard Disk 595 * In all cases, if booting from those devices failed, 596 * ROM DOS-32 is started. If it fails, INT 18h is called. 597 */ 598 599 DPRINT("BiosBootstrapLoader (BootOrder = 0x%02X) -->\n", BootOrder); 600 601 /* 602 * Format of the BootOrder command: 603 * 2 bytes. Each half-byte contains the ID of the drive to boot. 604 * Currently defined: 605 * 0x0: 1st Floppy disk 606 * 0x1: 1st Hard disk 607 * Other, or 0xF: Stop boot sequence. 608 */ 609 BootOrder = 0xFF00 | ((1 << (4 * BootOrder)) & 0xFF); 610 611 Retry: 612 switch (BootOrder & 0x0F) 613 { 614 /* Boot from 1st floppy drive */ 615 case 0: 616 { 617 setAH(0x02); // Read sectors 618 setAL(0x01); // Number of sectors 619 setDH(0x00); // Head 0 620 setCH(0x00); // Cylinder 0 621 setCL(0x01); // Sector 1 622 setDL(0x00); // First diskette drive (used by loader code, so should not be cleared) 623 setES(0x0000); // Write data in 0000:7C00 624 setBX(0x7C00); 625 BiosDiskService(Stack); 626 if (!(Stack[STACK_FLAGS] & EMULATOR_FLAG_CF)) goto Quit; 627 DPRINT1("An error happened while loading the bootsector from floppy 0, error = %d\n", getAH()); 628 629 break; 630 } 631 632 /* Boot from 1st HDD drive */ 633 case 1: 634 { 635 setAH(0x02); // Read sectors 636 setAL(0x01); // Number of sectors 637 setDH(0x00); // Head 0 638 setCH(0x00); // Cylinder 0 639 setCL(0x01); // Sector 1 640 setDL(0x80); // First HDD drive (used by loader code, so should not be cleared) 641 setES(0x0000); // Write data in 0000:7C00 642 setBX(0x7C00); 643 BiosDiskService(Stack); 644 if (!(Stack[STACK_FLAGS] & EMULATOR_FLAG_CF)) goto Quit; 645 DPRINT1("An error happened while loading the bootsector from HDD 0, error = %d\n", getAH()); 646 647 break; 648 } 649 650 default: 651 goto StartDos; 652 } 653 654 /* Go to next drive and invalidate the last half-byte. */ 655 BootOrder = (BootOrder >> 4) | 0xF000; 656 goto Retry; 657 658 StartDos: 659 /* Clear everything, we are going to load DOS32 */ 660 setAX(AX); 661 setBX(BX); 662 setCX(CX); 663 setDX(DX); 664 setES(ES); 665 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; 666 667 /* Load our DOS */ 668 DosBootsectorInitialize(); 669 670 Quit: 671 /* 672 * Jump to 0000:7C00 to boot the OS. 673 * 674 * Since we are called via the INT32 mechanism, we need to correctly set 675 * CS:IP, not by changing the current one (otherwise the interrupt could 676 * not be clean up and return properly), but by changing the CS:IP in the 677 * stack, so that when the interrupt returns, the modified CS:IP is popped 678 * off the stack and the CPU is correctly repositioned. 679 */ 680 Stack[STACK_CS] = 0x0000; 681 Stack[STACK_IP] = 0x7C00; 682 683 DPRINT("<-- BiosBootstrapLoader\n"); 684 } 685 686 static VOID WINAPI BiosTimeService(LPWORD Stack) 687 { 688 switch (getAH()) 689 { 690 /* Get System Time */ 691 case 0x00: 692 { 693 /* Set AL to 1 if midnight had passed, 0 otherwise */ 694 setAL(Bda->MidnightPassed ? 0x01 : 0x00); 695 696 /* Return the tick count in CX:DX */ 697 setCX(HIWORD(Bda->TickCounter)); 698 setDX(LOWORD(Bda->TickCounter)); 699 700 /* Reset the midnight flag */ 701 Bda->MidnightPassed = FALSE; 702 703 break; 704 } 705 706 /* Set System Time */ 707 case 0x01: 708 { 709 /* Set the tick count to CX:DX */ 710 Bda->TickCounter = MAKELONG(getDX(), getCX()); 711 712 /* Reset the midnight flag */ 713 Bda->MidnightPassed = FALSE; 714 715 break; 716 } 717 718 /* Get Real-Time Clock Time */ 719 case 0x02: 720 { 721 UCHAR StatusB; 722 723 IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_HOURS); 724 setCH(IOReadB(CMOS_DATA_PORT)); 725 726 IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_MINUTES); 727 setCL(IOReadB(CMOS_DATA_PORT)); 728 729 IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_SECONDS); 730 setDH(IOReadB(CMOS_DATA_PORT)); 731 732 /* Daylight Savings Time */ 733 IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_STATUS_B); 734 StatusB = IOReadB(CMOS_DATA_PORT); 735 setDL(StatusB & 0x01); 736 737 /* Clear CF */ 738 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; 739 break; 740 } 741 742 // /* Set Real-Time Clock Time */ 743 // case 0x03: 744 // { 745 // break; 746 // } 747 748 /* Get Real-Time Clock Date */ 749 case 0x04: 750 { 751 IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_CENTURY); 752 setCH(IOReadB(CMOS_DATA_PORT)); 753 754 IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_YEAR); 755 setCL(IOReadB(CMOS_DATA_PORT)); 756 757 IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_MONTH); 758 setDH(IOReadB(CMOS_DATA_PORT)); 759 760 IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_DAY); 761 setDL(IOReadB(CMOS_DATA_PORT)); 762 763 /* Clear CF */ 764 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; 765 break; 766 } 767 768 // /* Set Real-Time Clock Date */ 769 // case 0x05: 770 // { 771 // break; 772 // } 773 774 default: 775 { 776 DPRINT1("BIOS Function INT 1Ah, AH = 0x%02X NOT IMPLEMENTED\n", 777 getAH()); 778 } 779 } 780 } 781 782 static VOID WINAPI BiosSystemTimerInterrupt(LPWORD Stack) 783 { 784 /* Increase the system tick count */ 785 Bda->TickCounter++; 786 } 787 788 789 // From SeaBIOS 790 static VOID PicSetIRQMask(USHORT off, USHORT on) 791 { 792 UCHAR pic1off = off, pic1on = on, pic2off = off>>8, pic2on = on>>8; 793 IOWriteB(PIC_MASTER_DATA, (IOReadB(PIC_MASTER_DATA) & ~pic1off) | pic1on); 794 IOWriteB(PIC_SLAVE_DATA , (IOReadB(PIC_SLAVE_DATA ) & ~pic2off) | pic2on); 795 } 796 797 // From SeaBIOS 798 VOID EnableHwIRQ(UCHAR hwirq, EMULATOR_INT32_PROC func) 799 { 800 UCHAR vector; 801 802 PicSetIRQMask(1 << hwirq, 0); 803 if (hwirq < 8) 804 vector = BIOS_PIC_MASTER_INT + hwirq; 805 else 806 vector = BIOS_PIC_SLAVE_INT + hwirq - 8; 807 808 RegisterBiosInt32(vector, func); 809 } 810 811 812 VOID PicIRQComplete(BYTE IntNum) 813 { 814 /* 815 * If this was a PIC IRQ, send an End-of-Interrupt to the PIC. 816 */ 817 if (IntNum >= BIOS_PIC_MASTER_INT && IntNum < BIOS_PIC_MASTER_INT + 8) 818 { 819 /* It was an IRQ from the master PIC */ 820 IOWriteB(PIC_MASTER_CMD, PIC_OCW2_EOI); 821 } 822 else if (IntNum >= BIOS_PIC_SLAVE_INT && IntNum < BIOS_PIC_SLAVE_INT + 8) 823 { 824 /* It was an IRQ from the slave PIC */ 825 IOWriteB(PIC_SLAVE_CMD , PIC_OCW2_EOI); 826 IOWriteB(PIC_MASTER_CMD, PIC_OCW2_EOI); 827 } 828 } 829 830 static VOID WINAPI BiosHandleMasterPicIRQ(LPWORD Stack) 831 { 832 BYTE IrqNumber; 833 834 IOWriteB(PIC_MASTER_CMD, PIC_OCW3_READ_ISR /* == 0x0B */); 835 IrqNumber = IOReadB(PIC_MASTER_CMD); 836 837 DPRINT("Master - IrqNumber = 0x%02X\n", IrqNumber); 838 839 PicIRQComplete(LOBYTE(Stack[STACK_INT_NUM])); 840 } 841 842 static VOID WINAPI BiosHandleSlavePicIRQ(LPWORD Stack) 843 { 844 BYTE IrqNumber; 845 846 IOWriteB(PIC_SLAVE_CMD, PIC_OCW3_READ_ISR /* == 0x0B */); 847 IrqNumber = IOReadB(PIC_SLAVE_CMD); 848 849 DPRINT("Slave - IrqNumber = 0x%02X\n", IrqNumber); 850 851 PicIRQComplete(LOBYTE(Stack[STACK_INT_NUM])); 852 } 853 854 // Timer IRQ 0 855 static VOID WINAPI BiosTimerIrq(LPWORD Stack) 856 { 857 /* 858 * Perform the system timer interrupt. 859 * 860 * Do not call directly BiosSystemTimerInterrupt(Stack); 861 * because some programs may hook only BIOS_SYS_TIMER_INTERRUPT 862 * for their purpose... 863 */ 864 865 WORD AX = getAX(); 866 WORD CX = getCX(); 867 WORD DX = getDX(); 868 WORD BX = getBX(); 869 WORD BP = getBP(); 870 WORD SI = getSI(); 871 WORD DI = getDI(); 872 WORD DS = getDS(); 873 WORD ES = getES(); 874 875 Int32Call(&BiosContext, BIOS_SYS_TIMER_INTERRUPT); 876 877 setAX(AX); 878 setCX(CX); 879 setDX(DX); 880 setBX(BX); 881 setBP(BP); 882 setSI(SI); 883 setDI(DI); 884 setDS(DS); 885 setES(ES); 886 setCF(0); 887 888 // BiosSystemTimerInterrupt(Stack); 889 PicIRQComplete(LOBYTE(Stack[STACK_INT_NUM])); 890 } 891 892 893 static VOID BiosHwSetup(VOID) 894 { 895 /* Initialize the master and the slave PICs (cascade mode) */ 896 IOWriteB(PIC_MASTER_CMD, PIC_ICW1 | PIC_ICW1_ICW4); 897 IOWriteB(PIC_SLAVE_CMD , PIC_ICW1 | PIC_ICW1_ICW4); 898 899 /* 900 * Set the interrupt vector offsets for each PIC 901 * (base IRQs: 0x08-0x0F for IRQ 0-7, 0x70-0x77 for IRQ 8-15) 902 */ 903 IOWriteB(PIC_MASTER_DATA, BIOS_PIC_MASTER_INT); 904 IOWriteB(PIC_SLAVE_DATA , BIOS_PIC_SLAVE_INT ); 905 906 /* Tell the master PIC that there is a slave PIC at IRQ 2 */ 907 IOWriteB(PIC_MASTER_DATA, 1 << 2); 908 /* Tell the slave PIC its cascade identity */ 909 IOWriteB(PIC_SLAVE_DATA , 2); 910 911 /* Make sure both PICs are in 8086 mode */ 912 IOWriteB(PIC_MASTER_DATA, PIC_ICW4_8086); 913 IOWriteB(PIC_SLAVE_DATA , PIC_ICW4_8086); 914 915 /* Clear the masks for both PICs */ 916 // IOWriteB(PIC_MASTER_DATA, 0x00); 917 // IOWriteB(PIC_SLAVE_DATA , 0x00); 918 /* Disable all IRQs */ 919 IOWriteB(PIC_MASTER_DATA, 0xFF); 920 IOWriteB(PIC_SLAVE_DATA , 0xFF); 921 922 923 /* Initialize PIT Counter 0 - Mode 2, 16bit binary count */ 924 // NOTE: Some BIOSes set it to Mode 3 instead. 925 IOWriteB(PIT_COMMAND_PORT, 0x34); 926 // 18.2Hz refresh rate 927 IOWriteB(PIT_DATA_PORT(0), 0x00); 928 IOWriteB(PIT_DATA_PORT(0), 0x00); 929 930 /* Initialize PIT Counter 1 - Mode 2, 8bit binary count */ 931 IOWriteB(PIT_COMMAND_PORT, 0x54); 932 // DRAM refresh every 15ms: http://www.cs.dartmouth.edu/~spl/Academic/Organization/docs/PC%20Timer%208253.html 933 IOWriteB(PIT_DATA_PORT(1), 18); 934 935 /* Initialize PIT Counter 2 - Mode 3, 16bit binary count */ 936 IOWriteB(PIT_COMMAND_PORT, 0xB6); 937 // Count for 440Hz 938 IOWriteB(PIT_DATA_PORT(2), 0x97); 939 IOWriteB(PIT_DATA_PORT(2), 0x0A); 940 941 942 /* Initialize PS/2 keyboard port */ 943 // Enable the port 944 IOWriteB(PS2_CONTROL_PORT, 0xAE); 945 // Port interrupts and clock enabled, 946 // enable keyboard scancode translation. 947 // POST passed, force keyboard unlocking. 948 IOWriteB(PS2_CONTROL_PORT, 0x60); 949 IOWriteB(PS2_DATA_PORT , 0x6D); 950 // Enable data reporting 951 IOWriteB(PS2_DATA_PORT , 0xF4); 952 953 EnableHwIRQ(0, BiosTimerIrq); 954 } 955 956 static VOID InitializeBiosInt32(VOID) 957 { 958 USHORT i; 959 960 /* Initialize the callback context */ 961 InitializeContext(&BiosContext, BIOS_SEGMENT, 0x0000); 962 963 /* Register the default BIOS interrupt vectors */ 964 965 /* 966 * Zero out all of the IVT (0x00 -- 0xFF). Some applications 967 * indeed expect to have free vectors at the end of the IVT. 968 */ 969 RtlZeroMemory(BaseAddress, 0x0100 * sizeof(ULONG)); 970 971 #if defined(ADVANCED_DEBUGGING) && (ADVANCED_DEBUGGING_LEVEL >= 3) 972 // Initialize all the interrupt vectors to the default one. 973 for (i = 0x00; i <= 0xFF; i++) 974 RegisterBiosInt32(i, NULL); 975 #endif 976 977 /* Initialize the exception interrupt vectors to a default Exception handler */ 978 for (i = 0x00; i <= 0x07; i++) 979 RegisterBiosInt32(i, BiosException); 980 981 /* Initialize HW interrupt vectors to a default HW handler */ 982 for (i = BIOS_PIC_MASTER_INT; i < BIOS_PIC_MASTER_INT + 8; i++) // 0x08 -- 0x0F 983 RegisterBiosInt32(i, BiosHandleMasterPicIRQ); 984 for (i = BIOS_PIC_SLAVE_INT ; i < BIOS_PIC_SLAVE_INT + 8; i++) // 0x70 -- 0x77 985 RegisterBiosInt32(i, BiosHandleSlavePicIRQ); 986 987 /* Initialize software vector handlers */ 988 // BIOS_VIDEO_INTERRUPT : 0x10 (vidbios32.c) 989 RegisterBiosInt32(BIOS_EQUIPMENT_INTERRUPT, BiosEquipmentService ); 990 RegisterBiosInt32(BIOS_MEMORY_SIZE , BiosGetMemorySize ); 991 // BIOS_DISK_INTERRUPT : 0x13 (dskbios32.c) 992 // BIOS_SERIAL_INTERRUPT : 0x14 -- UNIMPLEMENTED 993 RegisterBiosInt32(BIOS_MISC_INTERRUPT , BiosMiscService ); 994 // BIOS_KBD_INTERRUPT : 0x16 (kbdbios32.c) 995 // BIOS_PRINTER_INTERRUPT: 0x17 -- UNIMPLEMENTED 996 RegisterBiosInt32(BIOS_ROM_BASIC , BiosRomBasic ); 997 RegisterBiosInt32(BIOS_BOOTSTRAP_LOADER , BiosBootstrapLoader ); 998 RegisterBiosInt32(BIOS_TIME_INTERRUPT , BiosTimeService ); 999 // BIOS_KBD_CTRL_BREAK_INTERRUPT: 0x1B -- UNIMPLEMENTED 1000 RegisterBiosInt32(BIOS_SYS_TIMER_INTERRUPT, BiosSystemTimerInterrupt); 1001 1002 /* Vectors that should be implemented (see above) */ 1003 RegisterBiosInt32(0x14, NULL); 1004 RegisterBiosInt32(0x17, NULL); 1005 RegisterBiosInt32(0x1B, NULL); 1006 RegisterBiosInt32(0x4A, NULL); // User Alarm Handler 1007 1008 /* Relocated services by the BIOS (when needed) */ 1009 RegisterBiosInt32(0x40, NULL); // ROM BIOS Diskette Handler relocated by Hard Disk BIOS 1010 RegisterBiosInt32(0x42, NULL); // Relocated Default INT 10h Video Services 1011 1012 /* Miscellaneous unimplemented vector handlers that should better have a default one */ 1013 RegisterBiosInt32(0x4B, NULL); // Virtual DMA Specification Services 1014 RegisterBiosInt32(0x5C, NULL); // NetBIOS 1015 1016 // ROM-BASIC interrupts span from 0x80 up to 0xEF. 1017 // They don't have any default handler at the moment. 1018 1019 /* Some vectors are in fact addresses to tables */ 1020 ((PULONG)BaseAddress)[0x1D] = NULL32; // Video Parameter Tables 1021 ((PULONG)BaseAddress)[0x1E] = NULL32; // Diskette Parameters 1022 ((PULONG)BaseAddress)[0x1F] = NULL32; // 8x8 Graphics Font 1023 ((PULONG)BaseAddress)[0x41] = NULL32; // Hard Disk 0 Parameter Table Address 1024 ((PULONG)BaseAddress)[0x43] = NULL32; // Character Table (EGA, MCGA, VGA) 1025 ((PULONG)BaseAddress)[0x46] = NULL32; // Hard Disk 1 Drive Parameter Table Address 1026 /* Tables that are always uninitialized */ 1027 ((PULONG)BaseAddress)[0x44] = NULL32; // ROM BIOS Character Font, Characters 00h-7Fh (PCjr) 1028 ((PULONG)BaseAddress)[0x48] = NULL32; // Cordless Keyboard Translation (PCjr) 1029 ((PULONG)BaseAddress)[0x49] = NULL32; // Non-Keyboard Scan-code Translation Table (PCJr) 1030 } 1031 1032 static VOID InitializeBiosData(VOID) 1033 { 1034 UCHAR Low, High; 1035 1036 /* Initialize the BDA contents */ 1037 RtlZeroMemory(Bda, sizeof(*Bda)); 1038 1039 /* 1040 * Retrieve the basic equipment list from the CMOS 1041 */ 1042 IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_EQUIPMENT_LIST | CMOS_DISABLE_NMI); 1043 Bda->EquipmentList = IOReadB(CMOS_DATA_PORT); 1044 // TODO: Update it if required. 1045 Bda->EquipmentList &= 0x00FF; // High byte cleared for now... 1046 1047 /* 1048 * Retrieve the conventional memory size 1049 * in kB from the CMOS, typically 640 kB. 1050 */ 1051 IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_BASE_MEMORY_LOW | CMOS_DISABLE_NMI); 1052 Low = IOReadB(CMOS_DATA_PORT); 1053 IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_BASE_MEMORY_HIGH | CMOS_DISABLE_NMI); 1054 High = IOReadB(CMOS_DATA_PORT); 1055 Bda->MemorySize = MAKEWORD(Low, High); 1056 } 1057 1058 1059 /* 1060 * The BIOS POST (Power On-Self Test) 1061 */ 1062 /*static*/ VOID 1063 WINAPI 1064 Bios32Post(LPWORD Stack) 1065 { 1066 static BOOLEAN FirstBoot = TRUE; 1067 BYTE ShutdownStatus; 1068 1069 /* 1070 * Initialize BIOS/Keyboard/Video RAM dynamic data 1071 */ 1072 1073 DPRINT("Bios32Post\n"); 1074 1075 /* Disable interrupts */ 1076 setIF(0); 1077 1078 /* Set the data segment */ 1079 setDS(BDA_SEGMENT); 1080 1081 /* Initialize the stack */ 1082 // Temporary stack for POST (to be used only before initializing the INT vectors) 1083 // setSS(0x0000); 1084 // setSP(0x0400); 1085 // 1086 // Stack to be used after the initialization of the INT vectors 1087 setSS(0x0000); // Stack at 00:8000, going downwards 1088 setSP(0x8000); 1089 1090 /* 1091 * Perform early CMOS shutdown status checks 1092 */ 1093 1094 /* Read the CMOS shutdown status byte and reset it */ 1095 IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_SHUTDOWN_STATUS | CMOS_DISABLE_NMI); 1096 ShutdownStatus = IOReadB(CMOS_DATA_PORT); 1097 IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_SHUTDOWN_STATUS | CMOS_DISABLE_NMI); 1098 IOWriteB(CMOS_DATA_PORT, 0x00); 1099 1100 DPRINT1("Bda->SoftReset = 0x%04X ; ShutdownStatus = 0x%02X\n", 1101 Bda->SoftReset, ShutdownStatus); 1102 1103 switch (ShutdownStatus) 1104 { 1105 /* Shutdown after Memory Tests (unsupported) */ 1106 case 0x01: case 0x02: case 0x03: 1107 /* Shutdown after Protected Mode Tests (unsupported) */ 1108 case 0x06: case 0x07: case 0x08: 1109 /* Shutdown after Block Move Test (unsupported) */ 1110 case 0x09: 1111 { 1112 DisplayMessage(L"Unsupported CMOS Shutdown Status value 0x%02X. The VDM will shut down.", ShutdownStatus); 1113 EmulatorTerminate(); 1114 return; 1115 } 1116 1117 /* Shutdown to Boot Loader */ 1118 case 0x04: 1119 { 1120 DPRINT1("Fast restart to Bootstrap Loader...\n"); 1121 goto Quit; // Reenable interrupts and exit. 1122 } 1123 1124 /* Flush keyboard, issue an EOI... */ 1125 case 0x05: 1126 { 1127 IOReadB(PS2_DATA_PORT); 1128 1129 /* Send EOI */ 1130 IOWriteB(PIC_SLAVE_CMD , PIC_OCW2_EOI); 1131 IOWriteB(PIC_MASTER_CMD, PIC_OCW2_EOI); 1132 1133 // Fall back 1134 } 1135 1136 /* 1137 * ... and far JMP to user-specified location at 0040:0067 1138 * (Bda->ResumeEntryPoint) with interrupts and NMI disabled. 1139 */ 1140 case 0x0A: 1141 { 1142 DPRINT1("Bda->ResumeEntryPoint = %04X:%04X\n", 1143 HIWORD(Bda->ResumeEntryPoint), 1144 LOWORD(Bda->ResumeEntryPoint)); 1145 1146 /* Position execution pointers and return with interrupts disabled */ 1147 setCS(HIWORD(Bda->ResumeEntryPoint)); 1148 setIP(LOWORD(Bda->ResumeEntryPoint)); 1149 return; 1150 } 1151 1152 /* Soft reset or unexpected shutdown... */ 1153 case 0x00: 1154 /* ... or other possible shutdown codes: just continue the POST */ 1155 default: 1156 break; 1157 } 1158 1159 /* 1160 * FIXME: UNIMPLEMENTED! 1161 * Check the word at 0040h:0072h (Bda->SoftReset) and do one of the 1162 * following actions: 1163 * - if the word is 0000h, perform a cold reboot (aka. Reset). Everything gets initialized. 1164 * - if the word is 1234h, perform a warm reboot (aka. Ctrl-Alt-Del). Some stuff is skipped. 1165 */ 1166 switch (Bda->SoftReset) 1167 { 1168 case 0x0000: 1169 { 1170 if (!FirstBoot) 1171 { 1172 DisplayMessage(L"NTVDM is performing a COLD reboot! The program you are currently testing does not seem to behave correctly! The VDM will shut down..."); 1173 EmulatorTerminate(); 1174 return; 1175 } 1176 break; 1177 } 1178 1179 case 0x1234: 1180 { 1181 DisplayMessage(L"NTVDM is performing a WARM reboot! This is not supported at the moment. The VDM will shut down..."); 1182 EmulatorTerminate(); 1183 return; 1184 } 1185 1186 default: 1187 break; 1188 } 1189 1190 FirstBoot = FALSE; 1191 1192 /* Initialize the BDA */ 1193 InitializeBiosData(); 1194 1195 /* Initialize the User Data Area at 0050:XXXX */ 1196 RtlZeroMemory(SEG_OFF_TO_PTR(0x50, 0x0000), sizeof(USER_DATA_AREA)); 1197 1198 1199 1200 //////// NOTE: This is more or less bios-specific //////// 1201 1202 /* 1203 * Initialize IVT and hardware 1204 */ 1205 1206 // WriteUnProtectRom(...); 1207 1208 /* Register the BIOS 32-bit Interrupts */ 1209 InitializeBiosInt32(); 1210 1211 /* Initialize platform hardware (PIC/PIT chips, ...) */ 1212 BiosHwSetup(); 1213 1214 /* Initialize the Keyboard, Video and Mouse BIOS */ 1215 KbdBios32Post(); 1216 VidBiosPost(); 1217 MouseBios32Post(); 1218 DiskBios32Post(); 1219 1220 // WriteProtectRom(...); 1221 1222 //////// End of more or less bios-specific section /////// 1223 1224 1225 1226 SearchAndInitRoms(&BiosContext); 1227 1228 /* 1229 * End of the 32-bit POST portion. We then fall back into 16-bit where 1230 * the rest of the POST code is executed, typically calling INT 19h 1231 * to boot up the OS. 1232 */ 1233 1234 Quit: 1235 /* Enable interrupts */ 1236 setIF(1); 1237 } 1238 1239 1240 /* PUBLIC FUNCTIONS ***********************************************************/ 1241 1242 BOOLEAN Bios32Initialize(VOID) 1243 { 1244 /* 1245 * Initialize BIOS/Keyboard/Video ROM static data 1246 */ 1247 1248 /* System BIOS Copyright */ 1249 RtlCopyMemory(SEG_OFF_TO_PTR(BIOS_SEGMENT, 0xE000), BiosCopyright, sizeof(BiosCopyright)-1); 1250 1251 /* System BIOS Version */ 1252 RtlCopyMemory(SEG_OFF_TO_PTR(BIOS_SEGMENT, 0xE070), BiosVersion, sizeof(BiosVersion)-1); 1253 1254 /* System BIOS Date */ 1255 RtlCopyMemory(SEG_OFF_TO_PTR(BIOS_SEGMENT, 0xFFF5), BiosDate, sizeof(BiosDate)-1); 1256 1257 /* Bootstrap code */ 1258 RtlCopyMemory(SEG_OFF_TO_PTR(BIOS_SEGMENT, 0xE05B), PostCode , sizeof(PostCode )); 1259 RtlCopyMemory(SEG_OFF_TO_PTR(BIOS_SEGMENT, 0xFFF0), Bootstrap, sizeof(Bootstrap)); 1260 1261 /* BIOS ROM Information */ 1262 RtlCopyMemory(SEG_OFF_TO_PTR(BIOS_SEGMENT, 0xE6F5), &BiosConfigTable, sizeof(BiosConfigTable)); 1263 1264 /* System BIOS Model (same as Bct->Model) */ 1265 *(PBYTE)(SEG_OFF_TO_PTR(BIOS_SEGMENT, 0xFFFE)) = BIOS_MODEL; 1266 1267 /* Initialize the Keyboard and Video BIOS */ 1268 if (!KbdBiosInitialize() || !VidBiosInitialize() || !MouseBiosInitialize() || !DiskBios32Initialize()) 1269 { 1270 /* Stop the VDM */ 1271 EmulatorTerminate(); 1272 return FALSE; 1273 } 1274 1275 /* Redefine our POST function */ 1276 RegisterBop(BOP_RESET, Bios32Post); 1277 1278 WriteProtectRom((PVOID)TO_LINEAR(BIOS_SEGMENT, 0x0000), 1279 ROM_AREA_END - TO_LINEAR(BIOS_SEGMENT, 0x0000) + 1); 1280 1281 /* We are done */ 1282 return TRUE; 1283 } 1284 1285 VOID Bios32Cleanup(VOID) 1286 { 1287 DiskBios32Cleanup(); 1288 MouseBios32Cleanup(); 1289 VidBios32Cleanup(); 1290 KbdBiosCleanup(); 1291 } 1292 1293 /* EOF */ 1294