]> git.proxmox.com Git - qemu.git/blame - hw/magic-load.c
audio clean up (initial patch by malc)
[qemu.git] / hw / magic-load.c
CommitLineData
420557e8
FB
1#include "vl.h"
2#include "disas.h"
3
420557e8
FB
4#define ELF_CLASS ELFCLASS32
5#define ELF_DATA ELFDATA2MSB
6#define ELF_ARCH EM_SPARC
7
8#include "elf.h"
9
420557e8
FB
10#ifdef BSWAP_NEEDED
11static void bswap_ehdr(Elf32_Ehdr *ehdr)
12{
13 bswap16s(&ehdr->e_type); /* Object file type */
14 bswap16s(&ehdr->e_machine); /* Architecture */
15 bswap32s(&ehdr->e_version); /* Object file version */
16 bswap32s(&ehdr->e_entry); /* Entry point virtual address */
17 bswap32s(&ehdr->e_phoff); /* Program header table file offset */
18 bswap32s(&ehdr->e_shoff); /* Section header table file offset */
19 bswap32s(&ehdr->e_flags); /* Processor-specific flags */
20 bswap16s(&ehdr->e_ehsize); /* ELF header size in bytes */
21 bswap16s(&ehdr->e_phentsize); /* Program header table entry size */
22 bswap16s(&ehdr->e_phnum); /* Program header table entry count */
23 bswap16s(&ehdr->e_shentsize); /* Section header table entry size */
24 bswap16s(&ehdr->e_shnum); /* Section header table entry count */
25 bswap16s(&ehdr->e_shstrndx); /* Section header string table index */
26}
27
28static void bswap_phdr(Elf32_Phdr *phdr)
29{
30 bswap32s(&phdr->p_type); /* Segment type */
31 bswap32s(&phdr->p_offset); /* Segment file offset */
32 bswap32s(&phdr->p_vaddr); /* Segment virtual address */
33 bswap32s(&phdr->p_paddr); /* Segment physical address */
34 bswap32s(&phdr->p_filesz); /* Segment size in file */
35 bswap32s(&phdr->p_memsz); /* Segment size in memory */
36 bswap32s(&phdr->p_flags); /* Segment flags */
37 bswap32s(&phdr->p_align); /* Segment alignment */
38}
39
40static void bswap_shdr(Elf32_Shdr *shdr)
41{
42 bswap32s(&shdr->sh_name);
43 bswap32s(&shdr->sh_type);
44 bswap32s(&shdr->sh_flags);
45 bswap32s(&shdr->sh_addr);
46 bswap32s(&shdr->sh_offset);
47 bswap32s(&shdr->sh_size);
48 bswap32s(&shdr->sh_link);
49 bswap32s(&shdr->sh_info);
50 bswap32s(&shdr->sh_addralign);
51 bswap32s(&shdr->sh_entsize);
52}
53
54static void bswap_sym(Elf32_Sym *sym)
55{
56 bswap32s(&sym->st_name);
57 bswap32s(&sym->st_value);
58 bswap32s(&sym->st_size);
59 bswap16s(&sym->st_shndx);
60}
8d5f07fa
FB
61#else
62#define bswap_ehdr(e) do { } while (0)
63#define bswap_phdr(e) do { } while (0)
64#define bswap_shdr(e) do { } while (0)
65#define bswap_sym(e) do { } while (0)
420557e8
FB
66#endif
67
8d5f07fa 68static int find_phdr(struct elfhdr *ehdr, int fd, struct elf_phdr *phdr, uint32_t type)
420557e8 69{
8d5f07fa
FB
70 int i, retval;
71
72 retval = lseek(fd, ehdr->e_phoff, SEEK_SET);
73 if (retval < 0)
74 return -1;
75
76 for (i = 0; i < ehdr->e_phnum; i++) {
77 retval = read(fd, phdr, sizeof(*phdr));
78 if (retval < 0)
79 return -1;
80 bswap_phdr(phdr);
81 if (phdr->p_type == type)
82 return 0;
420557e8 83 }
8d5f07fa 84 return -1;
420557e8
FB
85}
86
8d5f07fa 87static void *find_shdr(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, uint32_t type)
420557e8 88{
8d5f07fa
FB
89 int i, retval;
90
91 retval = lseek(fd, ehdr->e_shoff, SEEK_SET);
92 if (retval < 0)
93 return NULL;
94
95 for (i = 0; i < ehdr->e_shnum; i++) {
96 retval = read(fd, shdr, sizeof(*shdr));
97 if (retval < 0)
98 return NULL;
99 bswap_shdr(shdr);
100 if (shdr->sh_type == type)
101 return qemu_malloc(shdr->sh_size);
420557e8 102 }
8d5f07fa
FB
103 return NULL;
104}
420557e8 105
8d5f07fa
FB
106static int find_strtab(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab)
107{
108 int retval;
420557e8 109
8d5f07fa
FB
110 retval = lseek(fd, ehdr->e_shoff + sizeof(struct elf_shdr) * symtab->sh_link, SEEK_SET);
111 if (retval < 0)
112 return -1;
113
114 retval = read(fd, shdr, sizeof(*shdr));
115 if (retval < 0)
116 return -1;
117 bswap_shdr(shdr);
118 if (shdr->sh_type == SHT_STRTAB)
119 return qemu_malloc(shdr->sh_size);;
120 return 0;
420557e8
FB
121}
122
8d5f07fa 123static int read_program(int fd, struct elf_phdr *phdr, void *dst)
420557e8 124{
420557e8 125 int retval;
8d5f07fa
FB
126 retval = lseek(fd, 0x4000, SEEK_SET);
127 if (retval < 0)
128 return -1;
129 return read(fd, dst, phdr->p_filesz);
130}
420557e8 131
8d5f07fa
FB
132static int read_section(int fd, struct elf_shdr *s, void *dst)
133{
134 int retval;
420557e8 135
8d5f07fa
FB
136 retval = lseek(fd, s->sh_offset, SEEK_SET);
137 if (retval < 0)
138 return -1;
139 retval = read(fd, dst, s->sh_size);
140 if (retval < 0)
141 return -1;
142 return 0;
143}
420557e8 144
8d5f07fa
FB
145static void *process_section(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, uint32_t type)
146{
147 void *dst;
148
149 dst = find_shdr(ehdr, fd, shdr, type);
150 if (!dst)
151 goto error;
152
153 if (read_section(fd, shdr, dst))
154 goto error;
155 return dst;
156 error:
157 qemu_free(dst);
158 return NULL;
159}
420557e8 160
8d5f07fa
FB
161static void *process_strtab(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab)
162{
163 void *dst;
164
165 dst = find_strtab(ehdr, fd, shdr, symtab);
166 if (!dst)
167 goto error;
168
169 if (read_section(fd, shdr, dst))
170 goto error;
171 return dst;
172 error:
173 qemu_free(dst);
174 return NULL;
175}
420557e8 176
8d5f07fa
FB
177static void load_symbols(struct elfhdr *ehdr, int fd)
178{
179 struct elf_shdr symtab, strtab;
180 struct elf_sym *syms;
181 int nsyms, i;
182 char *str;
183
184 /* Symbol table */
185 syms = process_section(ehdr, fd, &symtab, SHT_SYMTAB);
186 if (!syms)
187 return;
420557e8 188
8d5f07fa
FB
189 nsyms = symtab.sh_size / sizeof(struct elf_sym);
190 for (i = 0; i < nsyms; i++)
191 bswap_sym(&syms[i]);
192
193 /* String table */
194 str = process_strtab(ehdr, fd, &strtab, &symtab);
195 if (!str)
196 goto error_freesyms;
197
198 /* 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;
206 return;
207 error_freesyms:
208 qemu_free(syms);
209 return;
210}
420557e8 211
8d5f07fa
FB
212int load_elf(const char * filename, uint8_t *addr)
213{
214 struct elfhdr ehdr;
215 struct elf_phdr phdr;
216 int retval, fd;
420557e8 217
8d5f07fa
FB
218 fd = open(filename, O_RDONLY | O_BINARY);
219 if (fd < 0)
220 goto error;
420557e8 221
8d5f07fa
FB
222 retval = read(fd, &ehdr, sizeof(ehdr));
223 if (retval < 0)
224 goto error;
420557e8 225
8d5f07fa 226 bswap_ehdr(&ehdr);
420557e8 227
8d5f07fa
FB
228 if (ehdr.e_ident[0] != 0x7f || ehdr.e_ident[1] != 'E'
229 || ehdr.e_ident[2] != 'L' || ehdr.e_ident[3] != 'F'
230 || ehdr.e_machine != EM_SPARC)
231 goto error;
420557e8 232
8d5f07fa
FB
233 if (find_phdr(&ehdr, fd, &phdr, PT_LOAD))
234 goto error;
235 retval = read_program(fd, &phdr, addr);
236 if (retval < 0)
237 goto error;
420557e8 238
8d5f07fa 239 load_symbols(&ehdr, fd);
420557e8 240
8d5f07fa
FB
241 close(fd);
242 return retval;
243 error:
244 close(fd);
245 return -1;
420557e8 246}
420557e8
FB
247
248int load_kernel(const char *filename, uint8_t *addr)
249{
250 int fd, size;
251
252 fd = open(filename, O_RDONLY | O_BINARY);
253 if (fd < 0)
254 return -1;
255 /* load 32 bit code */
256 size = read(fd, addr, 16 * 1024 * 1024);
257 if (size < 0)
258 goto fail;
259 close(fd);
260 return size;
261 fail:
262 close(fd);
263 return -1;
264}
265
8d5f07fa
FB
266typedef struct MAGICState {
267 uint32_t addr;
268 uint32_t saved_addr;
269 int magic_state;
270 char saved_kfn[1024];
271} MAGICState;
420557e8
FB
272
273static uint32_t magic_mem_readl(void *opaque, target_phys_addr_t addr)
274{
275 int ret;
8d5f07fa 276 MAGICState *s = opaque;
420557e8 277
8d5f07fa
FB
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);
420557e8
FB
282 if (ret < 0) {
283 fprintf(stderr, "qemu: could not load kernel '%s'\n",
8d5f07fa 284 s->saved_kfn);
420557e8 285 }
8d5f07fa 286 s->magic_state = 1; /* No more magic */
420557e8 287 tb_flush();
8d5f07fa 288 return bswap32(ret);
420557e8 289 }
8d5f07fa 290 return 0;
420557e8
FB
291}
292
293static void magic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
294{
295}
296
297
298static CPUReadMemoryFunc *magic_mem_read[3] = {
299 magic_mem_readl,
300 magic_mem_readl,
301 magic_mem_readl,
302};
303
304static CPUWriteMemoryFunc *magic_mem_write[3] = {
305 magic_mem_writel,
306 magic_mem_writel,
307 magic_mem_writel,
308};
309
8d5f07fa 310void magic_init(const char *kfn, int kloadaddr, uint32_t addr)
420557e8
FB
311{
312 int magic_io_memory;
8d5f07fa
FB
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);
420557e8
FB
325}
326