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