Merge PR #283 "[USBPORT] Transaction Translator (TT) support bringup"
[reactos.git] / 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 along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20 #define _NTSYSTEM_
21 #include <freeldr.h>
22
23 #include <debug.h>
24
25 #define DbgPrint printf
26
27 extern PVOID KernelBase;
28 extern PVOID KernelMemory;
29
30 PVOID
31 NTAPI
32 LdrPEGetExportByName(PVOID BaseAddress,
33 PUCHAR SymbolName,
34 USHORT Hint);
35
36 /* FUNCTIONS *****************************************************************/
37
38 PLOADER_MODULE
39 NTAPI
40 LdrGetModuleObject(PCHAR ModuleName)
41 {
42 ULONG i;
43
44 for (i = 0; i < LoaderBlock.ModsCount; i++)
45 {
46 if (strstr(_strupr((PCHAR)reactos_modules[i].String), _strupr(ModuleName)))
47 {
48 return &reactos_modules[i];
49 }
50 }
51
52 return NULL;
53 }
54
55 PVOID
56 NTAPI
57 LdrPEFixupForward(IN PCHAR ForwardName)
58 {
59 CHAR NameBuffer[128];
60 PCHAR p;
61 PLOADER_MODULE ModuleObject;
62
63 strcpy(NameBuffer, ForwardName);
64 p = strchr(NameBuffer, '.');
65 if (p == NULL) return NULL;
66 *p = 0;
67
68 ModuleObject = LdrGetModuleObject(NameBuffer);
69 if (!ModuleObject)
70 {
71 DbgPrint("LdrPEFixupForward: failed to find module %s\n", NameBuffer);
72 return NULL;
73 }
74
75 return LdrPEGetExportByName((PVOID)ModuleObject->ModStart, (PUCHAR)(p + 1), 0xffff);
76 }
77
78 PVOID
79 NTAPI
80 LdrPEGetExportByName(PVOID BaseAddress,
81 PUCHAR SymbolName,
82 USHORT Hint)
83 {
84 PIMAGE_EXPORT_DIRECTORY ExportDir;
85 PULONG * ExFunctions;
86 PULONG * ExNames;
87 USHORT * ExOrdinals;
88 PVOID ExName;
89 ULONG Ordinal;
90 PVOID Function;
91 LONG minn, maxn, mid, res;
92 ULONG ExportDirSize;
93
94 /* HAL and NTOS use a virtual address, switch it to physical mode */
95 if ((ULONG_PTR)BaseAddress & 0x80000000)
96 {
97 BaseAddress = (PVOID)((ULONG_PTR)BaseAddress - KSEG0_BASE + (ULONG)KernelMemory);
98 }
99
100 ExportDir = (PIMAGE_EXPORT_DIRECTORY)
101 RtlImageDirectoryEntryToData(BaseAddress,
102 TRUE,
103 IMAGE_DIRECTORY_ENTRY_EXPORT,
104 &ExportDirSize);
105 if (!ExportDir)
106 {
107 DbgPrint("LdrPEGetExportByName(): no export directory!\n");
108 return NULL;
109 }
110
111 /* The symbol names may be missing entirely */
112 if (!ExportDir->AddressOfNames)
113 {
114 DbgPrint("LdrPEGetExportByName(): symbol names missing entirely\n");
115 return NULL;
116 }
117
118 /*
119 * Get header pointers
120 */
121 ExNames = (PULONG *)RVA(BaseAddress, ExportDir->AddressOfNames);
122 ExOrdinals = (USHORT *)RVA(BaseAddress, ExportDir->AddressOfNameOrdinals);
123 ExFunctions = (PULONG *)RVA(BaseAddress, ExportDir->AddressOfFunctions);
124
125 /*
126 * Check the hint first
127 */
128 if (Hint < ExportDir->NumberOfNames)
129 {
130 ExName = RVA(BaseAddress, ExNames[Hint]);
131 if (strcmp(ExName, (PCHAR)SymbolName) == 0)
132 {
133 Ordinal = ExOrdinals[Hint];
134 Function = RVA(BaseAddress, ExFunctions[Ordinal]);
135 if ((ULONG_PTR)Function >= (ULONG_PTR)ExportDir &&
136 (ULONG_PTR)Function < (ULONG_PTR)ExportDir + ExportDirSize)
137 {
138 Function = LdrPEFixupForward((PCHAR)Function);
139 if (Function == NULL)
140 {
141 DbgPrint("LdrPEGetExportByName(): failed to find %s\n", Function);
142 }
143 return Function;
144 }
145
146 if (Function != NULL) return Function;
147 }
148 }
149
150 /*
151 * Binary search
152 */
153 minn = 0;
154 maxn = ExportDir->NumberOfNames - 1;
155 while (minn <= maxn)
156 {
157 mid = (minn + maxn) / 2;
158
159 ExName = RVA(BaseAddress, ExNames[mid]);
160 res = strcmp(ExName, (PCHAR)SymbolName);
161 if (res == 0)
162 {
163 Ordinal = ExOrdinals[mid];
164 Function = RVA(BaseAddress, ExFunctions[Ordinal]);
165 if ((ULONG_PTR)Function >= (ULONG_PTR)ExportDir &&
166 (ULONG_PTR)Function < (ULONG_PTR)ExportDir + ExportDirSize)
167 {
168 Function = LdrPEFixupForward((PCHAR)Function);
169 if (Function == NULL)
170 {
171 DbgPrint("1: failed to find %s\n", Function);
172 }
173 return Function;
174 }
175 if (Function != NULL)
176 {
177 return Function;
178 }
179 }
180 else if (res > 0)
181 {
182 maxn = mid - 1;
183 }
184 else
185 {
186 minn = mid + 1;
187 }
188 }
189
190 /* Fall back on unsorted */
191 minn = 0;
192 maxn = ExportDir->NumberOfNames - 1;
193 while (minn <= maxn)
194 {
195 ExName = RVA(BaseAddress, ExNames[minn]);
196 res = strcmp(ExName, (PCHAR)SymbolName);
197 if (res == 0)
198 {
199 Ordinal = ExOrdinals[minn];
200 Function = RVA(BaseAddress, ExFunctions[Ordinal]);
201 if ((ULONG_PTR)Function >= (ULONG_PTR)ExportDir &&
202 (ULONG_PTR)Function < (ULONG_PTR)ExportDir + ExportDirSize)
203 {
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 + (ULONG_PTR)KernelBase - (ULONG_PTR)KernelMemory;
267
268
269 //DbgPrint("Looked for: %s and found: %x\n", pe_name->Name, *ImportAddressList);
270 if ((*ImportAddressList) == NULL)
271 {
272 DbgPrint("Failed to import %s from %s\n", pe_name->Name, LoaderModule->String);
273 return STATUS_UNSUCCESSFUL;
274 }
275 }
276 ImportAddressList++;
277 FunctionNameList++;
278 }
279 return STATUS_SUCCESS;
280 }
281
282 extern BOOLEAN FrLdrLoadDriver(PCHAR szFileName, INT nPos);
283
284 NTSTATUS
285 NTAPI
286 LdrPEGetOrLoadModule(IN PCHAR ModuleName,
287 IN PCHAR ImportedName,
288 IN PLOADER_MODULE* ImportedModule)
289 {
290 NTSTATUS Status = STATUS_SUCCESS;
291
292 *ImportedModule = LdrGetModuleObject(ImportedName);
293 if (*ImportedModule == NULL)
294 {
295 /*
296 * For now, we only support import-loading the HAL.
297 * Later, FrLdrLoadDriver should be made to share the same
298 * code, and we'll just call it instead.
299 */
300 FrLdrLoadDriver(ImportedName, 0);
301
302 /* Return the new module */
303 *ImportedModule = LdrGetModuleObject(ImportedName);
304 if (*ImportedModule == NULL)
305 {
306 DbgPrint("Error loading import: %s\n", ImportedName);
307 return STATUS_UNSUCCESSFUL;
308 }
309 }
310
311 return Status;
312 }
313
314 NTSTATUS
315 NTAPI
316 LdrPEFixupImports(IN PVOID DllBase,
317 IN PCHAR DllName)
318 {
319 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory;
320 PCHAR ImportedName;
321 NTSTATUS Status;
322 PLOADER_MODULE ImportedModule;
323 ULONG Size;
324
325 /* Process each import module */
326 ImportModuleDirectory = (PIMAGE_IMPORT_DESCRIPTOR)
327 RtlImageDirectoryEntryToData(DllBase,
328 TRUE,
329 IMAGE_DIRECTORY_ENTRY_IMPORT,
330 &Size);
331 while (ImportModuleDirectory && ImportModuleDirectory->Name)
332 {
333 /* Check to make sure that import lib is kernel */
334 ImportedName = (PCHAR) DllBase + ImportModuleDirectory->Name;
335 //DbgPrint("Processing imports for file: %s into file: %s\n", DllName, ImportedName);
336
337 Status = LdrPEGetOrLoadModule(DllName, ImportedName, &ImportedModule);
338 if (!NT_SUCCESS(Status)) return Status;
339
340 Status = LdrPEProcessImportDirectoryEntry(DllBase, ImportedModule, ImportModuleDirectory);
341 if (!NT_SUCCESS(Status)) return Status;
342
343 //DbgPrint("Imports for file: %s into file: %s complete\n", DllName, ImportedName);
344 ImportModuleDirectory++;
345 }
346
347 return STATUS_SUCCESS;
348 }