1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
|
/* a.out boot loader
* As we have seek, this implementation can be straightforward.
* 2003-07 by SONE Takeshi
*/
#include "config.h"
#include "kernel/kernel.h"
#ifdef CONFIG_SPARC64
#define CONFIG_SPARC64_PAGE_SIZE_8KB
#endif
#include "libopenbios/sys_info.h"
#include "libopenbios/bindings.h"
#include "libopenbios/aout_load.h"
#include "libopenbios/initprogram.h"
#include "libc/diskio.h"
#define printf printk
#define debug printk
#define addr_fixup(addr) ((addr) & 0x00ffffff)
static char *image_name, *image_version;
static int fd;
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;
}
int
is_aout(struct exec *ehdr)
{
return ((ehdr->a_info & 0xffff) == OMAGIC
|| (ehdr->a_info & 0xffff) == NMAGIC
|| (ehdr->a_info & 0xffff) == ZMAGIC
|| (ehdr->a_info & 0xffff) == QMAGIC);
}
int
aout_load(struct sys_info *info, ihandle_t dev)
{
int retval = -1;
struct exec ehdr;
unsigned long start, size;
unsigned int offset;
image_name = image_version = NULL;
/* Mark the saved-program-state as invalid */
feval("0 state-valid !");
fd = open_ih(dev);
if (fd == -1) {
goto out;
}
for (offset = 0; offset < 16 * 512; offset += 512) {
seek_io(fd, offset);
if (read_io(fd, &ehdr, sizeof ehdr) != sizeof ehdr) {
debug("Can't read a.out header\n");
retval = LOADER_NOT_SUPPORT;
goto out;
}
if (is_aout(&ehdr))
break;
}
if (!is_aout(&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;
fword("load-base");
start = POP(); // N_TXTADDR(ehdr);
memcpy((void *)start, &ehdr, sizeof(ehdr));
if (!check_mem_ranges(info, start, size))
goto out;
printf("Loading a.out %s...\n", image_name ? image_name : "image");
seek_io(fd, offset + N_TXTOFF(ehdr));
if (N_MAGIC(ehdr) == NMAGIC) {
if ((size_t)read_io(fd, (void *)(start + N_TXTOFF(ehdr)), ehdr.a_text) != ehdr.a_text) {
printf("Can't read program text segment (size 0x" FMT_aout_ehdr ")\n", ehdr.a_text);
goto out;
}
if ((size_t)read_io(fd, (void *)(start + N_DATADDR(ehdr)), ehdr.a_data) != ehdr.a_data) {
printf("Can't read program data segment (size 0x" FMT_aout_ehdr ")\n", ehdr.a_data);
goto out;
}
} else {
if ((size_t)read_io(fd, (void *)(start + N_TXTOFF(ehdr)), size) != size) {
printf("Can't read program (size 0x" FMT_sizet ")\n", size);
goto out;
}
}
debug("Loaded %lu bytes\n", size);
debug("entry point is %#lx\n", start);
// Initialise saved-program-state
PUSH(size);
feval("load-state >ls.file-size !");
feval("aout load-state >ls.file-type !");
out:
close_io(fd);
return retval;
}
void
aout_init_program(void)
{
ucell start, size;
// Relocate a.out text down from load-base to load-base - header. This
// is similar to what OBP does and is needed for NextStep.
fword("load-base");
start = POP();
feval("load-state >ls.file-size @");
size = POP();
memmove((char *)start - sizeof(struct exec), (char *)start, size);
PUSH(start);
feval("load-state >ls.entry !");
arch_init_program();
feval("-1 state-valid !");
}
|