xref: /reactos/subsystems/mvdm/ntvdm/bios/rom.c (revision 84ccccab)
1 /*
2  * COPYRIGHT:       GPL - See COPYING in the top level directory
3  * PROJECT:         ReactOS Virtual DOS Machine
4  * FILE:            subsystems/mvdm/ntvdm/bios/rom.c
5  * PURPOSE:         ROM Support Functions
6  * PROGRAMMERS:     Hermes Belusca-Maito (hermes.belusca@sfr.fr)
7  */
8 
9 /* INCLUDES *******************************************************************/
10 
11 #include "ntvdm.h"
12 
13 #define NDEBUG
14 #include <debug.h>
15 
16 #include "emulator.h"
17 #include "memory.h"
18 #include "cpu/callback.h"
19 #include "rom.h"
20 
21 #include "utils.h"
22 
23 /* PRIVATE FUNCTIONS **********************************************************/
24 
25 static BOOLEAN FASTCALL ShadowRomWrite(ULONG Address, PVOID Buffer, ULONG Size)
26 {
27     /* Prevent writing to ROM */
28     return FALSE;
29 }
30 
31 static HANDLE
32 OpenRomFile(IN  PCSTR  RomFileName,
33             OUT PULONG RomSize OPTIONAL)
34 {
35     HANDLE hRomFile;
36     ULONG  ulRomSize = 0;
37 
38     /* Open the ROM image file */
39     hRomFile = FileOpen(RomFileName, &ulRomSize);
40 
41     /* If we failed, bail out */
42     if (hRomFile == NULL) return NULL;
43 
44     /*
45      * The size of the ROM image file is at most 256kB. For instance,
46      * the SeaBIOS image, which includes also expansion ROMs inside it,
47      * covers the range C000:0000 to F000:FFFF .
48      */
49     if (ulRomSize > 0x40000)
50     {
51         /* We failed, bail out */
52         DPRINT1("ROM image size 0x%lx too large, expected at most 0x40000 (256kB)", ulRomSize);
53         FileClose(hRomFile);
54         return NULL;
55     }
56 
57     /* Success, return file handle and size if needed */
58     if (RomSize) *RomSize = ulRomSize;
59     return hRomFile;
60 }
61 
62 static BOOLEAN
63 LoadRomFileByHandle(IN  HANDLE RomFileHandle,
64                     IN  PVOID  RomLocation,
65                     IN  ULONG  RomSize,
66                     OUT PULONG BytesRead)
67 {
68     /*
69      * The size of the ROM image file is at most 256kB. For instance,
70      * the SeaBIOS image, which includes also expansion ROMs inside it,
71      * covers the range C000:0000 to F000:FFFF .
72      */
73     if (RomSize > 0x40000)
74     {
75         DPRINT1("ROM image size 0x%lx too large, expected at most 0x40000 (256kB)", RomSize);
76         return FALSE;
77     }
78 
79     /* Attempt to load the ROM image file into memory */
80     return FileLoadByHandle(RomFileHandle,
81                             REAL_TO_PHYS(RomLocation),
82                             RomSize,
83                             BytesRead);
84 }
85 
86 static VOID
87 InitRomRange(IN PCALLBACK16 Context,
88              IN ULONG Start,
89              IN ULONG End,
90              IN ULONG Increment)
91 {
92     ULONG Address, EntryPoint;
93     ULONG RomSize;
94     UCHAR Checksum;
95 
96     for (Address = Start; Address < End; Address += Increment)
97     {
98         /* Does the ROM have a valid signature? */
99         if (*(PUSHORT)REAL_TO_PHYS(Address) == OPTION_ROM_SIGNATURE)
100         {
101             /* Check the control sum of the ROM */
102 
103             /*
104              * If this is an adapter ROM (Start: C8000, End: E0000),
105              * its reported size is stored in byte 2 of the ROM.
106              *
107              * If this is an expansion ROM (Start: E0000, End: F0000),
108              * its real length is 64kB.
109              */
110             RomSize = *(PUCHAR)REAL_TO_PHYS(Address + 2) * 512; // Size in blocks of 512 bytes
111             if (Address >= 0xE0000) RomSize = 0x10000;
112 
113             Checksum = CalcRomChecksum(Address, RomSize);
114             if (Checksum == 0x00)
115             {
116                 EntryPoint = Address + 3;
117                 DPRINT1("Going to run @ address 0x%p\n", EntryPoint);
118 
119                 EntryPoint = MAKELONG((EntryPoint & 0xFFFF), (EntryPoint & 0xF0000) >> 4);
120                 // setDS((Address & 0xF0000) >> 4);
121                 setDS((Address & 0xFF000) >> 4);
122                 RunCallback16(Context, EntryPoint);
123                 // Call16((EntryPoint & 0xF0000) >> 4, (EntryPoint & 0xFFFF));
124 
125                 DPRINT1("ROM @ address 0x%p initialized\n", Address);
126             }
127             else
128             {
129                 DPRINT1("ROM @ address 0x%p has invalid checksum of 0x%02x\n", Address, Checksum);
130             }
131         }
132     }
133 }
134 
135 /* PUBLIC FUNCTIONS ***********************************************************/
136 
137 BOOLEAN
138 WriteProtectRom(IN PVOID RomLocation,
139                 IN ULONG RomSize)
140 {
141     return MemInstallFastMemoryHook(RomLocation, RomSize,
142                                     NULL, ShadowRomWrite);
143 }
144 
145 BOOLEAN
146 WriteUnProtectRom(IN PVOID RomLocation,
147                   IN ULONG RomSize)
148 {
149     return MemRemoveFastMemoryHook(RomLocation, RomSize);
150 }
151 
152 UCHAR
153 CalcRomChecksum(IN ULONG RomLocation,
154                 IN ULONG RomSize)
155 {
156     ULONG RomLastAddress = RomLocation + RomSize;
157     UCHAR Sum = 0x00;   // Using a UCHAR guarantees that we wrap at 0xFF i.e. we do a sum modulo 0x100.
158 
159     while (RomLocation < RomLastAddress)
160     {
161         Sum += *(PUCHAR)REAL_TO_PHYS(RomLocation);
162         ++RomLocation;
163     }
164 
165     return Sum;
166 }
167 
168 BOOLEAN
169 LoadBios(IN  PCSTR  BiosFileName,
170          OUT PVOID* BiosLocation OPTIONAL,
171          OUT PULONG BiosSize     OPTIONAL)
172 {
173     BOOLEAN Success;
174     HANDLE  hBiosFile;
175     ULONG   ulBiosSize = 0;
176     PVOID   pBiosLocation;
177 
178     /* Open the BIOS image file */
179     hBiosFile = OpenRomFile(BiosFileName, &ulBiosSize);
180 
181     /* If we failed, bail out */
182     if (hBiosFile == NULL) return FALSE;
183 
184     /* BIOS location needs to be aligned on 32-bit boundary */
185     // (PVOID)((ULONG_PTR)BaseAddress + ROM_AREA_END + 1 - ulBiosSize)
186     pBiosLocation = MEM_ALIGN_DOWN(TO_LINEAR(0xF000, 0xFFFF) + 1 - ulBiosSize, sizeof(ULONG));
187 
188     /* Attempt to load the BIOS image file into memory */
189     Success = LoadRomFileByHandle(hBiosFile,
190                                   pBiosLocation,
191                                   ulBiosSize,
192                                   &ulBiosSize);
193     DPRINT1("BIOS loading %s ; GetLastError() = %u\n", Success ? "succeeded" : "failed", GetLastError());
194 
195     /* Close the BIOS image file */
196     FileClose(hBiosFile);
197 
198     /*
199      * In case of success, write-protect the BIOS location
200      * and return the BIOS location and its size if needed.
201      */
202     if (Success)
203     {
204         WriteProtectRom(pBiosLocation, ulBiosSize);
205 
206         if (BiosLocation) *BiosLocation = pBiosLocation;
207         if (BiosSize)     *BiosSize     = ulBiosSize;
208     }
209 
210     return Success;
211 }
212 
213 BOOLEAN
214 LoadRom(IN  PCSTR  RomFileName,
215         IN  PVOID  RomLocation,
216         OUT PULONG RomSize OPTIONAL)
217 {
218     BOOLEAN Success;
219     HANDLE  hRomFile;
220     ULONG   ulRomSize = 0;
221 
222     /* Open the ROM image file */
223     hRomFile = OpenRomFile(RomFileName, &ulRomSize);
224 
225     /* If we failed, bail out */
226     if (hRomFile == NULL) return FALSE;
227 
228     /* Attempt to load the ROM image file into memory */
229     Success = LoadRomFileByHandle(hRomFile,
230                                   RomLocation,
231                                   ulRomSize,
232                                   &ulRomSize);
233     DPRINT1("ROM loading %s ; GetLastError() = %u\n", Success ? "succeeded" : "failed", GetLastError());
234 
235     /* Close the ROM image file and return */
236     FileClose(hRomFile);
237 
238     /*
239      * In case of success, write-protect the ROM location
240      * and return the ROM size if needed.
241      */
242     if (Success)
243     {
244         WriteProtectRom(RomLocation, ulRomSize);
245         if (RomSize) *RomSize = ulRomSize;
246     }
247 
248     return Success;
249 }
250 
251 VOID
252 SearchAndInitRoms(IN PCALLBACK16 Context)
253 {
254     /* Video ROMs -- Start: C0000, End: C8000, 2kB blocks */
255     InitRomRange(Context, 0xC0000, 0xC8000, 0x0800);
256 
257     /* Adapters ROMs -- Start: C8000, End: E0000, 2kB blocks */
258     InitRomRange(Context, 0xC8000, 0xE0000, 0x0800);
259 
260     /* Expansion ROM -- Start: E0000, End: F0000, 64kB block */
261     InitRomRange(Context, 0xE0000, 0xEFFFF, 0x10000);
262 }
263 
264 /* EOF */
265