2009-09-18 23:01:28 +00:00
|
|
|
/*
|
|
|
|
|
*
|
|
|
|
|
* <elf-loader.c>
|
|
|
|
|
*
|
|
|
|
|
* ELF file loader
|
|
|
|
|
*
|
|
|
|
|
* Copyright (C) 2009 Laurent Vivier (Laurent@vivier.eu)
|
|
|
|
|
*
|
|
|
|
|
* Some parts Copyright (C) 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se)
|
|
|
|
|
*
|
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
|
* version 2
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|
2010-03-14 17:19:58 +00:00
|
|
|
#include "config.h"
|
2010-03-14 15:05:53 +00:00
|
|
|
#include "libopenbios/bindings.h"
|
2010-03-13 10:58:19 +00:00
|
|
|
#include "packages.h"
|
2010-03-14 15:05:53 +00:00
|
|
|
#include "libopenbios/ofmem.h"
|
2009-09-18 23:01:28 +00:00
|
|
|
|
2010-03-14 17:06:20 +00:00
|
|
|
#include "arch/common/elf.h"
|
2009-09-18 23:01:28 +00:00
|
|
|
#include "asm/elf.h"
|
|
|
|
|
|
|
|
|
|
/* TODO: manage ELF notes section */
|
|
|
|
|
|
|
|
|
|
//#define DEBUG_ELF
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG_ELF
|
|
|
|
|
#define DPRINTF(fmt, args...) \
|
|
|
|
|
do { printk("%s: " fmt, __func__ , ##args); } while (0)
|
|
|
|
|
#else
|
|
|
|
|
#define DPRINTF(fmt, args...) \
|
|
|
|
|
do { } while (0)
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
DECLARE_NODE(elf_loader, INSTALL_OPEN, 0, "+/packages/elf-loader" );
|
|
|
|
|
|
|
|
|
|
#ifdef CONFIG_PPC
|
|
|
|
|
extern void flush_icache_range( char *start, char *stop );
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
elf_loader_init_program( void *dummy )
|
|
|
|
|
{
|
|
|
|
|
char *base;
|
|
|
|
|
int i;
|
|
|
|
|
Elf_ehdr *ehdr;
|
|
|
|
|
Elf_phdr *phdr;
|
|
|
|
|
size_t size;
|
|
|
|
|
char *addr;
|
2010-03-28 20:18:30 +00:00
|
|
|
cell tmp;
|
2009-09-18 23:01:28 +00:00
|
|
|
|
2009-09-21 22:44:21 +00:00
|
|
|
feval("0 state-valid !");
|
|
|
|
|
|
2009-09-18 23:01:28 +00:00
|
|
|
feval("load-base");
|
|
|
|
|
base = (char*)POP();
|
|
|
|
|
|
|
|
|
|
ehdr = (Elf_ehdr *)base;
|
|
|
|
|
phdr = (Elf_phdr *)(base + ehdr->e_phoff);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < ehdr->e_phnum; i++) {
|
|
|
|
|
DPRINTF("filesz: %08lX memsz: %08lX p_offset: %08lX "
|
|
|
|
|
"p_vaddr %08lX\n",
|
|
|
|
|
(ulong)phdr[i].p_filesz, (ulong)phdr[i].p_memsz,
|
|
|
|
|
(ulong)phdr[i].p_offset, (ulong)phdr[i].p_vaddr );
|
|
|
|
|
|
|
|
|
|
size = MIN(phdr[i].p_filesz, phdr[i].p_memsz);
|
|
|
|
|
if (!size)
|
|
|
|
|
continue;
|
2010-03-28 20:18:30 +00:00
|
|
|
#if 0
|
2009-09-18 23:01:28 +00:00
|
|
|
if( ofmem_claim( phdr[i].p_vaddr, phdr[i].p_memsz, 0 ) == -1 ) {
|
|
|
|
|
printk("Claim failed!\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
2010-03-28 20:18:30 +00:00
|
|
|
#endif
|
|
|
|
|
/* Workaround for archs where sizeof(int) != pointer size */
|
|
|
|
|
tmp = phdr[i].p_vaddr;
|
|
|
|
|
addr = (char *)tmp;
|
|
|
|
|
|
2009-09-18 23:01:28 +00:00
|
|
|
memcpy(addr, base + phdr[i].p_offset, size);
|
|
|
|
|
#ifdef CONFIG_PPC
|
|
|
|
|
flush_icache_range( addr, addr + size );
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
/* FIXME: should initialize saved-program-state. */
|
|
|
|
|
PUSH(ehdr->e_entry);
|
|
|
|
|
feval("elf-entry !");
|
2009-09-21 22:44:21 +00:00
|
|
|
feval("-1 state-valid !");
|
2009-09-18 23:01:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NODE_METHODS( elf_loader ) = {
|
|
|
|
|
{ "init-program", elf_loader_init_program },
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void elf_loader_init( void )
|
|
|
|
|
{
|
|
|
|
|
REGISTER_NODE( elf_loader );
|
|
|
|
|
}
|