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
BiosCharPrint(CHAR Character)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
BiosException(LPWORD Stack)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
BiosEquipmentService(LPWORD Stack)200 VOID WINAPI BiosEquipmentService(LPWORD Stack)
201 {
202 /* Return the equipment list */
203 setAX(Bda->EquipmentList);
204 }
205
BiosGetMemorySize(LPWORD Stack)206 VOID WINAPI BiosGetMemorySize(LPWORD Stack)
207 {
208 /* Return the conventional memory size in kB, typically 640 kB */
209 setAX(Bda->MemorySize);
210 }
211
BiosMiscService(LPWORD Stack)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 reenable
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
BiosRomBasic(LPWORD Stack)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
BiosBootstrapLoader(LPWORD Stack)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 #ifdef ADVANCED_DEBUGGING
628 DPRINT1("An error happened while loading the bootsector from floppy 0, error = %d\n", getAH());
629 #endif
630
631 break;
632 }
633
634 /* Boot from 1st HDD drive */
635 case 1:
636 {
637 setAH(0x02); // Read sectors
638 setAL(0x01); // Number of sectors
639 setDH(0x00); // Head 0
640 setCH(0x00); // Cylinder 0
641 setCL(0x01); // Sector 1
642 setDL(0x80); // First HDD drive (used by loader code, so should not be cleared)
643 setES(0x0000); // Write data in 0000:7C00
644 setBX(0x7C00);
645 BiosDiskService(Stack);
646 if (!(Stack[STACK_FLAGS] & EMULATOR_FLAG_CF)) goto Quit;
647 #ifdef ADVANCED_DEBUGGING
648 DPRINT1("An error happened while loading the bootsector from HDD 0, error = %d\n", getAH());
649 #endif
650
651 break;
652 }
653
654 default:
655 goto StartDos;
656 }
657
658 /* Go to next drive and invalidate the last half-byte. */
659 BootOrder = (BootOrder >> 4) | 0xF000;
660 goto Retry;
661
662 StartDos:
663 /* Clear everything, we are going to load DOS32 */
664 setAX(AX);
665 setBX(BX);
666 setCX(CX);
667 setDX(DX);
668 setES(ES);
669 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
670
671 /* Load our DOS */
672 DosBootsectorInitialize();
673
674 Quit:
675 /*
676 * Jump to 0000:7C00 to boot the OS.
677 *
678 * Since we are called via the INT32 mechanism, we need to correctly set
679 * CS:IP, not by changing the current one (otherwise the interrupt could
680 * not be clean up and return properly), but by changing the CS:IP in the
681 * stack, so that when the interrupt returns, the modified CS:IP is popped
682 * off the stack and the CPU is correctly repositioned.
683 */
684 Stack[STACK_CS] = 0x0000;
685 Stack[STACK_IP] = 0x7C00;
686
687 DPRINT("<-- BiosBootstrapLoader\n");
688 }
689
BiosTimeService(LPWORD Stack)690 static VOID WINAPI BiosTimeService(LPWORD Stack)
691 {
692 switch (getAH())
693 {
694 /* Get System Time */
695 case 0x00:
696 {
697 /* Set AL to 1 if midnight had passed, 0 otherwise */
698 setAL(Bda->MidnightPassed ? 0x01 : 0x00);
699
700 /* Return the tick count in CX:DX */
701 setCX(HIWORD(Bda->TickCounter));
702 setDX(LOWORD(Bda->TickCounter));
703
704 /* Reset the midnight flag */
705 Bda->MidnightPassed = FALSE;
706
707 break;
708 }
709
710 /* Set System Time */
711 case 0x01:
712 {
713 /* Set the tick count to CX:DX */
714 Bda->TickCounter = MAKELONG(getDX(), getCX());
715
716 /* Reset the midnight flag */
717 Bda->MidnightPassed = FALSE;
718
719 break;
720 }
721
722 /* Get Real-Time Clock Time */
723 case 0x02:
724 {
725 UCHAR StatusB;
726
727 IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_HOURS);
728 setCH(IOReadB(CMOS_DATA_PORT));
729
730 IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_MINUTES);
731 setCL(IOReadB(CMOS_DATA_PORT));
732
733 IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_SECONDS);
734 setDH(IOReadB(CMOS_DATA_PORT));
735
736 /* Daylight Savings Time */
737 IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_STATUS_B);
738 StatusB = IOReadB(CMOS_DATA_PORT);
739 setDL(StatusB & 0x01);
740
741 /* Clear CF */
742 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
743 break;
744 }
745
746 // /* Set Real-Time Clock Time */
747 // case 0x03:
748 // {
749 // break;
750 // }
751
752 /* Get Real-Time Clock Date */
753 case 0x04:
754 {
755 IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_CENTURY);
756 setCH(IOReadB(CMOS_DATA_PORT));
757
758 IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_YEAR);
759 setCL(IOReadB(CMOS_DATA_PORT));
760
761 IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_MONTH);
762 setDH(IOReadB(CMOS_DATA_PORT));
763
764 IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_DAY);
765 setDL(IOReadB(CMOS_DATA_PORT));
766
767 /* Clear CF */
768 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
769 break;
770 }
771
772 // /* Set Real-Time Clock Date */
773 // case 0x05:
774 // {
775 // break;
776 // }
777
778 default:
779 {
780 DPRINT1("BIOS Function INT 1Ah, AH = 0x%02X NOT IMPLEMENTED\n",
781 getAH());
782 }
783 }
784 }
785
BiosSystemTimerInterrupt(LPWORD Stack)786 static VOID WINAPI BiosSystemTimerInterrupt(LPWORD Stack)
787 {
788 /* Increase the system tick count */
789 Bda->TickCounter++;
790 }
791
792
793 // From SeaBIOS
PicSetIRQMask(USHORT off,USHORT on)794 static VOID PicSetIRQMask(USHORT off, USHORT on)
795 {
796 UCHAR pic1off = off, pic1on = on, pic2off = off>>8, pic2on = on>>8;
797 IOWriteB(PIC_MASTER_DATA, (IOReadB(PIC_MASTER_DATA) & ~pic1off) | pic1on);
798 IOWriteB(PIC_SLAVE_DATA , (IOReadB(PIC_SLAVE_DATA ) & ~pic2off) | pic2on);
799 }
800
801 // From SeaBIOS
EnableHwIRQ(UCHAR hwirq,EMULATOR_INT32_PROC func)802 VOID EnableHwIRQ(UCHAR hwirq, EMULATOR_INT32_PROC func)
803 {
804 UCHAR vector;
805
806 PicSetIRQMask(1 << hwirq, 0);
807 if (hwirq < 8)
808 vector = BIOS_PIC_MASTER_INT + hwirq;
809 else
810 vector = BIOS_PIC_SLAVE_INT + hwirq - 8;
811
812 RegisterBiosInt32(vector, func);
813 }
814
815
PicIRQComplete(BYTE IntNum)816 VOID PicIRQComplete(BYTE IntNum)
817 {
818 /*
819 * If this was a PIC IRQ, send an End-of-Interrupt to the PIC.
820 */
821 if (IntNum >= BIOS_PIC_MASTER_INT && IntNum < BIOS_PIC_MASTER_INT + 8)
822 {
823 /* It was an IRQ from the master PIC */
824 IOWriteB(PIC_MASTER_CMD, PIC_OCW2_EOI);
825 }
826 else if (IntNum >= BIOS_PIC_SLAVE_INT && IntNum < BIOS_PIC_SLAVE_INT + 8)
827 {
828 /* It was an IRQ from the slave PIC */
829 IOWriteB(PIC_SLAVE_CMD , PIC_OCW2_EOI);
830 IOWriteB(PIC_MASTER_CMD, PIC_OCW2_EOI);
831 }
832 }
833
BiosHandleMasterPicIRQ(LPWORD Stack)834 static VOID WINAPI BiosHandleMasterPicIRQ(LPWORD Stack)
835 {
836 BYTE IrqNumber;
837
838 IOWriteB(PIC_MASTER_CMD, PIC_OCW3_READ_ISR /* == 0x0B */);
839 IrqNumber = IOReadB(PIC_MASTER_CMD);
840
841 DPRINT("Master - IrqNumber = 0x%02X\n", IrqNumber);
842
843 PicIRQComplete(LOBYTE(Stack[STACK_INT_NUM]));
844 }
845
BiosHandleSlavePicIRQ(LPWORD Stack)846 static VOID WINAPI BiosHandleSlavePicIRQ(LPWORD Stack)
847 {
848 BYTE IrqNumber;
849
850 IOWriteB(PIC_SLAVE_CMD, PIC_OCW3_READ_ISR /* == 0x0B */);
851 IrqNumber = IOReadB(PIC_SLAVE_CMD);
852
853 DPRINT("Slave - IrqNumber = 0x%02X\n", IrqNumber);
854
855 PicIRQComplete(LOBYTE(Stack[STACK_INT_NUM]));
856 }
857
858 // Timer IRQ 0
BiosTimerIrq(LPWORD Stack)859 static VOID WINAPI BiosTimerIrq(LPWORD Stack)
860 {
861 /*
862 * Perform the system timer interrupt.
863 *
864 * Do not call directly BiosSystemTimerInterrupt(Stack);
865 * because some programs may hook only BIOS_SYS_TIMER_INTERRUPT
866 * for their purpose...
867 */
868
869 WORD AX = getAX();
870 WORD CX = getCX();
871 WORD DX = getDX();
872 WORD BX = getBX();
873 WORD BP = getBP();
874 WORD SI = getSI();
875 WORD DI = getDI();
876 WORD DS = getDS();
877 WORD ES = getES();
878
879 Int32Call(&BiosContext, BIOS_SYS_TIMER_INTERRUPT);
880
881 setAX(AX);
882 setCX(CX);
883 setDX(DX);
884 setBX(BX);
885 setBP(BP);
886 setSI(SI);
887 setDI(DI);
888 setDS(DS);
889 setES(ES);
890 setCF(0);
891
892 // BiosSystemTimerInterrupt(Stack);
893 PicIRQComplete(LOBYTE(Stack[STACK_INT_NUM]));
894 }
895
896
BiosHwSetup(VOID)897 static VOID BiosHwSetup(VOID)
898 {
899 /* Initialize the master and the slave PICs (cascade mode) */
900 IOWriteB(PIC_MASTER_CMD, PIC_ICW1 | PIC_ICW1_ICW4);
901 IOWriteB(PIC_SLAVE_CMD , PIC_ICW1 | PIC_ICW1_ICW4);
902
903 /*
904 * Set the interrupt vector offsets for each PIC
905 * (base IRQs: 0x08-0x0F for IRQ 0-7, 0x70-0x77 for IRQ 8-15)
906 */
907 IOWriteB(PIC_MASTER_DATA, BIOS_PIC_MASTER_INT);
908 IOWriteB(PIC_SLAVE_DATA , BIOS_PIC_SLAVE_INT );
909
910 /* Tell the master PIC that there is a slave PIC at IRQ 2 */
911 IOWriteB(PIC_MASTER_DATA, 1 << 2);
912 /* Tell the slave PIC its cascade identity */
913 IOWriteB(PIC_SLAVE_DATA , 2);
914
915 /* Make sure both PICs are in 8086 mode */
916 IOWriteB(PIC_MASTER_DATA, PIC_ICW4_8086);
917 IOWriteB(PIC_SLAVE_DATA , PIC_ICW4_8086);
918
919 /* Clear the masks for both PICs */
920 // IOWriteB(PIC_MASTER_DATA, 0x00);
921 // IOWriteB(PIC_SLAVE_DATA , 0x00);
922 /* Disable all IRQs */
923 IOWriteB(PIC_MASTER_DATA, 0xFF);
924 IOWriteB(PIC_SLAVE_DATA , 0xFF);
925
926
927 /* Initialize PIT Counter 0 - Mode 2, 16bit binary count */
928 // NOTE: Some BIOSes set it to Mode 3 instead.
929 IOWriteB(PIT_COMMAND_PORT, 0x34);
930 // 18.2Hz refresh rate
931 IOWriteB(PIT_DATA_PORT(0), 0x00);
932 IOWriteB(PIT_DATA_PORT(0), 0x00);
933
934 /* Initialize PIT Counter 1 - Mode 2, 8bit binary count */
935 IOWriteB(PIT_COMMAND_PORT, 0x54);
936 // DRAM refresh every 15ms: http://www.cs.dartmouth.edu/~spl/Academic/Organization/docs/PC%20Timer%208253.html
937 IOWriteB(PIT_DATA_PORT(1), 18);
938
939 /* Initialize PIT Counter 2 - Mode 3, 16bit binary count */
940 IOWriteB(PIT_COMMAND_PORT, 0xB6);
941 // Count for 440Hz
942 IOWriteB(PIT_DATA_PORT(2), 0x97);
943 IOWriteB(PIT_DATA_PORT(2), 0x0A);
944
945
946 /* Initialize PS/2 keyboard port */
947 // Enable the port
948 IOWriteB(PS2_CONTROL_PORT, 0xAE);
949 // Port interrupts and clock enabled,
950 // enable keyboard scancode translation.
951 // POST passed, force keyboard unlocking.
952 IOWriteB(PS2_CONTROL_PORT, 0x60);
953 IOWriteB(PS2_DATA_PORT , 0x6D);
954 // Enable data reporting
955 IOWriteB(PS2_DATA_PORT , 0xF4);
956
957 EnableHwIRQ(0, BiosTimerIrq);
958 }
959
InitializeBiosInt32(VOID)960 static VOID InitializeBiosInt32(VOID)
961 {
962 USHORT i;
963
964 /* Initialize the callback context */
965 InitializeContext(&BiosContext, BIOS_SEGMENT, 0x0000);
966
967 /* Register the default BIOS interrupt vectors */
968
969 /*
970 * Zero out all of the IVT (0x00 -- 0xFF). Some applications
971 * indeed expect to have free vectors at the end of the IVT.
972 */
973 RtlZeroMemory(BaseAddress, 0x0100 * sizeof(ULONG));
974
975 #if defined(ADVANCED_DEBUGGING) && (ADVANCED_DEBUGGING_LEVEL >= 3)
976 // Initialize all the interrupt vectors to the default one.
977 for (i = 0x00; i <= 0xFF; i++)
978 RegisterBiosInt32(i, NULL);
979 #endif
980
981 /* Initialize the exception interrupt vectors to a default Exception handler */
982 for (i = 0x00; i <= 0x07; i++)
983 RegisterBiosInt32(i, BiosException);
984
985 /* Initialize HW interrupt vectors to a default HW handler */
986 for (i = BIOS_PIC_MASTER_INT; i < BIOS_PIC_MASTER_INT + 8; i++) // 0x08 -- 0x0F
987 RegisterBiosInt32(i, BiosHandleMasterPicIRQ);
988 for (i = BIOS_PIC_SLAVE_INT ; i < BIOS_PIC_SLAVE_INT + 8; i++) // 0x70 -- 0x77
989 RegisterBiosInt32(i, BiosHandleSlavePicIRQ);
990
991 /* Initialize software vector handlers */
992 // BIOS_VIDEO_INTERRUPT : 0x10 (vidbios32.c)
993 RegisterBiosInt32(BIOS_EQUIPMENT_INTERRUPT, BiosEquipmentService );
994 RegisterBiosInt32(BIOS_MEMORY_SIZE , BiosGetMemorySize );
995 // BIOS_DISK_INTERRUPT : 0x13 (dskbios32.c)
996 // BIOS_SERIAL_INTERRUPT : 0x14 -- UNIMPLEMENTED
997 RegisterBiosInt32(BIOS_MISC_INTERRUPT , BiosMiscService );
998 // BIOS_KBD_INTERRUPT : 0x16 (kbdbios32.c)
999 // BIOS_PRINTER_INTERRUPT: 0x17 -- UNIMPLEMENTED
1000 RegisterBiosInt32(BIOS_ROM_BASIC , BiosRomBasic );
1001 RegisterBiosInt32(BIOS_BOOTSTRAP_LOADER , BiosBootstrapLoader );
1002 RegisterBiosInt32(BIOS_TIME_INTERRUPT , BiosTimeService );
1003 // BIOS_KBD_CTRL_BREAK_INTERRUPT: 0x1B -- UNIMPLEMENTED
1004 RegisterBiosInt32(BIOS_SYS_TIMER_INTERRUPT, BiosSystemTimerInterrupt);
1005
1006 /* Vectors that should be implemented (see above) */
1007 RegisterBiosInt32(0x14, NULL);
1008 RegisterBiosInt32(0x17, NULL);
1009 RegisterBiosInt32(0x1B, NULL);
1010 RegisterBiosInt32(0x4A, NULL); // User Alarm Handler
1011
1012 /* Relocated services by the BIOS (when needed) */
1013 RegisterBiosInt32(0x40, NULL); // ROM BIOS Diskette Handler relocated by Hard Disk BIOS
1014 RegisterBiosInt32(0x42, NULL); // Relocated Default INT 10h Video Services
1015
1016 /* Miscellaneous unimplemented vector handlers that should better have a default one */
1017 RegisterBiosInt32(0x4B, NULL); // Virtual DMA Specification Services
1018 RegisterBiosInt32(0x5C, NULL); // NetBIOS
1019
1020 // ROM-BASIC interrupts span from 0x80 up to 0xEF.
1021 // They don't have any default handler at the moment.
1022
1023 /* Some vectors are in fact addresses to tables */
1024 ((PULONG)BaseAddress)[0x1D] = NULL32; // Video Parameter Tables
1025 ((PULONG)BaseAddress)[0x1E] = NULL32; // Diskette Parameters
1026 ((PULONG)BaseAddress)[0x1F] = NULL32; // 8x8 Graphics Font
1027 ((PULONG)BaseAddress)[0x41] = NULL32; // Hard Disk 0 Parameter Table Address
1028 ((PULONG)BaseAddress)[0x43] = NULL32; // Character Table (EGA, MCGA, VGA)
1029 ((PULONG)BaseAddress)[0x46] = NULL32; // Hard Disk 1 Drive Parameter Table Address
1030 /* Tables that are always uninitialized */
1031 ((PULONG)BaseAddress)[0x44] = NULL32; // ROM BIOS Character Font, Characters 00h-7Fh (PCjr)
1032 ((PULONG)BaseAddress)[0x48] = NULL32; // Cordless Keyboard Translation (PCjr)
1033 ((PULONG)BaseAddress)[0x49] = NULL32; // Non-Keyboard Scan-code Translation Table (PCJr)
1034 }
1035
InitializeBiosData(VOID)1036 static VOID InitializeBiosData(VOID)
1037 {
1038 UCHAR Low, High;
1039
1040 /* Initialize the BDA contents */
1041 RtlZeroMemory(Bda, sizeof(*Bda));
1042
1043 /*
1044 * Retrieve the basic equipment list from the CMOS
1045 */
1046 IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_EQUIPMENT_LIST | CMOS_DISABLE_NMI);
1047 Bda->EquipmentList = IOReadB(CMOS_DATA_PORT);
1048 // TODO: Update it if required.
1049 Bda->EquipmentList &= 0x00FF; // High byte cleared for now...
1050
1051 /*
1052 * Retrieve the conventional memory size
1053 * in kB from the CMOS, typically 640 kB.
1054 */
1055 IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_BASE_MEMORY_LOW | CMOS_DISABLE_NMI);
1056 Low = IOReadB(CMOS_DATA_PORT);
1057 IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_BASE_MEMORY_HIGH | CMOS_DISABLE_NMI);
1058 High = IOReadB(CMOS_DATA_PORT);
1059 Bda->MemorySize = MAKEWORD(Low, High);
1060 }
1061
1062
1063 /*
1064 * The BIOS POST (Power On-Self Test)
1065 */
1066 /*static*/ VOID
1067 WINAPI
Bios32Post(LPWORD Stack)1068 Bios32Post(LPWORD Stack)
1069 {
1070 static BOOLEAN FirstBoot = TRUE;
1071 BYTE ShutdownStatus;
1072
1073 /*
1074 * Initialize BIOS/Keyboard/Video RAM dynamic data
1075 */
1076
1077 DPRINT("Bios32Post\n");
1078
1079 /* Disable interrupts */
1080 setIF(0);
1081
1082 /* Set the data segment */
1083 setDS(BDA_SEGMENT);
1084
1085 /* Initialize the stack */
1086 // Temporary stack for POST (to be used only before initializing the INT vectors)
1087 // setSS(0x0000);
1088 // setSP(0x0400);
1089 //
1090 // Stack to be used after the initialization of the INT vectors
1091 setSS(0x0000); // Stack at 00:8000, going downwards
1092 setSP(0x8000);
1093
1094 /*
1095 * Perform early CMOS shutdown status checks
1096 */
1097
1098 /* Read the CMOS shutdown status byte and reset it */
1099 IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_SHUTDOWN_STATUS | CMOS_DISABLE_NMI);
1100 ShutdownStatus = IOReadB(CMOS_DATA_PORT);
1101 IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_SHUTDOWN_STATUS | CMOS_DISABLE_NMI);
1102 IOWriteB(CMOS_DATA_PORT, 0x00);
1103
1104 DPRINT1("Bda->SoftReset = 0x%04X ; ShutdownStatus = 0x%02X\n",
1105 Bda->SoftReset, ShutdownStatus);
1106
1107 switch (ShutdownStatus)
1108 {
1109 /* Shutdown after Memory Tests (unsupported) */
1110 case 0x01: case 0x02: case 0x03:
1111 /* Shutdown after Protected Mode Tests (unsupported) */
1112 case 0x06: case 0x07: case 0x08:
1113 /* Shutdown after Block Move Test (unsupported) */
1114 case 0x09:
1115 {
1116 DisplayMessage(L"Unsupported CMOS Shutdown Status value 0x%02X. The VDM will shut down.", ShutdownStatus);
1117 EmulatorTerminate();
1118 return;
1119 }
1120
1121 /* Shutdown to Boot Loader */
1122 case 0x04:
1123 {
1124 DPRINT1("Fast restart to Bootstrap Loader...\n");
1125 goto Quit; // Reenable interrupts and exit.
1126 }
1127
1128 /* Flush keyboard, issue an EOI... */
1129 case 0x05:
1130 {
1131 IOReadB(PS2_DATA_PORT);
1132
1133 /* Send EOI */
1134 IOWriteB(PIC_SLAVE_CMD , PIC_OCW2_EOI);
1135 IOWriteB(PIC_MASTER_CMD, PIC_OCW2_EOI);
1136
1137 // Fall back
1138 }
1139
1140 /*
1141 * ... and far JMP to user-specified location at 0040:0067
1142 * (Bda->ResumeEntryPoint) with interrupts and NMI disabled.
1143 */
1144 case 0x0A:
1145 {
1146 DPRINT1("Bda->ResumeEntryPoint = %04X:%04X\n",
1147 HIWORD(Bda->ResumeEntryPoint),
1148 LOWORD(Bda->ResumeEntryPoint));
1149
1150 /* Position execution pointers and return with interrupts disabled */
1151 setCS(HIWORD(Bda->ResumeEntryPoint));
1152 setIP(LOWORD(Bda->ResumeEntryPoint));
1153 return;
1154 }
1155
1156 /* Soft reset or unexpected shutdown... */
1157 case 0x00:
1158 /* ... or other possible shutdown codes: just continue the POST */
1159 default:
1160 break;
1161 }
1162
1163 /*
1164 * FIXME: UNIMPLEMENTED!
1165 * Check the word at 0040h:0072h (Bda->SoftReset) and do one of the
1166 * following actions:
1167 * - if the word is 0000h, perform a cold reboot (aka. Reset). Everything gets initialized.
1168 * - if the word is 1234h, perform a warm reboot (aka. Ctrl-Alt-Del). Some stuff is skipped.
1169 */
1170 switch (Bda->SoftReset)
1171 {
1172 case 0x0000:
1173 {
1174 if (!FirstBoot)
1175 {
1176 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...");
1177 EmulatorTerminate();
1178 return;
1179 }
1180 break;
1181 }
1182
1183 case 0x1234:
1184 {
1185 DisplayMessage(L"NTVDM is performing a WARM reboot! This is not supported at the moment. The VDM will shut down...");
1186 EmulatorTerminate();
1187 return;
1188 }
1189
1190 default:
1191 break;
1192 }
1193
1194 FirstBoot = FALSE;
1195
1196 /* Initialize the BDA */
1197 InitializeBiosData();
1198
1199 /* Initialize the User Data Area at 0050:XXXX */
1200 RtlZeroMemory(SEG_OFF_TO_PTR(0x50, 0x0000), sizeof(USER_DATA_AREA));
1201
1202
1203
1204 //////// NOTE: This is more or less bios-specific ////////
1205
1206 /*
1207 * Initialize IVT and hardware
1208 */
1209
1210 // WriteUnProtectRom(...);
1211
1212 /* Register the BIOS 32-bit Interrupts */
1213 InitializeBiosInt32();
1214
1215 /* Initialize platform hardware (PIC/PIT chips, ...) */
1216 BiosHwSetup();
1217
1218 /* Initialize the Keyboard, Video and Mouse BIOS */
1219 KbdBios32Post();
1220 VidBiosPost();
1221 MouseBios32Post();
1222 DiskBios32Post();
1223
1224 // WriteProtectRom(...);
1225
1226 //////// End of more or less bios-specific section ///////
1227
1228
1229
1230 SearchAndInitRoms(&BiosContext);
1231
1232 /*
1233 * End of the 32-bit POST portion. We then fall back into 16-bit where
1234 * the rest of the POST code is executed, typically calling INT 19h
1235 * to boot up the OS.
1236 */
1237
1238 Quit:
1239 /* Enable interrupts */
1240 setIF(1);
1241 }
1242
1243
1244 /* PUBLIC FUNCTIONS ***********************************************************/
1245
Bios32Initialize(VOID)1246 BOOLEAN Bios32Initialize(VOID)
1247 {
1248 /*
1249 * Initialize BIOS/Keyboard/Video ROM static data
1250 */
1251
1252 /* System BIOS Copyright */
1253 RtlCopyMemory(SEG_OFF_TO_PTR(BIOS_SEGMENT, 0xE000), BiosCopyright, sizeof(BiosCopyright)-1);
1254
1255 /* System BIOS Version */
1256 RtlCopyMemory(SEG_OFF_TO_PTR(BIOS_SEGMENT, 0xE070), BiosVersion, sizeof(BiosVersion)-1);
1257
1258 /* System BIOS Date */
1259 RtlCopyMemory(SEG_OFF_TO_PTR(BIOS_SEGMENT, 0xFFF5), BiosDate, sizeof(BiosDate)-1);
1260
1261 /* Bootstrap code */
1262 RtlCopyMemory(SEG_OFF_TO_PTR(BIOS_SEGMENT, 0xE05B), PostCode , sizeof(PostCode ));
1263 RtlCopyMemory(SEG_OFF_TO_PTR(BIOS_SEGMENT, 0xFFF0), Bootstrap, sizeof(Bootstrap));
1264
1265 /* BIOS ROM Information */
1266 RtlCopyMemory(SEG_OFF_TO_PTR(BIOS_SEGMENT, 0xE6F5), &BiosConfigTable, sizeof(BiosConfigTable));
1267
1268 /* System BIOS Model (same as Bct->Model) */
1269 *(PBYTE)(SEG_OFF_TO_PTR(BIOS_SEGMENT, 0xFFFE)) = BIOS_MODEL;
1270
1271 /* Initialize the Keyboard and Video BIOS */
1272 if (!KbdBiosInitialize() || !VidBiosInitialize() || !MouseBiosInitialize() || !DiskBios32Initialize())
1273 {
1274 /* Stop the VDM */
1275 EmulatorTerminate();
1276 return FALSE;
1277 }
1278
1279 /* Redefine our POST function */
1280 RegisterBop(BOP_RESET, Bios32Post);
1281
1282 WriteProtectRom((PVOID)TO_LINEAR(BIOS_SEGMENT, 0x0000),
1283 ROM_AREA_END - TO_LINEAR(BIOS_SEGMENT, 0x0000) + 1);
1284
1285 /* We are done */
1286 return TRUE;
1287 }
1288
Bios32Cleanup(VOID)1289 VOID Bios32Cleanup(VOID)
1290 {
1291 DiskBios32Cleanup();
1292 MouseBios32Cleanup();
1293 VidBios32Cleanup();
1294 KbdBiosCleanup();
1295 }
1296
1297 /* EOF */
1298