2008-07-08 16:02:43 +00:00
|
|
|
/* a.out boot loader
|
|
|
|
|
* As we have seek, this implementation can be straightforward.
|
|
|
|
|
* 2003-07 by SONE Takeshi
|
|
|
|
|
*/
|
|
|
|
|
|
2010-03-14 17:19:58 +00:00
|
|
|
#include "config.h"
|
2010-03-14 14:21:02 +00:00
|
|
|
#include "kernel/kernel.h"
|
2008-07-08 16:02:43 +00:00
|
|
|
#define CONFIG_SPARC64_PAGE_SIZE_8KB
|
2010-03-14 17:06:20 +00:00
|
|
|
#include "arch/common/a.out.h"
|
2010-03-14 16:09:44 +00:00
|
|
|
#include "libopenbios/sys_info.h"
|
2010-03-26 20:25:04 +00:00
|
|
|
#include "libc/diskio.h"
|
2008-07-08 16:02:43 +00:00
|
|
|
#include "boot.h"
|
|
|
|
|
#define printf printk
|
|
|
|
|
#define debug printk
|
|
|
|
|
|
|
|
|
|
#define addr_fixup(addr) ((addr) & 0x00ffffff)
|
|
|
|
|
|
|
|
|
|
static char *image_name, *image_version;
|
2010-03-26 20:25:04 +00:00
|
|
|
static int fd;
|
2008-07-08 16:02:43 +00:00
|
|
|
|
|
|
|
|
static int check_mem_ranges(struct sys_info *info,
|
|
|
|
|
unsigned long start,
|
|
|
|
|
unsigned long size)
|
|
|
|
|
{
|
|
|
|
|
int j;
|
|
|
|
|
unsigned long end;
|
|
|
|
|
unsigned long prog_start, prog_end;
|
|
|
|
|
struct memrange *mem;
|
|
|
|
|
|
|
|
|
|
prog_start = virt_to_phys(&_start);
|
|
|
|
|
prog_end = virt_to_phys(&_end);
|
|
|
|
|
|
|
|
|
|
end = start + size;
|
|
|
|
|
|
|
|
|
|
if (start < prog_start && end > prog_start)
|
|
|
|
|
goto conflict;
|
|
|
|
|
if (start < prog_end && end > prog_end)
|
|
|
|
|
goto conflict;
|
|
|
|
|
mem = info->memrange;
|
|
|
|
|
for (j = 0; j < info->n_memranges; j++) {
|
|
|
|
|
if (mem[j].base <= start && mem[j].base + mem[j].size >= end)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (j >= info->n_memranges)
|
|
|
|
|
goto badseg;
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
conflict:
|
|
|
|
|
printf("%s occupies [%#lx-%#lx]\n", program_name, prog_start, prog_end);
|
|
|
|
|
|
|
|
|
|
badseg:
|
|
|
|
|
printf("A.out file [%#lx-%#lx] doesn't fit into memory\n", start, end - 1);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2008-11-30 11:54:01 +00:00
|
|
|
int aout_load(struct sys_info *info, const char *filename)
|
2008-07-08 16:02:43 +00:00
|
|
|
{
|
|
|
|
|
int retval = -1;
|
|
|
|
|
int image_retval;
|
|
|
|
|
struct exec ehdr;
|
|
|
|
|
unsigned long start, size;
|
|
|
|
|
unsigned int offset;
|
|
|
|
|
|
2008-11-30 11:54:01 +00:00
|
|
|
image_name = image_version = NULL;
|
2008-07-08 16:02:43 +00:00
|
|
|
|
2010-03-26 20:25:04 +00:00
|
|
|
fd = open_io(filename);
|
|
|
|
|
if (!fd)
|
2008-07-08 16:02:43 +00:00
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
for (offset = 0; offset < 16 * 512; offset += 512) {
|
2010-03-26 20:25:04 +00:00
|
|
|
seek_io(fd, offset);
|
|
|
|
|
if (read_io(fd, &ehdr, sizeof ehdr) != sizeof ehdr) {
|
2008-07-08 16:02:43 +00:00
|
|
|
debug("Can't read a.out header\n");
|
|
|
|
|
retval = LOADER_NOT_SUPPORT;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
if (!N_BADMAG(ehdr))
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (N_BADMAG(ehdr)) {
|
|
|
|
|
debug("Not a bootable a.out image\n");
|
|
|
|
|
retval = LOADER_NOT_SUPPORT;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ehdr.a_text == 0x30800007)
|
|
|
|
|
ehdr.a_text=64*1024;
|
|
|
|
|
|
|
|
|
|
if (N_MAGIC(ehdr) == NMAGIC) {
|
|
|
|
|
size = addr_fixup(N_DATADDR(ehdr)) + addr_fixup(ehdr.a_data);
|
|
|
|
|
} else {
|
|
|
|
|
size = addr_fixup(ehdr.a_text) + addr_fixup(ehdr.a_data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (size < 7680)
|
|
|
|
|
size = 7680;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
start = 0x4000; // N_TXTADDR(ehdr);
|
|
|
|
|
|
|
|
|
|
if (!check_mem_ranges(info, start, size))
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
printf("Loading a.out %s...\n", image_name ? image_name : "image");
|
|
|
|
|
|
2010-03-26 20:25:04 +00:00
|
|
|
seek_io(fd, offset + N_TXTOFF(ehdr));
|
2008-07-08 16:02:43 +00:00
|
|
|
|
|
|
|
|
if (N_MAGIC(ehdr) == NMAGIC) {
|
2010-03-26 20:25:04 +00:00
|
|
|
if ((unsigned long)read_io(fd, (void *)start, ehdr.a_text) != ehdr.a_text) {
|
2008-11-29 16:24:51 +00:00
|
|
|
printf("Can't read program text segment (size 0x%x)\n", ehdr.a_text);
|
2008-07-08 16:02:43 +00:00
|
|
|
goto out;
|
|
|
|
|
}
|
2010-03-26 20:25:04 +00:00
|
|
|
if ((unsigned long)read_io(fd, (void *)(start + N_DATADDR(ehdr)), ehdr.a_data) != ehdr.a_data) {
|
2008-11-29 16:24:51 +00:00
|
|
|
printf("Can't read program data segment (size 0x%x)\n", ehdr.a_data);
|
2008-07-08 16:02:43 +00:00
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2010-03-26 20:25:04 +00:00
|
|
|
if ((unsigned long)read_io(fd, (void *)start, size) != size) {
|
2008-07-08 16:02:43 +00:00
|
|
|
printf("Can't read program (size 0x%lx)\n", size);
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
debug("Loaded %lu bytes\n", size);
|
|
|
|
|
|
|
|
|
|
debug("entry point is %#lx\n", start);
|
|
|
|
|
printf("Jumping to entry point...\n");
|
|
|
|
|
|
|
|
|
|
{
|
2009-07-11 12:25:26 +00:00
|
|
|
extern int sparc64_of_client_interface( int *params );
|
|
|
|
|
image_retval = start_client_image(addr_fixup(start), (uint64_t)&sparc64_of_client_interface);
|
2008-07-08 16:02:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
printf("Image returned with return value %#x\n", image_retval);
|
|
|
|
|
retval = 0;
|
|
|
|
|
|
|
|
|
|
out:
|
2010-03-26 20:25:04 +00:00
|
|
|
close_io(fd);
|
2008-07-08 16:02:43 +00:00
|
|
|
return retval;
|
|
|
|
|
}
|