Delete all Trailing spaces in code.
[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 DbgPrint("Exports: RtlImageDirectoryEntryToData\n");
100 ExportDir = (PIMAGE_EXPORT_DIRECTORY)
101 RtlImageDirectoryEntryToData(BaseAddress,
102 TRUE,
103 IMAGE_DIRECTORY_ENTRY_EXPORT,
104 &ExportDirSize);
105 DbgPrint("RtlImageDirectoryEntryToData done\n");
106 if (!ExportDir)
107 {
108 DbgPrint("LdrPEGetExportByName(): no export directory!\n");
109 return NULL;
110 }
111
112 /* The symbol names may be missing entirely */
113 if (!ExportDir->AddressOfNames)
114 {
115 DbgPrint("LdrPEGetExportByName(): symbol names missing entirely\n");
116 return NULL;
117 }
118
119 /*
120 * Get header pointers
121 */
122 ExNames = (PULONG *)RVA(BaseAddress, ExportDir->AddressOfNames);
123 ExOrdinals = (USHORT *)RVA(BaseAddress, ExportDir->AddressOfNameOrdinals);
124 ExFunctions = (PULONG *)RVA(BaseAddress, ExportDir->AddressOfFunctions);
125
126 /*
127 * Check the hint first
128 */
129 if (Hint < ExportDir->NumberOfNames)
130 {
131 ExName = RVA(BaseAddress, ExNames[Hint]);
132 if (strcmp(ExName, (PCHAR)SymbolName) == 0)
133 {
134 Ordinal = ExOrdinals[Hint];
135 Function = RVA(BaseAddress, ExFunctions[Ordinal]);
136 if ((ULONG_PTR)Function >= (ULONG_PTR)ExportDir &&
137 (ULONG_PTR)Function < (ULONG_PTR)ExportDir + ExportDirSize)
138 {
139 Function = LdrPEFixupForward((PCHAR)Function);
140 if (Function == NULL)
141 {
142 DbgPrint("LdrPEGetExportByName(): failed to find %s\n", Function);
143 }
144 return Function;
145 }
146
147 if (Function != NULL) return Function;
148 }
149 }
150
151 /*
152 * Binary search
153 */
154 minn = 0;
155 maxn = ExportDir->NumberOfNames - 1;
156 while (minn <= maxn)
157 {
158 mid = (minn + maxn) / 2;
159
160 ExName = RVA(BaseAddress, ExNames[mid]);
161 res = strcmp(ExName, (PCHAR)SymbolName);
162 if (res == 0)
163 {
164 Ordinal = ExOrdinals[mid];
165 Function = RVA(BaseAddress, ExFunctions[Ordinal]);
166 if ((ULONG_PTR)Function >= (ULONG_PTR)ExportDir &&
167 (ULONG_PTR)Function < (ULONG_PTR)ExportDir + ExportDirSize)
168 {
169 Function = LdrPEFixupForward((PCHAR)Function);
170 if (Function == NULL)
171 {
172 DbgPrint("1: failed to find %s\n", Function);
173 }
174 return Function;
175 }
176 if (Function != NULL)
177 {
178 return Function;
179 }
180 }
181 else if (res > 0)
182 {
183 maxn = mid - 1;
184 }
185 else
186 {
187 minn = mid + 1;
188 }
189 }
190
191 /* Fall back on unsorted */
192 minn = 0;
193 maxn = ExportDir->NumberOfNames - 1;
194 while (minn <= maxn)
195 {
196 ExName = RVA(BaseAddress, ExNames[minn]);
197 res = strcmp(ExName, (PCHAR)SymbolName);
198 if (res == 0)
199 {
200 Ordinal = ExOrdinals[minn];
201 Function = RVA(BaseAddress, ExFunctions[Ordinal]);
202 if ((ULONG_PTR)Function >= (ULONG_PTR)ExportDir &&
203 (ULONG_PTR)Function < (ULONG_PTR)ExportDir + ExportDirSize)
204 {
205 DbgPrint("Forward: %s\n", (PCHAR)Function);
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 + (KSEG0_BASE - (ULONG_PTR)KernelMemory));
269
270 //DbgPrint("Looked for: %s and found: %p\n", pe_name->Name, *ImportAddressList);
271 if ((*ImportAddressList) == NULL)
272 {
273 DbgPrint("Failed to import %s from %s\n", pe_name->Name, LoaderModule->String);
274 return STATUS_UNSUCCESSFUL;
275 }
276 }
277 ImportAddressList++;
278 FunctionNameList++;
279 }
280 return STATUS_SUCCESS;
281 }
282
283 extern BOOLEAN FrLdrLoadDriver(PCHAR szFileName, INT nPos);
284
285 NTSTATUS
286 NTAPI
287 LdrPEGetOrLoadModule(IN PCHAR ModuleName,
288 IN PCHAR ImportedName,
289 IN PLOADER_MODULE* ImportedModule)
290 {
291 NTSTATUS Status = STATUS_SUCCESS;
292
293 *ImportedModule = LdrGetModuleObject(ImportedName);
294 if (*ImportedModule == NULL)
295 {
296 /*
297 * For now, we only support import-loading the HAL.
298 * Later, FrLdrLoadDriver should be made to share the same
299 * code, and we'll just call it instead.
300 */
301 FrLdrLoadDriver(ImportedName, 0);
302
303 /* Return the new module */
304 *ImportedModule = LdrGetModuleObject(ImportedName);
305 if (*ImportedModule == NULL)
306 {
307 DbgPrint("Error loading import: %s\n", ImportedName);
308 return STATUS_UNSUCCESSFUL;
309 }
310 }
311
312 return Status;
313 }
314
315 NTSTATUS
316 NTAPI
317 LdrPEFixupImports(IN PVOID DllBase,
318 IN PCHAR DllName)
319 {
320 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory;
321 PCHAR ImportedName;
322 NTSTATUS Status;
323 PLOADER_MODULE ImportedModule;
324 ULONG Size;
325
326 printf("Fixing up %x (%s)\n", DllBase, DllName);
327
328 /* Process each import module */
329 DbgPrint("FixupImports: RtlImageDirectoryEntryToData\n");
330 ImportModuleDirectory = (PIMAGE_IMPORT_DESCRIPTOR)
331 RtlImageDirectoryEntryToData(DllBase,
332 TRUE,
333 IMAGE_DIRECTORY_ENTRY_IMPORT,
334 &Size);
335 DbgPrint("RtlImageDirectoryEntryToData done\n");
336 while (ImportModuleDirectory && ImportModuleDirectory->Name)
337 {
338 /* Check to make sure that import lib is kernel */
339 ImportedName = (PCHAR) DllBase + ImportModuleDirectory->Name;
340 //DbgPrint("Processing imports for file: %s into file: %s\n", DllName, ImportedName);
341
342 Status = LdrPEGetOrLoadModule(DllName, ImportedName, &ImportedModule);
343 if (!NT_SUCCESS(Status)) return Status;
344
345 Status = LdrPEProcessImportDirectoryEntry(DllBase, ImportedModule, ImportModuleDirectory);
346 if (!NT_SUCCESS(Status)) return Status;
347
348 //DbgPrint("Imports for file: %s into file: %s complete\n", DllName, ImportedName);
349 ImportModuleDirectory++;
350 }
351
352 return STATUS_SUCCESS;
353 }