[NTVDM]: The BIOS should have its BDA and BCT zero'ed out.
[reactos.git] / reactos / subsystems / ntvdm / bios / bios32 / bios32.c
1 /*
2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
4 * FILE: bios32.c
5 * PURPOSE: VDM 32-bit BIOS
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #define NDEBUG
12
13 /* For BIOS Version number */
14 #include <reactos/buildno.h>
15
16 #include "emulator.h"
17 #include "callback.h"
18 #include "bop.h"
19
20 #include "../bios.h"
21 #include "../rom.h"
22 #include "bios32.h"
23 #include "bios32p.h"
24 #include "kbdbios32.h"
25 #include "vidbios32.h"
26 #include "moubios32.h"
27
28 #include "io.h"
29 #include "hardware/cmos.h"
30 #include "hardware/pic.h"
31 #include "hardware/timer.h"
32
33 /* PRIVATE VARIABLES **********************************************************/
34
35 CALLBACK16 BiosContext;
36
37 /*
38
39 Bochs BIOS, see rombios.h
40 =========================
41
42 // model byte 0xFC = AT
43 #define SYS_MODEL_ID 0xFC
44 #define SYS_SUBMODEL_ID 0x00
45 #define BIOS_REVISION 1
46 #define BIOS_CONFIG_TABLE 0xe6f5
47
48 #ifndef BIOS_BUILD_DATE
49 # define BIOS_BUILD_DATE "06/23/99"
50 #endif
51
52 // 1K of base memory used for Extended Bios Data Area (EBDA)
53 // EBDA is used for PS/2 mouse support, and IDE BIOS, etc.
54 #define EBDA_SEG 0x9FC0
55 #define EBDA_SIZE 1 // In KiB
56 #define BASE_MEM_IN_K (640 - EBDA_SIZE)
57
58
59 See rombios.c
60 =============
61
62 ROM BIOS compatibility entry points:
63 ===================================
64 $e05b ; POST Entry Point
65 $e2c3 ; NMI Handler Entry Point
66 $e3fe ; INT 13h Fixed Disk Services Entry Point
67 $e401 ; Fixed Disk Parameter Table
68 $e6f2 ; INT 19h Boot Load Service Entry Point
69 $e6f5 ; Configuration Data Table
70 $e729 ; Baud Rate Generator Table
71 $e739 ; INT 14h Serial Communications Service Entry Point
72 $e82e ; INT 16h Keyboard Service Entry Point
73 $e987 ; INT 09h Keyboard Service Entry Point
74 $ec59 ; INT 13h Diskette Service Entry Point
75 $ef57 ; INT 0Eh Diskette Hardware ISR Entry Point
76 $efc7 ; Diskette Controller Parameter Table
77 $efd2 ; INT 17h Printer Service Entry Point
78 $f045 ; INT 10 Functions 0-Fh Entry Point
79 $f065 ; INT 10h Video Support Service Entry Point
80 $f0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
81 $f841 ; INT 12h Memory Size Service Entry Point
82 $f84d ; INT 11h Equipment List Service Entry Point
83 $f859 ; INT 15h System Services Entry Point
84 $fa6e ; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
85 $fe6e ; INT 1Ah Time-of-day Service Entry Point
86 $fea5 ; INT 08h System Timer ISR Entry Point
87 $fef3 ; Initial Interrupt Vector Offsets Loaded by POST
88 $ff53 ; IRET Instruction for Dummy Interrupt Handler
89 $ff54 ; INT 05h Print Screen Service Entry Point
90 $fff0 ; Power-up Entry Point
91 $fff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
92 $fffe ; System Model ID
93
94 */
95
96 /*
97 * See Ralf Brown: http://www.ctyme.com/intr/rb-1594.htm#Table515
98 * for more information.
99 */
100 #define BIOS_MODEL 0xFC // PC-AT
101 #define BIOS_SUBMODEL 0x01 // AT models 319,339 8 MHz, Enh Keyb, 3.5"
102 #define BIOS_REVISION 0x00
103 // FIXME: Find a nice PS/2 486 + 487 BIOS combination!
104
105 /*
106 * WARNING! For compatibility purposes the string "IBM" should be at F000:E00E .
107 * Some programs alternatively look at "COPR. IBM" that is at F000:E008 .
108 */
109 static const CHAR BiosCopyright[] = "0000000 NTVDM IBM Compatible 486 32-bit BIOS Copyright (C) ReactOS Team 1996-2014";
110 static const CHAR BiosVersion[] = "ReactOS NTVDM 32-bit BIOS "KERNEL_VERSION_STR" (Build "KERNEL_VERSION_BUILD_STR")";
111 static const CHAR BiosDate[] = "06/17/13";
112
113 C_ASSERT(sizeof(BiosCopyright)-1 <= 0x5B); // Ensures that we won't overflow on the POST Code starting at F000:E05B
114 C_ASSERT(sizeof(BiosDate)-1 == 0x08);
115
116 /* 16-bit bootstrap code at F000:FFF0 */
117 static BYTE Bootstrap[] =
118 {
119 0xEA, // jmp far ptr
120 0x5B, 0xE0, 0x00, 0xF0, // F000:E05B
121 };
122
123 /*
124 * Normally at F000:E05B there is the POST that finally calls the bootstrap
125 * interrupt. It should also check the value of Bda->SoftReset. Since we do
126 * all the POST in 32 bit from the start, we just place there the bootstrap
127 * interrupt call.
128 */
129 static BYTE PostCode[] =
130 {
131 0xCD, 0x19, // int 0x19, the bootstrap loader interrupt
132 // LOBYTE(EMULATOR_BOP), HIBYTE(EMULATOR_BOP), BOP_UNSIMULATE
133 };
134
135
136 /* PRIVATE FUNCTIONS **********************************************************/
137
138 static VOID WINAPI BiosException(LPWORD Stack)
139 {
140 /* Get the exception number and call the emulator API */
141 BYTE ExceptionNumber = LOBYTE(Stack[STACK_INT_NUM]);
142 EmulatorException(ExceptionNumber, Stack);
143 }
144
145 static VOID WINAPI BiosMiscService(LPWORD Stack)
146 {
147 switch (getAH())
148 {
149 /* Keyboard intercept */
150 case 0x4F:
151 {
152 /* CF should be set but let's just set it again just in case */
153 /* Do not modify AL (the hardware scan code), but set CF to continue processing */
154 // setCF(1);
155 Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
156 break;
157 }
158
159 /* Wait */
160 case 0x86:
161 {
162 /*
163 * Interval in microseconds in CX:DX
164 * See Ralf Brown: http://www.ctyme.com/intr/rb-1525.htm
165 * for more information.
166 */
167 Sleep(MAKELONG(getDX(), getCX()));
168
169 /* Clear CF */
170 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
171
172 break;
173 }
174
175 /* Copy Extended Memory */
176 case 0x87:
177 {
178 DWORD Count = (DWORD)getCX() * 2;
179 PFAST486_GDT_ENTRY Gdt = (PFAST486_GDT_ENTRY)SEG_OFF_TO_PTR(getES(), getSI());
180 DWORD SourceBase = Gdt[2].Base + (Gdt[2].BaseMid << 16) + (Gdt[2].BaseHigh << 24);
181 DWORD SourceLimit = Gdt[2].Limit + (Gdt[2].LimitHigh << 16);
182 DWORD DestBase = Gdt[3].Base + (Gdt[3].BaseMid << 16) + (Gdt[3].BaseHigh << 24);
183 DWORD DestLimit = Gdt[3].Limit + (Gdt[3].LimitHigh << 16);
184
185 /* Check for flags */
186 if (Gdt[2].Granularity) SourceLimit = (SourceLimit << 12) | 0xFFF;
187 if (Gdt[3].Granularity) DestLimit = (DestLimit << 12) | 0xFFF;
188
189 if ((Count > SourceLimit) || (Count > DestLimit))
190 {
191 setAX(0x80);
192 Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
193
194 break;
195 }
196
197 /* Copy */
198 RtlMoveMemory((PVOID)((ULONG_PTR)BaseAddress + DestBase),
199 (PVOID)((ULONG_PTR)BaseAddress + SourceBase),
200 Count);
201
202 setAX(ERROR_SUCCESS);
203 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
204 break;
205 }
206
207 /* Get Extended Memory Size */
208 case 0x88:
209 {
210 UCHAR Low, High;
211
212 /*
213 * Return the (usable) extended memory (after 1 MB)
214 * size in kB from CMOS.
215 */
216 IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_ACTUAL_EXT_MEMORY_LOW);
217 Low = IOReadB(CMOS_DATA_PORT);
218 IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_ACTUAL_EXT_MEMORY_HIGH);
219 High = IOReadB(CMOS_DATA_PORT);
220 setAX(MAKEWORD(Low, High));
221
222 /* Clear CF */
223 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
224
225 break;
226 }
227
228 /* Get Configuration */
229 case 0xC0:
230 {
231 /* Return the BIOS ROM Configuration Table address in ES:BX */
232 // The BCT is found at F000:E6F5 for 100% compatible BIOSes.
233 setES(BIOS_SEGMENT);
234 setBX(0xE6F5);
235
236 /* Call successful; clear CF */
237 setAH(0x00);
238 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
239
240 break;
241 }
242
243 case 0xC1:
244 case 0xC2:
245 {
246 DPRINT1("INT 15h, AH = 0x%02X must be implemented in order to support vendor mouse drivers\n");
247 break;
248 }
249
250 default:
251 {
252 DPRINT1("BIOS Function INT 15h, AH = 0x%02X NOT IMPLEMENTED\n",
253 getAH());
254 }
255 }
256 }
257
258 static VOID WINAPI BiosRomBasic(LPWORD Stack)
259 {
260 /* ROM Basic is unsupported, display a message to the user */
261 DisplayMessage(L"NTVDM doesn't support ROM Basic. The VDM is closing.");
262
263 /* Stop the VDM */
264 EmulatorTerminate();
265 return;
266 }
267
268 static VOID WINAPI BiosBootstrapLoader(LPWORD Stack)
269 {
270 /*
271 * In real bioses one loads the bootsector read from a diskette
272 * or from a disk, to 0000:7C00 and then one runs it.
273 * Since we are 32-bit VM and we hardcode our DOS at the moment,
274 * just call the DOS 32-bit initialization code.
275 */
276
277 DPRINT1("BiosBootstrapLoader -->\n");
278
279 DPRINT1("<-- BiosBootstrapLoader\n");
280 }
281
282 static VOID WINAPI BiosTimeService(LPWORD Stack)
283 {
284 switch (getAH())
285 {
286 case 0x00:
287 {
288 /* Set AL to 1 if midnight had passed, 0 otherwise */
289 setAL(Bda->MidnightPassed ? 0x01 : 0x00);
290
291 /* Return the tick count in CX:DX */
292 setCX(HIWORD(Bda->TickCounter));
293 setDX(LOWORD(Bda->TickCounter));
294
295 /* Reset the midnight flag */
296 Bda->MidnightPassed = FALSE;
297
298 break;
299 }
300
301 case 0x01:
302 {
303 /* Set the tick count to CX:DX */
304 Bda->TickCounter = MAKELONG(getDX(), getCX());
305
306 /* Reset the midnight flag */
307 Bda->MidnightPassed = FALSE;
308
309 break;
310 }
311
312 default:
313 {
314 DPRINT1("BIOS Function INT 1Ah, AH = 0x%02X NOT IMPLEMENTED\n",
315 getAH());
316 }
317 }
318 }
319
320 static VOID WINAPI BiosSystemTimerInterrupt(LPWORD Stack)
321 {
322 /* Increase the system tick count */
323 Bda->TickCounter++;
324 }
325
326
327 // From SeaBIOS
328 static VOID PicSetIRQMask(USHORT off, USHORT on)
329 {
330 UCHAR pic1off = off, pic1on = on, pic2off = off>>8, pic2on = on>>8;
331 IOWriteB(PIC_MASTER_DATA, (IOReadB(PIC_MASTER_DATA) & ~pic1off) | pic1on);
332 IOWriteB(PIC_SLAVE_DATA , (IOReadB(PIC_SLAVE_DATA ) & ~pic2off) | pic2on);
333 }
334
335 // From SeaBIOS
336 VOID EnableHwIRQ(UCHAR hwirq, EMULATOR_INT32_PROC func)
337 {
338 UCHAR vector;
339
340 PicSetIRQMask(1 << hwirq, 0);
341 if (hwirq < 8)
342 vector = BIOS_PIC_MASTER_INT + hwirq;
343 else
344 vector = BIOS_PIC_SLAVE_INT + hwirq - 8;
345
346 RegisterBiosInt32(vector, func);
347 }
348
349
350 VOID PicIRQComplete(LPWORD Stack)
351 {
352 /* Get the interrupt number */
353 BYTE IntNum = LOBYTE(Stack[STACK_INT_NUM]);
354
355 /*
356 * If this was a PIC IRQ, send an End-of-Interrupt to the PIC.
357 */
358
359 if (IntNum >= BIOS_PIC_MASTER_INT && IntNum < BIOS_PIC_MASTER_INT + 8)
360 {
361 /* It was an IRQ from the master PIC */
362 IOWriteB(PIC_MASTER_CMD, PIC_OCW2_EOI);
363 }
364 else if (IntNum >= BIOS_PIC_SLAVE_INT && IntNum < BIOS_PIC_SLAVE_INT + 8)
365 {
366 /* It was an IRQ from the slave PIC */
367 IOWriteB(PIC_SLAVE_CMD , PIC_OCW2_EOI);
368 IOWriteB(PIC_MASTER_CMD, PIC_OCW2_EOI);
369 }
370 }
371
372 static VOID WINAPI BiosHandleMasterPicIRQ(LPWORD Stack)
373 {
374 BYTE IrqNumber;
375
376 IOWriteB(PIC_MASTER_CMD, PIC_OCW3_READ_ISR /* == 0x0B */);
377 IrqNumber = IOReadB(PIC_MASTER_CMD);
378
379 DPRINT("Master - IrqNumber = 0x%02X\n", IrqNumber);
380
381 PicIRQComplete(Stack);
382 }
383
384 static VOID WINAPI BiosHandleSlavePicIRQ(LPWORD Stack)
385 {
386 BYTE IrqNumber;
387
388 IOWriteB(PIC_SLAVE_CMD, PIC_OCW3_READ_ISR /* == 0x0B */);
389 IrqNumber = IOReadB(PIC_SLAVE_CMD);
390
391 DPRINT("Slave - IrqNumber = 0x%02X\n", IrqNumber);
392
393 PicIRQComplete(Stack);
394 }
395
396 // Timer IRQ 0
397 static VOID WINAPI BiosTimerIrq(LPWORD Stack)
398 {
399 /*
400 * Perform the system timer interrupt.
401 *
402 * Do not call directly BiosSystemTimerInterrupt(Stack);
403 * because some programs may hook only BIOS_SYS_TIMER_INTERRUPT
404 * for their purpose...
405 */
406 /** EmulatorInterrupt(BIOS_SYS_TIMER_INTERRUPT); **/
407 Int32Call(&BiosContext, BIOS_SYS_TIMER_INTERRUPT);
408 PicIRQComplete(Stack);
409 }
410
411
412 static VOID BiosHwSetup(VOID)
413 {
414 /* Initialize the master and the slave PICs (cascade mode) */
415 IOWriteB(PIC_MASTER_CMD, PIC_ICW1 | PIC_ICW1_ICW4);
416 IOWriteB(PIC_SLAVE_CMD , PIC_ICW1 | PIC_ICW1_ICW4);
417
418 /*
419 * Set the interrupt vector offsets for each PIC
420 * (base IRQs: 0x08-0x0F for IRQ 0-7, 0x70-0x77 for IRQ 8-15)
421 */
422 IOWriteB(PIC_MASTER_DATA, BIOS_PIC_MASTER_INT);
423 IOWriteB(PIC_SLAVE_DATA , BIOS_PIC_SLAVE_INT );
424
425 /* Tell the master PIC that there is a slave PIC at IRQ 2 */
426 IOWriteB(PIC_MASTER_DATA, 1 << 2);
427 /* Tell the slave PIC its cascade identity */
428 IOWriteB(PIC_SLAVE_DATA , 2);
429
430 /* Make sure both PICs are in 8086 mode */
431 IOWriteB(PIC_MASTER_DATA, PIC_ICW4_8086);
432 IOWriteB(PIC_SLAVE_DATA , PIC_ICW4_8086);
433
434 /* Clear the masks for both PICs */
435 // IOWriteB(PIC_MASTER_DATA, 0x00);
436 // IOWriteB(PIC_SLAVE_DATA , 0x00);
437 /* Disable all IRQs */
438 IOWriteB(PIC_MASTER_DATA, 0xFF);
439 IOWriteB(PIC_SLAVE_DATA , 0xFF);
440
441
442 /* Initialize PIT Counter 0 */
443 IOWriteB(PIT_COMMAND_PORT, 0x34);
444 IOWriteB(PIT_DATA_PORT(0), 0x00);
445 IOWriteB(PIT_DATA_PORT(0), 0x00);
446
447 /* Initialize PIT Counter 1 */
448 IOWriteB(PIT_COMMAND_PORT, 0x74);
449 IOWriteB(PIT_DATA_PORT(1), 0x00);
450 IOWriteB(PIT_DATA_PORT(1), 0x00);
451
452 /* Initialize PIT Counter 2 */
453 IOWriteB(PIT_COMMAND_PORT, 0xB4);
454 IOWriteB(PIT_DATA_PORT(2), 0x00);
455 IOWriteB(PIT_DATA_PORT(2), 0x00);
456
457 EnableHwIRQ(0, BiosTimerIrq);
458 }
459
460 static VOID InitializeBiosInt32(VOID)
461 {
462 USHORT i;
463
464 /* Initialize the callback context */
465 InitializeContext(&BiosContext, BIOS_SEGMENT, 0x0000);
466
467 /* Register the default BIOS 32-bit Interrupts */
468 for (i = 0x00; i <= 0xFF; i++)
469 {
470 RegisterBiosInt32(i, NULL);
471 }
472
473 /* Initialize the exception vector interrupts to a default Exception handler */
474 for (i = 0; i < 8; i++)
475 RegisterBiosInt32(i, BiosException);
476
477 /* Initialize HW vector interrupts to a default HW handler */
478 for (i = BIOS_PIC_MASTER_INT; i < BIOS_PIC_MASTER_INT + 8; i++)
479 RegisterBiosInt32(i, BiosHandleMasterPicIRQ);
480 for (i = BIOS_PIC_SLAVE_INT ; i < BIOS_PIC_SLAVE_INT + 8; i++)
481 RegisterBiosInt32(i, BiosHandleSlavePicIRQ);
482
483 /* Initialize software vector handlers */
484 RegisterBiosInt32(BIOS_EQUIPMENT_INTERRUPT, BiosEquipmentService );
485 RegisterBiosInt32(BIOS_MEMORY_SIZE , BiosGetMemorySize );
486 RegisterBiosInt32(BIOS_MISC_INTERRUPT , BiosMiscService );
487 RegisterBiosInt32(BIOS_ROM_BASIC , BiosRomBasic );
488 RegisterBiosInt32(BIOS_BOOTSTRAP_LOADER , BiosBootstrapLoader );
489 RegisterBiosInt32(BIOS_TIME_INTERRUPT , BiosTimeService );
490 RegisterBiosInt32(BIOS_SYS_TIMER_INTERRUPT, BiosSystemTimerInterrupt);
491
492 /* Some interrupts are in fact addresses to tables */
493 ((PULONG)BaseAddress)[0x1E] = (ULONG)NULL;
494 ((PULONG)BaseAddress)[0x41] = (ULONG)NULL;
495 ((PULONG)BaseAddress)[0x46] = (ULONG)NULL;
496 ((PULONG)BaseAddress)[0x48] = (ULONG)NULL;
497 ((PULONG)BaseAddress)[0x49] = (ULONG)NULL;
498 }
499
500 static VOID InitializeBiosInfo(VOID)
501 {
502 RtlZeroMemory(Bct, sizeof(*Bct));
503
504 Bct->Length = sizeof(*Bct);
505 Bct->Model = BIOS_MODEL;
506 Bct->SubModel = BIOS_SUBMODEL;
507 Bct->Revision = BIOS_REVISION;
508 Bct->Feature[0] = 0x70; // At the moment we don't support "wait for external event (INT 15/AH=41h)", we also don't have any "extended BIOS area allocated (usually at top of RAM)"; see http://www.ctyme.com/intr/rb-1594.htm#Table510
509 Bct->Feature[1] = 0x00; // We don't support anything from here; see http://www.ctyme.com/intr/rb-1594.htm#Table511
510 Bct->Feature[2] = 0x00;
511 Bct->Feature[3] = 0x00;
512 Bct->Feature[4] = 0x00;
513 }
514
515 static VOID InitializeBiosData(VOID)
516 {
517 UCHAR Low, High;
518
519 /* System BIOS Copyright */
520 RtlCopyMemory(SEG_OFF_TO_PTR(0xF000, 0xE000), BiosCopyright, sizeof(BiosCopyright)-1);
521
522 /* System BIOS Version */
523 RtlCopyMemory(SEG_OFF_TO_PTR(0xF000, 0xE080), BiosVersion, sizeof(BiosVersion)-1); // FIXME: or E061, or E100 ??
524
525 /* System BIOS Date */
526 RtlCopyMemory(SEG_OFF_TO_PTR(0xF000, 0xFFF5), BiosDate, sizeof(BiosDate)-1);
527
528 /* System BIOS Model (same as Bct->Model) */
529 *(PBYTE)(SEG_OFF_TO_PTR(0xF000, 0xFFFE)) = BIOS_MODEL;
530
531 /* Initialize the BDA contents */
532 RtlZeroMemory(Bda, sizeof(*Bda));
533 Bda->EquipmentList = BIOS_EQUIPMENT_LIST;
534
535 /*
536 * Retrieve the conventional memory size
537 * in kB from CMOS, typically 640 kB.
538 */
539 IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_BASE_MEMORY_LOW);
540 Low = IOReadB(CMOS_DATA_PORT);
541 IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_BASE_MEMORY_HIGH);
542 High = IOReadB(CMOS_DATA_PORT);
543 Bda->MemorySize = MAKEWORD(Low, High);
544 }
545
546 /* PUBLIC FUNCTIONS ***********************************************************/
547
548 /*
549 * The BIOS POST (Power On-Self Test)
550 */
551 BOOLEAN Bios32Initialize(VOID)
552 {
553 BOOLEAN Success;
554
555 /* Initialize the stack */
556 // That's what says IBM... (stack at 30:00FF going downwards)
557 // setSS(0x0000);
558 // setSP(0x0400);
559 setSS(0x0050); // Stack at 50:0400, going downwards
560 setSP(0x0400);
561
562 /* Set data segment */
563 setDS(BDA_SEGMENT);
564
565 /* Initialize the BDA and the BIOS ROM Information */
566 InitializeBiosData();
567 InitializeBiosInfo();
568
569 /* Register the BIOS 32-bit Interrupts */
570 InitializeBiosInt32();
571
572 /* Initialize platform hardware (PIC/PIT chips, ...) */
573 BiosHwSetup();
574
575 /* Initialize the Keyboard, Video and Mouse BIOS */
576 if (!KbdBios32Initialize() || !VidBios32Initialize() || !MouseBios32Initialize())
577 return FALSE;
578
579 ///////////// MUST BE DONE AFTER IVT INITIALIZATION !! /////////////////////
580
581 /* Load some ROMs */
582 Success = LoadRom("boot.bin", (PVOID)0xE0000, NULL);
583 DPRINT1("Test ROM loading %s ; GetLastError() = %u\n", Success ? "succeeded" : "failed", GetLastError());
584
585 SearchAndInitRoms(&BiosContext);
586
587 /* Bootstrap code */
588 RtlCopyMemory(SEG_OFF_TO_PTR(0xF000, 0xE05B), PostCode , sizeof(PostCode ));
589 RtlCopyMemory(SEG_OFF_TO_PTR(0xF000, 0xFFF0), Bootstrap, sizeof(Bootstrap));
590
591 /* We are done */
592 return TRUE;
593 }
594
595 VOID Bios32Cleanup(VOID)
596 {
597 MouseBios32Cleanup();
598 VidBios32Cleanup();
599 KbdBios32Cleanup();
600 }
601
602 /* EOF */