[NTVDM] Revert r69435.
[reactos.git] / reactos / 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 LARGE_INTEGER TimeOut;
331 TimeOut.QuadPart = MAKELONG(getDX(), getCX()) * -10LL;
332
333 // HACK: For now, use the NT API (time in hundreds of nanoseconds).
334 NtDelayExecution(FALSE, &TimeOut);
335
336 /* Clear CF */
337 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
338 break;
339 }
340
341 /* Copy Extended Memory */
342 case 0x87:
343 {
344 DWORD Count = (DWORD)getCX() * 2;
345 PFAST486_GDT_ENTRY Gdt = (PFAST486_GDT_ENTRY)SEG_OFF_TO_PTR(getES(), getSI());
346 DWORD SourceBase = Gdt[2].Base + (Gdt[2].BaseMid << 16) + (Gdt[2].BaseHigh << 24);
347 DWORD SourceLimit = Gdt[2].Limit + (Gdt[2].LimitHigh << 16);
348 DWORD DestBase = Gdt[3].Base + (Gdt[3].BaseMid << 16) + (Gdt[3].BaseHigh << 24);
349 DWORD DestLimit = Gdt[3].Limit + (Gdt[3].LimitHigh << 16);
350
351 /* Check for flags */
352 if (Gdt[2].Granularity) SourceLimit = (SourceLimit << 12) | 0xFFF;
353 if (Gdt[3].Granularity) DestLimit = (DestLimit << 12) | 0xFFF;
354
355 if ((Count > SourceLimit) || (Count > DestLimit))
356 {
357 setAX(0x80);
358 Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
359 break;
360 }
361
362 /* Copy */
363 RtlMoveMemory((PVOID)((ULONG_PTR)BaseAddress + DestBase),
364 (PVOID)((ULONG_PTR)BaseAddress + SourceBase),
365 Count);
366
367 setAX(ERROR_SUCCESS);
368 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
369 break;
370 }
371
372 /* Get Extended Memory Size */
373 case 0x88:
374 {
375 UCHAR Low, High;
376
377 /*
378 * Return the (usable) extended memory (after 1 MB)
379 * size in kB from CMOS.
380 */
381 IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_ACTUAL_EXT_MEMORY_LOW | CMOS_DISABLE_NMI);
382 Low = IOReadB(CMOS_DATA_PORT);
383 IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_ACTUAL_EXT_MEMORY_HIGH | CMOS_DISABLE_NMI);
384 High = IOReadB(CMOS_DATA_PORT);
385 setAX(MAKEWORD(Low, High));
386
387 /* Clear CF */
388 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
389 break;
390 }
391
392 /* Switch to Protected Mode */
393 case 0x89:
394 {
395 DPRINT1("BIOS INT 15h, AH=89h \"Switch to Protected Mode\" is UNIMPLEMENTED");
396
397 Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
398 goto Default;
399 }
400
401 /* Get Configuration */
402 case 0xC0:
403 {
404 /* Return the BIOS ROM Configuration Table address in ES:BX */
405 // The BCT is found at F000:E6F5 for 100% compatible BIOSes.
406 setES(BIOS_SEGMENT);
407 setBX(0xE6F5);
408
409 /* Call successful; clear CF */
410 setAH(0x00);
411 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
412 break;
413 }
414
415 /* Return Extended-Bios Data-Area Segment Address (PS) */
416 case 0xC1:
417 {
418 /* We do not support EBDA yet */
419 UNIMPLEMENTED;
420 Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
421 goto Default;
422 }
423
424 /* Pointing Device BIOS Interface (PS) */
425 case 0xC2:
426 {
427 // FIXME: Reenable this call when we understand why
428 // our included mouse driver doesn't correctly reeanble
429 // mouse reporting!
430 // BiosMousePs2Interface(Stack);
431 // break;
432 goto Default;
433 }
434
435 /* Get CPU Type and Mask Revision */
436 case 0xC9:
437 {
438 /*
439 * We can see this function as a CPUID replacement.
440 * See Ralf Brown: http://www.ctyme.com/intr/rb-1613.htm
441 * for more information.
442 */
443
444 /*
445 * Fast486 is a 486DX with FPU included,
446 * but old enough to not support CPUID.
447 */
448 setCX(0x0400);
449
450 /* Call successful; clear CF */
451 setAH(0x00);
452 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
453 break;
454 }
455
456 /* Get System Memory Map */
457 case 0xE8:
458 {
459 if (getAL() == 0x01)
460 {
461 /* The amount of memory between 1M and 16M, in kilobytes */
462 ULONG Above1M = (min(MAX_ADDRESS, 0x01000000) - 0x00100000) >> 10;
463
464 /* The amount of memory above 16M, in 64K blocks */
465 ULONG Above16M = (MAX_ADDRESS > 0x01000000) ? ((MAX_ADDRESS - 0x01000000) >> 16) : 0;
466
467 setAX(Above1M);
468 setBX(Above16M);
469 setCX(Above1M);
470 setDX(Above16M);
471
472 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
473 }
474 else if (getAL() == 0x20 && getEDX() == 'SMAP')
475 {
476 ULONG Offset = getEBX();
477 ULONG Length;
478 ULONG BytesWritten = 0;
479 BOOLEAN Hooked;
480 PBIOS_MEMORY_MAP Map = (PBIOS_MEMORY_MAP)SEG_OFF_TO_PTR(getES(), getDI());
481
482 /* Assume the buffer won't be large enough */
483 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
484
485 while (BytesWritten < getECX() && (ULONG_PTR)Map < (MAX_ADDRESS - sizeof(BIOS_MEMORY_MAP)))
486 {
487 /* Let's ask our memory controller */
488 if (!MemQueryMemoryZone(Offset, &Length, &Hooked))
489 {
490 /* No more memory blocks */
491 Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
492 break;
493 }
494
495 Map->BaseAddress = (ULONGLONG)Offset;
496 Map->Length = (ULONGLONG)Length;
497 Map->Type = Hooked ? BIOS_MEMORY_RESERVED : BIOS_MEMORY_AVAILABLE;
498
499 /* Go to the next record */
500 Map++;
501 Offset += Length;
502 BytesWritten += sizeof(BIOS_MEMORY_MAP);
503 }
504
505 setEAX('SMAP');
506 setEBX(Offset);
507 setECX(BytesWritten);
508 }
509 else
510 {
511 DPRINT1("BIOS Function INT 15h, AH = 0xE8 - unexpected AL = %02X, EDX = %08X\n",
512 getAL(), getEDX());
513 }
514
515 break;
516 }
517
518 default: Default:
519 {
520 DPRINT1("BIOS Function INT 15h, AH = 0x%02X NOT IMPLEMENTED\n",
521 getAH());
522
523 /*
524 * The original signification of the error code 0x86 is that
525 * no PC Cassette is present. The CF is also set in this case.
526 * To keep backward compatibility, newer BIOSes use this value
527 * to indicate an unimplemented call in INT 15h.
528 */
529 setAH(0x86);
530 Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
531 }
532 }
533 }
534
535 static VOID WINAPI BiosRomBasic(LPWORD Stack)
536 {
537 PrintMessageAnsi(BiosCharPrint, "FATAL: INT18: BOOT FAILURE.");
538
539 /* ROM Basic is unsupported, display a message to the user */
540 DisplayMessage(L"NTVDM doesn't support ROM Basic. The VDM is closing.");
541
542 /* Stop the VDM */
543 EmulatorTerminate();
544 }
545
546
547 extern VOID DosBootsectorInitialize(VOID);
548 extern VOID WINAPI BiosDiskService(LPWORD Stack);
549
550 static VOID WINAPI BiosBootstrapLoader(LPWORD Stack)
551 {
552 USHORT BootOrder;
553
554 USHORT AX, BX, CX, DX, ES;
555 AX = getAX();
556 BX = getBX();
557 CX = getCX();
558 DX = getDX();
559 ES = getES();
560
561 /*
562 * Read the boot sequence order from the CMOS, old behaviour AMI-style.
563 *
564 * For more information, see:
565 * http://www.virtualbox.org/svn/vbox/trunk/src/VBox/Devices/PC/BIOS/orgs.asm
566 * http://www.virtualbox.org/svn/vbox/trunk/src/VBox/Devices/PC/BIOS/boot.c
567 * http://bochs.sourceforge.net/cgi-bin/lxr/source/iodev/cmos.cc
568 * https://web.archive.org/web/20111209041013/http://www-ivs.cs.uni-magdeburg.de/~zbrog/asm/cmos.html
569 * http://www.bioscentral.com/misc/cmosmap.htm
570 */
571 IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_SYSOP);
572 BootOrder = (IOReadB(CMOS_DATA_PORT) & 0x20) >> 5;
573
574 /*
575 * BootOrder =
576 * 0: Hard Disk, then Floppy Disk
577 * 1: Floppy Disk, then Hard Disk
578 * In all cases, if booting from those devices failed,
579 * ROM DOS-32 is started. If it fails, INT 18h is called.
580 */
581
582 DPRINT("BiosBootstrapLoader (BootOrder = 0x%02X) -->\n", BootOrder);
583
584 /*
585 * Format of the BootOrder command:
586 * 2 bytes. Each half-byte contains the ID of the drive to boot.
587 * Currently defined:
588 * 0x0: 1st Floppy disk
589 * 0x1: 1st Hard disk
590 * Other, or 0xF: Stop boot sequence.
591 */
592 BootOrder = 0xFF00 | ((1 << (4 * BootOrder)) & 0xFF);
593
594 Retry:
595 switch (BootOrder & 0x0F)
596 {
597 /* Boot from 1st floppy drive */
598 case 0:
599 {
600 setAH(0x02); // Read sectors
601 setAL(0x01); // Number of sectors
602 setDH(0x00); // Head 0
603 setCH(0x00); // Cylinder 0
604 setCL(0x01); // Sector 1
605 setDL(0x00); // First diskette drive (used by loader code, so should not be cleared)
606 setES(0x0000); // Write data in 0000:7C00
607 setBX(0x7C00);
608 BiosDiskService(Stack);
609 if (!(Stack[STACK_FLAGS] & EMULATOR_FLAG_CF)) goto Quit;
610 DPRINT1("An error happened while loading the bootsector from floppy 0, error = %d\n", getAH());
611
612 break;
613 }
614
615 /* Boot from 1st HDD drive */
616 case 1:
617 {
618 setAH(0x02); // Read sectors
619 setAL(0x01); // Number of sectors
620 setDH(0x00); // Head 0
621 setCH(0x00); // Cylinder 0
622 setCL(0x01); // Sector 1
623 setDL(0x80); // First HDD drive (used by loader code, so should not be cleared)
624 setES(0x0000); // Write data in 0000:7C00
625 setBX(0x7C00);
626 BiosDiskService(Stack);
627 if (!(Stack[STACK_FLAGS] & EMULATOR_FLAG_CF)) goto Quit;
628 DPRINT1("An error happened while loading the bootsector from HDD 0, error = %d\n", getAH());
629
630 break;
631 }
632
633 default:
634 goto StartDos;
635 }
636
637 /* Go to next drive and invalidate the last half-byte. */
638 BootOrder = (BootOrder >> 4) | 0xF000;
639 goto Retry;
640
641 StartDos:
642 /* Clear everything, we are going to load DOS32 */
643 setAX(AX);
644 setBX(BX);
645 setCX(CX);
646 setDX(DX);
647 setES(ES);
648 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
649
650 /* Load our DOS */
651 DosBootsectorInitialize();
652
653 Quit:
654 /*
655 * Jump to 0000:7C00 to boot the OS.
656 *
657 * Since we are called via the INT32 mechanism, we need to correctly set
658 * CS:IP, not by changing the current one (otherwise the interrupt could
659 * not be clean up and return properly), but by changing the CS:IP in the
660 * stack, so that when the interrupt returns, the modified CS:IP is popped
661 * off the stack and the CPU is correctly repositioned.
662 */
663 Stack[STACK_CS] = 0x0000;
664 Stack[STACK_IP] = 0x7C00;
665
666 DPRINT("<-- BiosBootstrapLoader\n");
667 }
668
669 static VOID WINAPI BiosTimeService(LPWORD Stack)
670 {
671 switch (getAH())
672 {
673 /* Get System Time */
674 case 0x00:
675 {
676 /* Set AL to 1 if midnight had passed, 0 otherwise */
677 setAL(Bda->MidnightPassed ? 0x01 : 0x00);
678
679 /* Return the tick count in CX:DX */
680 setCX(HIWORD(Bda->TickCounter));
681 setDX(LOWORD(Bda->TickCounter));
682
683 /* Reset the midnight flag */
684 Bda->MidnightPassed = FALSE;
685
686 break;
687 }
688
689 /* Set System Time */
690 case 0x01:
691 {
692 /* Set the tick count to CX:DX */
693 Bda->TickCounter = MAKELONG(getDX(), getCX());
694
695 /* Reset the midnight flag */
696 Bda->MidnightPassed = FALSE;
697
698 break;
699 }
700
701 /* Get Real-Time Clock Time */
702 case 0x02:
703 {
704 UCHAR StatusB;
705
706 IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_HOURS);
707 setCH(IOReadB(CMOS_DATA_PORT));
708
709 IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_MINUTES);
710 setCL(IOReadB(CMOS_DATA_PORT));
711
712 IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_SECONDS);
713 setDH(IOReadB(CMOS_DATA_PORT));
714
715 /* Daylight Savings Time */
716 IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_STATUS_B);
717 StatusB = IOReadB(CMOS_DATA_PORT);
718 setDL(StatusB & 0x01);
719
720 /* Clear CF */
721 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
722 break;
723 }
724
725 // /* Set Real-Time Clock Time */
726 // case 0x03:
727 // {
728 // break;
729 // }
730
731 /* Get Real-Time Clock Date */
732 case 0x04:
733 {
734 IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_CENTURY);
735 setCH(IOReadB(CMOS_DATA_PORT));
736
737 IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_YEAR);
738 setCL(IOReadB(CMOS_DATA_PORT));
739
740 IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_MONTH);
741 setDH(IOReadB(CMOS_DATA_PORT));
742
743 IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_DAY);
744 setDL(IOReadB(CMOS_DATA_PORT));
745
746 /* Clear CF */
747 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
748 break;
749 }
750
751 // /* Set Real-Time Clock Date */
752 // case 0x05:
753 // {
754 // break;
755 // }
756
757 default:
758 {
759 DPRINT1("BIOS Function INT 1Ah, AH = 0x%02X NOT IMPLEMENTED\n",
760 getAH());
761 }
762 }
763 }
764
765 static VOID WINAPI BiosSystemTimerInterrupt(LPWORD Stack)
766 {
767 /* Increase the system tick count */
768 Bda->TickCounter++;
769 }
770
771
772 // From SeaBIOS
773 static VOID PicSetIRQMask(USHORT off, USHORT on)
774 {
775 UCHAR pic1off = off, pic1on = on, pic2off = off>>8, pic2on = on>>8;
776 IOWriteB(PIC_MASTER_DATA, (IOReadB(PIC_MASTER_DATA) & ~pic1off) | pic1on);
777 IOWriteB(PIC_SLAVE_DATA , (IOReadB(PIC_SLAVE_DATA ) & ~pic2off) | pic2on);
778 }
779
780 // From SeaBIOS
781 VOID EnableHwIRQ(UCHAR hwirq, EMULATOR_INT32_PROC func)
782 {
783 UCHAR vector;
784
785 PicSetIRQMask(1 << hwirq, 0);
786 if (hwirq < 8)
787 vector = BIOS_PIC_MASTER_INT + hwirq;
788 else
789 vector = BIOS_PIC_SLAVE_INT + hwirq - 8;
790
791 RegisterBiosInt32(vector, func);
792 }
793
794
795 VOID PicIRQComplete(BYTE IntNum)
796 {
797 /*
798 * If this was a PIC IRQ, send an End-of-Interrupt to the PIC.
799 */
800 if (IntNum >= BIOS_PIC_MASTER_INT && IntNum < BIOS_PIC_MASTER_INT + 8)
801 {
802 /* It was an IRQ from the master PIC */
803 IOWriteB(PIC_MASTER_CMD, PIC_OCW2_EOI);
804 }
805 else if (IntNum >= BIOS_PIC_SLAVE_INT && IntNum < BIOS_PIC_SLAVE_INT + 8)
806 {
807 /* It was an IRQ from the slave PIC */
808 IOWriteB(PIC_SLAVE_CMD , PIC_OCW2_EOI);
809 IOWriteB(PIC_MASTER_CMD, PIC_OCW2_EOI);
810 }
811 }
812
813 static VOID WINAPI BiosHandleMasterPicIRQ(LPWORD Stack)
814 {
815 BYTE IrqNumber;
816
817 IOWriteB(PIC_MASTER_CMD, PIC_OCW3_READ_ISR /* == 0x0B */);
818 IrqNumber = IOReadB(PIC_MASTER_CMD);
819
820 DPRINT("Master - IrqNumber = 0x%02X\n", IrqNumber);
821
822 PicIRQComplete(LOBYTE(Stack[STACK_INT_NUM]));
823 }
824
825 static VOID WINAPI BiosHandleSlavePicIRQ(LPWORD Stack)
826 {
827 BYTE IrqNumber;
828
829 IOWriteB(PIC_SLAVE_CMD, PIC_OCW3_READ_ISR /* == 0x0B */);
830 IrqNumber = IOReadB(PIC_SLAVE_CMD);
831
832 DPRINT("Slave - IrqNumber = 0x%02X\n", IrqNumber);
833
834 PicIRQComplete(LOBYTE(Stack[STACK_INT_NUM]));
835 }
836
837 // Timer IRQ 0
838 static VOID WINAPI BiosTimerIrq(LPWORD Stack)
839 {
840 /*
841 * Perform the system timer interrupt.
842 *
843 * Do not call directly BiosSystemTimerInterrupt(Stack);
844 * because some programs may hook only BIOS_SYS_TIMER_INTERRUPT
845 * for their purpose...
846 */
847
848 WORD AX = getAX();
849 WORD CX = getCX();
850 WORD DX = getDX();
851 WORD BX = getBX();
852 WORD BP = getBP();
853 WORD SI = getSI();
854 WORD DI = getDI();
855 WORD DS = getDS();
856 WORD ES = getES();
857
858 Int32Call(&BiosContext, BIOS_SYS_TIMER_INTERRUPT);
859
860 setAX(AX);
861 setCX(CX);
862 setDX(DX);
863 setBX(BX);
864 setBP(BP);
865 setSI(SI);
866 setDI(DI);
867 setDS(DS);
868 setES(ES);
869 setCF(0);
870
871 // BiosSystemTimerInterrupt(Stack);
872 PicIRQComplete(LOBYTE(Stack[STACK_INT_NUM]));
873 }
874
875
876 static VOID BiosHwSetup(VOID)
877 {
878 /* Initialize the master and the slave PICs (cascade mode) */
879 IOWriteB(PIC_MASTER_CMD, PIC_ICW1 | PIC_ICW1_ICW4);
880 IOWriteB(PIC_SLAVE_CMD , PIC_ICW1 | PIC_ICW1_ICW4);
881
882 /*
883 * Set the interrupt vector offsets for each PIC
884 * (base IRQs: 0x08-0x0F for IRQ 0-7, 0x70-0x77 for IRQ 8-15)
885 */
886 IOWriteB(PIC_MASTER_DATA, BIOS_PIC_MASTER_INT);
887 IOWriteB(PIC_SLAVE_DATA , BIOS_PIC_SLAVE_INT );
888
889 /* Tell the master PIC that there is a slave PIC at IRQ 2 */
890 IOWriteB(PIC_MASTER_DATA, 1 << 2);
891 /* Tell the slave PIC its cascade identity */
892 IOWriteB(PIC_SLAVE_DATA , 2);
893
894 /* Make sure both PICs are in 8086 mode */
895 IOWriteB(PIC_MASTER_DATA, PIC_ICW4_8086);
896 IOWriteB(PIC_SLAVE_DATA , PIC_ICW4_8086);
897
898 /* Clear the masks for both PICs */
899 // IOWriteB(PIC_MASTER_DATA, 0x00);
900 // IOWriteB(PIC_SLAVE_DATA , 0x00);
901 /* Disable all IRQs */
902 IOWriteB(PIC_MASTER_DATA, 0xFF);
903 IOWriteB(PIC_SLAVE_DATA , 0xFF);
904
905
906 /* Initialize PIT Counter 0 - Mode 2, 16bit binary count */
907 // NOTE: Some BIOSes set it to Mode 3 instead.
908 IOWriteB(PIT_COMMAND_PORT, 0x34);
909 // 18.2Hz refresh rate
910 IOWriteB(PIT_DATA_PORT(0), 0x00);
911 IOWriteB(PIT_DATA_PORT(0), 0x00);
912
913 /* Initialize PIT Counter 1 - Mode 2, 8bit binary count */
914 IOWriteB(PIT_COMMAND_PORT, 0x54);
915 // DRAM refresh every 15ms: http://www.cs.dartmouth.edu/~spl/Academic/Organization/docs/PC%20Timer%208253.html
916 IOWriteB(PIT_DATA_PORT(1), 18);
917
918 /* Initialize PIT Counter 2 - Mode 3, 16bit binary count */
919 IOWriteB(PIT_COMMAND_PORT, 0xB6);
920 // Count for 440Hz
921 IOWriteB(PIT_DATA_PORT(2), 0x97);
922 IOWriteB(PIT_DATA_PORT(2), 0x0A);
923
924
925 /* Initialize PS/2 keyboard port */
926 // Enable the port
927 IOWriteB(PS2_CONTROL_PORT, 0xAE);
928 // Port interrupts and clock enabled,
929 // enable keyboard scancode translation.
930 // POST passed, force keyboard unlocking.
931 IOWriteB(PS2_CONTROL_PORT, 0x60);
932 IOWriteB(PS2_DATA_PORT , 0x6D);
933 // Enable data reporting
934 IOWriteB(PS2_DATA_PORT , 0xF4);
935
936 EnableHwIRQ(0, BiosTimerIrq);
937 }
938
939 static VOID InitializeBiosInt32(VOID)
940 {
941 USHORT i;
942
943 /* Initialize the callback context */
944 InitializeContext(&BiosContext, BIOS_SEGMENT, 0x0000);
945
946 /* Register the default BIOS interrupt vectors */
947
948 /*
949 * Zero out all of the IVT (0x00 -- 0xFF). Some applications
950 * indeed expect to have free vectors at the end of the IVT.
951 */
952 RtlZeroMemory(BaseAddress, 0x0100 * sizeof(ULONG));
953
954 #if defined(ADVANCED_DEBUGGING) && (ADVANCED_DEBUGGING_LEVEL >= 3)
955 // Initialize all the interrupt vectors to the default one.
956 for (i = 0x00; i <= 0xFF; i++)
957 RegisterBiosInt32(i, NULL);
958 #endif
959
960 /* Initialize the exception interrupt vectors to a default Exception handler */
961 for (i = 0x00; i <= 0x07; i++)
962 RegisterBiosInt32(i, BiosException);
963
964 /* Initialize HW interrupt vectors to a default HW handler */
965 for (i = BIOS_PIC_MASTER_INT; i < BIOS_PIC_MASTER_INT + 8; i++) // 0x08 -- 0x0F
966 RegisterBiosInt32(i, BiosHandleMasterPicIRQ);
967 for (i = BIOS_PIC_SLAVE_INT ; i < BIOS_PIC_SLAVE_INT + 8; i++) // 0x70 -- 0x77
968 RegisterBiosInt32(i, BiosHandleSlavePicIRQ);
969
970 /* Initialize software vector handlers */
971 // BIOS_VIDEO_INTERRUPT : 0x10 (vidbios32.c)
972 RegisterBiosInt32(BIOS_EQUIPMENT_INTERRUPT, BiosEquipmentService );
973 RegisterBiosInt32(BIOS_MEMORY_SIZE , BiosGetMemorySize );
974 // BIOS_DISK_INTERRUPT : 0x13 (dskbios32.c)
975 // BIOS_SERIAL_INTERRUPT : 0x14 -- UNIMPLEMENTED
976 RegisterBiosInt32(BIOS_MISC_INTERRUPT , BiosMiscService );
977 // BIOS_KBD_INTERRUPT : 0x16 (kbdbios32.c)
978 // BIOS_PRINTER_INTERRUPT: 0x17 -- UNIMPLEMENTED
979 RegisterBiosInt32(BIOS_ROM_BASIC , BiosRomBasic );
980 RegisterBiosInt32(BIOS_BOOTSTRAP_LOADER , BiosBootstrapLoader );
981 RegisterBiosInt32(BIOS_TIME_INTERRUPT , BiosTimeService );
982 // BIOS_KBD_CTRL_BREAK_INTERRUPT: 0x1B -- UNIMPLEMENTED
983 RegisterBiosInt32(BIOS_SYS_TIMER_INTERRUPT, BiosSystemTimerInterrupt);
984
985 /* Vectors that should be implemented (see above) */
986 RegisterBiosInt32(0x14, NULL);
987 RegisterBiosInt32(0x17, NULL);
988 RegisterBiosInt32(0x1B, NULL);
989 RegisterBiosInt32(0x4A, NULL); // User Alarm Handler
990
991 /* Relocated services by the BIOS (when needed) */
992 RegisterBiosInt32(0x40, NULL); // ROM BIOS Diskette Handler relocated by Hard Disk BIOS
993 RegisterBiosInt32(0x42, NULL); // Relocated Default INT 10h Video Services
994
995 /* Miscellaneous unimplemented vector handlers that should better have a default one */
996 RegisterBiosInt32(0x4B, NULL); // Virtual DMA Specification Services
997 RegisterBiosInt32(0x5C, NULL); // NetBIOS
998
999 // ROM-BASIC interrupts span from 0x80 up to 0xEF.
1000 // They don't have any default handler at the moment.
1001
1002 /* Some vectors are in fact addresses to tables */
1003 ((PULONG)BaseAddress)[0x1D] = (ULONG)NULL; // Video Parameter Tables
1004 ((PULONG)BaseAddress)[0x1E] = (ULONG)NULL; // Diskette Parameters
1005 ((PULONG)BaseAddress)[0x1F] = (ULONG)NULL; // 8x8 Graphics Font
1006 ((PULONG)BaseAddress)[0x41] = (ULONG)NULL; // Hard Disk 0 Parameter Table Address
1007 ((PULONG)BaseAddress)[0x43] = (ULONG)NULL; // Character Table (EGA, MCGA, VGA)
1008 ((PULONG)BaseAddress)[0x46] = (ULONG)NULL; // Hard Disk 1 Drive Parameter Table Address
1009 /* Tables that are always uninitialized */
1010 ((PULONG)BaseAddress)[0x44] = (ULONG)NULL; // ROM BIOS Character Font, Characters 00h-7Fh (PCjr)
1011 ((PULONG)BaseAddress)[0x48] = (ULONG)NULL; // Cordless Keyboard Translation (PCjr)
1012 ((PULONG)BaseAddress)[0x49] = (ULONG)NULL; // Non-Keyboard Scan-code Translation Table (PCJr)
1013 }
1014
1015 static VOID InitializeBiosData(VOID)
1016 {
1017 UCHAR Low, High;
1018
1019 /* Initialize the BDA contents */
1020 RtlZeroMemory(Bda, sizeof(*Bda));
1021
1022 /*
1023 * Retrieve the basic equipment list from the CMOS
1024 */
1025 IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_EQUIPMENT_LIST | CMOS_DISABLE_NMI);
1026 Bda->EquipmentList = IOReadB(CMOS_DATA_PORT);
1027 // TODO: Update it if required.
1028 Bda->EquipmentList &= 0x00FF; // High byte cleared for now...
1029
1030 /*
1031 * Retrieve the conventional memory size
1032 * in kB from the CMOS, typically 640 kB.
1033 */
1034 IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_BASE_MEMORY_LOW | CMOS_DISABLE_NMI);
1035 Low = IOReadB(CMOS_DATA_PORT);
1036 IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_BASE_MEMORY_HIGH | CMOS_DISABLE_NMI);
1037 High = IOReadB(CMOS_DATA_PORT);
1038 Bda->MemorySize = MAKEWORD(Low, High);
1039 }
1040
1041
1042 /*
1043 * The BIOS POST (Power On-Self Test)
1044 */
1045 /*static*/ VOID
1046 WINAPI
1047 Bios32Post(LPWORD Stack)
1048 {
1049 static BOOLEAN FirstBoot = TRUE;
1050 BYTE ShutdownStatus;
1051
1052 /*
1053 * Initialize BIOS/Keyboard/Video RAM dynamic data
1054 */
1055
1056 DPRINT("Bios32Post\n");
1057
1058 /* Disable interrupts */
1059 setIF(0);
1060
1061 /* Set the data segment */
1062 setDS(BDA_SEGMENT);
1063
1064 /* Initialize the stack */
1065 // Temporary stack for POST (to be used only before initializing the INT vectors)
1066 // setSS(0x0000);
1067 // setSP(0x0400);
1068 //
1069 // Stack to be used after the initialization of the INT vectors
1070 setSS(0x0000); // Stack at 00:8000, going downwards
1071 setSP(0x8000);
1072
1073 /*
1074 * Perform early CMOS shutdown status checks
1075 */
1076
1077 /* Read the CMOS shutdown status byte and reset it */
1078 IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_SHUTDOWN_STATUS | CMOS_DISABLE_NMI);
1079 ShutdownStatus = IOReadB(CMOS_DATA_PORT);
1080 IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_SHUTDOWN_STATUS | CMOS_DISABLE_NMI);
1081 IOWriteB(CMOS_DATA_PORT, 0x00);
1082
1083 DPRINT1("Bda->SoftReset = 0x%04X ; ShutdownStatus = 0x%02X\n",
1084 Bda->SoftReset, ShutdownStatus);
1085
1086 switch (ShutdownStatus)
1087 {
1088 /* Shutdown after Memory Tests (unsupported) */
1089 case 0x01: case 0x02: case 0x03:
1090 /* Shutdown after Protected Mode Tests (unsupported) */
1091 case 0x06: case 0x07: case 0x08:
1092 /* Shutdown after Block Move Test (unsupported) */
1093 case 0x09:
1094 {
1095 DisplayMessage(L"Unsupported CMOS Shutdown Status value 0x%02X. The VDM will shut down.", ShutdownStatus);
1096 EmulatorTerminate();
1097 return;
1098 }
1099
1100 /* Shutdown to Boot Loader */
1101 case 0x04:
1102 {
1103 DPRINT1("Fast restart to Bootstrap Loader...\n");
1104 goto Quit; // Reenable interrupts and exit.
1105 }
1106
1107 /* Flush keyboard, issue an EOI... */
1108 case 0x05:
1109 {
1110 IOReadB(PS2_DATA_PORT);
1111
1112 /* Send EOI */
1113 IOWriteB(PIC_SLAVE_CMD , PIC_OCW2_EOI);
1114 IOWriteB(PIC_MASTER_CMD, PIC_OCW2_EOI);
1115
1116 // Fall back
1117 }
1118
1119 /*
1120 * ... and far JMP to user-specified location at 0040:0067
1121 * (Bda->ResumeEntryPoint) with interrupts and NMI disabled.
1122 */
1123 case 0x0A:
1124 {
1125 DPRINT1("Bda->ResumeEntryPoint = %04X:%04X\n",
1126 HIWORD(Bda->ResumeEntryPoint),
1127 LOWORD(Bda->ResumeEntryPoint));
1128
1129 /* Position execution pointers and return with interrupts disabled */
1130 setCS(HIWORD(Bda->ResumeEntryPoint));
1131 setIP(LOWORD(Bda->ResumeEntryPoint));
1132 return;
1133 }
1134
1135 /* Soft reset or unexpected shutdown... */
1136 case 0x00:
1137 /* ... or other possible shutdown codes: just continue the POST */
1138 default:
1139 break;
1140 }
1141
1142 /*
1143 * FIXME: UNIMPLEMENTED!
1144 * Check the word at 0040h:0072h (Bda->SoftReset) and do one of the
1145 * following actions:
1146 * - if the word is 0000h, perform a cold reboot (aka. Reset). Everything gets initialized.
1147 * - if the word is 1234h, perform a warm reboot (aka. Ctrl-Alt-Del). Some stuff is skipped.
1148 */
1149 switch (Bda->SoftReset)
1150 {
1151 case 0x0000:
1152 {
1153 if (!FirstBoot)
1154 {
1155 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...");
1156 EmulatorTerminate();
1157 return;
1158 }
1159 break;
1160 }
1161
1162 case 0x1234:
1163 {
1164 DisplayMessage(L"NTVDM is performing a WARM reboot! This is not supported at the moment. The VDM will shut down...");
1165 EmulatorTerminate();
1166 return;
1167 }
1168
1169 default:
1170 break;
1171 }
1172
1173 FirstBoot = FALSE;
1174
1175 /* Initialize the BDA */
1176 InitializeBiosData();
1177
1178 /* Initialize the User Data Area at 0050:XXXX */
1179 RtlZeroMemory(SEG_OFF_TO_PTR(0x50, 0x0000), sizeof(USER_DATA_AREA));
1180
1181
1182
1183 //////// NOTE: This is more or less bios-specific ////////
1184
1185 /*
1186 * Initialize IVT and hardware
1187 */
1188
1189 // WriteUnProtectRom(...);
1190
1191 /* Register the BIOS 32-bit Interrupts */
1192 InitializeBiosInt32();
1193
1194 /* Initialize platform hardware (PIC/PIT chips, ...) */
1195 BiosHwSetup();
1196
1197 /* Initialize the Keyboard, Video and Mouse BIOS */
1198 KbdBios32Post();
1199 VidBiosPost();
1200 MouseBios32Post();
1201 DiskBios32Post();
1202
1203 // WriteProtectRom(...);
1204
1205 //////// End of more or less bios-specific section ///////
1206
1207
1208
1209 SearchAndInitRoms(&BiosContext);
1210
1211 /*
1212 * End of the 32-bit POST portion. We then fall back into 16-bit where
1213 * the rest of the POST code is executed, typically calling INT 19h
1214 * to boot up the OS.
1215 */
1216
1217 Quit:
1218 /* Enable interrupts */
1219 setIF(1);
1220 }
1221
1222
1223 /* PUBLIC FUNCTIONS ***********************************************************/
1224
1225 BOOLEAN Bios32Initialize(VOID)
1226 {
1227 /*
1228 * Initialize BIOS/Keyboard/Video ROM static data
1229 */
1230
1231 /* System BIOS Copyright */
1232 RtlCopyMemory(SEG_OFF_TO_PTR(BIOS_SEGMENT, 0xE000), BiosCopyright, sizeof(BiosCopyright)-1);
1233
1234 /* System BIOS Version */
1235 RtlCopyMemory(SEG_OFF_TO_PTR(BIOS_SEGMENT, 0xE070), BiosVersion, sizeof(BiosVersion)-1);
1236
1237 /* System BIOS Date */
1238 RtlCopyMemory(SEG_OFF_TO_PTR(BIOS_SEGMENT, 0xFFF5), BiosDate, sizeof(BiosDate)-1);
1239
1240 /* Bootstrap code */
1241 RtlCopyMemory(SEG_OFF_TO_PTR(BIOS_SEGMENT, 0xE05B), PostCode , sizeof(PostCode ));
1242 RtlCopyMemory(SEG_OFF_TO_PTR(BIOS_SEGMENT, 0xFFF0), Bootstrap, sizeof(Bootstrap));
1243
1244 /* BIOS ROM Information */
1245 RtlCopyMemory(SEG_OFF_TO_PTR(BIOS_SEGMENT, 0xE6F5), &BiosConfigTable, sizeof(BiosConfigTable));
1246
1247 /* System BIOS Model (same as Bct->Model) */
1248 *(PBYTE)(SEG_OFF_TO_PTR(BIOS_SEGMENT, 0xFFFE)) = BIOS_MODEL;
1249
1250 /* Initialize the Keyboard and Video BIOS */
1251 if (!KbdBiosInitialize() || !VidBiosInitialize() || !MouseBiosInitialize() || !DiskBios32Initialize())
1252 {
1253 /* Stop the VDM */
1254 EmulatorTerminate();
1255 return FALSE;
1256 }
1257
1258 /* Redefine our POST function */
1259 RegisterBop(BOP_RESET, Bios32Post);
1260
1261 WriteProtectRom((PVOID)TO_LINEAR(BIOS_SEGMENT, 0x0000),
1262 ROM_AREA_END - TO_LINEAR(BIOS_SEGMENT, 0x0000) + 1);
1263
1264 /* We are done */
1265 return TRUE;
1266 }
1267
1268 VOID Bios32Cleanup(VOID)
1269 {
1270 DiskBios32Cleanup();
1271 MouseBios32Cleanup();
1272 VidBios32Cleanup();
1273 KbdBiosCleanup();
1274 }
1275
1276 /* EOF */