ne2000 savevm support (Johannes Schindelin)
[qemu] / hw / magic-load.c
1 /* This is the Linux kernel elf-loading code, ported into user space */
2 #include "vl.h"
3 #include "disas.h"
4
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 #define ELF_CLASS   ELFCLASS32
21 #define ELF_DATA    ELFDATA2MSB
22 #define ELF_ARCH    EM_SPARC
23
24 #include "elf.h"
25
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 #ifdef BSWAP_NEEDED
40 static void bswap_ehdr(Elf32_Ehdr *ehdr)
41 {
42     bswap16s(&ehdr->e_type);                    /* Object file type */
43     bswap16s(&ehdr->e_machine);         /* Architecture */
44     bswap32s(&ehdr->e_version);         /* Object file version */
45     bswap32s(&ehdr->e_entry);           /* Entry point virtual address */
46     bswap32s(&ehdr->e_phoff);           /* Program header table file offset */
47     bswap32s(&ehdr->e_shoff);           /* Section header table file offset */
48     bswap32s(&ehdr->e_flags);           /* Processor-specific flags */
49     bswap16s(&ehdr->e_ehsize);          /* ELF header size in bytes */
50     bswap16s(&ehdr->e_phentsize);               /* Program header table entry size */
51     bswap16s(&ehdr->e_phnum);           /* Program header table entry count */
52     bswap16s(&ehdr->e_shentsize);               /* Section header table entry size */
53     bswap16s(&ehdr->e_shnum);           /* Section header table entry count */
54     bswap16s(&ehdr->e_shstrndx);                /* Section header string table index */
55 }
56
57 static void bswap_phdr(Elf32_Phdr *phdr)
58 {
59     bswap32s(&phdr->p_type);                    /* Segment type */
60     bswap32s(&phdr->p_offset);          /* Segment file offset */
61     bswap32s(&phdr->p_vaddr);           /* Segment virtual address */
62     bswap32s(&phdr->p_paddr);           /* Segment physical address */
63     bswap32s(&phdr->p_filesz);          /* Segment size in file */
64     bswap32s(&phdr->p_memsz);           /* Segment size in memory */
65     bswap32s(&phdr->p_flags);           /* Segment flags */
66     bswap32s(&phdr->p_align);           /* Segment alignment */
67 }
68
69 static void bswap_shdr(Elf32_Shdr *shdr)
70 {
71     bswap32s(&shdr->sh_name);
72     bswap32s(&shdr->sh_type);
73     bswap32s(&shdr->sh_flags);
74     bswap32s(&shdr->sh_addr);
75     bswap32s(&shdr->sh_offset);
76     bswap32s(&shdr->sh_size);
77     bswap32s(&shdr->sh_link);
78     bswap32s(&shdr->sh_info);
79     bswap32s(&shdr->sh_addralign);
80     bswap32s(&shdr->sh_entsize);
81 }
82
83 static void bswap_sym(Elf32_Sym *sym)
84 {
85     bswap32s(&sym->st_name);
86     bswap32s(&sym->st_value);
87     bswap32s(&sym->st_size);
88     bswap16s(&sym->st_shndx);
89 }
90 #endif
91
92 static int prepare_binprm(struct linux_binprm *bprm)
93 {
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);
108     }
109 }
110
111 /* Best attempt to load symbols from this ELF object. */
112 static void load_symbols(struct elfhdr *hdr, int fd)
113 {
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         }
137     }
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;
150
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
155
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);
160 }
161
162 static int load_elf_binary(struct linux_binprm * bprm, uint8_t *addr)
163 {
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     int retval;
170
171     elf_ex = *((struct elfhdr *) bprm->buf);          /* exec-header */
172 #ifdef BSWAP_NEEDED
173     bswap_ehdr(&elf_ex);
174 #endif
175
176     if (elf_ex.e_ident[0] != 0x7f ||
177         strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) {
178         return  -ENOEXEC;
179     }
180
181     /* First of all, some simple consistency checks */
182     if (! elf_check_arch(elf_ex.e_machine)) {
183         return -ENOEXEC;
184     }
185
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     }
191
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     }
197
198     if (retval < 0) {
199         perror("load_elf_binary");
200         exit(-1);
201         qemu_free (elf_phdata);
202         return -errno;
203     }
204
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     }
244
245     qemu_free(elf_phdata);
246
247     load_symbols(&elf_ex, bprm->fd);
248
249     return addr-startaddr;
250 }
251
252 int elf_exec(const char * filename, uint8_t *addr)
253 {
254         struct linux_binprm bprm;
255         int retval;
256
257         retval = open(filename, O_RDONLY);
258         if (retval < 0)
259             return retval;
260         bprm.fd = retval;
261
262         retval = prepare_binprm(&bprm);
263
264         if(retval>=0) {
265             retval = load_elf_binary(&bprm, addr);
266         }
267         return retval;
268 }
269 #endif
270
271 int load_kernel(const char *filename, uint8_t *addr)
272 {
273     int fd, size;
274
275     fd = open(filename, O_RDONLY | O_BINARY);
276     if (fd < 0)
277         return -1;
278     /* load 32 bit code */
279     size = read(fd, addr, 16 * 1024 * 1024);
280     if (size < 0)
281         goto fail;
282     close(fd);
283     return size;
284  fail:
285     close(fd);
286     return -1;
287 }
288
289 static char saved_kfn[1024];
290 static uint32_t saved_addr;
291 static int magic_state;
292
293 static uint32_t magic_mem_readl(void *opaque, target_phys_addr_t addr)
294 {
295     int ret;
296
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
303         if (ret < 0) {
304             fprintf(stderr, "qemu: could not load kernel '%s'\n", 
305                     saved_kfn);
306         }
307         magic_state = 1; /* No more magic */
308         tb_flush();
309     }
310     return ret;
311 }
312
313 static void magic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
314 {
315 }
316
317
318 static CPUReadMemoryFunc *magic_mem_read[3] = {
319     magic_mem_readl,
320     magic_mem_readl,
321     magic_mem_readl,
322 };
323
324 static CPUWriteMemoryFunc *magic_mem_write[3] = {
325     magic_mem_writel,
326     magic_mem_writel,
327     magic_mem_writel,
328 };
329
330 void magic_init(const char *kfn, int kloadaddr)
331 {
332     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);
340 }
341