]>
Commit | Line | Data |
---|---|---|
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 |
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 | } | |
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 | 68 | static 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 | 87 | static 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 |
106 | static 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 | 123 | static 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 |
132 | static 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 |
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 | } | |
420557e8 | 160 | |
8d5f07fa FB |
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 | } | |
420557e8 | 176 | |
8d5f07fa FB |
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; | |
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 |
212 | int 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 | |
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 | ||
8d5f07fa FB |
266 | typedef 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 | |
273 | static 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 | ||
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 | ||
8d5f07fa | 310 | void 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 |