Chameleon

Chameleon Svn Source Tree

Root/branches/ErmaC/Enoch/i386/libsaio/load.c

1/*
2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 2.0 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 *
22 * load.c - Functions for decoding a Mach-o Kernel.
23 *
24 * Copyright (c) 1998-2003 Apple Computer, Inc.
25 *
26 */
27
28#include <mach-o/fat.h>
29#include <mach-o/loader.h>
30#include <mach/machine/thread_status.h>
31
32#include <sl.h>
33#include "boot.h"
34#include "kernel_patcher_internal.h"
35
36#if DEBUG
37#define DBG(x...)printf(x)
38#else
39#define DBG(x...)msglog(x)
40#endif
41
42// Private functions.
43static long DecodeSegment(long cmdBase, unsigned int *load_addr, unsigned int *load_size, void *binary, u_int32_t uncompressed_size);
44static long DecodeUnixThread(long cmdBase, unsigned int *entry);
45static long DecodeSymbolTable(long cmdBase);
46
47
48static unsigned long gBinaryAddress;
49bool gHaveKernelCache;/* XXX aserebln: uninitialized? and only set to true, never to false */
50cpu_type_t archCpuType = CPU_TYPE_I386;
51
52bool incompatibleModuleLoaded = false;
53
54//==============================================================================
55// Public function.
56
57long ThinFatFile(void **binary, unsigned long *length)
58{
59unsigned long nfat, swapped, size = 0;
60struct fat_header *fhp = (struct fat_header *)*binary;
61struct fat_arch *fap = (struct fat_arch *)((unsigned long)*binary + sizeof(struct fat_header));
62cpu_type_t fapcputype;
63uint32_t fapoffset;
64uint32_t fapsize;
65
66if (fhp->magic == FAT_MAGIC)/* 0xcafebabe */
67{
68nfat = fhp->nfat_arch;
69swapped = 0;
70}
71else if (fhp->magic == FAT_CIGAM)/* 0xbebafeca */
72{
73nfat = OSSwapInt32(fhp->nfat_arch);
74swapped = 1;
75}
76else
77{
78return -1;
79}
80
81for (; nfat > 0; nfat--, fap++)
82{
83if (swapped)
84{
85fapcputype = OSSwapInt32(fap->cputype);
86fapoffset = OSSwapInt32(fap->offset);
87fapsize = OSSwapInt32(fap->size);
88}
89else
90{
91fapcputype = fap->cputype;
92fapoffset = fap->offset;
93fapsize = fap->size;
94}
95
96if (fapcputype == archCpuType)
97{
98*binary = (void *) ((unsigned long)*binary + fapoffset);
99size = fapsize;
100break;
101}
102}
103
104if (length != 0)
105{
106*length = size;
107}
108
109return 0;
110}
111
112
113//==============================================================================
114
115long DecodeMachO(void *binary, u_int32_t uncompressed_size, entry_t *rentry, char **raddr, int *rsize)
116{
117struct mach_header *mH;
118unsigned long ncmds, cmdBase, cmd, cmdsize, cmdstart;
119// long headerBase, headerAddr, headerSize;
120unsigned int vmaddr = ~0;
121unsigned int vmend = 0;
122unsigned long cnt;
123long ret = -1;
124unsigned int entry = 0;
125
126gBinaryAddress = (unsigned long)binary;
127
128mH = (struct mach_header *)(gBinaryAddress);
129
130/*#if DEBUG
131DBG("magic: 0x%x\n", (unsigned)mH->magic);
132DBG("cputype: 0x%x\n", (unsigned)mH->cputype);
133DBG("cpusubtype: 0x%x\n", (unsigned)mH->cpusubtype);
134DBG("filetype: 0x%x\n", (unsigned)mH->filetype);
135DBG("ncmds: 0x%x\n", (unsigned)mH->ncmds);
136DBG("sizeofcmds: 0x%x\n", (unsigned)mH->sizeofcmds);
137DBG("flags: 0x%x\n", (unsigned)mH->flags);
138DBG("archCpuType: 0x%x\n", archCpuType);
139//getchar();
140#endif*/
141
142switch (archCpuType)
143{
144case CPU_TYPE_I386:
145
146if (mH->magic != MH_MAGIC)
147{
148error("Mach-O (i386) file has bad magic number\n");
149return -1;
150}
151
152cmdstart = (unsigned long)gBinaryAddress + sizeof(struct mach_header);
153break;
154
155case CPU_TYPE_X86_64:
156/*
157if (mH->magic != MH_MAGIC_64 && mH->magic == MH_MAGIC)
158{
159return -1;
160}
161*/
162if (mH->magic != MH_MAGIC_64)
163{
164error("Mach-O file (x86_64) has bad magic number\n");
165return -1;
166}
167
168cmdstart = (unsigned long)gBinaryAddress + sizeof(struct mach_header_64);
169break;
170
171default:
172
173error("Unknown CPU type\n");
174return -1;
175}
176
177if (skipKernelPatcher)
178{
179verbose("\nInternal kernel patcher skipped as requested\n\n");
180}
181else
182{
183
184if( is_module_loaded("KernelPatcher.dylib"))
185{
186verbose("\nKernelPatcher.dylib prevent the internal kernel/kexts Patcher, skipped!\n\n");
187incompatibleModuleLoaded = true;
188}
189else
190{
191// call the kernel patcher main function
192/*
193if (( KernelBooter_kexts ||
194KernelPm ||
195KernelLapicError ||
196KernelLapicVersion ||
197KernelHaswell ||
198KernelcpuFamily ||
199KernelSSE3 ) &&
200(MacOSVerCurrent >= MacOSVer2Int("10.6"))
201)
202{
203patch_kernel_internal(binary, uncompressed_size);
204}
205*/
206
207// since users can done their own patches, just ensure for the minimum OS version
208// w/o dependencies from other patches (e.g KernelBooter_kexts)
209if (MacOSVerCurrent >= MacOSVer2Int("10.6"))
210{
211patch_kernel_internal(binary, uncompressed_size);
212}
213}
214}
215
216cmdBase = cmdstart;
217ncmds = mH->ncmds;
218
219for (cnt = 0; cnt < ncmds; cnt++)
220{
221cmd = ((long *)cmdBase)[0];
222cmdsize = ((long *)cmdBase)[1];
223unsigned int load_addr;
224unsigned int load_size;
225
226switch (cmd)
227{
228case LC_SEGMENT:
229case LC_SEGMENT_64:
230ret = DecodeSegment(cmdBase, &load_addr, &load_size, binary, uncompressed_size);
231
232if (ret == 0 && load_size != 0 && load_addr >= KERNEL_ADDR)
233{
234vmaddr = MIN(vmaddr, load_addr);
235vmend = MAX(vmend, load_addr + load_size);
236}
237break;
238
239case LC_MAIN:/* Mountain Lion's replacement for LC_UNIXTHREAD */
240case LC_UNIXTHREAD:
241ret = DecodeUnixThread(cmdBase, &entry);
242break;
243
244case LC_SYMTAB:
245break;
246
247default:
248#if NOTDEF
249printf("Ignoring cmd type %d.\n", (unsigned)cmd);
250#endif
251break;
252}
253
254if (ret != 0)
255{
256return -1;
257}
258
259cmdBase += cmdsize;
260}
261
262*rentry = (entry_t)( (unsigned long) entry & 0x3fffffff );
263*rsize = vmend - vmaddr;
264*raddr = (char *)vmaddr;
265
266cmdBase = cmdstart;
267
268for (cnt = 0; cnt < ncmds; cnt++)
269{
270cmd = ((long *)cmdBase)[0];
271cmdsize = ((long *)cmdBase)[1];
272
273if (cmd == LC_SYMTAB)
274{
275if (DecodeSymbolTable(cmdBase) != 0)
276{
277return -1;
278}
279}
280
281cmdBase += cmdsize;
282}
283
284return ret;
285}
286
287
288//==============================================================================
289// Private function.
290
291static long DecodeSegment(long cmdBase, unsigned int *load_addr, unsigned int *load_size, void *binary, u_int32_t uncompressed_size)
292{
293char *segname;
294long vmsize, filesize;
295unsigned long vmaddr, fileoff, fileaddr;
296
297if (((long *)cmdBase)[0] == LC_SEGMENT_64)
298{
299struct segment_command_64 *segCmd;
300segCmd = (struct segment_command_64 *)cmdBase;
301vmaddr = (segCmd->vmaddr & 0x3fffffff);
302vmsize = segCmd->vmsize;
303fileoff = segCmd->fileoff;
304fileaddr = (gBinaryAddress + segCmd->fileoff);
305filesize = segCmd->filesize;
306segname = (char *)segCmd->segname;
307
308#ifdef DEBUG
309printf("segname: %s, vmaddr: %x, vmsize: %x, fileoff: %x, fileaddr: %x, filesize: %x, nsects: %d, flags: %x.\n",
310segCmd->segname, (unsigned)vmaddr, (unsigned)vmsize, segCmd->fileoff, (unsigned)fileaddr, (unsigned)filesize,
311(unsigned) segCmd->nsects, (unsigned)segCmd->flags);
312getchar();
313#endif
314}
315else
316{
317struct segment_command *segCmd;
318
319segCmd = (struct segment_command *)cmdBase;
320
321vmaddr = (segCmd->vmaddr & 0x3fffffff);
322vmsize = segCmd->vmsize;
323fileoff = segCmd->fileoff;
324fileaddr = (gBinaryAddress + segCmd->fileoff);
325filesize = segCmd->filesize;
326segname = (char *)segCmd->segname;
327
328#ifdef DEBUG
329printf("segname: %s, vmaddr: %x, vmsize: %x, fileoff: %x, fileaddr: %x, filesize: %x, nsects: %d, flags: %x.\n",
330segCmd->segname, (unsigned)vmaddr, (unsigned)vmsize, segCmd->fileoff, (unsigned)fileaddr, (unsigned)filesize,
331(unsigned) segCmd->nsects, (unsigned)segCmd->flags);
332getchar();
333#endif
334}
335
336// patching prelinked kexts
337if (!strcmp(segname, "__PRELINK_TEXT") && !incompatibleModuleLoaded)
338{
339if (!skipKextsPatcher)
340{
341if (vmaddr && fileoff)
342{
343patch_prelinked_kexts(binary,
344uncompressed_size,
345vmaddr,
346fileoff);
347}
348}
349else
350{
351verbose("\nInternal kexts patcher skipped as requested\n\n");
352}
353}
354//===================================================
355
356if (vmsize == 0 || filesize == 0)
357{
358*load_addr = ~0;
359*load_size = 0;
360return 0;
361}
362
363if (! ((vmaddr >= KERNEL_ADDR && (vmaddr + vmsize) <= (KERNEL_ADDR + KERNEL_LEN)) ||
364 (vmaddr >= HIB_ADDR && (vmaddr + vmsize) <= (HIB_ADDR + HIB_LEN))))
365{
366stop("Kernel overflows available space");
367}
368
369if (vmsize && ((strncmp(segname, "__PRELINK_INFO", sizeof("__PRELINK_INFO")) == 0) || (strncmp(segname, "__PRELINK", sizeof("__PRELINK")) == 0)))
370{
371gHaveKernelCache = true;
372}
373
374// Copy from file load area.
375if (vmsize>0 && filesize > 0)
376{
377bcopy((char *)fileaddr, (char *)vmaddr, vmsize > filesize ? filesize : vmsize);
378}
379
380// Zero space at the end of the segment.
381if (vmsize > filesize)
382{
383bzero((char *)(vmaddr + filesize), vmsize - filesize);
384}
385
386*load_addr = vmaddr;
387*load_size = vmsize;
388
389return 0;
390}
391
392//==============================================================================
393
394static long DecodeUnixThread(long cmdBase, unsigned int *entry)
395{
396switch (archCpuType)
397{
398case CPU_TYPE_I386:
399{
400i386_thread_state_t *i386ThreadState;
401i386ThreadState = (i386_thread_state_t *) (cmdBase + sizeof(struct thread_command) + 8);
402
403*entry = i386ThreadState->eip;
404return 0;
405}
406
407case CPU_TYPE_X86_64:
408{
409x86_thread_state64_t *x86_64ThreadState;
410x86_64ThreadState = (x86_thread_state64_t *) (cmdBase + sizeof(struct thread_command) + 8);
411*entry = x86_64ThreadState->rip;
412return 0;
413}
414
415default:
416error("Unknown CPU type\n");
417return -1;
418}
419}
420
421
422//==============================================================================
423
424static long DecodeSymbolTable(long cmdBase)
425{
426long tmpAddr, symsSize, totalSize;
427long gSymbolTableAddr;
428long gSymbolTableSize;
429
430struct symtab_command *symTab, *symTableSave;
431
432symTab = (struct symtab_command *)cmdBase;
433
434#if DEBUG
435printf("symoff: %x, nsyms: %x, stroff: %x, strsize: %x\n",
436symTab->symoff, symTab->nsyms, symTab->stroff, symTab->strsize);
437getchar();
438#endif
439
440symsSize = symTab->stroff - symTab->symoff;
441totalSize = symsSize + symTab->strsize;
442
443gSymbolTableSize = totalSize + sizeof(struct symtab_command);
444gSymbolTableAddr = AllocateKernelMemory(gSymbolTableSize);
445// Add the SymTab to the memory-map.
446AllocateMemoryRange("Kernel-__SYMTAB", gSymbolTableAddr, gSymbolTableSize, -1);
447
448symTableSave = (struct symtab_command *)gSymbolTableAddr;
449tmpAddr = gSymbolTableAddr + sizeof(struct symtab_command);
450
451symTableSave->symoff = tmpAddr;
452symTableSave->nsyms = symTab->nsyms;
453symTableSave->stroff = tmpAddr + symsSize;
454symTableSave->strsize = symTab->strsize;
455
456bcopy((char *)(gBinaryAddress + symTab->symoff), (char *)tmpAddr, totalSize);
457
458return 0;
459}
460

Archive Download this file

Revision: HEAD