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