Revision ca20cf32
b/Makefile.hw | ||
---|---|---|
11 | 11 |
QEMU_CFLAGS+=-I.. -I$(SRC_PATH)/fpu |
12 | 12 |
|
13 | 13 |
obj-y = |
14 |
obj-y += loader.o |
|
14 | 15 |
obj-y += virtio.o |
15 | 16 |
obj-y += fw_cfg.o |
16 | 17 |
obj-y += watchdog.o |
b/Makefile.target | ||
---|---|---|
155 | 155 |
# System emulator target |
156 | 156 |
ifdef CONFIG_SOFTMMU |
157 | 157 |
|
158 |
obj-y = vl.o monitor.o pci.o loader.o isa_mmio.o machine.o \
|
|
158 |
obj-y = vl.o monitor.o pci.o isa_mmio.o machine.o \ |
|
159 | 159 |
gdbstub.o gdbstub-xml.o msix.o ioport.o |
160 | 160 |
# virtio has to be here due to weird dependency between PCI and virtio-net. |
161 | 161 |
# need to fix this properly |
b/disas.h | ||
---|---|---|
3 | 3 |
|
4 | 4 |
#include "qemu-common.h" |
5 | 5 |
|
6 |
#ifdef NEED_CPU_H |
|
6 | 7 |
/* Disassemble this for me please... (debugging). */ |
7 | 8 |
void disas(FILE *out, void *code, unsigned long size); |
8 | 9 |
void target_disas(FILE *out, target_ulong code, target_ulong size, int flags); |
... | ... | |
15 | 16 |
|
16 | 17 |
/* Look up symbol for debugging purpose. Returns "" if unknown. */ |
17 | 18 |
const char *lookup_symbol(target_ulong orig_addr); |
19 |
#endif |
|
18 | 20 |
|
19 | 21 |
struct syminfo; |
20 | 22 |
struct elf32_sym; |
21 | 23 |
struct elf64_sym; |
22 | 24 |
|
23 |
typedef const char *(*lookup_symbol_t)(struct syminfo *s, target_ulong orig_addr);
|
|
25 |
typedef const char *(*lookup_symbol_t)(struct syminfo *s, target_phys_addr_t orig_addr);
|
|
24 | 26 |
|
25 | 27 |
struct syminfo { |
26 | 28 |
lookup_symbol_t lookup_symbol; |
/dev/null | ||
---|---|---|
1 |
static void glue(bswap_ehdr, SZ)(struct elfhdr *ehdr) |
|
2 |
{ |
|
3 |
bswap16s(&ehdr->e_type); /* Object file type */ |
|
4 |
bswap16s(&ehdr->e_machine); /* Architecture */ |
|
5 |
bswap32s(&ehdr->e_version); /* Object file version */ |
|
6 |
bswapSZs(&ehdr->e_entry); /* Entry point virtual address */ |
|
7 |
bswapSZs(&ehdr->e_phoff); /* Program header table file offset */ |
|
8 |
bswapSZs(&ehdr->e_shoff); /* Section header table file offset */ |
|
9 |
bswap32s(&ehdr->e_flags); /* Processor-specific flags */ |
|
10 |
bswap16s(&ehdr->e_ehsize); /* ELF header size in bytes */ |
|
11 |
bswap16s(&ehdr->e_phentsize); /* Program header table entry size */ |
|
12 |
bswap16s(&ehdr->e_phnum); /* Program header table entry count */ |
|
13 |
bswap16s(&ehdr->e_shentsize); /* Section header table entry size */ |
|
14 |
bswap16s(&ehdr->e_shnum); /* Section header table entry count */ |
|
15 |
bswap16s(&ehdr->e_shstrndx); /* Section header string table index */ |
|
16 |
} |
|
17 |
|
|
18 |
static void glue(bswap_phdr, SZ)(struct elf_phdr *phdr) |
|
19 |
{ |
|
20 |
bswap32s(&phdr->p_type); /* Segment type */ |
|
21 |
bswapSZs(&phdr->p_offset); /* Segment file offset */ |
|
22 |
bswapSZs(&phdr->p_vaddr); /* Segment virtual address */ |
|
23 |
bswapSZs(&phdr->p_paddr); /* Segment physical address */ |
|
24 |
bswapSZs(&phdr->p_filesz); /* Segment size in file */ |
|
25 |
bswapSZs(&phdr->p_memsz); /* Segment size in memory */ |
|
26 |
bswap32s(&phdr->p_flags); /* Segment flags */ |
|
27 |
bswapSZs(&phdr->p_align); /* Segment alignment */ |
|
28 |
} |
|
29 |
|
|
30 |
static void glue(bswap_shdr, SZ)(struct elf_shdr *shdr) |
|
31 |
{ |
|
32 |
bswap32s(&shdr->sh_name); |
|
33 |
bswap32s(&shdr->sh_type); |
|
34 |
bswapSZs(&shdr->sh_flags); |
|
35 |
bswapSZs(&shdr->sh_addr); |
|
36 |
bswapSZs(&shdr->sh_offset); |
|
37 |
bswapSZs(&shdr->sh_size); |
|
38 |
bswap32s(&shdr->sh_link); |
|
39 |
bswap32s(&shdr->sh_info); |
|
40 |
bswapSZs(&shdr->sh_addralign); |
|
41 |
bswapSZs(&shdr->sh_entsize); |
|
42 |
} |
|
43 |
|
|
44 |
static void glue(bswap_sym, SZ)(struct elf_sym *sym) |
|
45 |
{ |
|
46 |
bswap32s(&sym->st_name); |
|
47 |
bswapSZs(&sym->st_value); |
|
48 |
bswapSZs(&sym->st_size); |
|
49 |
bswap16s(&sym->st_shndx); |
|
50 |
} |
|
51 |
|
|
52 |
static struct elf_shdr *glue(find_section, SZ)(struct elf_shdr *shdr_table, |
|
53 |
int n, int type) |
|
54 |
{ |
|
55 |
int i; |
|
56 |
for(i=0;i<n;i++) { |
|
57 |
if (shdr_table[i].sh_type == type) |
|
58 |
return shdr_table + i; |
|
59 |
} |
|
60 |
return NULL; |
|
61 |
} |
|
62 |
|
|
63 |
static int glue(symfind, SZ)(const void *s0, const void *s1) |
|
64 |
{ |
|
65 |
struct elf_sym *key = (struct elf_sym *)s0; |
|
66 |
struct elf_sym *sym = (struct elf_sym *)s1; |
|
67 |
int result = 0; |
|
68 |
if (key->st_value < sym->st_value) { |
|
69 |
result = -1; |
|
70 |
} else if (key->st_value >= sym->st_value + sym->st_size) { |
|
71 |
result = 1; |
|
72 |
} |
|
73 |
return result; |
|
74 |
} |
|
75 |
|
|
76 |
static const char *glue(lookup_symbol, SZ)(struct syminfo *s, target_ulong orig_addr) |
|
77 |
{ |
|
78 |
struct elf_sym *syms = glue(s->disas_symtab.elf, SZ); |
|
79 |
struct elf_sym key; |
|
80 |
struct elf_sym *sym; |
|
81 |
|
|
82 |
key.st_value = orig_addr; |
|
83 |
|
|
84 |
sym = bsearch(&key, syms, s->disas_num_syms, sizeof(*syms), glue(symfind, SZ)); |
|
85 |
if (sym != NULL) { |
|
86 |
return s->disas_strtab + sym->st_name; |
|
87 |
} |
|
88 |
|
|
89 |
return ""; |
|
90 |
} |
|
91 |
|
|
92 |
static int glue(symcmp, SZ)(const void *s0, const void *s1) |
|
93 |
{ |
|
94 |
struct elf_sym *sym0 = (struct elf_sym *)s0; |
|
95 |
struct elf_sym *sym1 = (struct elf_sym *)s1; |
|
96 |
return (sym0->st_value < sym1->st_value) |
|
97 |
? -1 |
|
98 |
: ((sym0->st_value > sym1->st_value) ? 1 : 0); |
|
99 |
} |
|
100 |
|
|
101 |
static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab) |
|
102 |
{ |
|
103 |
struct elf_shdr *symtab, *strtab, *shdr_table = NULL; |
|
104 |
struct elf_sym *syms = NULL; |
|
105 |
struct syminfo *s; |
|
106 |
int nsyms, i; |
|
107 |
char *str = NULL; |
|
108 |
|
|
109 |
shdr_table = load_at(fd, ehdr->e_shoff, |
|
110 |
sizeof(struct elf_shdr) * ehdr->e_shnum); |
|
111 |
if (!shdr_table) |
|
112 |
return -1; |
|
113 |
|
|
114 |
if (must_swab) { |
|
115 |
for (i = 0; i < ehdr->e_shnum; i++) { |
|
116 |
glue(bswap_shdr, SZ)(shdr_table + i); |
|
117 |
} |
|
118 |
} |
|
119 |
|
|
120 |
symtab = glue(find_section, SZ)(shdr_table, ehdr->e_shnum, SHT_SYMTAB); |
|
121 |
if (!symtab) |
|
122 |
goto fail; |
|
123 |
syms = load_at(fd, symtab->sh_offset, symtab->sh_size); |
|
124 |
if (!syms) |
|
125 |
goto fail; |
|
126 |
|
|
127 |
nsyms = symtab->sh_size / sizeof(struct elf_sym); |
|
128 |
|
|
129 |
i = 0; |
|
130 |
while (i < nsyms) { |
|
131 |
if (must_swab) |
|
132 |
glue(bswap_sym, SZ)(&syms[i]); |
|
133 |
/* We are only interested in function symbols. |
|
134 |
Throw everything else away. */ |
|
135 |
if (syms[i].st_shndx == SHN_UNDEF || |
|
136 |
syms[i].st_shndx >= SHN_LORESERVE || |
|
137 |
ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) { |
|
138 |
nsyms--; |
|
139 |
if (i < nsyms) { |
|
140 |
syms[i] = syms[nsyms]; |
|
141 |
} |
|
142 |
continue; |
|
143 |
} |
|
144 |
#if defined(TARGET_ARM) || defined (TARGET_MIPS) |
|
145 |
/* The bottom address bit marks a Thumb or MIPS16 symbol. */ |
|
146 |
syms[i].st_value &= ~(target_ulong)1; |
|
147 |
#endif |
|
148 |
i++; |
|
149 |
} |
|
150 |
syms = qemu_realloc(syms, nsyms * sizeof(*syms)); |
|
151 |
|
|
152 |
qsort(syms, nsyms, sizeof(*syms), glue(symcmp, SZ)); |
|
153 |
|
|
154 |
/* String table */ |
|
155 |
if (symtab->sh_link >= ehdr->e_shnum) |
|
156 |
goto fail; |
|
157 |
strtab = &shdr_table[symtab->sh_link]; |
|
158 |
|
|
159 |
str = load_at(fd, strtab->sh_offset, strtab->sh_size); |
|
160 |
if (!str) |
|
161 |
goto fail; |
|
162 |
|
|
163 |
/* Commit */ |
|
164 |
s = qemu_mallocz(sizeof(*s)); |
|
165 |
s->lookup_symbol = glue(lookup_symbol, SZ); |
|
166 |
glue(s->disas_symtab.elf, SZ) = syms; |
|
167 |
s->disas_num_syms = nsyms; |
|
168 |
s->disas_strtab = str; |
|
169 |
s->next = syminfos; |
|
170 |
syminfos = s; |
|
171 |
qemu_free(shdr_table); |
|
172 |
return 0; |
|
173 |
fail: |
|
174 |
qemu_free(syms); |
|
175 |
qemu_free(str); |
|
176 |
qemu_free(shdr_table); |
|
177 |
return -1; |
|
178 |
} |
|
179 |
|
|
180 |
static int glue(load_elf, SZ)(int fd, int64_t address_offset, |
|
181 |
int must_swab, uint64_t *pentry, |
|
182 |
uint64_t *lowaddr, uint64_t *highaddr) |
|
183 |
{ |
|
184 |
struct elfhdr ehdr; |
|
185 |
struct elf_phdr *phdr = NULL, *ph; |
|
186 |
int size, i, total_size; |
|
187 |
elf_word mem_size; |
|
188 |
uint64_t addr, low = (uint64_t)-1, high = 0; |
|
189 |
uint8_t *data = NULL; |
|
190 |
|
|
191 |
if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr)) |
|
192 |
goto fail; |
|
193 |
if (must_swab) { |
|
194 |
glue(bswap_ehdr, SZ)(&ehdr); |
|
195 |
} |
|
196 |
|
|
197 |
switch (ELF_MACHINE) { |
|
198 |
case EM_PPC64: |
|
199 |
if (EM_PPC64 != ehdr.e_machine) |
|
200 |
if (EM_PPC != ehdr.e_machine) |
|
201 |
goto fail; |
|
202 |
break; |
|
203 |
case EM_X86_64: |
|
204 |
if (EM_X86_64 != ehdr.e_machine) |
|
205 |
if (EM_386 != ehdr.e_machine) |
|
206 |
goto fail; |
|
207 |
break; |
|
208 |
default: |
|
209 |
if (ELF_MACHINE != ehdr.e_machine) |
|
210 |
goto fail; |
|
211 |
} |
|
212 |
|
|
213 |
if (pentry) |
|
214 |
*pentry = (uint64_t)(elf_sword)ehdr.e_entry; |
|
215 |
|
|
216 |
glue(load_symbols, SZ)(&ehdr, fd, must_swab); |
|
217 |
|
|
218 |
size = ehdr.e_phnum * sizeof(phdr[0]); |
|
219 |
lseek(fd, ehdr.e_phoff, SEEK_SET); |
|
220 |
phdr = qemu_mallocz(size); |
|
221 |
if (!phdr) |
|
222 |
goto fail; |
|
223 |
if (read(fd, phdr, size) != size) |
|
224 |
goto fail; |
|
225 |
if (must_swab) { |
|
226 |
for(i = 0; i < ehdr.e_phnum; i++) { |
|
227 |
ph = &phdr[i]; |
|
228 |
glue(bswap_phdr, SZ)(ph); |
|
229 |
} |
|
230 |
} |
|
231 |
|
|
232 |
total_size = 0; |
|
233 |
for(i = 0; i < ehdr.e_phnum; i++) { |
|
234 |
ph = &phdr[i]; |
|
235 |
if (ph->p_type == PT_LOAD) { |
|
236 |
mem_size = ph->p_memsz; |
|
237 |
/* XXX: avoid allocating */ |
|
238 |
data = qemu_mallocz(mem_size); |
|
239 |
if (ph->p_filesz > 0) { |
|
240 |
if (lseek(fd, ph->p_offset, SEEK_SET) < 0) |
|
241 |
goto fail; |
|
242 |
if (read(fd, data, ph->p_filesz) != ph->p_filesz) |
|
243 |
goto fail; |
|
244 |
} |
|
245 |
/* address_offset is hack for kernel images that are |
|
246 |
linked at the wrong physical address. */ |
|
247 |
addr = ph->p_paddr + address_offset; |
|
248 |
|
|
249 |
cpu_physical_memory_write_rom(addr, data, mem_size); |
|
250 |
|
|
251 |
total_size += mem_size; |
|
252 |
if (addr < low) |
|
253 |
low = addr; |
|
254 |
if ((addr + mem_size) > high) |
|
255 |
high = addr + mem_size; |
|
256 |
|
|
257 |
qemu_free(data); |
|
258 |
data = NULL; |
|
259 |
} |
|
260 |
} |
|
261 |
qemu_free(phdr); |
|
262 |
if (lowaddr) |
|
263 |
*lowaddr = (uint64_t)(elf_sword)low; |
|
264 |
if (highaddr) |
|
265 |
*highaddr = (uint64_t)(elf_sword)high; |
|
266 |
return total_size; |
|
267 |
fail: |
|
268 |
qemu_free(data); |
|
269 |
qemu_free(phdr); |
|
270 |
return -1; |
|
271 |
} |
b/hw/an5206.c | ||
---|---|---|
11 | 11 |
#include "mcf.h" |
12 | 12 |
#include "sysemu.h" |
13 | 13 |
#include "boards.h" |
14 |
#include "loader.h" |
|
15 |
#include "elf.h" |
|
14 | 16 |
|
15 | 17 |
#define KERNEL_LOAD_ADDR 0x10000 |
16 | 18 |
#define AN5206_MBAR_ADDR 0x10000000 |
... | ... | |
35 | 37 |
CPUState *env; |
36 | 38 |
int kernel_size; |
37 | 39 |
uint64_t elf_entry; |
38 |
target_ulong entry;
|
|
40 |
target_phys_addr_t entry;
|
|
39 | 41 |
|
40 | 42 |
if (!cpu_model) |
41 | 43 |
cpu_model = "m5206"; |
... | ... | |
66 | 68 |
exit(1); |
67 | 69 |
} |
68 | 70 |
|
69 |
kernel_size = load_elf(kernel_filename, 0, &elf_entry, NULL, NULL); |
|
71 |
kernel_size = load_elf(kernel_filename, 0, &elf_entry, NULL, NULL, |
|
72 |
1, ELF_MACHINE, 0); |
|
70 | 73 |
entry = elf_entry; |
71 | 74 |
if (kernel_size < 0) { |
72 | 75 |
kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL); |
b/hw/arm_boot.c | ||
---|---|---|
10 | 10 |
#include "hw.h" |
11 | 11 |
#include "arm-misc.h" |
12 | 12 |
#include "sysemu.h" |
13 |
#include "loader.h" |
|
14 |
#include "elf.h" |
|
13 | 15 |
|
14 | 16 |
#define KERNEL_ARGS_ADDR 0x100 |
15 | 17 |
#define KERNEL_LOAD_ADDR 0x00010000 |
... | ... | |
191 | 193 |
int n; |
192 | 194 |
int is_linux = 0; |
193 | 195 |
uint64_t elf_entry; |
194 |
target_ulong entry; |
|
196 |
target_phys_addr_t entry; |
|
197 |
int big_endian; |
|
195 | 198 |
|
196 | 199 |
/* Load the kernel. */ |
197 | 200 |
if (!info->kernel_filename) { |
... | ... | |
206 | 209 |
qemu_register_reset(main_cpu_reset, env); |
207 | 210 |
} |
208 | 211 |
|
212 |
#ifdef TARGET_WORDS_BIGENDIAN |
|
213 |
big_endian = 1; |
|
214 |
#else |
|
215 |
big_endian = 0; |
|
216 |
#endif |
|
217 |
|
|
209 | 218 |
/* Assume that raw images are linux kernels, and ELF images are not. */ |
210 |
kernel_size = load_elf(info->kernel_filename, 0, &elf_entry, NULL, NULL); |
|
219 |
kernel_size = load_elf(info->kernel_filename, 0, &elf_entry, NULL, NULL, |
|
220 |
big_endian, ELF_MACHINE, 1); |
|
211 | 221 |
entry = elf_entry; |
212 | 222 |
if (kernel_size < 0) { |
213 | 223 |
kernel_size = load_uimage(info->kernel_filename, &entry, NULL, |
b/hw/armv7m.c | ||
---|---|---|
10 | 10 |
#include "sysbus.h" |
11 | 11 |
#include "arm-misc.h" |
12 | 12 |
#include "sysemu.h" |
13 |
#include "loader.h" |
|
14 |
#include "elf.h" |
|
13 | 15 |
|
14 | 16 |
/* Bitbanded IO. Each word corresponds to a single bit. */ |
15 | 17 |
|
... | ... | |
166 | 168 |
uint64_t entry; |
167 | 169 |
uint64_t lowaddr; |
168 | 170 |
int i; |
171 |
int big_endian; |
|
169 | 172 |
|
170 | 173 |
flash_size *= 1024; |
171 | 174 |
sram_size *= 1024; |
... | ... | |
206 | 209 |
pic[i] = qdev_get_gpio_in(nvic, i); |
207 | 210 |
} |
208 | 211 |
|
209 |
image_size = load_elf(kernel_filename, 0, &entry, &lowaddr, NULL); |
|
212 |
#ifdef TARGET_WORDS_BIGENDIAN |
|
213 |
big_endian = 1; |
|
214 |
#else |
|
215 |
big_endian = 0; |
|
216 |
#endif |
|
217 |
|
|
218 |
image_size = load_elf(kernel_filename, 0, &entry, &lowaddr, NULL, |
|
219 |
big_endian, ELF_MACHINE, 1); |
|
210 | 220 |
if (image_size < 0) { |
211 | 221 |
image_size = load_image_targphys(kernel_filename, 0, flash_size); |
212 | 222 |
lowaddr = 0; |
b/hw/axis_dev88.c | ||
---|---|---|
28 | 28 |
#include "boards.h" |
29 | 29 |
#include "sysemu.h" |
30 | 30 |
#include "etraxfs.h" |
31 |
#include "loader.h" |
|
32 |
#include "elf.h" |
|
31 | 33 |
|
32 | 34 |
#define D(x) |
33 | 35 |
#define DNAND(x) |
... | ... | |
344 | 346 |
/* Boots a kernel elf binary, os/linux-2.6/vmlinux from the axis |
345 | 347 |
devboard SDK. */ |
346 | 348 |
kernel_size = load_elf(kernel_filename, -0x80000000LL, |
347 |
&entry, NULL, &high); |
|
349 |
&entry, NULL, &high, 0, ELF_MACHINE, 0);
|
|
348 | 350 |
bootstrap_pc = entry; |
349 | 351 |
if (kernel_size < 0) { |
350 | 352 |
/* Takes a kimage from the axis devboard SDK. */ |
b/hw/dummy_m68k.c | ||
---|---|---|
9 | 9 |
#include "hw.h" |
10 | 10 |
#include "sysemu.h" |
11 | 11 |
#include "boards.h" |
12 |
#include "loader.h" |
|
13 |
#include "elf.h" |
|
12 | 14 |
|
13 | 15 |
#define KERNEL_LOAD_ADDR 0x10000 |
14 | 16 |
|
... | ... | |
22 | 24 |
CPUState *env; |
23 | 25 |
int kernel_size; |
24 | 26 |
uint64_t elf_entry; |
25 |
target_ulong entry;
|
|
27 |
target_phys_addr_t entry;
|
|
26 | 28 |
|
27 | 29 |
if (!cpu_model) |
28 | 30 |
cpu_model = "cfv4e"; |
... | ... | |
41 | 43 |
|
42 | 44 |
/* Load kernel. */ |
43 | 45 |
if (kernel_filename) { |
44 |
kernel_size = load_elf(kernel_filename, 0, &elf_entry, NULL, NULL); |
|
46 |
kernel_size = load_elf(kernel_filename, 0, &elf_entry, NULL, NULL, |
|
47 |
1, ELF_MACHINE, 0); |
|
45 | 48 |
entry = elf_entry; |
46 | 49 |
if (kernel_size < 0) { |
47 | 50 |
kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL); |
b/hw/elf_ops.h | ||
---|---|---|
1 |
static void glue(bswap_ehdr, SZ)(struct elfhdr *ehdr) |
|
2 |
{ |
|
3 |
bswap16s(&ehdr->e_type); /* Object file type */ |
|
4 |
bswap16s(&ehdr->e_machine); /* Architecture */ |
|
5 |
bswap32s(&ehdr->e_version); /* Object file version */ |
|
6 |
bswapSZs(&ehdr->e_entry); /* Entry point virtual address */ |
|
7 |
bswapSZs(&ehdr->e_phoff); /* Program header table file offset */ |
|
8 |
bswapSZs(&ehdr->e_shoff); /* Section header table file offset */ |
|
9 |
bswap32s(&ehdr->e_flags); /* Processor-specific flags */ |
|
10 |
bswap16s(&ehdr->e_ehsize); /* ELF header size in bytes */ |
|
11 |
bswap16s(&ehdr->e_phentsize); /* Program header table entry size */ |
|
12 |
bswap16s(&ehdr->e_phnum); /* Program header table entry count */ |
|
13 |
bswap16s(&ehdr->e_shentsize); /* Section header table entry size */ |
|
14 |
bswap16s(&ehdr->e_shnum); /* Section header table entry count */ |
|
15 |
bswap16s(&ehdr->e_shstrndx); /* Section header string table index */ |
|
16 |
} |
|
17 |
|
|
18 |
static void glue(bswap_phdr, SZ)(struct elf_phdr *phdr) |
|
19 |
{ |
|
20 |
bswap32s(&phdr->p_type); /* Segment type */ |
|
21 |
bswapSZs(&phdr->p_offset); /* Segment file offset */ |
|
22 |
bswapSZs(&phdr->p_vaddr); /* Segment virtual address */ |
|
23 |
bswapSZs(&phdr->p_paddr); /* Segment physical address */ |
|
24 |
bswapSZs(&phdr->p_filesz); /* Segment size in file */ |
|
25 |
bswapSZs(&phdr->p_memsz); /* Segment size in memory */ |
|
26 |
bswap32s(&phdr->p_flags); /* Segment flags */ |
|
27 |
bswapSZs(&phdr->p_align); /* Segment alignment */ |
|
28 |
} |
|
29 |
|
|
30 |
static void glue(bswap_shdr, SZ)(struct elf_shdr *shdr) |
|
31 |
{ |
|
32 |
bswap32s(&shdr->sh_name); |
|
33 |
bswap32s(&shdr->sh_type); |
|
34 |
bswapSZs(&shdr->sh_flags); |
|
35 |
bswapSZs(&shdr->sh_addr); |
|
36 |
bswapSZs(&shdr->sh_offset); |
|
37 |
bswapSZs(&shdr->sh_size); |
|
38 |
bswap32s(&shdr->sh_link); |
|
39 |
bswap32s(&shdr->sh_info); |
|
40 |
bswapSZs(&shdr->sh_addralign); |
|
41 |
bswapSZs(&shdr->sh_entsize); |
|
42 |
} |
|
43 |
|
|
44 |
static void glue(bswap_sym, SZ)(struct elf_sym *sym) |
|
45 |
{ |
|
46 |
bswap32s(&sym->st_name); |
|
47 |
bswapSZs(&sym->st_value); |
|
48 |
bswapSZs(&sym->st_size); |
|
49 |
bswap16s(&sym->st_shndx); |
|
50 |
} |
|
51 |
|
|
52 |
static struct elf_shdr *glue(find_section, SZ)(struct elf_shdr *shdr_table, |
|
53 |
int n, int type) |
|
54 |
{ |
|
55 |
int i; |
|
56 |
for(i=0;i<n;i++) { |
|
57 |
if (shdr_table[i].sh_type == type) |
|
58 |
return shdr_table + i; |
|
59 |
} |
|
60 |
return NULL; |
|
61 |
} |
|
62 |
|
|
63 |
static int glue(symfind, SZ)(const void *s0, const void *s1) |
|
64 |
{ |
|
65 |
struct elf_sym *key = (struct elf_sym *)s0; |
|
66 |
struct elf_sym *sym = (struct elf_sym *)s1; |
|
67 |
int result = 0; |
|
68 |
if (key->st_value < sym->st_value) { |
|
69 |
result = -1; |
|
70 |
} else if (key->st_value >= sym->st_value + sym->st_size) { |
|
71 |
result = 1; |
|
72 |
} |
|
73 |
return result; |
|
74 |
} |
|
75 |
|
|
76 |
static const char *glue(lookup_symbol, SZ)(struct syminfo *s, |
|
77 |
target_phys_addr_t orig_addr) |
|
78 |
{ |
|
79 |
struct elf_sym *syms = glue(s->disas_symtab.elf, SZ); |
|
80 |
struct elf_sym key; |
|
81 |
struct elf_sym *sym; |
|
82 |
|
|
83 |
key.st_value = orig_addr; |
|
84 |
|
|
85 |
sym = bsearch(&key, syms, s->disas_num_syms, sizeof(*syms), glue(symfind, SZ)); |
|
86 |
if (sym != NULL) { |
|
87 |
return s->disas_strtab + sym->st_name; |
|
88 |
} |
|
89 |
|
|
90 |
return ""; |
|
91 |
} |
|
92 |
|
|
93 |
static int glue(symcmp, SZ)(const void *s0, const void *s1) |
|
94 |
{ |
|
95 |
struct elf_sym *sym0 = (struct elf_sym *)s0; |
|
96 |
struct elf_sym *sym1 = (struct elf_sym *)s1; |
|
97 |
return (sym0->st_value < sym1->st_value) |
|
98 |
? -1 |
|
99 |
: ((sym0->st_value > sym1->st_value) ? 1 : 0); |
|
100 |
} |
|
101 |
|
|
102 |
static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab, |
|
103 |
int clear_lsb) |
|
104 |
{ |
|
105 |
struct elf_shdr *symtab, *strtab, *shdr_table = NULL; |
|
106 |
struct elf_sym *syms = NULL; |
|
107 |
struct syminfo *s; |
|
108 |
int nsyms, i; |
|
109 |
char *str = NULL; |
|
110 |
|
|
111 |
shdr_table = load_at(fd, ehdr->e_shoff, |
|
112 |
sizeof(struct elf_shdr) * ehdr->e_shnum); |
|
113 |
if (!shdr_table) |
|
114 |
return -1; |
|
115 |
|
|
116 |
if (must_swab) { |
|
117 |
for (i = 0; i < ehdr->e_shnum; i++) { |
|
118 |
glue(bswap_shdr, SZ)(shdr_table + i); |
|
119 |
} |
|
120 |
} |
|
121 |
|
|
122 |
symtab = glue(find_section, SZ)(shdr_table, ehdr->e_shnum, SHT_SYMTAB); |
|
123 |
if (!symtab) |
|
124 |
goto fail; |
|
125 |
syms = load_at(fd, symtab->sh_offset, symtab->sh_size); |
|
126 |
if (!syms) |
|
127 |
goto fail; |
|
128 |
|
|
129 |
nsyms = symtab->sh_size / sizeof(struct elf_sym); |
|
130 |
|
|
131 |
i = 0; |
|
132 |
while (i < nsyms) { |
|
133 |
if (must_swab) |
|
134 |
glue(bswap_sym, SZ)(&syms[i]); |
|
135 |
/* We are only interested in function symbols. |
|
136 |
Throw everything else away. */ |
|
137 |
if (syms[i].st_shndx == SHN_UNDEF || |
|
138 |
syms[i].st_shndx >= SHN_LORESERVE || |
|
139 |
ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) { |
|
140 |
nsyms--; |
|
141 |
if (i < nsyms) { |
|
142 |
syms[i] = syms[nsyms]; |
|
143 |
} |
|
144 |
continue; |
|
145 |
} |
|
146 |
if (clear_lsb) { |
|
147 |
/* The bottom address bit marks a Thumb or MIPS16 symbol. */ |
|
148 |
syms[i].st_value &= ~(glue(glue(Elf, SZ), _Addr))1; |
|
149 |
} |
|
150 |
i++; |
|
151 |
} |
|
152 |
syms = qemu_realloc(syms, nsyms * sizeof(*syms)); |
|
153 |
|
|
154 |
qsort(syms, nsyms, sizeof(*syms), glue(symcmp, SZ)); |
|
155 |
|
|
156 |
/* String table */ |
|
157 |
if (symtab->sh_link >= ehdr->e_shnum) |
|
158 |
goto fail; |
|
159 |
strtab = &shdr_table[symtab->sh_link]; |
|
160 |
|
|
161 |
str = load_at(fd, strtab->sh_offset, strtab->sh_size); |
|
162 |
if (!str) |
|
163 |
goto fail; |
|
164 |
|
|
165 |
/* Commit */ |
|
166 |
s = qemu_mallocz(sizeof(*s)); |
|
167 |
s->lookup_symbol = glue(lookup_symbol, SZ); |
|
168 |
glue(s->disas_symtab.elf, SZ) = syms; |
|
169 |
s->disas_num_syms = nsyms; |
|
170 |
s->disas_strtab = str; |
|
171 |
s->next = syminfos; |
|
172 |
syminfos = s; |
|
173 |
qemu_free(shdr_table); |
|
174 |
return 0; |
|
175 |
fail: |
|
176 |
qemu_free(syms); |
|
177 |
qemu_free(str); |
|
178 |
qemu_free(shdr_table); |
|
179 |
return -1; |
|
180 |
} |
|
181 |
|
|
182 |
static int glue(load_elf, SZ)(int fd, int64_t address_offset, |
|
183 |
int must_swab, uint64_t *pentry, |
|
184 |
uint64_t *lowaddr, uint64_t *highaddr, |
|
185 |
int elf_machine, int clear_lsb) |
|
186 |
{ |
|
187 |
struct elfhdr ehdr; |
|
188 |
struct elf_phdr *phdr = NULL, *ph; |
|
189 |
int size, i, total_size; |
|
190 |
elf_word mem_size; |
|
191 |
uint64_t addr, low = (uint64_t)-1, high = 0; |
|
192 |
uint8_t *data = NULL; |
|
193 |
|
|
194 |
if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr)) |
|
195 |
goto fail; |
|
196 |
if (must_swab) { |
|
197 |
glue(bswap_ehdr, SZ)(&ehdr); |
|
198 |
} |
|
199 |
|
|
200 |
switch (elf_machine) { |
|
201 |
case EM_PPC64: |
|
202 |
if (EM_PPC64 != ehdr.e_machine) |
|
203 |
if (EM_PPC != ehdr.e_machine) |
|
204 |
goto fail; |
|
205 |
break; |
|
206 |
case EM_X86_64: |
|
207 |
if (EM_X86_64 != ehdr.e_machine) |
|
208 |
if (EM_386 != ehdr.e_machine) |
|
209 |
goto fail; |
|
210 |
break; |
|
211 |
default: |
|
212 |
if (elf_machine != ehdr.e_machine) |
|
213 |
goto fail; |
|
214 |
} |
|
215 |
|
|
216 |
if (pentry) |
|
217 |
*pentry = (uint64_t)(elf_sword)ehdr.e_entry; |
|
218 |
|
|
219 |
glue(load_symbols, SZ)(&ehdr, fd, must_swab, clear_lsb); |
|
220 |
|
|
221 |
size = ehdr.e_phnum * sizeof(phdr[0]); |
|
222 |
lseek(fd, ehdr.e_phoff, SEEK_SET); |
|
223 |
phdr = qemu_mallocz(size); |
|
224 |
if (!phdr) |
|
225 |
goto fail; |
|
226 |
if (read(fd, phdr, size) != size) |
|
227 |
goto fail; |
|
228 |
if (must_swab) { |
|
229 |
for(i = 0; i < ehdr.e_phnum; i++) { |
|
230 |
ph = &phdr[i]; |
|
231 |
glue(bswap_phdr, SZ)(ph); |
|
232 |
} |
|
233 |
} |
|
234 |
|
|
235 |
total_size = 0; |
|
236 |
for(i = 0; i < ehdr.e_phnum; i++) { |
|
237 |
ph = &phdr[i]; |
|
238 |
if (ph->p_type == PT_LOAD) { |
|
239 |
mem_size = ph->p_memsz; |
|
240 |
/* XXX: avoid allocating */ |
|
241 |
data = qemu_mallocz(mem_size); |
|
242 |
if (ph->p_filesz > 0) { |
|
243 |
if (lseek(fd, ph->p_offset, SEEK_SET) < 0) |
|
244 |
goto fail; |
|
245 |
if (read(fd, data, ph->p_filesz) != ph->p_filesz) |
|
246 |
goto fail; |
|
247 |
} |
|
248 |
/* address_offset is hack for kernel images that are |
|
249 |
linked at the wrong physical address. */ |
|
250 |
addr = ph->p_paddr + address_offset; |
|
251 |
|
|
252 |
cpu_physical_memory_write_rom(addr, data, mem_size); |
|
253 |
|
|
254 |
total_size += mem_size; |
|
255 |
if (addr < low) |
|
256 |
low = addr; |
|
257 |
if ((addr + mem_size) > high) |
|
258 |
high = addr + mem_size; |
|
259 |
|
|
260 |
qemu_free(data); |
|
261 |
data = NULL; |
|
262 |
} |
|
263 |
} |
|
264 |
qemu_free(phdr); |
|
265 |
if (lowaddr) |
|
266 |
*lowaddr = (uint64_t)(elf_sword)low; |
|
267 |
if (highaddr) |
|
268 |
*highaddr = (uint64_t)(elf_sword)high; |
|
269 |
return total_size; |
|
270 |
fail: |
|
271 |
qemu_free(data); |
|
272 |
qemu_free(phdr); |
|
273 |
return -1; |
|
274 |
} |
b/hw/etraxfs.c | ||
---|---|---|
28 | 28 |
#include "net.h" |
29 | 29 |
#include "flash.h" |
30 | 30 |
#include "etraxfs.h" |
31 |
#include "loader.h" |
|
32 |
#include "elf.h" |
|
31 | 33 |
|
32 | 34 |
#define FLASH_SIZE 0x2000000 |
33 | 35 |
#define INTMEM_SIZE (128 * 1024) |
... | ... | |
136 | 138 |
/* Boots a kernel elf binary, os/linux-2.6/vmlinux from the axis |
137 | 139 |
devboard SDK. */ |
138 | 140 |
kernel_size = load_elf(kernel_filename, -0x80000000LL, |
139 |
&entry, NULL, &high); |
|
141 |
&entry, NULL, &high, 0, ELF_MACHINE, 0);
|
|
140 | 142 |
bootstrap_pc = entry; |
141 | 143 |
if (kernel_size < 0) { |
142 | 144 |
/* Takes a kimage from the axis devboard SDK. */ |
b/hw/loader.c | ||
---|---|---|
1 |
/* |
|
2 |
* QEMU Executable loader |
|
3 |
* |
|
4 |
* Copyright (c) 2006 Fabrice Bellard |
|
5 |
* |
|
6 |
* Permission is hereby granted, free of charge, to any person obtaining a copy |
|
7 |
* of this software and associated documentation files (the "Software"), to deal |
|
8 |
* in the Software without restriction, including without limitation the rights |
|
9 |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
10 |
* copies of the Software, and to permit persons to whom the Software is |
|
11 |
* furnished to do so, subject to the following conditions: |
|
12 |
* |
|
13 |
* The above copyright notice and this permission notice shall be included in |
|
14 |
* all copies or substantial portions of the Software. |
|
15 |
* |
|
16 |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
17 |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
18 |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|
19 |
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
20 |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
21 |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
22 |
* THE SOFTWARE. |
|
23 |
* |
|
24 |
* Gunzip functionality in this file is derived from u-boot: |
|
25 |
* |
|
26 |
* (C) Copyright 2008 Semihalf |
|
27 |
* |
|
28 |
* (C) Copyright 2000-2005 |
|
29 |
* Wolfgang Denk, DENX Software Engineering, wd@denx.de. |
|
30 |
* |
|
31 |
* This program is free software; you can redistribute it and/or |
|
32 |
* modify it under the terms of the GNU General Public License as |
|
33 |
* published by the Free Software Foundation; either version 2 of |
|
34 |
* the License, or (at your option) any later version. |
|
35 |
* |
|
36 |
* This program is distributed in the hope that it will be useful, |
|
37 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
38 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
39 |
* GNU General Public License for more details. |
|
40 |
* |
|
41 |
* You should have received a copy of the GNU General Public License along |
|
42 |
* with this program; if not, see <http://www.gnu.org/licenses/>. |
|
43 |
*/ |
|
44 |
|
|
45 |
#include "hw.h" |
|
46 |
#include "disas.h" |
|
47 |
#include "sysemu.h" |
|
48 |
#include "uboot_image.h" |
|
49 |
#include "loader.h" |
|
50 |
|
|
51 |
#include <zlib.h> |
|
52 |
|
|
53 |
/* return the size or -1 if error */ |
|
54 |
int get_image_size(const char *filename) |
|
55 |
{ |
|
56 |
int fd, size; |
|
57 |
fd = open(filename, O_RDONLY | O_BINARY); |
|
58 |
if (fd < 0) |
|
59 |
return -1; |
|
60 |
size = lseek(fd, 0, SEEK_END); |
|
61 |
close(fd); |
|
62 |
return size; |
|
63 |
} |
|
64 |
|
|
65 |
/* return the size or -1 if error */ |
|
66 |
/* deprecated, because caller does not specify buffer size! */ |
|
67 |
int load_image(const char *filename, uint8_t *addr) |
|
68 |
{ |
|
69 |
int fd, size; |
|
70 |
fd = open(filename, O_RDONLY | O_BINARY); |
|
71 |
if (fd < 0) |
|
72 |
return -1; |
|
73 |
size = lseek(fd, 0, SEEK_END); |
|
74 |
lseek(fd, 0, SEEK_SET); |
|
75 |
if (read(fd, addr, size) != size) { |
|
76 |
close(fd); |
|
77 |
return -1; |
|
78 |
} |
|
79 |
close(fd); |
|
80 |
return size; |
|
81 |
} |
|
82 |
|
|
83 |
/* return the amount read, just like fread. 0 may mean error or eof */ |
|
84 |
int fread_targphys(target_phys_addr_t dst_addr, size_t nbytes, FILE *f) |
|
85 |
{ |
|
86 |
uint8_t buf[4096]; |
|
87 |
target_phys_addr_t dst_begin = dst_addr; |
|
88 |
size_t want, did; |
|
89 |
|
|
90 |
while (nbytes) { |
|
91 |
want = nbytes > sizeof(buf) ? sizeof(buf) : nbytes; |
|
92 |
did = fread(buf, 1, want, f); |
|
93 |
|
|
94 |
cpu_physical_memory_write_rom(dst_addr, buf, did); |
|
95 |
dst_addr += did; |
|
96 |
nbytes -= did; |
|
97 |
if (did != want) |
|
98 |
break; |
|
99 |
} |
|
100 |
return dst_addr - dst_begin; |
|
101 |
} |
|
102 |
|
|
103 |
/* returns 0 on error, 1 if ok */ |
|
104 |
int fread_targphys_ok(target_phys_addr_t dst_addr, size_t nbytes, FILE *f) |
|
105 |
{ |
|
106 |
return fread_targphys(dst_addr, nbytes, f) == nbytes; |
|
107 |
} |
|
108 |
|
|
109 |
/* read()-like version */ |
|
110 |
int read_targphys(int fd, target_phys_addr_t dst_addr, size_t nbytes) |
|
111 |
{ |
|
112 |
uint8_t buf[4096]; |
|
113 |
target_phys_addr_t dst_begin = dst_addr; |
|
114 |
size_t want, did; |
|
115 |
|
|
116 |
while (nbytes) { |
|
117 |
want = nbytes > sizeof(buf) ? sizeof(buf) : nbytes; |
|
118 |
did = read(fd, buf, want); |
|
119 |
if (did != want) break; |
|
120 |
|
|
121 |
cpu_physical_memory_write_rom(dst_addr, buf, did); |
|
122 |
dst_addr += did; |
|
123 |
nbytes -= did; |
|
124 |
} |
|
125 |
return dst_addr - dst_begin; |
|
126 |
} |
|
127 |
|
|
128 |
/* return the size or -1 if error */ |
|
129 |
int load_image_targphys(const char *filename, |
|
130 |
target_phys_addr_t addr, int max_sz) |
|
131 |
{ |
|
132 |
FILE *f; |
|
133 |
size_t got; |
|
134 |
|
|
135 |
f = fopen(filename, "rb"); |
|
136 |
if (!f) return -1; |
|
137 |
|
|
138 |
got = fread_targphys(addr, max_sz, f); |
|
139 |
if (ferror(f)) { fclose(f); return -1; } |
|
140 |
fclose(f); |
|
141 |
|
|
142 |
return got; |
|
143 |
} |
|
144 |
|
|
145 |
void pstrcpy_targphys(target_phys_addr_t dest, int buf_size, |
|
146 |
const char *source) |
|
147 |
{ |
|
148 |
static const uint8_t nul_byte = 0; |
|
149 |
const char *nulp; |
|
150 |
|
|
151 |
if (buf_size <= 0) return; |
|
152 |
nulp = memchr(source, 0, buf_size); |
|
153 |
if (nulp) { |
|
154 |
cpu_physical_memory_write_rom(dest, (uint8_t *)source, |
|
155 |
(nulp - source) + 1); |
|
156 |
} else { |
|
157 |
cpu_physical_memory_write_rom(dest, (uint8_t *)source, buf_size - 1); |
|
158 |
cpu_physical_memory_write_rom(dest, &nul_byte, 1); |
|
159 |
} |
|
160 |
} |
|
161 |
|
|
162 |
/* A.OUT loader */ |
|
163 |
|
|
164 |
struct exec |
|
165 |
{ |
|
166 |
uint32_t a_info; /* Use macros N_MAGIC, etc for access */ |
|
167 |
uint32_t a_text; /* length of text, in bytes */ |
|
168 |
uint32_t a_data; /* length of data, in bytes */ |
|
169 |
uint32_t a_bss; /* length of uninitialized data area, in bytes */ |
|
170 |
uint32_t a_syms; /* length of symbol table data in file, in bytes */ |
|
171 |
uint32_t a_entry; /* start address */ |
|
172 |
uint32_t a_trsize; /* length of relocation info for text, in bytes */ |
|
173 |
uint32_t a_drsize; /* length of relocation info for data, in bytes */ |
|
174 |
}; |
|
175 |
|
|
176 |
static void bswap_ahdr(struct exec *e) |
|
177 |
{ |
|
178 |
bswap32s(&e->a_info); |
|
179 |
bswap32s(&e->a_text); |
|
180 |
bswap32s(&e->a_data); |
|
181 |
bswap32s(&e->a_bss); |
|
182 |
bswap32s(&e->a_syms); |
|
183 |
bswap32s(&e->a_entry); |
|
184 |
bswap32s(&e->a_trsize); |
|
185 |
bswap32s(&e->a_drsize); |
|
186 |
} |
|
187 |
|
|
188 |
#define N_MAGIC(exec) ((exec).a_info & 0xffff) |
|
189 |
#define OMAGIC 0407 |
|
190 |
#define NMAGIC 0410 |
|
191 |
#define ZMAGIC 0413 |
|
192 |
#define QMAGIC 0314 |
|
193 |
#define _N_HDROFF(x) (1024 - sizeof (struct exec)) |
|
194 |
#define N_TXTOFF(x) \ |
|
195 |
(N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) : \ |
|
196 |
(N_MAGIC(x) == QMAGIC ? 0 : sizeof (struct exec))) |
|
197 |
#define N_TXTADDR(x, target_page_size) (N_MAGIC(x) == QMAGIC ? target_page_size : 0) |
|
198 |
#define _N_SEGMENT_ROUND(x, target_page_size) (((x) + target_page_size - 1) & ~(target_page_size - 1)) |
|
199 |
|
|
200 |
#define _N_TXTENDADDR(x, target_page_size) (N_TXTADDR(x, target_page_size)+(x).a_text) |
|
201 |
|
|
202 |
#define N_DATADDR(x, target_page_size) \ |
|
203 |
(N_MAGIC(x)==OMAGIC? (_N_TXTENDADDR(x, target_page_size)) \ |
|
204 |
: (_N_SEGMENT_ROUND (_N_TXTENDADDR(x, target_page_size), target_page_size))) |
|
205 |
|
|
206 |
|
|
207 |
int load_aout(const char *filename, target_phys_addr_t addr, int max_sz, |
|
208 |
int bswap_needed, target_phys_addr_t target_page_size) |
|
209 |
{ |
|
210 |
int fd, size, ret; |
|
211 |
struct exec e; |
|
212 |
uint32_t magic; |
|
213 |
|
|
214 |
fd = open(filename, O_RDONLY | O_BINARY); |
|
215 |
if (fd < 0) |
|
216 |
return -1; |
|
217 |
|
|
218 |
size = read(fd, &e, sizeof(e)); |
|
219 |
if (size < 0) |
|
220 |
goto fail; |
|
221 |
|
|
222 |
if (bswap_needed) { |
|
223 |
bswap_ahdr(&e); |
|
224 |
} |
|
225 |
|
|
226 |
magic = N_MAGIC(e); |
|
227 |
switch (magic) { |
|
228 |
case ZMAGIC: |
|
229 |
case QMAGIC: |
|
230 |
case OMAGIC: |
|
231 |
if (e.a_text + e.a_data > max_sz) |
|
232 |
goto fail; |
|
233 |
lseek(fd, N_TXTOFF(e), SEEK_SET); |
|
234 |
size = read_targphys(fd, addr, e.a_text + e.a_data); |
|
235 |
if (size < 0) |
|
236 |
goto fail; |
|
237 |
break; |
|
238 |
case NMAGIC: |
|
239 |
if (N_DATADDR(e, target_page_size) + e.a_data > max_sz) |
|
240 |
goto fail; |
|
241 |
lseek(fd, N_TXTOFF(e), SEEK_SET); |
|
242 |
size = read_targphys(fd, addr, e.a_text); |
|
243 |
if (size < 0) |
|
244 |
goto fail; |
|
245 |
ret = read_targphys(fd, addr + N_DATADDR(e, target_page_size), |
|
246 |
e.a_data); |
|
247 |
if (ret < 0) |
|
248 |
goto fail; |
|
249 |
size += ret; |
|
250 |
break; |
|
251 |
default: |
|
252 |
goto fail; |
|
253 |
} |
|
254 |
close(fd); |
|
255 |
return size; |
|
256 |
fail: |
|
257 |
close(fd); |
|
258 |
return -1; |
|
259 |
} |
|
260 |
|
|
261 |
/* ELF loader */ |
|
262 |
|
|
263 |
static void *load_at(int fd, int offset, int size) |
|
264 |
{ |
|
265 |
void *ptr; |
|
266 |
if (lseek(fd, offset, SEEK_SET) < 0) |
|
267 |
return NULL; |
|
268 |
ptr = qemu_malloc(size); |
|
269 |
if (read(fd, ptr, size) != size) { |
|
270 |
qemu_free(ptr); |
|
271 |
return NULL; |
|
272 |
} |
|
273 |
return ptr; |
|
274 |
} |
|
275 |
|
|
276 |
#ifdef ELF_CLASS |
|
277 |
#undef ELF_CLASS |
|
278 |
#endif |
|
279 |
|
|
280 |
#define ELF_CLASS ELFCLASS32 |
|
281 |
#include "elf.h" |
|
282 |
|
|
283 |
#define SZ 32 |
|
284 |
#define elf_word uint32_t |
|
285 |
#define elf_sword int32_t |
|
286 |
#define bswapSZs bswap32s |
|
287 |
#include "elf_ops.h" |
|
288 |
|
|
289 |
#undef elfhdr |
|
290 |
#undef elf_phdr |
|
291 |
#undef elf_shdr |
|
292 |
#undef elf_sym |
|
293 |
#undef elf_note |
|
294 |
#undef elf_word |
|
295 |
#undef elf_sword |
|
296 |
#undef bswapSZs |
|
297 |
#undef SZ |
|
298 |
#define elfhdr elf64_hdr |
|
299 |
#define elf_phdr elf64_phdr |
|
300 |
#define elf_note elf64_note |
|
301 |
#define elf_shdr elf64_shdr |
|
302 |
#define elf_sym elf64_sym |
|
303 |
#define elf_word uint64_t |
|
304 |
#define elf_sword int64_t |
|
305 |
#define bswapSZs bswap64s |
|
306 |
#define SZ 64 |
|
307 |
#include "elf_ops.h" |
|
308 |
|
|
309 |
/* return < 0 if error, otherwise the number of bytes loaded in memory */ |
|
310 |
int load_elf(const char *filename, int64_t address_offset, |
|
311 |
uint64_t *pentry, uint64_t *lowaddr, uint64_t *highaddr, |
|
312 |
int big_endian, int elf_machine, int clear_lsb) |
|
313 |
{ |
|
314 |
int fd, data_order, target_data_order, must_swab, ret; |
|
315 |
uint8_t e_ident[EI_NIDENT]; |
|
316 |
|
|
317 |
fd = open(filename, O_RDONLY | O_BINARY); |
|
318 |
if (fd < 0) { |
|
319 |
perror(filename); |
|
320 |
return -1; |
|
321 |
} |
|
322 |
if (read(fd, e_ident, sizeof(e_ident)) != sizeof(e_ident)) |
|
323 |
goto fail; |
|
324 |
if (e_ident[0] != ELFMAG0 || |
|
325 |
e_ident[1] != ELFMAG1 || |
|
326 |
e_ident[2] != ELFMAG2 || |
|
327 |
e_ident[3] != ELFMAG3) |
|
328 |
goto fail; |
|
329 |
#ifdef HOST_WORDS_BIGENDIAN |
|
330 |
data_order = ELFDATA2MSB; |
|
331 |
#else |
|
332 |
data_order = ELFDATA2LSB; |
|
333 |
#endif |
|
334 |
must_swab = data_order != e_ident[EI_DATA]; |
|
335 |
if (big_endian) { |
|
336 |
target_data_order = ELFDATA2MSB; |
|
337 |
} else { |
|
338 |
target_data_order = ELFDATA2LSB; |
|
339 |
} |
|
340 |
|
|
341 |
if (target_data_order != e_ident[EI_DATA]) |
|
342 |
return -1; |
|
343 |
|
|
344 |
lseek(fd, 0, SEEK_SET); |
|
345 |
if (e_ident[EI_CLASS] == ELFCLASS64) { |
|
346 |
ret = load_elf64(fd, address_offset, must_swab, pentry, |
|
347 |
lowaddr, highaddr, elf_machine, clear_lsb); |
|
348 |
} else { |
|
349 |
ret = load_elf32(fd, address_offset, must_swab, pentry, |
|
350 |
lowaddr, highaddr, elf_machine, clear_lsb); |
|
351 |
} |
|
352 |
|
|
353 |
close(fd); |
|
354 |
return ret; |
|
355 |
|
|
356 |
fail: |
|
357 |
close(fd); |
|
358 |
return -1; |
|
359 |
} |
|
360 |
|
|
361 |
static void bswap_uboot_header(uboot_image_header_t *hdr) |
|
362 |
{ |
|
363 |
#ifndef HOST_WORDS_BIGENDIAN |
|
364 |
bswap32s(&hdr->ih_magic); |
|
365 |
bswap32s(&hdr->ih_hcrc); |
|
366 |
bswap32s(&hdr->ih_time); |
|
367 |
bswap32s(&hdr->ih_size); |
|
368 |
bswap32s(&hdr->ih_load); |
|
369 |
bswap32s(&hdr->ih_ep); |
|
370 |
bswap32s(&hdr->ih_dcrc); |
|
371 |
#endif |
|
372 |
} |
|
373 |
|
|
374 |
|
|
375 |
#define ZALLOC_ALIGNMENT 16 |
|
376 |
|
|
377 |
static void *zalloc(void *x, unsigned items, unsigned size) |
|
378 |
{ |
|
379 |
void *p; |
|
380 |
|
|
381 |
size *= items; |
|
382 |
size = (size + ZALLOC_ALIGNMENT - 1) & ~(ZALLOC_ALIGNMENT - 1); |
|
383 |
|
|
384 |
p = qemu_malloc(size); |
|
385 |
|
|
386 |
return (p); |
|
387 |
} |
|
388 |
|
|
389 |
static void zfree(void *x, void *addr) |
|
390 |
{ |
|
391 |
qemu_free(addr); |
|
392 |
} |
|
393 |
|
|
394 |
|
|
395 |
#define HEAD_CRC 2 |
|
396 |
#define EXTRA_FIELD 4 |
|
397 |
#define ORIG_NAME 8 |
|
398 |
#define COMMENT 0x10 |
|
399 |
#define RESERVED 0xe0 |
|
400 |
|
|
401 |
#define DEFLATED 8 |
|
402 |
|
|
403 |
/* This is the maximum in uboot, so if a uImage overflows this, it would |
|
404 |
* overflow on real hardware too. */ |
|
405 |
#define UBOOT_MAX_GUNZIP_BYTES 0x800000 |
|
406 |
|
|
407 |
static ssize_t gunzip(void *dst, size_t dstlen, uint8_t *src, |
|
408 |
size_t srclen) |
|
409 |
{ |
|
410 |
z_stream s; |
|
411 |
ssize_t dstbytes; |
|
412 |
int r, i, flags; |
|
413 |
|
|
414 |
/* skip header */ |
|
415 |
i = 10; |
|
416 |
flags = src[3]; |
|
417 |
if (src[2] != DEFLATED || (flags & RESERVED) != 0) { |
|
418 |
puts ("Error: Bad gzipped data\n"); |
|
419 |
return -1; |
|
420 |
} |
|
421 |
if ((flags & EXTRA_FIELD) != 0) |
|
422 |
i = 12 + src[10] + (src[11] << 8); |
|
423 |
if ((flags & ORIG_NAME) != 0) |
|
424 |
while (src[i++] != 0) |
|
425 |
; |
|
426 |
if ((flags & COMMENT) != 0) |
|
427 |
while (src[i++] != 0) |
|
428 |
; |
|
429 |
if ((flags & HEAD_CRC) != 0) |
|
430 |
i += 2; |
|
431 |
if (i >= srclen) { |
|
432 |
puts ("Error: gunzip out of data in header\n"); |
|
433 |
return -1; |
|
434 |
} |
|
435 |
|
|
436 |
s.zalloc = zalloc; |
|
437 |
s.zfree = zfree; |
|
438 |
|
|
439 |
r = inflateInit2(&s, -MAX_WBITS); |
|
440 |
if (r != Z_OK) { |
|
441 |
printf ("Error: inflateInit2() returned %d\n", r); |
|
442 |
return (-1); |
|
443 |
} |
|
444 |
s.next_in = src + i; |
|
445 |
s.avail_in = srclen - i; |
|
446 |
s.next_out = dst; |
|
447 |
s.avail_out = dstlen; |
|
448 |
r = inflate(&s, Z_FINISH); |
|
449 |
if (r != Z_OK && r != Z_STREAM_END) { |
|
450 |
printf ("Error: inflate() returned %d\n", r); |
|
451 |
return -1; |
|
452 |
} |
|
453 |
dstbytes = s.next_out - (unsigned char *) dst; |
|
454 |
inflateEnd(&s); |
|
455 |
|
|
456 |
return dstbytes; |
|
457 |
} |
|
458 |
|
|
459 |
/* Load a U-Boot image. */ |
|
460 |
int load_uimage(const char *filename, target_phys_addr_t *ep, |
|
461 |
target_phys_addr_t *loadaddr, int *is_linux) |
|
462 |
{ |
|
463 |
int fd; |
|
464 |
int size; |
|
465 |
uboot_image_header_t h; |
|
466 |
uboot_image_header_t *hdr = &h; |
|
467 |
uint8_t *data = NULL; |
|
468 |
int ret = -1; |
|
469 |
|
|
470 |
fd = open(filename, O_RDONLY | O_BINARY); |
|
471 |
if (fd < 0) |
|
472 |
return -1; |
|
473 |
|
|
474 |
size = read(fd, hdr, sizeof(uboot_image_header_t)); |
|
475 |
if (size < 0) |
|
476 |
goto out; |
|
477 |
|
|
478 |
bswap_uboot_header(hdr); |
|
479 |
|
|
480 |
if (hdr->ih_magic != IH_MAGIC) |
|
481 |
goto out; |
|
482 |
|
|
483 |
/* TODO: Implement other image types. */ |
|
484 |
if (hdr->ih_type != IH_TYPE_KERNEL) { |
|
485 |
fprintf(stderr, "Can only load u-boot image type \"kernel\"\n"); |
|
486 |
goto out; |
|
487 |
} |
|
488 |
|
|
489 |
switch (hdr->ih_comp) { |
|
490 |
case IH_COMP_NONE: |
|
491 |
case IH_COMP_GZIP: |
|
492 |
break; |
|
493 |
default: |
|
494 |
fprintf(stderr, |
|
495 |
"Unable to load u-boot images with compression type %d\n", |
|
496 |
hdr->ih_comp); |
|
497 |
goto out; |
|
498 |
} |
|
499 |
|
|
500 |
/* TODO: Check CPU type. */ |
|
501 |
if (is_linux) { |
|
502 |
if (hdr->ih_os == IH_OS_LINUX) |
|
503 |
*is_linux = 1; |
|
504 |
else |
|
505 |
*is_linux = 0; |
|
506 |
} |
|
507 |
|
|
508 |
*ep = hdr->ih_ep; |
|
509 |
data = qemu_malloc(hdr->ih_size); |
|
510 |
|
|
511 |
if (read(fd, data, hdr->ih_size) != hdr->ih_size) { |
|
512 |
fprintf(stderr, "Error reading file\n"); |
|
513 |
goto out; |
|
514 |
} |
|
515 |
|
|
516 |
if (hdr->ih_comp == IH_COMP_GZIP) { |
|
517 |
uint8_t *compressed_data; |
|
518 |
size_t max_bytes; |
|
519 |
ssize_t bytes; |
|
520 |
|
|
521 |
compressed_data = data; |
|
522 |
max_bytes = UBOOT_MAX_GUNZIP_BYTES; |
|
523 |
data = qemu_malloc(max_bytes); |
|
524 |
|
|
525 |
bytes = gunzip(data, max_bytes, compressed_data, hdr->ih_size); |
|
526 |
qemu_free(compressed_data); |
|
527 |
if (bytes < 0) { |
|
528 |
fprintf(stderr, "Unable to decompress gzipped image!\n"); |
|
529 |
goto out; |
|
530 |
} |
|
531 |
hdr->ih_size = bytes; |
|
532 |
} |
|
533 |
|
|
534 |
cpu_physical_memory_write_rom(hdr->ih_load, data, hdr->ih_size); |
|
535 |
|
|
536 |
if (loadaddr) |
|
537 |
*loadaddr = hdr->ih_load; |
|
538 |
|
|
539 |
ret = hdr->ih_size; |
|
540 |
|
|
541 |
out: |
|
542 |
if (data) |
|
543 |
qemu_free(data); |
|
544 |
close(fd); |
|
545 |
return ret; |
|
546 |
} |
b/hw/loader.h | ||
---|---|---|
1 |
#ifndef LOADER_H |
|
2 |
#define LOADER_H |
|
3 |
|
|
4 |
/* loader.c */ |
|
5 |
int get_image_size(const char *filename); |
|
6 |
int load_image(const char *filename, uint8_t *addr); /* deprecated */ |
|
7 |
int load_image_targphys(const char *filename, target_phys_addr_t, int max_sz); |
|
8 |
int load_elf(const char *filename, int64_t address_offset, |
|
9 |
uint64_t *pentry, uint64_t *lowaddr, uint64_t *highaddr, |
|
10 |
int big_endian, int elf_machine, int clear_lsb); |
|
11 |
int load_aout(const char *filename, target_phys_addr_t addr, int max_sz, |
|
12 |
int bswap_needed, target_phys_addr_t target_page_size); |
|
13 |
int load_uimage(const char *filename, target_phys_addr_t *ep, |
|
14 |
target_phys_addr_t *loadaddr, int *is_linux); |
|
15 |
|
|
16 |
int fread_targphys(target_phys_addr_t dst_addr, size_t nbytes, FILE *f); |
|
17 |
int fread_targphys_ok(target_phys_addr_t dst_addr, size_t nbytes, FILE *f); |
|
18 |
int read_targphys(int fd, target_phys_addr_t dst_addr, size_t nbytes); |
|
19 |
void pstrcpy_targphys(target_phys_addr_t dest, int buf_size, |
|
20 |
const char *source); |
|
21 |
#endif |
b/hw/mcf5208.c | ||
---|---|---|
11 | 11 |
#include "sysemu.h" |
12 | 12 |
#include "net.h" |
13 | 13 |
#include "boards.h" |
14 |
#include "loader.h" |
|
15 |
#include "elf.h" |
|
14 | 16 |
|
15 | 17 |
#define SYS_FREQ 66000000 |
16 | 18 |
|
... | ... | |
201 | 203 |
CPUState *env; |
202 | 204 |
int kernel_size; |
203 | 205 |
uint64_t elf_entry; |
204 |
target_ulong entry;
|
|
206 |
target_phys_addr_t entry;
|
|
205 | 207 |
qemu_irq *pic; |
206 | 208 |
|
207 | 209 |
if (!cpu_model) |
... | ... | |
268 | 270 |
exit(1); |
269 | 271 |
} |
270 | 272 |
|
271 |
kernel_size = load_elf(kernel_filename, 0, &elf_entry, NULL, NULL); |
|
273 |
kernel_size = load_elf(kernel_filename, 0, &elf_entry, NULL, NULL, |
|
274 |
1, ELF_MACHINE, 0); |
|
272 | 275 |
entry = elf_entry; |
273 | 276 |
if (kernel_size < 0) { |
274 | 277 |
kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL); |
b/hw/mips_jazz.c | ||
---|---|---|
33 | 33 |
#include "net.h" |
34 | 34 |
#include "scsi.h" |
35 | 35 |
#include "mips-bios.h" |
36 |
#include "loader.h" |
|
36 | 37 |
|
37 | 38 |
enum jazz_model_e |
38 | 39 |
{ |
b/hw/mips_malta.c | ||
---|---|---|
39 | 39 |
#include "qemu-log.h" |
40 | 40 |
#include "mips-bios.h" |
41 | 41 |
#include "ide.h" |
42 |
#include "loader.h" |
|
43 |
#include "elf.h" |
|
42 | 44 |
|
43 | 45 |
//#define DEBUG_BOARD_INIT |
44 | 46 |
|
... | ... | |
687 | 689 |
int index = 0; |
688 | 690 |
long initrd_size; |
689 | 691 |
ram_addr_t initrd_offset; |
692 |
int big_endian; |
|
693 |
|
|
694 |
#ifdef TARGET_WORDS_BIGENDIAN |
|
695 |
big_endian = 1; |
|
696 |
#else |
|
697 |
big_endian = 0; |
|
698 |
#endif |
|
690 | 699 |
|
691 | 700 |
if (load_elf(loaderparams.kernel_filename, VIRT_TO_PHYS_ADDEND, |
692 | 701 |
(uint64_t *)&kernel_entry, (uint64_t *)&kernel_low, |
693 |
(uint64_t *)&kernel_high) < 0) { |
|
702 |
(uint64_t *)&kernel_high, big_endian, ELF_MACHINE, 1) < 0) {
|
|
694 | 703 |
fprintf(stderr, "qemu: could not load kernel '%s'\n", |
695 | 704 |
loaderparams.kernel_filename); |
696 | 705 |
exit(1); |
b/hw/mips_mipssim.c | ||
---|---|---|
32 | 32 |
#include "sysemu.h" |
33 | 33 |
#include "boards.h" |
34 | 34 |
#include "mips-bios.h" |
35 |
#include "loader.h" |
|
36 |
#include "elf.h" |
|
35 | 37 |
|
36 | 38 |
#ifdef TARGET_MIPS64 |
37 | 39 |
#define PHYS_TO_VIRT(x) ((x) | ~0x7fffffffULL) |
... | ... | |
54 | 56 |
long kernel_size; |
55 | 57 |
long initrd_size; |
56 | 58 |
ram_addr_t initrd_offset; |
59 |
int big_endian; |
|
60 |
|
|
61 |
#ifdef TARGET_WORDS_BIGENDIAN |
|
62 |
big_endian = 1; |
|
63 |
#else |
|
64 |
big_endian = 0; |
|
65 |
#endif |
|
57 | 66 |
|
58 | 67 |
kernel_size = load_elf(loaderparams.kernel_filename, VIRT_TO_PHYS_ADDEND, |
59 | 68 |
(uint64_t *)&entry, (uint64_t *)&kernel_low, |
60 |
(uint64_t *)&kernel_high); |
|
69 |
(uint64_t *)&kernel_high, big_endian, ELF_MACHINE, 1);
|
|
61 | 70 |
if (kernel_size >= 0) { |
62 | 71 |
if ((entry & ~0x7fffffffULL) == 0x80000000) |
63 | 72 |
entry = (int32_t)entry; |
Also available in: Unified diff