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