]> git.saurik.com Git - apple/boot.git/blob - i386/libsaio/load.c
f12f7f80d303b3b565ddd6d6b96416e32a2772ec
[apple/boot.git] / i386 / libsaio / load.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.1 (the "License"). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24 /*
25 * Copyright 1993 NeXT Computer, Inc.
26 * All rights reserved.
27 */
28
29 #include "libsaio.h"
30 #include "memory.h"
31 #include "kernBootStruct.h"
32 #include "rcz_common.h"
33 #include <ufs/ufs/dir.h>
34 #include <mach-o/fat.h>
35
36 static int devMajor[3] = { 6, 3, 1 }; // sd, hd, fd major dev #'s
37
38 //==========================================================================
39 // Open a file for reading. If the file doesn't exist,
40 // try opening the compressed version.
41
42 #ifdef RCZ_COMPRESSED_FILE_SUPPORT
43 int
44 openfile(char *filename, int ignored)
45 {
46 unsigned char *buf;
47 int fd, size, ret;
48 unsigned char *addr;
49
50 if ((fd = open(filename, 0)) < 0) {
51 buf = malloc(256);
52 sprintf(buf, "%s%s", filename, RCZ_EXTENSION);
53 if ((fd = open(buf, 0)) >= 0) {
54 size = rcz_file_size(fd);
55 addr = (unsigned char *)((KERNEL_ADDR + KERNEL_LEN) - size);
56 ret = rcz_decompress_file(fd, addr);
57 close(fd);
58 if (ret < 0)
59 fd = -1;
60 else
61 fd = openmem(addr, size);
62 }
63 free(buf);
64 }
65 return fd;
66 }
67 #else
68 int
69 openfile(char *filename, int ignored)
70 {
71 return open(filename, 0);
72 }
73 #endif
74
75 //==========================================================================
76 // loadprog
77
78 int
79 loadprog( int dev,
80 int fd,
81 struct mach_header * headOut,
82 entry_t * entry, /* entry point */
83 char ** addr, /* load address */
84 int * size ) /* size of loaded program */
85 {
86 struct mach_header head;
87 int file_offset = 0;
88
89 read_again:
90
91 /* get file header */
92 read(fd, (char *) &head, sizeof(head));
93
94 if ( headOut )
95 bcopy((char *) &head, (char *) headOut, sizeof(head));
96
97 if ( head.magic == MH_MAGIC )
98 {
99 #if 0
100 printf("oneway fat binary found\n"); sleep(1);
101 #endif 1
102 return loadmacho(&head, dev, fd, entry, addr, size, file_offset);
103 }
104 else if ( file_offset == 0 &&
105 ((head.magic == FAT_CIGAM) || (head.magic == FAT_MAGIC)) )
106 {
107 int swap = (head.magic == FAT_CIGAM) ? 1 : 0;
108 struct fat_header * fhp = (struct fat_header *) &head;
109 struct fat_arch * fap;
110 int i, narch = swap ? NXSwapLong(fhp->nfat_arch) : fhp->nfat_arch;
111 int cpu, size;
112 char * buf;
113
114 size = sizeof(struct fat_arch) * narch;
115 buf = malloc(size);
116 b_lseek(fd, 0, 0);
117 read(fd, buf, size);
118
119 for ( i = 0, fap = (struct fat_arch *)(buf+sizeof(struct fat_header));
120 i < narch;
121 i++, fap++ )
122 {
123 cpu = swap ? NXSwapLong(fap->cputype) : fap->cputype;
124 if (cpu == CPU_TYPE_I386)
125 {
126 /* that's specific enough */
127 free(buf);
128 file_offset = swap ? NXSwapLong(fap->offset) : fap->offset;
129 b_lseek(fd, file_offset, 0);
130 goto read_again;
131 }
132 }
133 free(buf);
134 error("Fat binary file doesn't contain i386 code\n");
135 return -1;
136 }
137 error("Unrecognized binary format: %08x\n", head.magic);
138 return -1;
139 }
140
141 //==========================================================================
142 // xread
143 //
144 // Read from file descriptor. addr is a physical address.
145
146 int xread( int fd,
147 char * addr,
148 int size )
149 {
150 char * orgaddr = addr;
151 long offset;
152 unsigned count;
153 long max;
154 #define BUFSIZ 8192
155 char * buf;
156 int bufsize = BUFSIZ;
157
158 #if 0
159 printf("xread: addr=%x, size=%x\n", addr, size);
160 sleep(1);
161 #endif
162
163 buf = malloc(BUFSIZ);
164
165 // align your read to increase speed
166 offset = tell(fd) & 4095;
167 if ( offset != 0 )
168 max = 4096 - offset;
169 else
170 max = bufsize;
171
172 while ( size > 0 )
173 {
174 if ( size > max ) count = max;
175 else count = size;
176 #if 0
177 printf("xread: loop size=%x, count=%x\n", size, count);
178 sleep(1);
179 #endif
180
181 if ( read(fd, buf, count) != count) break;
182
183 bcopy(buf, ptov(addr), count);
184 size -= count;
185 addr += count;
186
187 max = bufsize;
188
189 #if 0
190 tick += count;
191 if ( tick > (50*1024) )
192 {
193 putchar('+');
194 tick = 0;
195 }
196 #endif
197 }
198
199 free(buf);
200 return addr-orgaddr;
201 }
202
203 //==========================================================================
204 // loadmacho
205
206 int
207 loadmacho(
208 struct mach_header * head,
209 int dev,
210 int io,
211 entry_t * rentry,
212 char ** raddr,
213 int * rsize,
214 int file_offset
215 )
216 {
217 int ncmds;
218 unsigned cmds, cp;
219 struct xxx_thread_command {
220 unsigned long cmd;
221 unsigned long cmdsize;
222 unsigned long flavor;
223 unsigned long count;
224 i386_thread_state_t state;
225 } *th;
226 unsigned int entry = 0;
227 int vmsize = 0;
228 unsigned int vmaddr = ~0;
229
230 // XXX should check cputype
231 cmds = (unsigned int) malloc(head->sizeofcmds);
232 b_lseek(io, sizeof (struct mach_header) + file_offset, 0);
233
234 if ( read(io, (char *) cmds, head->sizeofcmds) != head->sizeofcmds )
235 {
236 error("loadmacho: error reading commands\n");
237 goto shread;
238 }
239
240 for ( ncmds = head->ncmds, cp = cmds; ncmds > 0; ncmds-- )
241 {
242 unsigned int addr;
243
244 #define lcp ((struct load_command *) cp)
245 #define scp ((struct segment_command *) cp)
246
247 switch ( lcp->cmd )
248 {
249 case LC_SEGMENT:
250 addr = (scp->vmaddr & 0x3fffffff) + (int)*raddr;
251 if ( scp->filesize )
252 {
253 // Is this an OK assumption?
254 // if the filesize is zero, it doesn't
255 // take up any virtual space...
256 // (Hopefully this only excludes PAGEZERO.)
257 // Also, ignore linkedit segment when
258 // computing size, because we will erase
259 // the linkedit segment later.
260
261 if ( strncmp(scp->segname, SEG_LINKEDIT,
262 sizeof(scp->segname)) != 0)
263 vmsize += scp->vmsize;
264
265 vmaddr = min(vmaddr, addr);
266
267 // Zero any space at the end of the segment.
268 bzero((char *)(addr + scp->filesize),
269 scp->vmsize - scp->filesize);
270
271 // FIXME: check to see if we overflow
272 // the available space (should be passed in
273 // as the size argument).
274
275 #if 0
276 printf("LC_SEGMENT\n");
277 printf("LS;file_off %x; fos %x; fsize %x ; addr %x \n",
278 scp->fileoff, file_offset,scp->filesize, addr);
279 sleep(1);
280 #endif
281
282 b_lseek(io, scp->fileoff + file_offset, 0);
283 if ( xread(io, (char *)addr, scp->filesize)
284 != scp->filesize)
285 {
286 error("loadmacho: error loading section\n");
287 goto shread;
288 }
289 }
290 break;
291
292 case LC_THREAD:
293 case LC_UNIXTHREAD:
294 th = (struct xxx_thread_command *) cp;
295 entry = th->state.eip;
296 break;
297 }
298 cp += lcp->cmdsize;
299 }
300
301 kernBootStruct->rootdev = (dev & 0xffffff00) | devMajor[Dev(dev)];
302
303 free((char *) cmds);
304 *rentry = (entry_t)( (int) entry & 0x3fffffff );
305 *rsize = vmsize;
306 *raddr = (char *)vmaddr;
307
308 #if 0
309 printf("suceesful load;vmaddr=%x; vmsize=%x;entry=%x\n", vmaddr, vmsize,entry);
310 sleep(5);
311 #endif
312
313 return 0;
314
315 shread:
316 free((char *) cmds);
317 error("loadmacho: read error\n");
318 return -1;
319 }