Revision 8d5f07fa hw/magic-load.c

b/hw/magic-load.c
1
/* This is the Linux kernel elf-loading code, ported into user space */
2 1
#include "vl.h"
3 2
#include "disas.h"
4 3

  
5
/* XXX: this code is not used as it is under the GPL license. Please
6
   remove or recode it */
7
//#define USE_ELF_LOADER
8

  
9
#ifdef USE_ELF_LOADER
10
/* should probably go in elf.h */
11
#ifndef ELIBBAD
12
#define ELIBBAD 80
13
#endif
14

  
15

  
16
#define ELF_START_MMAP 0x80000000
17

  
18
#define elf_check_arch(x) ( (x) == EM_SPARC )
19

  
20 4
#define ELF_CLASS   ELFCLASS32
21 5
#define ELF_DATA    ELFDATA2MSB
22 6
#define ELF_ARCH    EM_SPARC
23 7

  
24 8
#include "elf.h"
25 9

  
26
/*
27
 * This structure is used to hold the arguments that are 
28
 * used when loading binaries.
29
 */
30
struct linux_binprm {
31
        char buf[128];
32
	int fd;
33
};
34

  
35
#define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE
36
#define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1))
37
#define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1))
38

  
39 10
#ifdef BSWAP_NEEDED
40 11
static void bswap_ehdr(Elf32_Ehdr *ehdr)
41 12
{
......
87 58
    bswap32s(&sym->st_size);
88 59
    bswap16s(&sym->st_shndx);
89 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)
90 66
#endif
91 67

  
92
static int prepare_binprm(struct linux_binprm *bprm)
68
static int find_phdr(struct elfhdr *ehdr, int fd, struct elf_phdr *phdr, uint32_t type)
93 69
{
94
    int retval;
95

  
96
    memset(bprm->buf, 0, sizeof(bprm->buf));
97
    retval = lseek(bprm->fd, 0L, SEEK_SET);
98
    if(retval >= 0) {
99
        retval = read(bprm->fd, bprm->buf, 128);
100
    }
101
    if(retval < 0) {
102
	perror("prepare_binprm");
103
	exit(-1);
104
	/* return(-errno); */
105
    }
106
    else {
107
	return(retval);
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;
108 83
    }
84
    return -1;
109 85
}
110 86

  
111
/* Best attempt to load symbols from this ELF object. */
112
static void load_symbols(struct elfhdr *hdr, int fd)
87
static void *find_shdr(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, uint32_t type)
113 88
{
114
    unsigned int i;
115
    struct elf_shdr sechdr, symtab, strtab;
116
    char *strings;
117

  
118
    lseek(fd, hdr->e_shoff, SEEK_SET);
119
    for (i = 0; i < hdr->e_shnum; i++) {
120
	if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr))
121
	    return;
122
#ifdef BSWAP_NEEDED
123
	bswap_shdr(&sechdr);
124
#endif
125
	if (sechdr.sh_type == SHT_SYMTAB) {
126
	    symtab = sechdr;
127
	    lseek(fd, hdr->e_shoff
128
		  + sizeof(sechdr) * sechdr.sh_link, SEEK_SET);
129
	    if (read(fd, &strtab, sizeof(strtab))
130
		!= sizeof(strtab))
131
		return;
132
#ifdef BSWAP_NEEDED
133
	    bswap_shdr(&strtab);
134
#endif
135
	    goto found;
136
	}
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);
137 102
    }
138
    return; /* Shouldn't happen... */
139

  
140
 found:
141
    /* Now know where the strtab and symtab are.  Snarf them. */
142
    disas_symtab = qemu_malloc(symtab.sh_size);
143
    disas_strtab = strings = qemu_malloc(strtab.sh_size);
144
    if (!disas_symtab || !disas_strtab)
145
	return;
146
	
147
    lseek(fd, symtab.sh_offset, SEEK_SET);
148
    if (read(fd, disas_symtab, symtab.sh_size) != symtab.sh_size)
149
	return;
103
    return NULL;
104
}
150 105

  
151
#ifdef BSWAP_NEEDED
152
    for (i = 0; i < symtab.sh_size / sizeof(struct elf_sym); i++)
153
	bswap_sym(disas_symtab + sizeof(struct elf_sym)*i);
154
#endif
106
static int find_strtab(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab)
107
{
108
    int retval;
155 109

  
156
    lseek(fd, strtab.sh_offset, SEEK_SET);
157
    if (read(fd, strings, strtab.sh_size) != strtab.sh_size)
158
	return;
159
    disas_num_syms = symtab.sh_size / sizeof(struct elf_sym);
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;
160 121
}
161 122

  
162
static int load_elf_binary(struct linux_binprm * bprm, uint8_t *addr)
123
static int read_program(int fd, struct elf_phdr *phdr, void *dst)
163 124
{
164
    struct elfhdr elf_ex;
165
    unsigned long startaddr = addr;
166
    int i;
167
    struct elf_phdr * elf_ppnt;
168
    struct elf_phdr *elf_phdata;
169 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
}
170 131

  
171
    elf_ex = *((struct elfhdr *) bprm->buf);          /* exec-header */
172
#ifdef BSWAP_NEEDED
173
    bswap_ehdr(&elf_ex);
174
#endif
132
static int read_section(int fd, struct elf_shdr *s, void *dst)
133
{
134
    int retval;
175 135

  
176
    if (elf_ex.e_ident[0] != 0x7f ||
177
	strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) {
178
	return  -ENOEXEC;
179
    }
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
}
180 144

  
181
    /* First of all, some simple consistency checks */
