t's a bit embarrasing that some of this was undone until recently, but we now
[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
26 #undef DbgPrint
27 #define DbgPrint printf
28
29 extern PVOID KernelBase;
30 extern PVOID KernelMemory;
31
32 PVOID
33 NTAPI
34 LdrPEGetExportByName(PVOID BaseAddress,
35 PUCHAR SymbolName,
36 USHORT Hint);
37
38 /* FUNCTIONS *****************************************************************/
39
40 PLOADER_MODULE
41 NTAPI
42 LdrGetModuleObject(PCHAR ModuleName)
43 {
44 ULONG i;
45
46 for (i = 0; i < LoaderBlock.ModsCount; i++)
47 {
48 if (strstr(_strupr((PCHAR)reactos_modules[i].String), _strupr(ModuleName)))
49 {
50 return &reactos_modules[i];
51 }
52 }
53
54 return NULL;
55 }
56
57 PVOID
58 NTAPI
59 LdrPEFixupForward(IN PCHAR ForwardName)
60 {
61 CHAR NameBuffer[128];
62 PCHAR p;
63 PLOADER_MODULE ModuleObject;
64
65 strcpy(NameBuffer, ForwardName);
66 p = strchr(NameBuffer, '.');
67 if (p == NULL) return NULL;
68 *p = 0;
69
70 ModuleObject = LdrGetModuleObject(NameBuffer);
71 if (!ModuleObject)
72 {
73 DbgPrint("LdrPEFixupForward: failed to find module %s\n", NameBuffer);
74 return NULL;
75 }
76
77 return LdrPEGetExportByName((PVOID)ModuleObject->ModStart, (PUCHAR)(p + 1), 0xffff);
78 }
79
80 PVOID
81 NTAPI
82 LdrPEGetExportByName(PVOID BaseAddress,
83 PUCHAR SymbolName,
84 USHORT Hint)
85 {
86 PIMAGE_EXPORT_DIRECTORY ExportDir;
87 PULONG * ExFunctions;
88 PULONG * ExNames;
89 USHORT * ExOrdinals;
90 PVOID ExName;
91 ULONG Ordinal;
92 PVOID Function;
93 LONG minn, maxn, mid, res;
94 ULONG ExportDirSize;
95
96 /* HAL and NTOS use a virtual address, switch it to physical mode */
97 if ((ULONG_PTR)BaseAddress & 0x80000000)
98 {
99 BaseAddress = (PVOID)((ULONG_PTR)BaseAddress - KSEG0_BASE + (ULONG)KernelMemory);
100 }
101
102 ExportDir = (PIMAGE_EXPORT_DIRECTORY)
103 RtlImageDirectoryEntryToData(BaseAddress,
104 TRUE,
105 IMAGE_DIRECTORY_ENTRY_EXPORT,
106 &ExportDirSize);
107 if (!ExportDir)
108 {
109 DbgPrint("LdrPEGetExportByName(): no export directory!\n");
110 return NULL;
111 }
112
113 /* The symbol names may be missing entirely */
114 if (!ExportDir->AddressOfNames)
115 {
116 DbgPrint("LdrPEGetExportByName(): symbol names missing entirely\n");
117 return NULL;
118 }
119
120 /*
121 * Get header pointers
122 */
123 ExNames = (PULONG *)RVA(BaseAddress, ExportDir->AddressOfNames);
124 ExOrdinals = (USHORT *)RVA(BaseAddress, ExportDir->AddressOfNameOrdinals);
125 ExFunctions = (PULONG *)RVA(BaseAddress, ExportDir->AddressOfFunctions);
126
127 /*
128 * Check the hint first
129 */
130 if (Hint < ExportDir->NumberOfNames)
131 {
132 ExName = RVA(BaseAddress, ExNames[Hint]);
133 if (strcmp(ExName, (PCHAR)SymbolName) == 0)
134 {
135 Ordinal = ExOrdinals[Hint];
136 Function = RVA(BaseAddress, ExFunctions[Ordinal]);
137 if ((ULONG_PTR)Function >= (ULONG_PTR)ExportDir &&
138 (ULONG_PTR)Function < (ULONG_PTR)ExportDir + ExportDirSize)
139 {
140 Function = LdrPEFixupForward((PCHAR)Function);
141 if (Function == NULL)
142 {
143 DbgPrint("LdrPEGetExportByName(): failed to find %s\n", Function);
144 }
145 return Function;
146 }
147
148 if (Function != NULL) return Function;
149 }
150 }
151
152 /*
153 * Binary search
154 */
155 minn = 0;
156 maxn = ExportDir->NumberOfNames - 1;
157 while (minn <= maxn)
158 {
159 mid = (minn + maxn) / 2;
160
161 ExName = RVA(BaseAddress, ExNames[mid]);
162 res = strcmp(ExName, (PCHAR)SymbolName);
163 if (res == 0)
164 {
165 Ordinal = ExOrdinals[mid];
166 Function = RVA(BaseAddress, ExFunctions[Ordinal]);
167 if ((ULONG_PTR)Function >= (ULONG_PTR)ExportDir &&
168 (ULONG_PTR)Function < (ULONG_PTR)ExportDir + ExportDirSize)
169 {
170 Function = LdrPEFixupForward((PCHAR)Function);
171 if (Function == NULL)
172 {
173 DbgPrint("1: failed to find %s\n", Function);
174 }
175 return Function;
176 }
177 if (Function != NULL)
178 {
179 return Function;
180 }
181 }
182 else if (res > 0)
183 {
184 maxn = mid - 1;
185 }
186 else
187 {
188 minn = mid + 1;
189 }
190 }
191
192 /* Fall back on unsorted */
193 minn = 0;
194 maxn = ExportDir->NumberOfNames - 1;
195 while (minn <= maxn)
196 {
197 ExName = RVA(BaseAddress, ExNames[minn]);
198 res = strcmp(ExName, (PCHAR)SymbolName);
199 if (res == 0)
200 {
201 Ordinal = ExOrdinals[minn];
202 Function = RVA(BaseAddress, ExFunctions[Ordinal]);
203 if ((ULONG_PTR)Function >= (ULONG_PTR)ExportDir &&
204 (ULONG_PTR)Function < (ULONG_PTR)ExportDir + ExportDirSize)
205 {
206 Function = LdrPEFixupForward((PCHAR)Function);
207 if (Function == NULL)
208 {
209 DbgPrint("LdrPEGetExportByName(): failed to find %s\n",SymbolName);
210 }
211 return Function;
212 }
213 if (Function != NULL)
214 {
215 return Function;
216 }
217 DbgPrint("Failed to get function %s\n", SymbolName);
218 }
219 minn++;
220 }
221
222 DbgPrint("2: failed to find %s\n",SymbolName);
223 return (PVOID)NULL;
224 }
225
226 NTSTATUS
227 NTAPI
228 LdrPEProcessImportDirectoryEntry(PVOID DriverBase,
229 PLOADER_MODULE LoaderModule,
230 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory)
231 {
232 PVOID* ImportAddressList;
233 PULONG FunctionNameList;
234
235 if (ImportModuleDirectory == NULL || ImportModuleDirectory->Name == 0)
236 {
237 return STATUS_UNSUCCESSFUL;
238 }
239
240 /* Get the import address list. */
241 ImportAddressList = (PVOID*)RVA(DriverBase, ImportModuleDirectory->FirstThunk);
242
243 /* Get the list of functions to import. */
244 if (ImportModuleDirectory->OriginalFirstThunk != 0)
245 {
246 FunctionNameList = (PULONG)RVA(DriverBase, ImportModuleDirectory->OriginalFirstThunk);
247 }
248 else
249 {
250 FunctionNameList = (PULONG)RVA(DriverBase, ImportModuleDirectory->FirstThunk);
251 }
252
253 /* Walk through function list and fixup addresses. */
254 while (*FunctionNameList != 0L)
255 {
256 if ((*FunctionNameList) & 0x80000000)
257 {
258 DbgPrint("Failed to import ordinal from %s\n", LoaderModule->String);
259 return STATUS_UNSUCCESSFUL;
260 }
261 else
262 {
263 IMAGE_IMPORT_BY_NAME *pe_name;
264 pe_name = RVA(DriverBase, *FunctionNameList);
265 *ImportAddressList = LdrPEGetExportByName((PVOID)LoaderModule->ModStart, pe_name->Name, pe_name->Hint);
266
267 /* Fixup the address to be virtual */
268 *ImportAddressList = (PVOID)(ULONG_PTR)*ImportAddressList + (ULONG_PTR)KernelBase - (ULONG_PTR)KernelMemory;
269
270
271 //DbgPrint("Looked for: %s and found: %x\n", pe_name->Name, *ImportAddressList);
272 if ((*ImportAddressList) == NULL)
273 {
274 DbgPrint("Failed to import %s from %s\n", pe_name->Name, LoaderModule->String);
275 return STATUS_UNSUCCESSFUL;
276 }
277 }
278 ImportAddressList++;
279 FunctionNameList++;
280 }
281 return STATUS_SUCCESS;
282 }
283
284 extern BOOLEAN FrLdrLoadDriver(PCHAR szFileName, INT nPos);
285
286 NTSTATUS
287 NTAPI
288 LdrPEGetOrLoadModule(IN PCHAR ModuleName,
289 IN PCHAR ImportedName,
290 IN PLOADER_MODULE* ImportedModule)
291 {
292 NTSTATUS Status = STATUS_SUCCESS;
293
294 *ImportedModule = LdrGetModuleObject(ImportedName);
295 if (*ImportedModule == NULL)
296 {
297 /*
298 * For now, we only support import-loading the HAL.
299 * Later, FrLdrLoadDriver should be made to share the same
300 * code, and we'll just call it instead.
301 */
302 FrLdrLoadDriver(ImportedName, 0);
303
304 /* Return the new module */
305 *ImportedModule = LdrGetModuleObject(ImportedName);
306 if (*ImportedModule == NULL)
307 {
308 DbgPrint("Error loading import: %s\n", ImportedName);
309 return STATUS_UNSUCCESSFUL;
310 }
311 }
312
313 return Status;
314 }
315
316 NTSTATUS
317 NTAPI
318 LdrPEFixupImports(IN PVOID DllBase,
319 IN PCHAR DllName)
320 {
321 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory;
322 PCHAR ImportedName;
323 NTSTATUS Status;
324 PLOADER_MODULE ImportedModule;
325 ULONG Size;
326
327 /* Process each import module */
328 ImportModuleDirectory = (PIMAGE_IMPORT_DESCRIPTOR)
329 RtlImageDirectoryEntryToData(DllBase,
330 TRUE,
331 IMAGE_DIRECTORY_ENTRY_IMPORT,
332 &Size);
333 while (ImportModuleDirectory && ImportModuleDirectory->Name)
334 {
335 /* Check to make sure that import lib is kernel */
336 ImportedName = (PCHAR) DllBase + ImportModuleDirectory->Name;
337 //DbgPrint("Processing imports for file: %s into file: %s\n", DllName, ImportedName);
338
339 Status = LdrPEGetOrLoadModule(DllName, ImportedName, &ImportedModule);
340 if (!NT_SUCCESS(Status)) return Status;
341
342 Status = LdrPEProcessImportDirectoryEntry(DllBase, ImportedModule, ImportModuleDirectory);
343 if (!NT_SUCCESS(Status)) return Status;
344
345 //DbgPrint("Imports for file: %s into file: %s complete\n", DllName, ImportedName);
346 ImportModuleDirectory++;
347 }
348
349 return STATUS_SUCCESS;
350 }