]> git.saurik.com Git - apple/bootx.git/blob - bootx.tproj/sl.subproj/macho.c
BootX-81.tar.gz
[apple/bootx.git] / bootx.tproj / sl.subproj / macho.c
1 /*
2 * Copyright (c) 2000 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 1.1 (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 /*
23 * macho.c - Functions for decoding a Mach-o Kernel.
24 *
25 * Copyright (c) 1998-2003 Apple Computer, Inc.
26 *
27 * DRI: Josh de Cesare
28 */
29
30 #define __srr0 srr0 // so we can build in both (conformant/not) worlds
31 #include <mach-o/fat.h>
32 #include <mach-o/loader.h>
33 #include <mach/machine/thread_status.h>
34
35 #include <sl.h>
36
37 static long DecodeSegment(long cmdBase);
38 static long DecodeUnixThread(long cmdBase);
39 static long DecodeSymbolTable(long cmdBase);
40
41 static unsigned long gPPCAddress;
42
43 // Public Functions
44
45 long ThinFatBinaryMachO(void **binary, unsigned long *length)
46 {
47 unsigned long nfat, swapped, size = 0;
48 struct fat_header *fhp = (struct fat_header *)*binary;
49 struct fat_arch *fap =
50 (struct fat_arch *)((unsigned long)*binary + sizeof(struct fat_header));
51
52 if (fhp->magic == FAT_MAGIC) {
53 nfat = fhp->nfat_arch;
54 swapped = 0;
55 } else if (fhp->magic == FAT_CIGAM) {
56 nfat = NXSwapInt(fhp->nfat_arch);
57 swapped = 1;
58 } else {
59 return -1;
60 }
61
62 for (; nfat > 0; nfat--, fap++) {
63 if (swapped) {
64 fap->cputype = NXSwapInt(fap->cputype);
65 fap->offset = NXSwapInt(fap->offset);
66 fap->size = NXSwapInt(fap->size);
67 }
68
69 if (fap->cputype == CPU_TYPE_POWERPC) {
70 *binary = (void *) ((unsigned long)*binary + fap->offset);
71 size = fap->size;
72 break;
73 }
74 }
75
76 if (length != 0) *length = size;
77
78 return 0;
79 }
80
81 long DecodeMachO(void *binary)
82 {
83 struct mach_header *mH;
84 long ncmds, cmdBase, cmd, cmdsize, headerBase, headerAddr, headerSize;
85 long cnt, ret = 0;
86
87 gPPCAddress = (unsigned long)binary;
88
89 headerBase = gPPCAddress;
90 cmdBase = headerBase + sizeof(struct mach_header);
91
92 mH = (struct mach_header *)(headerBase);
93 if (mH->magic != MH_MAGIC) return -1;
94
95 #if 0
96 printf("magic: %x\n", mH->magic);
97 printf("cputype: %x\n", mH->cputype);
98 printf("cpusubtype: %x\n", mH->cpusubtype);
99 printf("filetype: %x\n", mH->filetype);
100 printf("ncmds: %x\n", mH->ncmds);
101 printf("sizeofcmds: %x\n", mH->sizeofcmds);
102 printf("flags: %x\n", mH->flags);
103 #endif
104
105 ncmds = mH->ncmds;
106
107 for (cnt = 0; cnt < ncmds; cnt++) {
108 cmd = ((long *)cmdBase)[0];
109 cmdsize = ((long *)cmdBase)[1];
110
111 switch (cmd) {
112
113 case LC_SEGMENT:
114 ret = DecodeSegment(cmdBase);
115 break;
116
117 case LC_UNIXTHREAD:
118 ret = DecodeUnixThread(cmdBase);
119 break;
120
121 case LC_SYMTAB:
122 ret = DecodeSymbolTable(cmdBase);
123 break;
124
125 default:
126 printf("Ignoring cmd type %d.\n", cmd);
127 break;
128 }
129
130 if (ret != 0) return -1;
131
132 cmdBase += cmdsize;
133 }
134
135 // Save the mach-o header.
136 headerSize = cmdBase - headerBase;
137 headerAddr = AllocateKernelMemory(headerSize);
138 bcopy((char *)headerBase, (char *)headerAddr, headerSize);
139
140 // Add the Mach-o header to the memory-map.
141 AllocateMemoryRange("Kernel-__HEADER", headerAddr, headerSize);
142
143 return ret;
144 }
145
146 // Private Functions
147
148 static long DecodeSegment(long cmdBase)
149 {
150 struct segment_command *segCmd;
151 char rangeName[32];
152 char *vmaddr, *fileaddr;
153 long vmsize, filesize;
154
155 segCmd = (struct segment_command *)cmdBase;
156
157 vmaddr = (char *)segCmd->vmaddr;
158 vmsize = segCmd->vmsize;
159
160 fileaddr = (char *)(gPPCAddress + segCmd->fileoff);
161 filesize = segCmd->filesize;
162
163 #if 0
164 printf("segname: %s, vmaddr: %x, vmsize: %x, fileoff: %x, filesize: %x, nsects: %d, flags: %x.\n",
165 segCmd->segname, vmaddr, vmsize, fileaddr, filesize,
166 segCmd->nsects, segCmd->flags);
167 #endif
168
169 // Add the Segment to the memory-map.
170 sprintf(rangeName, "Kernel-%s", segCmd->segname);
171 AllocateMemoryRange(rangeName, (long)vmaddr, vmsize);
172
173 if (vmsize && (strcmp(segCmd->segname, "__PRELINK") == 0))
174 gHaveKernelCache = 1;
175
176 // Handle special segments first.
177
178 // If it is the vectors, save them in their special place.
179 if ((strcmp(segCmd->segname, "__VECTORS") == 0) &&
180 ((long)vmaddr < (kVectorAddr + kVectorSize)) &&
181 (vmsize != 0) && (filesize != 0)) {
182
183 // Copy the first part into the save area.
184 bcopy(fileaddr, gVectorSaveAddr,
185 (filesize <= kVectorSize) ? filesize : kVectorSize);
186
187 // Copy the rest into memory.
188 if (filesize > kVectorSize)
189 bcopy(fileaddr + kVectorSize, (char *)kVectorSize,
190 filesize - kVectorSize);
191
192 return 0;
193 }
194
195 // It is nothing special, so do the usual. Only copy sections
196 // that have a filesize. Others are handle by the original bzero.
197 if (filesize != 0) {
198 bcopy(fileaddr, vmaddr, filesize);
199 }
200
201 // Adjust the last address used by the kernel
202 if ((long)vmaddr + vmsize > AllocateKernelMemory(0)) {
203 AllocateKernelMemory((long)vmaddr + vmsize - AllocateKernelMemory(0));
204 }
205
206 return 0;
207 }
208
209
210 static long DecodeUnixThread(long cmdBase)
211 {
212 ppc_thread_state_t *ppcThreadState;
213
214 // The PPC Thread State starts after the thread command stuct plus,
215 // 2 longs for the flaver an num longs.
216 ppcThreadState = (ppc_thread_state_t *)
217 (cmdBase + sizeof(struct thread_command) + 8);
218
219 gKernelEntryPoint = ppcThreadState->srr0;
220
221 #if 0
222 printf("gKernelEntryPoint = %x\n", gKernelEntryPoint);
223 #endif
224
225 return 0;
226 }
227
228
229 static long DecodeSymbolTable(long cmdBase)
230 {
231 struct symtab_command *symTab, *symTableSave;
232 long tmpAddr, symsSize, totalSize;
233
234 symTab = (struct symtab_command *)cmdBase;
235
236 #if 0
237 printf("symoff: %x, nsyms: %x, stroff: %x, strsize: %x\n",
238 symTab->symoff, symTab->nsyms, symTab->stroff, symTab->strsize);
239 #endif
240
241 symsSize = symTab->stroff - symTab->symoff;
242 totalSize = symsSize + symTab->strsize;
243
244 gSymbolTableSize = totalSize + sizeof(struct symtab_command);
245 gSymbolTableAddr = AllocateKernelMemory(gSymbolTableSize);
246
247 // Add the SymTab to the memory-map.
248 AllocateMemoryRange("Kernel-__SYMTAB", gSymbolTableAddr, gSymbolTableSize);
249
250 symTableSave = (struct symtab_command *)gSymbolTableAddr;
251 tmpAddr = gSymbolTableAddr + sizeof(struct symtab_command);
252
253 symTableSave->symoff = tmpAddr;
254 symTableSave->nsyms = symTab->nsyms;
255 symTableSave->stroff = tmpAddr + symsSize;
256 symTableSave->strsize = symTab->strsize;
257
258 bcopy((char *)(gPPCAddress + symTab->symoff),
259 (char *)tmpAddr, totalSize);
260
261 return 0;
262 }