Revision e80cfcfc hw/magic-load.c
b/hw/magic-load.c | ||
---|---|---|
1 | 1 |
#include "vl.h" |
2 | 2 |
#include "disas.h" |
3 |
#include "exec-all.h" |
|
4 |
|
|
5 |
struct exec |
|
6 |
{ |
|
7 |
uint32_t a_info; /* Use macros N_MAGIC, etc for access */ |
|
8 |
uint32_t a_text; /* length of text, in bytes */ |
|
9 |
uint32_t a_data; /* length of data, in bytes */ |
|
10 |
uint32_t a_bss; /* length of uninitialized data area, in bytes */ |
|
11 |
uint32_t a_syms; /* length of symbol table data in file, in bytes */ |
|
12 |
uint32_t a_entry; /* start address */ |
|
13 |
uint32_t a_trsize; /* length of relocation info for text, in bytes */ |
|
14 |
uint32_t a_drsize; /* length of relocation info for data, in bytes */ |
|
15 |
}; |
|
16 |
|
|
17 |
#ifdef BSWAP_NEEDED |
|
18 |
static void bswap_ahdr(struct exec *e) |
|
19 |
{ |
|
20 |
bswap32s(&e->a_info); |
|
21 |
bswap32s(&e->a_text); |
|
22 |
bswap32s(&e->a_data); |
|
23 |
bswap32s(&e->a_bss); |
|
24 |
bswap32s(&e->a_syms); |
|
25 |
bswap32s(&e->a_entry); |
|
26 |
bswap32s(&e->a_trsize); |
|
27 |
bswap32s(&e->a_drsize); |
|
28 |
} |
|
29 |
#else |
|
30 |
#define bswap_ahdr(x) do { } while (0) |
|
31 |
#endif |
|
32 |
|
|
33 |
#define N_MAGIC(exec) ((exec).a_info & 0xffff) |
|
34 |
#define OMAGIC 0407 |
|
35 |
#define NMAGIC 0410 |
|
36 |
#define ZMAGIC 0413 |
|
37 |
#define QMAGIC 0314 |
|
38 |
#define _N_HDROFF(x) (1024 - sizeof (struct exec)) |
|
39 |
#define N_TXTOFF(x) \ |
|
40 |
(N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) : \ |
|
41 |
(N_MAGIC(x) == QMAGIC ? 0 : sizeof (struct exec))) |
|
42 |
#define N_TXTADDR(x) (N_MAGIC(x) == QMAGIC ? TARGET_PAGE_SIZE : 0) |
|
43 |
#define N_DATOFF(x) (N_TXTOFF(x) + (x).a_text) |
|
44 |
#define _N_SEGMENT_ROUND(x) (((x) + TARGET_PAGE_SIZE - 1) & ~(TARGET_PAGE_SIZE - 1)) |
|
45 |
|
|
46 |
#define _N_TXTENDADDR(x) (N_TXTADDR(x)+(x).a_text) |
|
47 |
|
|
48 |
#define N_DATADDR(x) \ |
|
49 |
(N_MAGIC(x)==OMAGIC? (_N_TXTENDADDR(x)) \ |
|
50 |
: (_N_SEGMENT_ROUND (_N_TXTENDADDR(x)))) |
|
51 |
|
|
3 | 52 |
|
4 | 53 |
#define ELF_CLASS ELFCLASS32 |
5 | 54 |
#define ELF_DATA ELFDATA2MSB |
... | ... | |
103 | 152 |
return NULL; |
104 | 153 |
} |
105 | 154 |
|
106 |
static int find_strtab(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab)
|
|
155 |
static void *find_strtab(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab)
|
|
107 | 156 |
{ |
108 | 157 |
int retval; |
109 | 158 |
|
110 | 159 |
retval = lseek(fd, ehdr->e_shoff + sizeof(struct elf_shdr) * symtab->sh_link, SEEK_SET); |
111 | 160 |
if (retval < 0) |
112 |
return -1;
|
|
161 |
return NULL;
|
|
113 | 162 |
|
114 | 163 |
retval = read(fd, shdr, sizeof(*shdr)); |
115 | 164 |
if (retval < 0) |
116 |
return -1;
|
|
165 |
return NULL;
|
|
117 | 166 |
bswap_shdr(shdr); |
118 | 167 |
if (shdr->sh_type == SHT_STRTAB) |
119 | 168 |
return qemu_malloc(shdr->sh_size);; |
120 |
return 0;
|
|
169 |
return NULL;
|
|
121 | 170 |
} |
122 | 171 |
|
123 |
static int read_program(int fd, struct elf_phdr *phdr, void *dst) |
|
172 |
static int read_program(int fd, struct elf_phdr *phdr, void *dst, uint32_t entry)
|
|
124 | 173 |
{ |
125 | 174 |
int retval; |
126 |
retval = lseek(fd, 0x4000, SEEK_SET);
|
|
175 |
retval = lseek(fd, phdr->p_offset + entry - phdr->p_vaddr, SEEK_SET);
|
|
127 | 176 |
if (retval < 0) |
128 | 177 |
return -1; |
129 | 178 |
return read(fd, dst, phdr->p_filesz); |
... | ... | |
178 | 227 |
{ |
179 | 228 |
struct elf_shdr symtab, strtab; |
180 | 229 |
struct elf_sym *syms; |
230 |
struct syminfo *s; |
|
181 | 231 |
int nsyms, i; |
182 | 232 |
char *str; |
183 | 233 |
|
... | ... | |
196 | 246 |
goto error_freesyms; |
197 | 247 |
|
198 | 248 |
/* Commit */ |
199 |
if (disas_symtab) |
|
200 |
qemu_free(disas_symtab); /* XXX Merge with old symbols? */ |
|
201 |
if (disas_strtab) |
|
202 |
qemu_free(disas_strtab); |
|
203 |
disas_symtab = syms; |
|
204 |
disas_num_syms = nsyms; |
|
205 |
disas_strtab = str; |
|
249 |
s = qemu_mallocz(sizeof(*s)); |
|
250 |
s->disas_symtab = syms; |
|
251 |
s->disas_num_syms = nsyms; |
|
252 |
s->disas_strtab = str; |
|
253 |
s->next = syminfos; |
|
254 |
syminfos = s; |
|
206 | 255 |
return; |
207 | 256 |
error_freesyms: |
208 | 257 |
qemu_free(syms); |
209 | 258 |
return; |
210 | 259 |
} |
211 | 260 |
|
212 |
int load_elf(const char * filename, uint8_t *addr)
|
|
261 |
int load_elf(const char *filename, uint8_t *addr) |
|
213 | 262 |
{ |
214 | 263 |
struct elfhdr ehdr; |
215 | 264 |
struct elf_phdr phdr; |
... | ... | |
227 | 276 |
|
228 | 277 |
if (ehdr.e_ident[0] != 0x7f || ehdr.e_ident[1] != 'E' |
229 | 278 |
|| ehdr.e_ident[2] != 'L' || ehdr.e_ident[3] != 'F' |
230 |
|| ehdr.e_machine != EM_SPARC) |
|
279 |
|| (ehdr.e_machine != EM_SPARC |
|
280 |
&& ehdr.e_machine != EM_SPARC32PLUS)) |
|
231 | 281 |
goto error; |
232 | 282 |
|
233 | 283 |
if (find_phdr(&ehdr, fd, &phdr, PT_LOAD)) |
234 | 284 |
goto error; |
235 |
retval = read_program(fd, &phdr, addr); |
|
285 |
retval = read_program(fd, &phdr, addr, ehdr.e_entry);
|
|
236 | 286 |
if (retval < 0) |
237 | 287 |
goto error; |
238 | 288 |
|
... | ... | |
245 | 295 |
return -1; |
246 | 296 |
} |
247 | 297 |
|
248 |
int load_kernel(const char *filename, uint8_t *addr)
|
|
298 |
int load_aout(const char *filename, uint8_t *addr)
|
|
249 | 299 |
{ |
250 |
int fd, size; |
|
300 |
int fd, size, ret; |
|
301 |
struct exec e; |
|
302 |
uint32_t magic; |
|
251 | 303 |
|
252 | 304 |
fd = open(filename, O_RDONLY | O_BINARY); |
253 | 305 |
if (fd < 0) |
254 | 306 |
return -1; |
255 |
/* load 32 bit code */ |
|
256 |
size = read(fd, addr, 16 * 1024 * 1024);
|
|
307 |
|
|
308 |
size = read(fd, &e, sizeof(e));
|
|
257 | 309 |
if (size < 0) |
258 | 310 |
goto fail; |
311 |
|
|
312 |
bswap_ahdr(&e); |
|
313 |
|
|
314 |
magic = N_MAGIC(e); |
|
315 |
switch (magic) { |
|
316 |
case ZMAGIC: |
|
317 |
case QMAGIC: |
|
318 |
case OMAGIC: |
|
319 |
lseek(fd, N_TXTOFF(e), SEEK_SET); |
|
320 |
size = read(fd, addr, e.a_text + e.a_data); |
|
321 |
if (size < 0) |
|
322 |
goto fail; |
|
323 |
break; |
|
324 |
case NMAGIC: |
|
325 |
lseek(fd, N_TXTOFF(e), SEEK_SET); |
|
326 |
size = read(fd, addr, e.a_text); |
|
327 |
if (size < 0) |
|
328 |
goto fail; |
|
329 |
ret = read(fd, addr + N_DATADDR(e), e.a_data); |
|
330 |
if (ret < 0) |
|
331 |
goto fail; |
|
332 |
size += ret; |
|
333 |
break; |
|
334 |
default: |
|
335 |
goto fail; |
|
336 |
} |
|
259 | 337 |
close(fd); |
260 | 338 |
return size; |
261 | 339 |
fail: |
... | ... | |
263 | 341 |
return -1; |
264 | 342 |
} |
265 | 343 |
|
266 |
typedef struct MAGICState { |
|
267 |
uint32_t addr; |
|
268 |
uint32_t saved_addr; |
|
269 |
int magic_state; |
|
270 |
char saved_kfn[1024]; |
|
271 |
} MAGICState; |
|
272 |
|
|
273 |
static uint32_t magic_mem_readl(void *opaque, target_phys_addr_t addr) |
|
274 |
{ |
|
275 |
int ret; |
|
276 |
MAGICState *s = opaque; |
|
277 |
|
|
278 |
if (s->magic_state == 0) { |
|
279 |
ret = load_elf(s->saved_kfn, (uint8_t *)s->saved_addr); |
|
280 |
if (ret < 0) |
|
281 |
ret = load_kernel(s->saved_kfn, (uint8_t *)s->saved_addr); |
|
282 |
if (ret < 0) { |
|
283 |
fprintf(stderr, "qemu: could not load kernel '%s'\n", |
|
284 |
s->saved_kfn); |
|
285 |
} |
|
286 |
s->magic_state = 1; /* No more magic */ |
|
287 |
tb_flush(); |
|
288 |
return bswap32(ret); |
|
289 |
} |
|
290 |
return 0; |
|
291 |
} |
|
292 |
|
|
293 |
static void magic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) |
|
294 |
{ |
|
295 |
} |
|
296 |
|
|
297 |
|
|
298 |
static CPUReadMemoryFunc *magic_mem_read[3] = { |
|
299 |
magic_mem_readl, |
|
300 |
magic_mem_readl, |
|
301 |
magic_mem_readl, |
|
302 |
}; |
|
303 |
|
|
304 |
static CPUWriteMemoryFunc *magic_mem_write[3] = { |
|
305 |
magic_mem_writel, |
|
306 |
magic_mem_writel, |
|
307 |
magic_mem_writel, |
|
308 |
}; |
|
309 |
|
|
310 |
void magic_init(const char *kfn, int kloadaddr, uint32_t addr) |
|
311 |
{ |
|
312 |
int magic_io_memory; |
|
313 |
MAGICState *s; |
|
314 |
|
|
315 |
s = qemu_mallocz(sizeof(MAGICState)); |
|
316 |
if (!s) |
|
317 |
return; |
|
318 |
|
|
319 |
strcpy(s->saved_kfn, kfn); |
|
320 |
s->saved_addr = kloadaddr; |
|
321 |
s->magic_state = 0; |
|
322 |
s->addr = addr; |
|
323 |
magic_io_memory = cpu_register_io_memory(0, magic_mem_read, magic_mem_write, s); |
|
324 |
cpu_register_physical_memory(addr, 4, magic_io_memory); |
|
325 |
} |
|
326 |
|
Also available in: Unified diff