[mvdm] Fix missing pointer dereference
[reactos.git] / subsystems / mvdm / ntvdm / bios / bios32 / bios32.c
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 */