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