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