-/* This is the Linux kernel elf-loading code, ported into user space */
#include "vl.h"
#include "disas.h"
+#include "exec-all.h"
-/* XXX: this code is not used as it is under the GPL license. Please
- remove or recode it */
-//#define USE_ELF_LOADER
-
-#ifdef USE_ELF_LOADER
-/* should probably go in elf.h */
-#ifndef ELIBBAD
-#define ELIBBAD 80
-#endif
-
-
-#define ELF_START_MMAP 0x80000000
-
-#define elf_check_arch(x) ( (x) == EM_SPARC )
-
-#define ELF_CLASS ELFCLASS32
-#define ELF_DATA ELFDATA2MSB
-#define ELF_ARCH EM_SPARC
-
-#include "elf.h"
-
-/*
- * This structure is used to hold the arguments that are
- * used when loading binaries.
- */
-struct linux_binprm {
- char buf[128];
- int fd;
+struct exec
+{
+ uint32_t a_info; /* Use macros N_MAGIC, etc for access */
+ uint32_t a_text; /* length of text, in bytes */
+ uint32_t a_data; /* length of data, in bytes */
+ uint32_t a_bss; /* length of uninitialized data area, in bytes */
+ uint32_t a_syms; /* length of symbol table data in file, in bytes */
+ uint32_t a_entry; /* start address */
+ uint32_t a_trsize; /* length of relocation info for text, in bytes */
+ uint32_t a_drsize; /* length of relocation info for data, in bytes */
};
-#define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE
-#define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1))
-#define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1))
-
#ifdef BSWAP_NEEDED
-static void bswap_ehdr(Elf32_Ehdr *ehdr)
+static void bswap_ahdr(struct exec *e)
{
- bswap16s(&ehdr->e_type); /* Object file type */
- bswap16s(&ehdr->e_machine); /* Architecture */
- bswap32s(&ehdr->e_version); /* Object file version */
- bswap32s(&ehdr->e_entry); /* Entry point virtual address */
- bswap32s(&ehdr->e_phoff); /* Program header table file offset */
- bswap32s(&ehdr->e_shoff); /* Section header table file offset */
- bswap32s(&ehdr->e_flags); /* Processor-specific flags */
- bswap16s(&ehdr->e_ehsize); /* ELF header size in bytes */
- bswap16s(&ehdr->e_phentsize); /* Program header table entry size */
- bswap16s(&ehdr->e_phnum); /* Program header table entry count */
- bswap16s(&ehdr->e_shentsize); /* Section header table entry size */
- bswap16s(&ehdr->e_shnum); /* Section header table entry count */
- bswap16s(&ehdr->e_shstrndx); /* Section header string table index */
+ bswap32s(&e->a_info);
+ bswap32s(&e->a_text);
+ bswap32s(&e->a_data);
+ bswap32s(&e->a_bss);
+ bswap32s(&e->a_syms);
+ bswap32s(&e->a_entry);
+ bswap32s(&e->a_trsize);
+ bswap32s(&e->a_drsize);
}
+#else
+#define bswap_ahdr(x) do { } while (0)
+#endif
-static void bswap_phdr(Elf32_Phdr *phdr)
-{
- bswap32s(&phdr->p_type); /* Segment type */
- bswap32s(&phdr->p_offset); /* Segment file offset */
- bswap32s(&phdr->p_vaddr); /* Segment virtual address */
- bswap32s(&phdr->p_paddr); /* Segment physical address */
- bswap32s(&phdr->p_filesz); /* Segment size in file */
- bswap32s(&phdr->p_memsz); /* Segment size in memory */
- bswap32s(&phdr->p_flags); /* Segment flags */
- bswap32s(&phdr->p_align); /* Segment alignment */
-}
+#define N_MAGIC(exec) ((exec).a_info & 0xffff)
+#define OMAGIC 0407
+#define NMAGIC 0410
+#define ZMAGIC 0413
+#define QMAGIC 0314
+#define _N_HDROFF(x) (1024 - sizeof (struct exec))
+#define N_TXTOFF(x) \
+ (N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) : \
+ (N_MAGIC(x) == QMAGIC ? 0 : sizeof (struct exec)))
+#define N_TXTADDR(x) (N_MAGIC(x) == QMAGIC ? TARGET_PAGE_SIZE : 0)
+#define N_DATOFF(x) (N_TXTOFF(x) + (x).a_text)
+#define _N_SEGMENT_ROUND(x) (((x) + TARGET_PAGE_SIZE - 1) & ~(TARGET_PAGE_SIZE - 1))
-static void bswap_shdr(Elf32_Shdr *shdr)
-{
- bswap32s(&shdr->sh_name);
- bswap32s(&shdr->sh_type);
- bswap32s(&shdr->sh_flags);
- bswap32s(&shdr->sh_addr);
- bswap32s(&shdr->sh_offset);
- bswap32s(&shdr->sh_size);
- bswap32s(&shdr->sh_link);
- bswap32s(&shdr->sh_info);
- bswap32s(&shdr->sh_addralign);
- bswap32s(&shdr->sh_entsize);
-}
+#define _N_TXTENDADDR(x) (N_TXTADDR(x)+(x).a_text)
-static void bswap_sym(Elf32_Sym *sym)
-{
- bswap32s(&sym->st_name);
- bswap32s(&sym->st_value);
- bswap32s(&sym->st_size);
- bswap16s(&sym->st_shndx);
-}
-#endif
+#define N_DATADDR(x) \
+ (N_MAGIC(x)==OMAGIC? (_N_TXTENDADDR(x)) \
+ : (_N_SEGMENT_ROUND (_N_TXTENDADDR(x))))
-static int prepare_binprm(struct linux_binprm *bprm)
-{
- int retval;
- memset(bprm->buf, 0, sizeof(bprm->buf));
- retval = lseek(bprm->fd, 0L, SEEK_SET);
- if(retval >= 0) {
- retval = read(bprm->fd, bprm->buf, 128);
- }
- if(retval < 0) {
- perror("prepare_binprm");
- exit(-1);
- /* return(-errno); */
- }
- else {
- return(retval);
- }
-}
+#define ELF_CLASS ELFCLASS32
+#define ELF_DATA ELFDATA2MSB
+#define ELF_ARCH EM_SPARC
-/* Best attempt to load symbols from this ELF object. */
-static void load_symbols(struct elfhdr *hdr, int fd)
-{
- unsigned int i;
- struct elf_shdr sechdr, symtab, strtab;
- char *strings;
+#include "elf.h"
- lseek(fd, hdr->e_shoff, SEEK_SET);
- for (i = 0; i < hdr->e_shnum; i++) {
- if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr))
- return;
-#ifdef BSWAP_NEEDED
- bswap_shdr(&sechdr);
+#ifndef BSWAP_NEEDED
+#define bswap_ehdr32(e) do { } while (0)
+#define bswap_phdr32(e) do { } while (0)
+#define bswap_shdr32(e) do { } while (0)
+#define bswap_sym32(e) do { } while (0)
+#ifdef TARGET_SPARC64
+#define bswap_ehdr64(e) do { } while (0)
+#define bswap_phdr64(e) do { } while (0)
+#define bswap_shdr64(e) do { } while (0)
+#define bswap_sym64(e) do { } while (0)
#endif
- if (sechdr.sh_type == SHT_SYMTAB) {
- symtab = sechdr;
- lseek(fd, hdr->e_shoff
- + sizeof(sechdr) * sechdr.sh_link, SEEK_SET);
- if (read(fd, &strtab, sizeof(strtab))
- != sizeof(strtab))
- return;
-#ifdef BSWAP_NEEDED
- bswap_shdr(&strtab);
#endif
- goto found;
- }
- }
- return; /* Shouldn't happen... */
-
- found:
- /* Now know where the strtab and symtab are. Snarf them. */
- disas_symtab = qemu_malloc(symtab.sh_size);
- disas_strtab = strings = qemu_malloc(strtab.sh_size);
- if (!disas_symtab || !disas_strtab)
- return;
-
- lseek(fd, symtab.sh_offset, SEEK_SET);
- if (read(fd, disas_symtab, symtab.sh_size) != symtab.sh_size)
- return;
-#ifdef BSWAP_NEEDED
- for (i = 0; i < symtab.sh_size / sizeof(struct elf_sym); i++)
- bswap_sym(disas_symtab + sizeof(struct elf_sym)*i);
+#define SZ 32
+#define elf_word uint32_t
+#define bswapSZs bswap32s
+#include "elf_ops.h"
+
+#ifdef TARGET_SPARC64
+#undef elfhdr
+#undef elf_phdr
+#undef elf_shdr
+#undef elf_sym
+#undef elf_note
+#undef elf_word
+#undef bswapSZs
+#undef SZ
+#define elfhdr elf64_hdr
+#define elf_phdr elf64_phdr
+#define elf_note elf64_note
+#define elf_shdr elf64_shdr
+#define elf_sym elf64_sym
+#define elf_word uint64_t
+#define bswapSZs bswap64s
+#define SZ 64
+#include "elf_ops.h"
#endif
- lseek(fd, strtab.sh_offset, SEEK_SET);
- if (read(fd, strings, strtab.sh_size) != strtab.sh_size)
- return;
- disas_num_syms = symtab.sh_size / sizeof(struct elf_sym);
-}
-
-static int load_elf_binary(struct linux_binprm * bprm, uint8_t *addr)
+int load_elf(const char *filename, uint8_t *addr)
{
- struct elfhdr elf_ex;
- unsigned long startaddr = addr;
- int i;
- struct elf_phdr * elf_ppnt;
- struct elf_phdr *elf_phdata;
- int retval;
+ struct elf32_hdr ehdr;
+ int retval, fd;
+ Elf32_Half machine;
- elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */
-#ifdef BSWAP_NEEDED
- bswap_ehdr(&elf_ex);
-#endif
-
- if (elf_ex.e_ident[0] != 0x7f ||
- strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) {
- return -ENOEXEC;
- }
-
- /* First of all, some simple consistency checks */
- if (! elf_check_arch(elf_ex.e_machine)) {
- return -ENOEXEC;
+ fd = open(filename, O_RDONLY | O_BINARY);
+ if (fd < 0)
+ goto error;
+
+ retval = read(fd, &ehdr, sizeof(ehdr));
+ if (retval < 0)
+ goto error;
+
+ if (ehdr.e_ident[0] != 0x7f || ehdr.e_ident[1] != 'E'
+ || ehdr.e_ident[2] != 'L' || ehdr.e_ident[3] != 'F')
+ goto error;
+ machine = tswap16(ehdr.e_machine);
+ if (machine == EM_SPARC || machine == EM_SPARC32PLUS) {
+ struct elf32_phdr phdr;
+
+ bswap_ehdr32(&ehdr);
+
+ if (find_phdr32(&ehdr, fd, &phdr, PT_LOAD))
+ goto error;
+ retval = read_program32(fd, &phdr, addr, ehdr.e_entry);
+ if (retval < 0)
+ goto error;
+ load_symbols32(&ehdr, fd);
}
+#ifdef TARGET_SPARC64
+ else if (machine == EM_SPARCV9) {
+ struct elf64_hdr ehdr64;
+ struct elf64_phdr phdr;
- /* Now read in all of the header information */
- elf_phdata = (struct elf_phdr *)qemu_malloc(elf_ex.e_phentsize*elf_ex.e_phnum);
- if (elf_phdata == NULL) {
- return -ENOMEM;
- }
+ lseek(fd, 0, SEEK_SET);
- retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET);
- if(retval > 0) {
- retval = read(bprm->fd, (char *) elf_phdata,
- elf_ex.e_phentsize * elf_ex.e_phnum);
- }
+ retval = read(fd, &ehdr64, sizeof(ehdr64));
+ if (retval < 0)
+ goto error;
- if (retval < 0) {
- perror("load_elf_binary");
- exit(-1);
- qemu_free (elf_phdata);
- return -errno;
- }
+ bswap_ehdr64(&ehdr64);
-#ifdef BSWAP_NEEDED
- elf_ppnt = elf_phdata;
- for (i=0; i<elf_ex.e_phnum; i++, elf_ppnt++) {
- bswap_phdr(elf_ppnt);
+ if (find_phdr64(&ehdr64, fd, &phdr, PT_LOAD))
+ goto error;
+ retval = read_program64(fd, &phdr, addr, ehdr64.e_entry);
+ if (retval < 0)
+ goto error;
+ load_symbols64(&ehdr64, fd);
}
#endif
- elf_ppnt = elf_phdata;
-
- /* Now we do a little grungy work by mmaping the ELF image into
- * the correct location in memory. At this point, we assume that
- * the image should be loaded at fixed address, not at a variable
- * address.
- */
-
- for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
- unsigned long error, offset, len;
-
- if (elf_ppnt->p_type != PT_LOAD)
- continue;
-#if 0
- error = target_mmap(TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr),
- elf_prot,
- (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE),
- bprm->fd,
- (elf_ppnt->p_offset -
- TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
-#endif
- //offset = elf_ppnt->p_offset - TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr);
- offset = 0x4000;
- lseek(bprm->fd, offset, SEEK_SET);
- len = elf_ppnt->p_filesz + TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr);
- error = read(bprm->fd, addr, len);
-
- if (error == -1) {
- perror("mmap");
- exit(-1);
- }
- addr += len;
- }
-
- qemu_free(elf_phdata);
-
- load_symbols(&elf_ex, bprm->fd);
- return addr-startaddr;
-}
-
-int elf_exec(const char * filename, uint8_t *addr)
-{
- struct linux_binprm bprm;
- int retval;
-
- retval = open(filename, O_RDONLY);
- if (retval < 0)
- return retval;
- bprm.fd = retval;
-
- retval = prepare_binprm(&bprm);
-
- if(retval>=0) {
- retval = load_elf_binary(&bprm, addr);
- }
- return retval;
+ close(fd);
+ return retval;
+ error:
+ close(fd);
+ return -1;
}
-#endif
-int load_kernel(const char *filename, uint8_t *addr)
+int load_aout(const char *filename, uint8_t *addr)
{
- int fd, size;
+ int fd, size, ret;
+ struct exec e;
+ uint32_t magic;
fd = open(filename, O_RDONLY | O_BINARY);
if (fd < 0)
return -1;
- /* load 32 bit code */
- size = read(fd, addr, 16 * 1024 * 1024);
+
+ size = read(fd, &e, sizeof(e));
if (size < 0)
goto fail;
+
+ bswap_ahdr(&e);
+
+ magic = N_MAGIC(e);
+ switch (magic) {
+ case ZMAGIC:
+ case QMAGIC:
+ case OMAGIC:
+ lseek(fd, N_TXTOFF(e), SEEK_SET);
+ size = read(fd, addr, e.a_text + e.a_data);
+ if (size < 0)
+ goto fail;
+ break;
+ case NMAGIC:
+ lseek(fd, N_TXTOFF(e), SEEK_SET);
+ size = read(fd, addr, e.a_text);
+ if (size < 0)
+ goto fail;
+ ret = read(fd, addr + N_DATADDR(e), e.a_data);
+ if (ret < 0)
+ goto fail;
+ size += ret;
+ break;
+ default:
+ goto fail;
+ }
close(fd);
return size;
fail:
return -1;
}
-static char saved_kfn[1024];
-static uint32_t saved_addr;
-static int magic_state;
-
-static uint32_t magic_mem_readl(void *opaque, target_phys_addr_t addr)
-{
- int ret;
-
- if (magic_state == 0) {
-#ifdef USE_ELF_LOADER
- ret = elf_exec(saved_kfn, saved_addr);
-#else
- ret = load_kernel(saved_kfn, (uint8_t *)saved_addr);
-#endif
- if (ret < 0) {
- fprintf(stderr, "qemu: could not load kernel '%s'\n",
- saved_kfn);
- }
- magic_state = 1; /* No more magic */
- tb_flush();
- }
- return ret;
-}
-
-static void magic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-}
-
-
-static CPUReadMemoryFunc *magic_mem_read[3] = {
- magic_mem_readl,
- magic_mem_readl,
- magic_mem_readl,
-};
-
-static CPUWriteMemoryFunc *magic_mem_write[3] = {
- magic_mem_writel,
- magic_mem_writel,
- magic_mem_writel,
-};
-
-void magic_init(const char *kfn, int kloadaddr)
-{
- int magic_io_memory;
-
- strcpy(saved_kfn, kfn);
- saved_addr = kloadaddr;
- magic_state = 0;
- magic_io_memory = cpu_register_io_memory(0, magic_mem_read, magic_mem_write, 0);
- cpu_register_physical_memory(0x20000000, 4,
- magic_io_memory);
-}
-