1 |
#include "vl.h" |
#include "vl.h" |
2 |
#include "disas.h" |
#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 |
|
|
52 |
|
|
53 |
#define ELF_CLASS ELFCLASS32 |
#define ELF_CLASS ELFCLASS32 |
54 |
#define ELF_DATA ELFDATA2MSB |
#define ELF_DATA ELFDATA2MSB |
152 |
return NULL; |
return NULL; |
153 |
} |
} |
154 |
|
|
155 |
static int find_strtab(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab) |
static void *find_strtab(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab) |
156 |
{ |
{ |
157 |
int retval; |
int retval; |
158 |
|
|
159 |
retval = lseek(fd, ehdr->e_shoff + sizeof(struct elf_shdr) * symtab->sh_link, SEEK_SET); |
retval = lseek(fd, ehdr->e_shoff + sizeof(struct elf_shdr) * symtab->sh_link, SEEK_SET); |
160 |
if (retval < 0) |
if (retval < 0) |
161 |
return -1; |
return NULL; |
162 |
|
|
163 |
retval = read(fd, shdr, sizeof(*shdr)); |
retval = read(fd, shdr, sizeof(*shdr)); |
164 |
if (retval < 0) |
if (retval < 0) |
165 |
return -1; |
return NULL; |
166 |
bswap_shdr(shdr); |
bswap_shdr(shdr); |
167 |
if (shdr->sh_type == SHT_STRTAB) |
if (shdr->sh_type == SHT_STRTAB) |
168 |
return qemu_malloc(shdr->sh_size);; |
return qemu_malloc(shdr->sh_size);; |
169 |
return 0; |
return NULL; |
170 |
} |
} |
171 |
|
|
172 |
static int read_program(int fd, struct elf_phdr *phdr, void *dst) |
static int read_program(int fd, struct elf_phdr *phdr, void *dst, uint32_t entry) |
173 |
{ |
{ |
174 |
int retval; |
int retval; |
175 |
retval = lseek(fd, 0x4000, SEEK_SET); |
retval = lseek(fd, phdr->p_offset + entry - phdr->p_vaddr, SEEK_SET); |
176 |
if (retval < 0) |
if (retval < 0) |
177 |
return -1; |
return -1; |
178 |
return read(fd, dst, phdr->p_filesz); |
return read(fd, dst, phdr->p_filesz); |
227 |
{ |
{ |
228 |
struct elf_shdr symtab, strtab; |
struct elf_shdr symtab, strtab; |
229 |
struct elf_sym *syms; |
struct elf_sym *syms; |
230 |
|
struct syminfo *s; |
231 |
int nsyms, i; |
int nsyms, i; |
232 |
char *str; |
char *str; |
233 |
|
|
246 |
goto error_freesyms; |
goto error_freesyms; |
247 |
|
|
248 |
/* Commit */ |
/* Commit */ |
249 |
if (disas_symtab) |
s = qemu_mallocz(sizeof(*s)); |
250 |
qemu_free(disas_symtab); /* XXX Merge with old symbols? */ |
s->disas_symtab = syms; |
251 |
if (disas_strtab) |
s->disas_num_syms = nsyms; |
252 |
qemu_free(disas_strtab); |
s->disas_strtab = str; |
253 |
disas_symtab = syms; |
s->next = syminfos; |
254 |
disas_num_syms = nsyms; |
syminfos = s; |
|
disas_strtab = str; |
|
255 |
return; |
return; |
256 |
error_freesyms: |
error_freesyms: |
257 |
qemu_free(syms); |
qemu_free(syms); |
258 |
return; |
return; |
259 |
} |
} |
260 |
|
|
261 |
int load_elf(const char * filename, uint8_t *addr) |
int load_elf(const char *filename, uint8_t *addr) |
262 |
{ |
{ |
263 |
struct elfhdr ehdr; |
struct elfhdr ehdr; |
264 |
struct elf_phdr phdr; |
struct elf_phdr phdr; |
276 |
|
|
277 |
if (ehdr.e_ident[0] != 0x7f || ehdr.e_ident[1] != 'E' |
if (ehdr.e_ident[0] != 0x7f || ehdr.e_ident[1] != 'E' |
278 |
|| ehdr.e_ident[2] != 'L' || ehdr.e_ident[3] != 'F' |
|| ehdr.e_ident[2] != 'L' || ehdr.e_ident[3] != 'F' |
279 |
|| ehdr.e_machine != EM_SPARC) |
|| (ehdr.e_machine != EM_SPARC |
280 |
|
&& ehdr.e_machine != EM_SPARC32PLUS)) |
281 |
goto error; |
goto error; |
282 |
|
|
283 |
if (find_phdr(&ehdr, fd, &phdr, PT_LOAD)) |
if (find_phdr(&ehdr, fd, &phdr, PT_LOAD)) |
284 |
goto error; |
goto error; |
285 |
retval = read_program(fd, &phdr, addr); |
retval = read_program(fd, &phdr, addr, ehdr.e_entry); |
286 |
if (retval < 0) |
if (retval < 0) |
287 |
goto error; |
goto error; |
288 |
|
|
295 |
return -1; |
return -1; |
296 |
} |
} |
297 |
|
|
298 |
int load_kernel(const char *filename, uint8_t *addr) |
int load_aout(const char *filename, uint8_t *addr) |
299 |
{ |
{ |
300 |
int fd, size; |
int fd, size, ret; |
301 |
|
struct exec e; |
302 |
|
uint32_t magic; |
303 |
|
|
304 |
fd = open(filename, O_RDONLY | O_BINARY); |
fd = open(filename, O_RDONLY | O_BINARY); |
305 |
if (fd < 0) |
if (fd < 0) |
306 |
return -1; |
return -1; |
307 |
/* load 32 bit code */ |
|
308 |
size = read(fd, addr, 16 * 1024 * 1024); |
size = read(fd, &e, sizeof(e)); |
309 |
if (size < 0) |
if (size < 0) |
310 |
goto fail; |
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 |
|
} |
337 |
close(fd); |
close(fd); |
338 |
return size; |
return size; |
339 |
fail: |
fail: |
341 |
return -1; |
return -1; |
342 |
} |
} |
343 |
|
|
|
typedef struct MAGICState { |
|
|
uint32_t addr; |
|
|
uint32_t saved_addr; |
|
|
int magic_state; |
|
|
char saved_kfn[1024]; |
|
|
} MAGICState; |
|
|
|
|
|
static uint32_t magic_mem_readl(void *opaque, target_phys_addr_t addr) |
|
|
{ |
|
|
int ret; |
|
|
MAGICState *s = opaque; |
|
|
|
|
|
if (s->magic_state == 0) { |
|
|
ret = load_elf(s->saved_kfn, (uint8_t *)s->saved_addr); |
|
|
if (ret < 0) |
|
|
ret = load_kernel(s->saved_kfn, (uint8_t *)s->saved_addr); |
|
|
if (ret < 0) { |
|
|
fprintf(stderr, "qemu: could not load kernel '%s'\n", |
|
|
s->saved_kfn); |
|
|
} |
|
|
s->magic_state = 1; /* No more magic */ |
|
|
tb_flush(); |
|
|
return bswap32(ret); |
|
|
} |
|
|
return 0; |
|
|
} |
|
|
|
|
|
static void magic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) |
|
|
{ |
|
|
} |
|
|
|
|
|
|
|
|
static CPUReadMemoryFunc *magic_mem_read[3] = { |
|
|
magic_mem_readl, |
|
|
magic_mem_readl, |
|
|
magic_mem_readl, |
|
|
}; |
|
|
|
|
|
static CPUWriteMemoryFunc *magic_mem_write[3] = { |
|
|
magic_mem_writel, |
|
|
magic_mem_writel, |
|
|
magic_mem_writel, |
|
|
}; |
|
|
|
|
|
void magic_init(const char *kfn, int kloadaddr, uint32_t addr) |
|
|
{ |
|
|
int magic_io_memory; |
|
|
MAGICState *s; |
|
|
|
|
|
s = qemu_mallocz(sizeof(MAGICState)); |
|
|
if (!s) |
|
|
return; |
|
|
|
|
|
strcpy(s->saved_kfn, kfn); |
|
|
s->saved_addr = kloadaddr; |
|
|
s->magic_state = 0; |
|
|
s->addr = addr; |
|
|
magic_io_memory = cpu_register_io_memory(0, magic_mem_read, magic_mem_write, s); |
|
|
cpu_register_physical_memory(addr, 4, magic_io_memory); |
|
|
} |
|
|
|
|