]> git.saurik.com Git - apple/boot.git/blob - i386/libsaio/load.c
a5be78083b047b6bd59c819d0d67c3ef7384b08e
[apple/boot.git] / i386 / libsaio / load.c
1 /*
2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /*
26 * load.c - Functions for decoding a Mach-o Kernel.
27 *
28 * Copyright (c) 1998-2003 Apple Computer, Inc.
29 *
30 */
31
32 #include <mach-o/fat.h>
33 #include <mach-o/loader.h>
34 #include <mach/machine/thread_status.h>
35
36 #include <sl.h>
37
38 static long DecodeSegment(long cmdBase, unsigned int*load_addr, unsigned int *load_size);
39 static long DecodeUnixThread(long cmdBase, unsigned int *entry);
40
41
42 static unsigned long gBinaryAddress;
43 BOOL gHaveKernelCache;
44
45 // Public Functions
46
47 long ThinFatFile(void **binary, unsigned long *length)
48 {
49 unsigned long nfat, swapped, size = 0;
50 struct fat_header *fhp = (struct fat_header *)*binary;
51 struct fat_arch *fap =
52 (struct fat_arch *)((unsigned long)*binary + sizeof(struct fat_header));
53
54 if (fhp->magic == FAT_MAGIC) {
55 nfat = fhp->nfat_arch;
56 swapped = 0;
57 } else if (fhp->magic == FAT_CIGAM) {
58 nfat = NXSwapInt(fhp->nfat_arch);
59 swapped = 1;
60 } else {
61 return -1;
62 }
63
64 for (; nfat > 0; nfat--, fap++) {
65 if (swapped) {
66 fap->cputype = NXSwapInt(fap->cputype);
67 fap->offset = NXSwapInt(fap->offset);
68 fap->size = NXSwapInt(fap->size);
69 }
70
71 if (fap->cputype == CPU_TYPE_I386) {
72 *binary = (void *) ((unsigned long)*binary + fap->offset);
73 size = fap->size;
74 break;
75 }
76 }
77
78 if (length != 0) *length = size;
79
80 return 0;
81 }
82
83 long DecodeMachO(void *binary, entry_t *rentry, char **raddr, int *rsize)
84 {
85 struct mach_header *mH;
86 unsigned long ncmds, cmdBase, cmd, cmdsize;
87 // long headerBase, headerAddr, headerSize;
88 unsigned int vmaddr = ~0;
89 unsigned int vmend = 0;
90 unsigned long cnt;
91 long ret = -1;
92 unsigned int entry;
93
94 gBinaryAddress = (unsigned long)binary;
95
96 // headerBase = gBinaryAddress;
97 cmdBase = (unsigned long)gBinaryAddress + sizeof(struct mach_header);
98
99 mH = (struct mach_header *)(gBinaryAddress);
100 if (mH->magic != MH_MAGIC) {
101 error("Mach-O file has bad magic number\n");
102 return -1;
103 }
104
105 #if NOTDEF
106 printf("magic: %x\n", (unsigned)mH->magic);
107 printf("cputype: %x\n", (unsigned)mH->cputype);
108 printf("cpusubtype: %x\n", (unsigned)mH->cpusubtype);
109 printf("filetype: %x\n", (unsigned)mH->filetype);
110 printf("ncmds: %x\n", (unsigned)mH->ncmds);
111 printf("sizeofcmds: %x\n", (unsigned)mH->sizeofcmds);
112 printf("flags: %x\n", (unsigned)mH->flags);
113 getc();
114 #endif
115
116 ncmds = mH->ncmds;
117
118 for (cnt = 0; cnt < ncmds; cnt++) {
119 cmd = ((long *)cmdBase)[0];
120 cmdsize = ((long *)cmdBase)[1];
121 unsigned int load_addr;
122 unsigned int load_size;
123
124 switch (cmd) {
125
126 case LC_SEGMENT:
127 ret = DecodeSegment(cmdBase, &load_addr, &load_size);
128 if (ret == 0 && load_size != 0) {
129 vmaddr = min(vmaddr, load_addr);
130 vmend = max(vmend, load_addr + load_size);
131 }
132 break;
133
134 case LC_UNIXTHREAD:
135 ret = DecodeUnixThread(cmdBase, &entry);
136 break;
137
138 default:
139 #if NOTDEF
140 printf("Ignoring cmd type %d.\n", (unsigned)cmd);
141 #endif
142 break;
143 }
144
145 if (ret != 0) return -1;
146
147 cmdBase += cmdsize;
148 }
149
150 *rentry = (entry_t)( (unsigned long) entry & 0x3fffffff );
151 *rsize = vmend - vmaddr;
152 *raddr = (char *)vmaddr;
153
154 return ret;
155 }
156
157 // Private Functions
158
159 static long DecodeSegment(long cmdBase, unsigned int *load_addr, unsigned int *load_size)
160 {
161 struct segment_command *segCmd;
162 unsigned long vmaddr, fileaddr;
163 long vmsize, filesize;
164
165 segCmd = (struct segment_command *)cmdBase;
166
167 vmaddr = (segCmd->vmaddr & 0x3fffffff);
168 vmsize = segCmd->vmsize;
169
170 fileaddr = (gBinaryAddress + segCmd->fileoff);
171 filesize = segCmd->filesize;
172
173 if (filesize == 0) {
174 *load_addr = ~0;
175 *load_size = 0;
176 return 0;
177 }
178
179 #if NOTDEF
180 printf("segname: %s, vmaddr: %x, vmsize: %x, fileoff: %x, filesize: %x, nsects: %d, flags: %x.\n",
181 segCmd->segname, (unsigned)vmaddr, (unsigned)vmsize, (unsigned)fileaddr, (unsigned)filesize,
182 (unsigned) segCmd->nsects, (unsigned)segCmd->flags);
183 getc();
184 #endif
185
186 if (vmaddr < KERNEL_ADDR ||
187 (vmaddr + vmsize) > (KERNEL_ADDR + KERNEL_LEN)) {
188 stop("Kernel overflows available space");
189 }
190
191 if (vmsize && (strcmp(segCmd->segname, "__PRELINK") == 0)) {
192 gHaveKernelCache = 1;
193 }
194
195 // Copy from file load area.
196 bcopy((char *)fileaddr, (char *)vmaddr, filesize);
197
198 // Zero space at the end of the segment.
199 bzero((char *)(vmaddr + filesize), vmsize - filesize);
200
201 *load_addr = vmaddr;
202 *load_size = vmsize;
203
204 return 0;
205 }
206
207
208 static long DecodeUnixThread(long cmdBase, unsigned int *entry)
209 {
210 i386_thread_state_t *i386ThreadState;
211
212 i386ThreadState = (i386_thread_state_t *)
213 (cmdBase + sizeof(struct thread_command) + 8);
214
215 *entry = i386ThreadState->eip;
216
217 return 0;
218 }
219