24c958a7974a4a562c31c1d0837737236a2819d7
[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 #define NDEBUG
24 #include <debug.h>
25
26 #define DbgPrint printf
27
28 extern PVOID KernelBase;
29 extern PVOID KernelMemory;
30
31 PVOID
32 NTAPI
33 LdrPEGetExportByName(PVOID BaseAddress,
34 PUCHAR SymbolName,
35 USHORT Hint);
36
37 /* FUNCTIONS *****************************************************************/
38
39 PLOADER_MODULE
40 NTAPI
41 LdrGetModuleObject(PCHAR ModuleName)
42 {
43 ULONG i;
44
45 for (i = 0; i < LoaderBlock.ModsCount; i++)
46 {
47 if (strstr(_strupr((PCHAR)reactos_modules[i].String), _strupr(ModuleName)))
48 {
49 return &reactos_modules[i];
50 }
51 }
52
53 return NULL;
54 }
55
56 PVOID
57 NTAPI
58 LdrPEFixupForward(IN PCHAR ForwardName)
59 {
60 CHAR NameBuffer[128];
61 PCHAR p;
62 PLOADER_MODULE ModuleObject;
63
64 strcpy(NameBuffer, ForwardName);
65 p = strchr(NameBuffer, '.');
66 if (p == NULL) return NULL;
67 *p = 0;
68
69 ModuleObject = LdrGetModuleObject(NameBuffer);
70 if (!ModuleObject)
71 {
72 DbgPrint("LdrPEFixupForward: failed to find module %s\n", NameBuffer);
73 return NULL;
74 }
75
76 return LdrPEGetExportByName((PVOID)ModuleObject->ModStart, (PUCHAR)(p + 1), 0xffff);
77 }
78
79 PVOID
80 NTAPI
81 LdrPEGetExportByName(PVOID BaseAddress,
82 PUCHAR SymbolName,
83 USHORT Hint)
84 {
85 PIMAGE_EXPORT_DIRECTORY ExportDir;
86 PULONG * ExFunctions;
87 PULONG * ExNames;
88 USHORT * ExOrdinals;
89 PVOID ExName;
90 ULONG Ordinal;
91 PVOID Function;
92 LONG minn, maxn, mid, res;
93 ULONG ExportDirSize;
94
95 /* HAL and NTOS use a virtual address, switch it to physical mode */
96 if ((ULONG_PTR)BaseAddress & 0x80000000)
97 {
98 BaseAddress = (PVOID)((ULONG_PTR)BaseAddress - KSEG0_BASE + (ULONG)KernelMemory);
99 }
100
101 ExportDir = (PIMAGE_EXPORT_DIRECTORY)
102 RtlImageDirectoryEntryToData(BaseAddress,
103 TRUE,
104 IMAGE_DIRECTORY_ENTRY_EXPORT,
105 &ExportDirSize);
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 Function = LdrPEFixupForward((PCHAR)Function);
206 if (Function == NULL)
207 {
208 DbgPrint("LdrPEGetExportByName(): failed to find %s\n",SymbolName);
209 }
210 return Function;
211 }
212 if (Function != NULL)
213 {
214 return Function;
215 }
216 DbgPrint("Failed to get function %s\n", SymbolName);
217 }
218 minn++;
219 }
220
221 DbgPrint("2: failed to find %s\n",SymbolName);
222 return (PVOID)NULL;
223 }
224
225 NTSTATUS
226 NTAPI
227 LdrPEProcessImportDirectoryEntry(PVOID DriverBase,
228 PLOADER_MODULE LoaderModule,
229 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory)
230 {
231 PVOID* ImportAddressList;
232 PULONG FunctionNameList;
233
234 if (ImportModuleDirectory == NULL || ImportModuleDirectory->Name == 0)
235 {
236 return STATUS_UNSUCCESSFUL;
237 }
238
239 /* Get the import address list. */
240 ImportAddressList = (PVOID*)RVA(DriverBase, ImportModuleDirectory->FirstThunk);
241
242 /* Get the list of functions to import. */
243 if (ImportModuleDirectory->OriginalFirstThunk != 0)
244 {
245 FunctionNameList = (PULONG)RVA(DriverBase, ImportModuleDirectory->OriginalFirstThunk);
246 }
247 else
248 {
249 FunctionNameList = (PULONG)RVA(DriverBase, ImportModuleDirectory->FirstThunk);
250 }
251
252 /* Walk through function list and fixup addresses. */
253 while (*FunctionNameList != 0L)
254 {
255 if ((*FunctionNameList) & 0x80000000)
256 {
257 DbgPrint("Failed to import ordinal from %s\n", LoaderModule->String);
258 return STATUS_UNSUCCESSFUL;
259 }
260 else
261 {
262 IMAGE_IMPORT_BY_NAME *pe_name;
263 pe_name = RVA(DriverBase, *FunctionNameList);
264 *ImportAddressList = LdrPEGetExportByName((PVOID)LoaderModule->ModStart, pe_name->Name, pe_name->Hint);
265
266 /* Fixup the address to be virtual */
267 *ImportAddressList = (PVOID)(ULONG_PTR)*ImportAddressList + (ULONG_PTR)KernelBase - (ULONG_PTR)KernelMemory;
268
269
270 //DbgPrint("Looked for: %s and found: %x\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 /* 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 }