sparc merge (Blue Swirl)
[qemu] / hw / magic-load.c
1 #include "vl.h"
2 #include "disas.h"
3
4 #define ELF_CLASS   ELFCLASS32
5 #define ELF_DATA    ELFDATA2MSB
6 #define ELF_ARCH    EM_SPARC
7
8 #include "elf.h"
9
10 #ifdef BSWAP_NEEDED
11 static 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
28 static 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
40 static 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
54 static 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 }
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)
66 #endif
67
68 static int find_phdr(struct elfhdr *ehdr, int fd, struct elf_phdr *phdr, uint32_t type)
69 {
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;
83     }
84     return -1;
85 }
86
87 static void *find_shdr(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, uint32_t type)
88 {
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);
102     }
103     return NULL;
104 }
105
106 static int find_strtab(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab)
107 {
108     int retval;
109
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;
121 }
122
123 static int read_program(int fd, struct elf_phdr *phdr, void *dst)
124 {
125     int retval;
126     retval = lseek(fd, 0x4000, SEEK_SET);
127     if (retval < 0)
128         return -1;
129     return read(fd, dst, phdr->p_filesz);
130 }
131
132 static int read_section(int fd, struct elf_shdr *s, void *dst)
133 {
134     int retval;
135
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 }
144
145 static 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 }
160
161 static 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 }
176
177 static 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;
188
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 }
211
212 int load_elf(const char * filename, uint8_t *addr)
213 {
214     struct elfhdr ehdr;
215     struct elf_phdr phdr;
216     int retval, fd;
217
218     fd = open(filename, O_RDONLY | O_BINARY);
219     if (fd < 0)
220         goto error;
221
222     retval = read(fd, &ehdr, sizeof(ehdr));
223     if (retval < 0)
224         goto error;
225
226     bswap_ehdr(&ehdr);
227
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;
232
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;
238
239     load_symbols(&ehdr, fd);
240
241     close(fd);
242     return retval;
243  error:
244     close(fd);
245     return -1;
246 }
247
248 int 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
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