]> git.saurik.com Git - apple/boot.git/blob - i386/libsaio/load.c
ef3973415f6225288f5f5a3ff7bccb842cf17893
[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 return loadmacho(&head, dev, fd, entry, addr, size, file_offset);
100 }
101 else if ( file_offset == 0 &&
102 ((head.magic == FAT_CIGAM) || (head.magic == FAT_MAGIC)) )
103 {
104 int swap = (head.magic == FAT_CIGAM) ? 1 : 0;
105 struct fat_header * fhp = (struct fat_header *) &head;
106 struct fat_arch * fap;
107 int i, narch = swap ? NXSwapLong(fhp->nfat_arch) : fhp->nfat_arch;
108 int cpu, size;
109 char * buf;
110
111 size = sizeof(struct fat_arch) * narch;
112 buf = malloc(size);
113 b_lseek(fd, 0, 0);
114 read(fd, buf, size);
115
116 for ( i = 0, fap = (struct fat_arch *)(buf+sizeof(struct fat_header));
117 i < narch;
118 i++, fap++ )
119 {
120 cpu = swap ? NXSwapLong(fap->cputype) : fap->cputype;
121 if (cpu == CPU_TYPE_I386)
122 {
123 /* that's specific enough */
124 free(buf);
125 file_offset = swap ? NXSwapLong(fap->offset) : fap->offset;
126 b_lseek(fd, file_offset, 0);
127 goto read_again;
128 }
129 }
130 free(buf);
131 error("Fat binary file doesn't contain i386 code\n");
132 return -1;
133 }
134 error("Unrecognized binary format: %08x\n", head.magic);
135 return -1;
136 }
137
138 //==========================================================================
139 // xread
140 //
141 // Read from file descriptor. addr is a physical address.
142
143 int xread( int fd,
144 char * addr,
145 int size )
146 {
147 char * orgaddr = addr;
148 long offset;
149 unsigned count;
150 long max;
151 #define BUFSIZ 8192
152 char * buf;
153 int bufsize = BUFSIZ;
154
155 #if 0
156 printf("xread: addr=%x, size=%x\n", addr, size);
157 sleep(1);
158 #endif
159
160 buf = malloc(BUFSIZ);
161
162 // align your read to increase speed
163 offset = tell(fd) & 4095;
164 if ( offset != 0 )
165 max = 4096 - offset;
166 else
167 max = bufsize;
168
169 while ( size > 0 )
170 {
171 if ( size > max ) count = max;
172 else count = size;
173 #if 0
174 printf("xread: loop size=%x, count=%x\n", size, count);
175 sleep(1);
176 #endif
177
178 if ( read(fd, buf, count) != count) break;
179
180 bcopy(buf, ptov(addr), count);
181 size -= count;
182 addr += count;
183
184 max = bufsize;
185
186 #if 0
187 tick += count;
188 if ( tick > (50*1024) )
189 {
190 putchar('+');
191 tick = 0;
192 }
193 #endif
194 }
195
196 free(buf);
197 return addr-orgaddr;
198 }
199
200 //==========================================================================
201 // loadmacho
202
203 int
204 loadmacho( struct mach_header * head,
205 int dev,
206 int io,
207 entry_t * rentry,
208 char ** raddr,
209 int * rsize,
210 int file_offset )
211 {
212 int ncmds;
213 void * cmds;
214 void * cp;
215 unsigned int entry = 0;
216 int vmsize = 0;
217 unsigned int vmaddr = ~0;
218 unsigned int vmend = 0;
219
220 struct xxx_thread_command {
221 unsigned long cmd;
222 unsigned long cmdsize;
223 unsigned long flavor;
224 unsigned long count;
225 i386_thread_state_t state;
226 } * th;
227
228 // XXX should check cputype
229 cmds = malloc(head->sizeofcmds);
230 b_lseek(io, sizeof(struct mach_header) + file_offset, 0);
231
232 if ( read(io, (char *) cmds, head->sizeofcmds) != head->sizeofcmds )
233 {
234 error("loadmacho: error reading commands\n");
235 goto shread;
236 }
237
238 for ( ncmds = head->ncmds, cp = cmds; ncmds > 0; ncmds-- )
239 {
240 unsigned int addr;
241
242 #define lcp ((struct load_command *) cp)
243 #define scp ((struct segment_command *) cp)
244
245 switch ( lcp->cmd )
246 {
247 case LC_SEGMENT:
248 addr = (scp->vmaddr & 0x3fffffff) + (int)*raddr;
249 if ( scp->filesize )
250 {
251 vmsize += scp->vmsize;
252 vmaddr = min(vmaddr, addr);
253 vmend = max(vmend, addr + scp->vmsize);
254
255 // Zero any space at the end of the segment.
256
257 bzero((char *)(addr + scp->filesize),
258 scp->vmsize - scp->filesize);
259
260 // FIXME: check to see if we overflow
261 // the available space (should be passed in
262 // as the size argument).
263
264 #if 0
265 printf("LC: fileoff %x, filesize %x, off %x, addr %x\n",
266 scp->fileoff, scp->filesize, file_offset, addr);
267 sleep(1);
268 #endif
269
270 b_lseek(io, scp->fileoff + file_offset, 0);
271 if ( xread(io, (char *)addr, scp->filesize)
272 != scp->filesize)
273 {
274 error("loadmacho: error loading section\n");
275 goto shread;
276 }
277 }
278 break;
279
280 case LC_THREAD:
281 case LC_UNIXTHREAD:
282 th = (struct xxx_thread_command *) cp;
283 entry = th->state.eip;
284 break;
285 }
286 cp += lcp->cmdsize;
287 }
288
289 kernBootStruct->rootdev = (dev & 0xffffff00) | devMajor[Dev(dev)];
290
291 free(cmds);
292
293 *rentry = (entry_t)( (int) entry & 0x3fffffff );
294 *rsize = vmend - vmaddr;
295 *raddr = (char *)vmaddr;
296
297 return 0;
298
299 shread:
300 free(cmds);
301 return -1;
302 }