]> git.saurik.com Git - apple/boot.git/blob - i386/libsaio/load.c
77e6ad0a7f909a309a4c734adc34eb7eb4bed5e6
[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 "rcz_common.h"
31 #include "rcz_decompress_file.h"
32 #include <mach-o/fat.h>
33
34 static int devMajor[3] = { 6, 3, 1 }; // sd, hd, fd major dev #'s
35
36 static int xread(int fd, char * addr, int size);
37 static int loadmacho(struct mach_header * head, int dev, int io,
38 entry_t * rentry, char ** raddr, int * rsize,
39 int file_offset);
40
41 //==========================================================================
42 // Open a file for reading. If the file doesn't exist,
43 // try opening the compressed version.
44
45 #ifdef RCZ_COMPRESSED_FILE_SUPPORT
46 int openfile(const char * filename, int ignored)
47 {
48 unsigned char *buf;
49 int fd, size, ret;
50 unsigned char *addr;
51
52 if ((fd = open(filename, 0)) < 0) {
53 buf = malloc(256);
54 sprintf(buf, "%s%s", filename, RCZ_EXTENSION);
55 if ((fd = open(buf, 0)) >= 0) {
56 size = rcz_file_size(fd);
57 addr = (unsigned char *)((KERNEL_ADDR + KERNEL_LEN) - size);
58 ret = rcz_decompress_file(fd, addr);
59 close(fd);
60 if (ret < 0)
61 fd = -1;
62 else
63 fd = openmem(addr, size);
64 }
65 free(buf);
66 }
67 return fd;
68 }
69 #else
70 int openfile(char * filename, int ignored)
71 {
72 return open(filename, 0);
73 }
74 #endif
75
76 //==========================================================================
77 // loadprog
78
79 int loadprog( int dev, int fd, struct mach_header * headOut,
80 entry_t * entry, /* entry point */
81 char ** addr, /* load address */
82 int * size ) /* size of loaded program */
83 {
84 struct mach_header head;
85 int file_offset = 0;
86
87 read_again:
88
89 /* get file header */
90 read(fd, (char *) &head, sizeof(head));
91
92 if ( headOut )
93 bcopy((char *) &head, (char *) headOut, sizeof(head));
94
95 if ( head.magic == MH_MAGIC )
96 {
97 return loadmacho(&head, dev, fd, entry, addr, size, file_offset);
98 }
99 else if ( file_offset == 0 &&
100 ((head.magic == FAT_CIGAM) || (head.magic == FAT_MAGIC)) )
101 {
102 int swap = (head.magic == FAT_CIGAM) ? 1 : 0;
103 struct fat_header * fhp = (struct fat_header *) &head;
104 struct fat_arch * fap;
105 int i, narch = swap ? NXSwapLong(fhp->nfat_arch) : fhp->nfat_arch;
106 int cpu, size;
107 char * buf;
108
109 size = sizeof(struct fat_arch) * narch;
110 buf = malloc(size);
111 b_lseek(fd, 0, 0);
112 read(fd, buf, size);
113
114 for ( i = 0, fap = (struct fat_arch *)(buf+sizeof(struct fat_header));
115 i < narch;
116 i++, fap++ )
117 {
118 cpu = swap ? NXSwapLong(fap->cputype) : fap->cputype;
119 if (cpu == CPU_TYPE_I386)
120 {
121 /* that's specific enough */
122 free(buf);
123 file_offset = swap ? NXSwapLong(fap->offset) : fap->offset;
124 b_lseek(fd, file_offset, 0);
125 goto read_again;
126 }
127 }
128 free(buf);
129 error("Fat binary file doesn't contain i386 code\n");
130 return -1;
131 }
132 error("Unrecognized binary format: %08x\n", head.magic);
133 return -1;
134 }
135
136 //==========================================================================
137 // xread
138 //
139 // Read from file descriptor. addr is a physical address.
140
141 static int xread( int fd, char * addr, int size )
142 {
143 char * orgaddr = addr;
144 long offset;
145 unsigned count;
146 long max;
147 #define BUFSIZ 8192
148 char * buf;
149 int bufsize = BUFSIZ;
150
151 #if 0
152 printf("xread: addr=%x, size=%x\n", addr, size);
153 sleep(1);
154 #endif
155
156 buf = malloc(BUFSIZ);
157
158 // align your read to increase speed
159 offset = tell(fd) & 4095;
160 if ( offset != 0 )
161 max = 4096 - offset;
162 else
163 max = bufsize;
164
165 while ( size > 0 )
166 {
167 if ( size > max ) count = max;
168 else count = size;
169 #if 0
170 printf("xread: loop size=%x, count=%x\n", size, count);
171 sleep(1);
172 #endif
173
174 if ( read(fd, buf, count) != count) break;
175
176 bcopy(buf, ptov(addr), count);
177 size -= count;
178 addr += count;
179
180 max = bufsize;
181
182 #if 0
183 tick += count;
184 if ( tick > (50*1024) )
185 {
186 putchar('+');
187 tick = 0;
188 }
189 #endif
190 }
191
192 free(buf);
193 return addr-orgaddr;
194 }
195
196 //==========================================================================
197 // loadmacho
198
199 static int loadmacho( struct mach_header * head, int dev, int io,
200 entry_t * rentry, char ** raddr, int * rsize,
201 int file_offset )
202 {
203 int ncmds;
204 void * cmds;
205 void * cp;
206 unsigned int entry = 0;
207 int vmsize = 0;
208 unsigned int vmaddr = ~0;
209 unsigned int vmend = 0;
210
211 struct xxx_thread_command {
212 unsigned long cmd;
213 unsigned long cmdsize;
214 unsigned long flavor;
215 unsigned long count;
216 i386_thread_state_t state;
217 } * th;
218
219 // XXX should check cputype
220 cmds = malloc(head->sizeofcmds);
221 b_lseek(io, sizeof(struct mach_header) + file_offset, 0);
222
223 if ( read(io, (char *) cmds, head->sizeofcmds) != head->sizeofcmds )
224 {
225 error("loadmacho: error reading commands\n");
226 goto shread;
227 }
228
229 for ( ncmds = head->ncmds, cp = cmds; ncmds > 0; ncmds-- )
230 {
231 unsigned int addr;
232
233 #define lcp ((struct load_command *) cp)
234 #define scp ((struct segment_command *) cp)
235
236 switch ( lcp->cmd )
237 {
238 case LC_SEGMENT:
239 addr = (scp->vmaddr & 0x3fffffff) + (int)*raddr;
240 if ( scp->filesize )
241 {
242 vmsize += scp->vmsize;
243 vmaddr = min(vmaddr, addr);
244 vmend = max(vmend, addr + scp->vmsize);
245
246 // Zero any space at the end of the segment.
247
248 bzero((char *)(addr + scp->filesize),
249 scp->vmsize - scp->filesize);
250
251 // FIXME: check to see if we overflow
252 // the available space (should be passed in
253 // as the size argument).
254
255 #if 0
256 printf("LC: fileoff %x, filesize %x, off %x, addr %x\n",
257 scp->fileoff, scp->filesize, file_offset, addr);
258 sleep(1);
259 #endif
260
261 b_lseek(io, scp->fileoff + file_offset, 0);
262 if ( xread(io, (char *)addr, scp->filesize)
263 != scp->filesize)
264 {
265 error("loadmacho: error loading section\n");
266 goto shread;
267 }
268 }
269 break;
270
271 case LC_THREAD:
272 case LC_UNIXTHREAD:
273 th = (struct xxx_thread_command *) cp;
274 entry = th->state.eip;
275 break;
276 }
277 cp += lcp->cmdsize;
278 }
279
280 kernBootStruct->rootdev = (dev & 0xffffff00) | devMajor[B_TYPE(dev)];
281
282 free(cmds);
283
284 *rentry = (entry_t)( (int) entry & 0x3fffffff );
285 *rsize = vmend - vmaddr;
286 *raddr = (char *)vmaddr;
287
288 return 0;
289
290 shread:
291 free(cmds);
292 return -1;
293 }