Statistics
| Branch: | Revision:

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

History | View | Annotate | Download (7.6 kB)

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