Statistics
| Branch: | Revision:

root / hw / magic-load.c @ 546fa6ab

History | View | Annotate | Download (7.6 kB)

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