Added freeldr and hal from PPC branch, along with needed headers and
[reactos.git] / reactos / boot / freeldr / freeldr / arch / powerpc / loader.c
1 /*
2 * FreeLoader
3 * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
4 * Copyright (C) 2005 Alex Ionescu <alex@relsoft.net>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20 #define _NTSYSTEM_
21 #include <freeldr.h>
22
23 #define NDEBUG
24 #include <debug.h>
25 #undef DbgPrint
26
27 extern PVOID KernelMemory;
28
29 PVOID
30 NTAPI
31 LdrPEGetExportByName(PVOID BaseAddress,
32 PUCHAR SymbolName,
33 USHORT Hint);
34
35 /* FUNCTIONS *****************************************************************/
36
37 PLOADER_MODULE
38 NTAPI
39 LdrGetModuleObject(PCHAR ModuleName)
40 {
41 ULONG i;
42
43 for (i = 0; i < LoaderBlock.ModsCount; i++)
44 {
45 if (strstr(_strupr((PCHAR)reactos_modules[i].String), _strupr(ModuleName)))
46 {
47 return &reactos_modules[i];
48 }
49 }
50
51 return NULL;
52 }
53
54 PVOID
55 NTAPI
56 LdrPEFixupForward(IN PCHAR ForwardName)
57 {
58 CHAR NameBuffer[128];
59 PCHAR p;
60 PLOADER_MODULE ModuleObject;
61
62 strcpy(NameBuffer, ForwardName);
63 p = strchr(NameBuffer, '.');
64 if (p == NULL) return NULL;
65 *p = 0;
66
67 ModuleObject = LdrGetModuleObject(NameBuffer);
68 if (!ModuleObject)
69 {
70 DbgPrint("LdrPEFixupForward: failed to find module %s\n", NameBuffer);
71 return NULL;
72 }
73
74 return LdrPEGetExportByName((PVOID)ModuleObject->ModStart, (PUCHAR)(p + 1), 0xffff);
75 }
76
77 PVOID
78 NTAPI
79 LdrPEGetExportByName(PVOID BaseAddress,
80 PUCHAR SymbolName,
81 USHORT Hint)
82 {
83 PIMAGE_EXPORT_DIRECTORY ExportDir;
84 PULONG * ExFunctions;
85 PULONG * ExNames;
86 USHORT * ExOrdinals;
87 PVOID ExName;
88 ULONG Ordinal;
89 PVOID Function;
90 LONG minn, maxn, mid, res;
91 ULONG ExportDirSize;
92
93 /* HAL and NTOS use a virtual address, switch it to physical mode */
94 if ((ULONG_PTR)BaseAddress & 0x80000000)
95 {
96 BaseAddress = (PVOID)((ULONG_PTR)BaseAddress - KSEG0_BASE + (ULONG)KernelMemory);
97 }
98
99 ExportDir = (PIMAGE_EXPORT_DIRECTORY)
100 RtlImageDirectoryEntryToData(BaseAddress,
101 TRUE,
102 IMAGE_DIRECTORY_ENTRY_EXPORT,
103 &ExportDirSize);
104 if (!ExportDir)
105 {
106 DbgPrint("LdrPEGetExportByName(): no export directory!\n");
107 return NULL;
108 }
109
110 /* The symbol names may be missing entirely */
111 if (!ExportDir->AddressOfNames)
112 {
113 DbgPrint("LdrPEGetExportByName(): symbol names missing entirely\n");
114 return NULL;
115 }
116
117 /*
118 * Get header pointers
119 */
120 ExNames = (PULONG *)RVA(BaseAddress, ExportDir->AddressOfNames);
121 ExOrdinals = (USHORT *)RVA(BaseAddress, ExportDir->AddressOfNameOrdinals);
122 ExFunctions = (PULONG *)RVA(BaseAddress, ExportDir->AddressOfFunctions);
123
124 /*
125 * Check the hint first
126 */
127 if (Hint < ExportDir->NumberOfNames)
128 {
129 ExName = RVA(BaseAddress, ExNames[Hint]);
130 if (strcmp(ExName, (PCHAR)SymbolName) == 0)
131 {
132 Ordinal = ExOrdinals[Hint];
133 Function = RVA(BaseAddress, ExFunctions[Ordinal]);
134 if ((ULONG_PTR)Function >= (ULONG_PTR)ExportDir &&
135 (ULONG_PTR)Function < (ULONG_PTR)ExportDir + ExportDirSize)
136 {
137 Function = LdrPEFixupForward((PCHAR)Function);
138 if (Function == NULL)
139 {
140 DbgPrint("LdrPEGetExportByName(): failed to find %s\n", Function);
141 }
142 return Function;
143 }
144
145 if (Function != NULL) return Function;
146 }
147 }
148
149 /*
150 * Binary search
151 */
152 minn = 0;
153 maxn = ExportDir->NumberOfNames - 1;
154 while (minn <= maxn)
155 {
156 mid = (minn + maxn) / 2;
157
158 ExName = RVA(BaseAddress, ExNames[mid]);
159 res = strcmp(ExName, (PCHAR)SymbolName);
160 if (res == 0)
161 {
162 Ordinal = ExOrdinals[mid];
163 Function = RVA(BaseAddress, ExFunctions[Ordinal]);
164 if ((ULONG_PTR)Function >= (ULONG_PTR)ExportDir &&
165 (ULONG_PTR)Function < (ULONG_PTR)ExportDir + ExportDirSize)
166 {
167 Function = LdrPEFixupForward((PCHAR)Function);
168 if (Function == NULL)
169 {
170 DbgPrint("1: failed to find %s\n", Function);
171 }
172 return Function;
173 }
174 if (Function != NULL)
175 {
176 return Function;
177 }
178 }
179 else if (res > 0)
180 {
181 maxn = mid - 1;
182 }
183 else
184 {
185 minn = mid + 1;
186 }
187 }
188
189 /* Fall back on unsorted */
190 minn = 0;
191 maxn = ExportDir->NumberOfNames - 1;
192 while (minn <= maxn)
193 {
194 ExName = RVA(BaseAddress, ExNames[minn]);
195 res = strcmp(ExName, (PCHAR)SymbolName);
196 if (res == 0)
197 {
198 Ordinal = ExOrdinals[minn];
199 Function = RVA(BaseAddress, ExFunctions[Ordinal]);
200 if ((ULONG_PTR)Function >= (ULONG_PTR)ExportDir &&
201 (ULONG_PTR)Function < (ULONG_PTR)ExportDir + ExportDirSize)
202 {
203 DbgPrint("Forward: %s\n", (PCHAR)Function);
204 Function = LdrPEFixupForward((PCHAR)Function);
205 if (Function == NULL)
206 {
207 DbgPrint("LdrPEGetExportByName(): failed to find %s\n",SymbolName);
208 }
209 return Function;
210 }
211 if (Function != NULL)
212 {
213 return Function;
214 }
215 DbgPrint("Failed to get function %s\n", SymbolName);
216 }
217 minn++;
218 }
219
220 DbgPrint("2: failed to find %s\n",SymbolName);
221 return (PVOID)NULL;
222 }
223
224 NTSTATUS
225 NTAPI
226 LdrPEProcessImportDirectoryEntry(PVOID DriverBase,
227 PLOADER_MODULE LoaderModule,
228 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory)
229 {
230 PVOID* ImportAddressList;
231 PULONG FunctionNameList;
232
233 if (ImportModuleDirectory == NULL || ImportModuleDirectory->Name == 0)
234 {
235 return STATUS_UNSUCCESSFUL;
236 }
237
238 /* Get the import address list. */
239 ImportAddressList = (PVOID*)RVA(DriverBase, ImportModuleDirectory->FirstThunk);
240
241 /* Get the list of functions to import. */
242 if (ImportModuleDirectory->OriginalFirstThunk != 0)
243 {
244 FunctionNameList = (PULONG)RVA(DriverBase, ImportModuleDirectory->OriginalFirstThunk);
245 }
246 else
247 {
248 FunctionNameList = (PULONG)RVA(DriverBase, ImportModuleDirectory->FirstThunk);
249 }
250
251 /* Walk through function list and fixup addresses. */
252 while (*FunctionNameList != 0L)
253 {
254 if ((*FunctionNameList) & 0x80000000)
255 {
256 DbgPrint("Failed to import ordinal from %s\n", LoaderModule->String);
257 return STATUS_UNSUCCESSFUL;
258 }
259 else
260 {
261 IMAGE_IMPORT_BY_NAME *pe_name;
262 pe_name = RVA(DriverBase, *FunctionNameList);
263 *ImportAddressList = LdrPEGetExportByName((PVOID)LoaderModule->ModStart, pe_name->Name, pe_name->Hint);
264
265 /* Fixup the address to be virtual */
266 *ImportAddressList = (PVOID)((ULONG_PTR)*ImportAddressList + (KSEG0_BASE - (ULONG_PTR)KernelMemory));
267
268 //DbgPrint("Looked for: %s and found: %p\n", pe_name->Name, *ImportAddressList);
269 if ((*ImportAddressList) == NULL)
270 {
271 DbgPrint("Failed to import %s from %s\n", pe_name->Name, LoaderModule->String);
272 return STATUS_UNSUCCESSFUL;
273 }
274 }
275 ImportAddressList++;
276 FunctionNameList++;
277 }
278 return STATUS_SUCCESS;
279 }
280
281 extern BOOLEAN FrLdrLoadDriver(PCHAR szFileName, INT nPos);
282
283 NTSTATUS
284 NTAPI
285 LdrPEGetOrLoadModule(IN PCHAR ModuleName,
286 IN PCHAR ImportedName,
287 IN PLOADER_MODULE* ImportedModule)
288 {
289 NTSTATUS Status = STATUS_SUCCESS;
290
291 *ImportedModule = LdrGetModuleObject(ImportedName);
292 if (*ImportedModule == NULL)
293 {
294 /*
295 * For now, we only support import-loading the HAL.
296 * Later, FrLdrLoadDriver should be made to share the same
297 * code, and we'll just call it instead.
298 */
299 FrLdrLoadDriver(ImportedName, 0);
300
301 /* Return the new module */
302 *ImportedModule = LdrGetModuleObject(ImportedName);
303 if (*ImportedModule == NULL)
304 {
305 DbgPrint("Error loading import: %s\n", ImportedName);
306 return STATUS_UNSUCCESSFUL;
307 }
308 }
309
310 return Status;
311 }
312
313 NTSTATUS
314 NTAPI
315 LdrPEFixupImports(IN PVOID DllBase,
316 IN PCHAR DllName)
317 {
318 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory;
319 PCHAR ImportedName;
320 NTSTATUS Status;
321 PLOADER_MODULE ImportedModule;
322 ULONG Size;
323
324 printf("Fixing up %x (%s)\n", DllBase, DllName);
325
326 /* Process each import module */
327 ImportModuleDirectory = (PIMAGE_IMPORT_DESCRIPTOR)
328 RtlImageDirectoryEntryToData(DllBase,
329 TRUE,
330 IMAGE_DIRECTORY_ENTRY_IMPORT,
331 &Size);
332 while (ImportModuleDirectory && ImportModuleDirectory->Name)
333 {
334 /* Check to make sure that import lib is kernel */
335 ImportedName = (PCHAR) DllBase + ImportModuleDirectory->Name;
336 //DbgPrint("Processing imports for file: %s into file: %s\n", DllName, ImportedName);
337
338 Status = LdrPEGetOrLoadModule(DllName, ImportedName, &ImportedModule);
339 if (!NT_SUCCESS(Status)) return Status;
340
341 Status = LdrPEProcessImportDirectoryEntry(DllBase, ImportedModule, ImportModuleDirectory);
342 if (!NT_SUCCESS(Status)) return Status;
343
344 //DbgPrint("Imports for file: %s into file: %s complete\n", DllName, ImportedName);
345 ImportModuleDirectory++;
346 }
347
348 return STATUS_SUCCESS;
349 }