182
    if (! elf_check_arch(elf_ex.e_machine)) {
183
	return -ENOEXEC;
184
    }
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
}
185 160

  
186
    /* Now read in all of the header information */
187
    elf_phdata = (struct elf_phdr *)qemu_malloc(elf_ex.e_phentsize*elf_ex.e_phnum);
188
    if (elf_phdata == NULL) {
189
	return -ENOMEM;
190
    }
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
}
191 176

  
192
    retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET);
193
    if(retval > 0) {
194
	retval = read(bprm->fd, (char *) elf_phdata, 
195
				elf_ex.e_phentsize * elf_ex.e_phnum);
196
    }
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;
197 188

  
198
    if (retval < 0) {
199
	perror("load_elf_binary");
200
	exit(-1);
201
	qemu_free (elf_phdata);
202
	return -errno;
203
    }
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
}
204 211

  
205
#ifdef BSWAP_NEEDED
206
    elf_ppnt = elf_phdata;
207
    for (i=0; i<elf_ex.e_phnum; i++, elf_ppnt++) {
208
        bswap_phdr(elf_ppnt);
209
    }
210
#endif
211
    elf_ppnt = elf_phdata;
212

  
213
    /* Now we do a little grungy work by mmaping the ELF image into
214
     * the correct location in memory.  At this point, we assume that
215
     * the image should be loaded at fixed address, not at a variable
216
     * address.
217
     */
218

  
219
    for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
220
        unsigned long error, offset, len;
221
        
222
	if (elf_ppnt->p_type != PT_LOAD)
223
            continue;
224
#if 0        
225
        error = target_mmap(TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr),
226
                            elf_prot,
227
                            (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE),
228
                            bprm->fd,
229
                            (elf_ppnt->p_offset - 
230
                             TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
231
#endif
232
	//offset = elf_ppnt->p_offset - TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr);
233
	offset = 0x4000;
234
	lseek(bprm->fd, offset, SEEK_SET);
235
	len = elf_ppnt->p_filesz + TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr);
236
	error = read(bprm->fd, addr, len); 
237

  
238
        if (error == -1) {
239
            perror("mmap");
240
            exit(-1);
241
        }
242
	addr += len;
243
    }
212
int load_elf(const char * filename, uint8_t *addr)
213
{
214
    struct elfhdr ehdr;
215
    struct elf_phdr phdr;
216
    int retval, fd;
244 217

  
245
    qemu_free(elf_phdata);
218
    fd = open(filename, O_RDONLY | O_BINARY);
219
    if (fd < 0)
220
	goto error;
246 221

  
247
    load_symbols(&elf_ex, bprm->fd);
222
    retval = read(fd, &ehdr, sizeof(ehdr));
223
    if (retval < 0)
224
	goto error;
248 225

  
249
    return addr-startaddr;
250
}
226
    bswap_ehdr(&ehdr);
251 227

  
252
int elf_exec(const char * filename, uint8_t *addr)
253
{
254
        struct linux_binprm bprm;
255
        int retval;
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;
256 232

  
257
        retval = open(filename, O_RDONLY);
258
        if (retval < 0)
259
            return retval;
260
        bprm.fd = retval;
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;
261 238

  
262
        retval = prepare_binprm(&bprm);
239
    load_symbols(&ehdr, fd);
263 240

  
264
        if(retval>=0) {
265
	    retval = load_elf_binary(&bprm, addr);
266
	}
267
	return retval;
241
    close(fd);
242
    return retval;
243
 error:
244
    close(fd);
245
    return -1;
268 246
}
269
#endif
270 247

  
271 248
int load_kernel(const char *filename, uint8_t *addr)
272 249
{
......
286 263
    return -1;
287 264
}
288 265

  
289
static char saved_kfn[1024];
290
static uint32_t saved_addr;
291
static int magic_state;
266
typedef struct MAGICState {
267
    uint32_t addr;
268
    uint32_t saved_addr;
269
    int magic_state;
270
    char saved_kfn[1024];
271
} MAGICState;
292 272

  
293 273
static uint32_t magic_mem_readl(void *opaque, target_phys_addr_t addr)
294 274
{
295 275
    int ret;
276
    MAGICState *s = opaque;
296 277

  
297
    if (magic_state == 0) {
298
#ifdef USE_ELF_LOADER
299
        ret = elf_exec(saved_kfn, saved_addr);
300
#else
301
        ret = load_kernel(saved_kfn, (uint8_t *)saved_addr);
302
#endif
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);
303 282
        if (ret < 0) {
304 283
            fprintf(stderr, "qemu: could not load kernel '%s'\n", 
305
                    saved_kfn);
284
                    s->saved_kfn);
306 285
        }
307
	magic_state = 1; /* No more magic */
286
	s->magic_state = 1; /* No more magic */
308 287
	tb_flush();
288
	return bswap32(ret);
309 289
    }
310
    return ret;
290
    return 0;
311 291
}
312 292

  
313 293
static void magic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
......
327 307
    magic_mem_writel,
328 308
};
329 309

  
330
void magic_init(const char *kfn, int kloadaddr)
310
void magic_init(const char *kfn, int kloadaddr, uint32_t addr)
331 311
{
332 312
    int magic_io_memory;
333

  
334
    strcpy(saved_kfn, kfn);
335
    saved_addr = kloadaddr;
336
    magic_state = 0;
337
    magic_io_memory = cpu_register_io_memory(0, magic_mem_read, magic_mem_write, 0);
338
    cpu_register_physical_memory(0x20000000, 4,
339
                                 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);
340 325
}
341 326

  

Also available in: Unified diff