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//===================================================
337
338if (vmsize == 0 || filesize == 0)
339{
340*load_addr = ~0;
341*load_size = 0;
342return 0;
343}
344
345if (! ((vmaddr >= KERNEL_ADDR && (vmaddr + vmsize) <= (KERNEL_ADDR + KERNEL_LEN)) ||
346 (vmaddr >= HIB_ADDR && (vmaddr + vmsize) <= (HIB_ADDR + HIB_LEN))))
347{
348stop("Kernel overflows available space");
349}
350
351if (vmsize && ((strncmp(segname, "__PRELINK_INFO", sizeof("__PRELINK_INFO")) == 0) || (strncmp(segname, "__PRELINK", sizeof("__PRELINK")) == 0)))
352{
353gHaveKernelCache = true;
354}
355
356// Copy from file load area.
357if (vmsize>0 && filesize > 0)
358{
359bcopy((char *)fileaddr, (char *)vmaddr, vmsize > filesize ? filesize : vmsize);
360}
361
362// Zero space at the end of the segment.
363if (vmsize > filesize)
364{
365bzero((char *)(vmaddr + filesize), vmsize - filesize);
366}
367
368*load_addr = vmaddr;
369*load_size = vmsize;
370
371return 0;
372}
373
374//==============================================================================
375
376static long DecodeUnixThread(long cmdBase, unsigned int *entry)
377{
378switch (archCpuType)
379{
380case CPU_TYPE_I386:
381{
382i386_thread_state_t *i386ThreadState;
383i386ThreadState = (i386_thread_state_t *) (cmdBase + sizeof(struct thread_command) + 8);
384
385*entry = i386ThreadState->eip;
386return 0;
387}
388
389case CPU_TYPE_X86_64:
390{
391x86_thread_state64_t *x86_64ThreadState;
392x86_64ThreadState = (x86_thread_state64_t *) (cmdBase + sizeof(struct thread_command) + 8);
393*entry = x86_64ThreadState->rip;
394return 0;
395}
396
397default:
398error("Unknown CPU type\n");
399return -1;
400}
401}
402
403
404//==============================================================================
405
406static long DecodeSymbolTable(long cmdBase)
407{
408long tmpAddr, symsSize, totalSize;
409long gSymbolTableAddr;
410long gSymbolTableSize;
411
412struct symtab_command *symTab, *symTableSave;
413
414symTab = (struct symtab_command *)cmdBase;
415
416#if DEBUG
417printf("symoff: %x, nsyms: %x, stroff: %x, strsize: %x\n",
418symTab->symoff, symTab->nsyms, symTab->stroff, symTab->strsize);
419getchar();
420#endif
421
422symsSize = symTab->stroff - symTab->symoff;
423totalSize = symsSize + symTab->strsize;
424
425gSymbolTableSize = totalSize + sizeof(struct symtab_command);
426gSymbolTableAddr = AllocateKernelMemory(gSymbolTableSize);
427// Add the SymTab to the memory-map.
428AllocateMemoryRange("Kernel-__SYMTAB", gSymbolTableAddr, gSymbolTableSize, -1);
429
430symTableSave = (struct symtab_command *)gSymbolTableAddr;
431tmpAddr = gSymbolTableAddr + sizeof(struct symtab_command);
432
433symTableSave->symoff = tmpAddr;
434symTableSave->nsyms = symTab->nsyms;
435symTableSave->stroff = tmpAddr + symsSize;
436symTableSave->strsize = symTab->strsize;
437
438bcopy((char *)(gBinaryAddress + symTab->symoff), (char *)tmpAddr, totalSize);
439
440return 0;
441}
442

Archive Download this file

Revision: 2871