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