Make ELF kernel loadable, by itohy-san.

This commit is contained in:
isaki 2002-05-18 13:54:38 +00:00
parent 7ab28ee8d5
commit 1dc0c84b6b
5 changed files with 431 additions and 98 deletions

View File

@ -0,0 +1,340 @@
/* $NetBSD: exec_sub.c,v 1.1 2002/05/18 13:54:38 isaki Exp $ */
#include <sys/cdefs.h>
#include "execkern.h"
#include <a.out.h>
#include <sys/param.h>
#ifdef BOOT
void B_PRINT __P((const unsigned char *p));
#endif
static __inline void bzero4 __P((void *ptr, size_t siz));
static void xk_aout __P((struct execkern_arg *xarg, struct exec *hdr));
static void xk_elf __P((struct execkern_arg *xarg, Elf32_Ehdr *hdr));
#ifdef LOADBSD
static void DPRINT_SEC __P((const char *ident,
const struct execkern_section *sec));
extern int opt_v;
extern const char *kernel_fn;
static void
DPRINT_SEC(ident, sec)
const char *ident;
const struct execkern_section *sec;
{
if (opt_v)
xwarnx("section (%s): img %p, sz %d, pad %d", ident,
sec->sec_image, sec->sec_size, sec->sec_pad);
}
#define ERRX(arg) xerrx arg
#else
#define DPRINT_SEC(ident, sec) /**/
#define ERRX(arg) return 1
#endif
/*
* This code is size-hacked version of
*
* sec->sec_image = (image);
* sec->sec_size = (size);
* sec->sec_pad = (pad);
* DPRINT_SEC((ident), sec);
* sec++;
*/
#define SECTION(sec, ident, image, size, pad) \
do { \
u_long *wp = (void *) sec; \
*(void **)wp++ = (image); \
*wp++ = (size); \
*wp++ = (pad); \
DPRINT_SEC((ident), sec); \
sec = (void *) wp; \
} while (0)
#define SECTION_NOPAD(sec, ident, image, size) \
SECTION(sec, (ident), (image), (size), 0)
static __inline void
bzero4(ptr, siz)
void *ptr;
size_t siz;
{
u_long *p;
u_short s;
p = ptr;
s = siz >> 2;
while (s--)
*p++ = 0;
}
/*
* fill in loading information from an a.out executable
*/
static void
xk_aout(xarg, hdr)
struct execkern_arg *xarg;
struct exec *hdr;
{
unsigned u;
char *s;
struct execkern_section *sec;
xarg->entry_addr = hdr->a_entry;
sec = xarg->sec;
/* text section and padding between data section */
s = (void *) (hdr + 1);
SECTION(sec, "text", s, hdr->a_text, -hdr->a_text & (__LDPGSZ-1));
/* data and bss sections */
s += hdr->a_text;
SECTION(sec, "data/bss", s, hdr->a_data, hdr->a_bss);
/* size of symbol table */
SECTION_NOPAD(sec, "symtab size", &sec[1].sec_size, sizeof(u_long));
/* symbol table section */
s += hdr->a_data;
SECTION_NOPAD(sec, "symbol", s, u = hdr->a_syms);
/* string table section */
if (u) {
#ifdef LOADBSD
if (opt_v)
xwarnx("symbol table found");
#endif
s += u;
SECTION_NOPAD(sec, "string", s, *(u_long *) s);
}
}
/*
* fill in loading information from an ELF executable
*/
static void
xk_elf(xarg, hdr)
struct execkern_arg *xarg;
Elf32_Ehdr *hdr;
{
char *top = (void *) hdr;
struct execkern_section *sec;
Elf32_Phdr *ph;
Elf32_Shdr *sh, *sym, *str, *stab, *shstr;
const char *shstrtab, *shname;
unsigned u, dpos, pd;
const char *const shstrtab_new = SHSTRTAB_FAKE;
xarg->entry_addr = hdr->e_entry;
/*
* text, data, bss
*/
ph = (void *) (top + hdr->e_phoff);
xarg->load_addr = ph->p_vaddr;
sec = xarg->sec;
sec->sec_image = top + ph->p_offset;
sec->sec_size = ph->p_filesz;
if (hdr->e_phnum != 1) {
sec->sec_pad = ph[1].p_vaddr - (ph->p_vaddr + ph->p_filesz);
DPRINT_SEC("program (text)", sec);
sec++;
ph++;
sec->sec_image = top + ph->p_offset;
sec->sec_size = ph->p_filesz;
}
sec->sec_pad = ph->p_memsz - ph->p_filesz;
DPRINT_SEC("program (data/bss)", sec);
sec++;
/*
* symbol size
*/
xarg->elfsymsiz = 0; /* no symbol */
SECTION_NOPAD(sec, "symtab size", &xarg->elfsymsiz, sizeof(int));
/*
* ELF header
*/
xarg->ehdr = *hdr;
xarg->ehdr.e_shstrndx = 0; /* .shstrtab will be the 1st section */
SECTION_NOPAD(sec, "ELF header", &xarg->ehdr, sizeof(Elf32_Ehdr));
sh = (void *) (top + hdr->e_shoff); /* section header */
shstr = sh + hdr->e_shstrndx; /* .shstrtab */
shstrtab = top + shstr->sh_offset;
sym = str = stab = 0;
for (u = 0; sh++, ++u < hdr->e_shnum; ) {
shname = shstrtab + sh->sh_name;
if (!strcmp(shname, shstrtab_new + SHNAME_OFF_SYMTAB))
sym = sh; /* .symtab */
if (!strcmp(shname, shstrtab_new + SHNAME_OFF_STRTAB))
str = sh; /* .strtab */
if (!strcmp(shname, shstrtab_new + SHNAME_OFF_STAB))
stab = sh; /* .stab */
}
if (shstr == 0 || sym == 0 || str == 0)
xarg->ehdr.e_shnum = 0; /* no symbol */
else {
#ifdef LOADBSD
if (opt_v) {
xwarnx("symbol table found");
if (stab)
xwarnx("debugging information found");
}
#endif
xarg->elfsymsiz = 1; /* has symbol */
xarg->ehdr.e_shnum = 3;
xarg->ehdr.e_shoff = sizeof(Elf32_Ehdr);
SECTION_NOPAD(sec, "section header (shstrtab)",
shstr, sizeof(Elf32_Shdr));
SECTION_NOPAD(sec, "section header (symbol)",
sym, sizeof(Elf32_Shdr));
SECTION_NOPAD(sec, "section header (string)",
str, sizeof(Elf32_Shdr));
dpos = sizeof(Elf32_Ehdr) + sizeof(Elf32_Shdr) * 3;
u = SIZE_SHSTRTAB_FAKE;
if (stab) {
xarg->ehdr.e_shnum++;
SECTION_NOPAD(sec, "section header (stab)",
stab, sizeof(Elf32_Shdr));
dpos += sizeof(Elf32_Shdr);
u = SIZE_SHSTRTAB_FAKE_WITH_STAB;
}
/* new .shstrtab section */
memcpy(xarg->shstrtab_fake, shstrtab_new, u);
/*
* DDB requires symtab be aligned.
*/
pd = -u & ALIGNBYTES;
SECTION(sec, "shstrtab", &xarg->shstrtab_fake, u, pd);
shstr->sh_name = SHNAME_OFF_SHSTRTAB;
shstr->sh_offset = dpos;
dpos += u + pd;
SECTION_NOPAD(sec, "symtab",
top + sym->sh_offset, sym->sh_size);
sym->sh_name = SHNAME_OFF_SYMTAB;
sym->sh_offset = dpos;
dpos += sym->sh_size;
SECTION_NOPAD(sec, "strtab",
top + str->sh_offset, str->sh_size);
str->sh_name = SHNAME_OFF_STRTAB;
str->sh_offset = dpos;
dpos += str->sh_size;
if (stab) {
SECTION_NOPAD(sec, "stab",
top + stab->sh_offset, stab->sh_size);
stab->sh_name = SHNAME_OFF_STAB;
stab->sh_offset = dpos;
}
}
}
int
xk_load(xarg, buf, loadaddr)
struct execkern_arg *xarg;
void *buf;
u_long loadaddr; /* for a.out */
{
struct exec *ahdr;
Elf32_Ehdr *ehdr;
unsigned u;
/* Unused section entries should be cleared to zero. */
bzero4(xarg->sec, sizeof xarg->sec);
xarg->load_addr = loadaddr;
/*
* check exec header
*/
ahdr = buf;
ehdr = buf;
if (N_GETMAGIC(*ahdr) == NMAGIC) {
/*
* this is an a.out
*/
#ifdef LOADBSD
if (opt_v)
xwarnx("%s: is an a.out", kernel_fn);
#endif
#ifdef BOOT
B_PRINT("This is an a.out\r\n");
#endif
if ((u = N_GETMID(*ahdr)) != MID_M68K)
ERRX((1, "%s: Wrong architecture (mid %u)",
kernel_fn, u));
/*
* fill in loading information
*/
xk_aout(xarg, ahdr);
} else {
/*
* check ELF header
*/
if (*(u_int32_t *)&ehdr->e_ident[EI_MAG0] !=
(ELFMAG0<<24 | ELFMAG1<<16 | ELFMAG2<<8 | ELFMAG3) ||
*(u_int16_t *)&ehdr->e_ident[EI_CLASS] !=
(ELFCLASS32 << 8 | ELFDATA2MSB))
ERRX((1, "%s: Not an NMAGIC a.out or a 32bit BE ELF",
kernel_fn));
/*
* this is an ELF
*/
#ifdef LOADBSD
if (opt_v)
xwarnx("%s: is an ELF", kernel_fn);
#endif
#ifdef BOOT
B_PRINT("This is an ELF\r\n");
#endif
if (ehdr->e_ident[EI_VERSION] != EV_CURRENT ||
ehdr->e_version != EV_CURRENT)
ERRX((1, "%s: Unsupported ELF version", kernel_fn));
if ((u = ehdr->e_machine) != EM_68K)
ERRX((1, "%s: Wrong architecture (mid %u)",
kernel_fn, u));
if (ehdr->e_type != ET_EXEC)
ERRX((1, "%s: Not an executable", kernel_fn));
if ((u = ehdr->e_phnum) != 1 && u != 2)
ERRX((1, "%s: Wrong number (%u) of loading sections",
kernel_fn, u));
/*
* fill in loading information
*/
xk_elf(xarg, ehdr);
}
return 0;
}

View File

@ -4,10 +4,10 @@
| written by Yasha (ITOH Yasufumi)
| public domain
|
| $NetBSD: execkern.S,v 1.2 2001/06/12 16:57:27 minoura Exp $
| $NetBSD: execkern.S,v 1.3 2002/05/18 13:54:38 isaki Exp $
/* XXX this value is from <machine/exec_aout.h> */
#define __LDPGSZ 8192
#include <machine/asm.h>
#include "execkern.h"
#define MFP 0x00E88000 /* MFP */
#define MFP_IERA (MFP+0x07) /* (B) interrupt enable reg A */
@ -19,16 +19,20 @@
#define SRAM_MEMSZ (SRAM + 8) /* (L) size of main memory */
#endif
| %a3+0 kernel image top address (a.out header is excluded)
| %a3+4 load address
| %a3+8 text size
| %a3+12 data size
| %a3+16 bss size
| %a3+20 symbol size
| %a3+24 (reserved) (%d5)
| %a3+28 bootdev (%d6)
| %a3+32 boothowto (%d7)
| %a3+36 entry address (absolute address)
| a3+0 load address
|
| a3+4 section #1 image top address
| a3+8 section #1 size
| a3+12 section #1 gap size
| : :
| a3+n-12 section #XK_NSEC image top address
| a3+n-8 section #XK_NSEC size
| a3+n-4 section #XK_NSEC gap size
|
| a3+n (reserved) (d5)
| a3+n+4 bootdev (d6)
| a3+n+8 boothowto (d7)
| a3+n+12 entry address (absolute address)
#ifndef XK_NO_C_INTERFACE
.text
@ -38,7 +42,6 @@ ENTRY_NOPROFILE(exec_kernel)
moveal %sp@+,%a3 | struct execkern_arg *
#endif
moveal %a3@+,%a0 | image address
moveal %a3@+,%a1 | load address
movel %a1,%d3
@ -46,41 +49,16 @@ ENTRY_NOPROFILE(exec_kernel)
| copy image
|
| copy text segment
movel %a3@+,%d0 | text size
movel #XK_NSEC-1,%d2
Lloop:
moveal %a3@+,%a0 | section image address
movel %a3@+,%d0 | section size
movel %d0,%d1
jbsr copy
| clear gap between text and data
negl %d1
andil #__LDPGSZ-1,%d1
movel %d1,%d0 | gap size between text and data
movel %a3@+,%d0 | section gap
jbsr clear
| copy data segment
movel %a3@+,%d0 | data size
jbsr copy
| clear bss
movel %a3@+,%d0 | bss size
jbsr clear
| copy symbol table
movel %a3@+,%d0 | symbol table size
movel %d0,%a1@+
beqs Lnotable
jbsr copy
| copy string table size
movel %a0@+,%d0
movel %d0,%a1@+
beqs Lnotable
| copy string table
subql #4,%d0 | table size is already copied
jbsr copy
Lnotable:
dbra %d2,Lloop
| stop MFP interrupts (for compatibility)
clrb MFP_IERA
@ -95,7 +73,7 @@ Lnotable:
addql #3,%d0
andib #0xFC,%d0
subl %d3,%d0
movel %d0,%sp@- | arg #3 (kernel size)
movel %d0,%sp@- | arg #3 (end of kernel)
movel SRAM_MEMSZ,%sp@- | arg #2 (RAM size from SRAM)
movel %d3,%sp@- | arg #1 (load address)

View File

@ -4,25 +4,56 @@
* written by Yasha (ITOH Yasufumi)
* public domain
*
* $NetBSD: execkern.h,v 1.1 1998/09/01 19:51:56 itohy Exp $
* $NetBSD: execkern.h,v 1.2 2002/05/18 13:54:38 isaki Exp $
*/
#ifndef X68K_BOOT_EXECKERN_H
#define X68K_BOOT_EXECKERN_H
/*
* Max number of ``sections''.
* Currently this includes: .text, .data, size sym, Elf32_Ehdr, Elf32_Shdr x 4,
* .shstrtab, .symtab, .strtab, .stab
*/
#define XK_NSEC 12
#ifndef __ASSEMBLER__
#include <sys/types.h>
#include <sys/exec_elf.h>
struct execkern_arg {
void *image_top;
u_long load_addr;
u_long text_size;
u_long data_size;
u_long bss_size;
u_long symbol_size;
/* Don't change this structure (see exec_sub.c). */
u_long load_addr; /* text start address */
struct execkern_section {
void *sec_image; /* section image source address */
u_long sec_size; /* section size */
u_long sec_pad; /* zero fill size after the image */
} sec[XK_NSEC];
unsigned d5; /* reserved */
int rootdev;
u_long boothowto;
u_long entry_addr;
/* end of "Don't change this" */
int elfsymsiz;
Elf32_Ehdr ehdr; /* saved ELF header */
#define SHSTRTAB_FAKE "\0.shstrtab\0.symtab\0.strtab\0.stab"
#define SIZE_SHSTRTAB_FAKE_WITH_STAB 33 /* sizeof SHSTRTAB_FAKE */
#define SIZE_SHSTRTAB_FAKE 27 /* - sizeof ".stab" */
#define SHNAME_OFF_SHSTRTAB 1
#define SHNAME_OFF_SYMTAB 11
#define SHNAME_OFF_STRTAB 19
#define SHNAME_OFF_STAB 27
char shstrtab_fake[SIZE_SHSTRTAB_FAKE_WITH_STAB];
};
int xk_load __P((struct execkern_arg *, void *, u_long));
void __dead exec_kernel __P((struct execkern_arg *)) __attribute__((noreturn));
#endif /* __ASSEMBLER__ */
#endif /* X68K_BOOT_EXECKERN_H */

View File

@ -1,4 +1,4 @@
# $NetBSD: Makefile,v 1.8 2001/12/12 01:49:56 tv Exp $
# $NetBSD: Makefile,v 1.9 2002/05/18 13:54:39 isaki Exp $
BASE= loadbsd
PROG= ${BASE}.x # Human68k ".x" executable
@ -34,7 +34,7 @@ ${PROG}: ${BASE}1 ${BASE}2
.for i in 1 2
${BASE}${i}: ${OBJS} ${LIBDOS}/libdos.a ${LIBIOCS}/libiocs.a
${CC} -o ${.TARGET} ${LDFLAGS} -Wl,-Ttext -Wl,${i}${i}000 ${OBJS} ${LDLIBS}
${CC} -o ${.TARGET} ${LDFLAGS} -Wl,-Ttext,${i}${i}000 ${OBJS} ${LDLIBS}
.endfor
.ifdef RELEASEDIR

View File

@ -19,18 +19,19 @@
* -q quiet boot
* -v verbose boot (also turn on verbosity of loadbsd)
*
* $NetBSD: loadbsd.c,v 1.7 2001/06/12 16:57:28 minoura Exp $
* $NetBSD: loadbsd.c,v 1.8 2002/05/18 13:54:39 isaki Exp $
*/
#include <sys/cdefs.h>
__RCSID("$NetBSD: loadbsd.c,v 1.7 2001/06/12 16:57:28 minoura Exp $");
#define VERSION "$Revision: 1.7 $ $Date: 2001/06/12 16:57:28 $"
__RCSID("$NetBSD: loadbsd.c,v 1.8 2002/05/18 13:54:39 isaki Exp $");
#define VERSION "$Revision: 1.8 $ $Date: 2002/05/18 13:54:39 $"
#include <sys/types.h> /* ntohl */
#include <sys/reboot.h>
#include <sys/param.h> /* ALIGN, ALIGNBYTES */
#include <a.out.h>
#include <sys/exec_elf.h>
#include <string.h>
#include <machine/bootinfo.h>
@ -59,6 +60,7 @@ int main __P((int argc, char *argv[]));
int opt_v;
int opt_N;
const char *kernel_fn;
const struct hatbl {
char name[4];
@ -278,12 +280,15 @@ found: major = devtable[u].major;
return dev;
}
#define LOADBSD
#include "../common/exec_sub.c"
/*
* read kernel and create trampoline
*
* |----------------------| <- allocated buf addr
* | kernel image |
* ~ (header is excluded) ~
* ~ (exec file contents) ~
* | |
* |----------------------| <- return value (entry addr of trampoline)
* | struct tramparg |
@ -301,12 +306,12 @@ read_kernel(fn)
union dos_fcb *fcb;
size_t filesize, nread;
void *buf;
struct exec hdr;
int i;
struct tramparg *arg;
size_t size_tramp = end_trampoline - trampoline;
if ((fd = DOS_OPEN(fn, 0x20)) < 0) /* RO, share READ */
kernel_fn = fn;
if ((fd = DOS_OPEN(fn, 0x00)) < 0) /* read only */
xerr(1, "%s: open", fn);
if ((int)(fcb = DOS_GET_FCB_ADR(fd)) < 0)
@ -322,38 +327,18 @@ read_kernel(fn)
/*filesize = fcb->blk.size;*/
filesize = IOCS_B_LPEEK(&fcb->blk.size);
/*
* read a.out header
*/
if ((nread = DOS_READ(fd, (void *) &hdr, sizeof hdr)) != sizeof hdr) {
if ((int)nread < 0)
xerr(1, "%s: read header", fn);
else
xerrx(1, "%s: Not an a.out", fn);
}
/*
* check header
*/
if (N_GETMAGIC(hdr) != NMAGIC)
xerrx(1, "%s: Bad magic number", fn);
if ((i = N_GETMID(hdr)) != MID_M68K)
xerrx(1, "%s: Wrong architecture (mid %d)", fn, i);
if (opt_v)
xwarnx("%s: %u bytes; text %u, data %u, bss %u, sym %u",
fn, filesize, hdr.a_text, hdr.a_data,
hdr.a_bss, hdr.a_syms);
if (filesize < sizeof(Elf32_Ehdr))
xerrx(1, "%s: Unknown format", fn);
/*
* then, read entire body
* read entire file
*/
if ((int)(buf = DOS_MALLOC(filesize + ALIGNBYTES - sizeof hdr
if ((int)(buf = DOS_MALLOC(filesize + ALIGNBYTES
+ sizeof(struct tramparg)
+ size_tramp + SIZE_TMPSTACK)) < 0)
xerr(1, "read_kernel");
if ((nread = DOS_READ(fd, buf, filesize - sizeof hdr))
!= filesize - sizeof hdr) {
if ((nread = DOS_READ(fd, buf, filesize)) != filesize) {
if ((int)nread < 0)
xerr(1, "%s: read", fn);
else
@ -364,35 +349,34 @@ read_kernel(fn)
xerr(1, "%s: close", fn);
/*
* create argument for trampoline code
* address for argument for trampoline code
*/
arg = (struct tramparg *) ALIGN(buf + nread);
arg = (struct tramparg *) ALIGN((char *) buf + nread);
if (opt_v)
xwarnx("trampoline arg at %p", arg);
xk_load(&arg->xk, buf, 0 /* XXX load addr should not be fixed */);
/*
* create argument for trampoline code
*/
arg->bsr_inst = TRAMP_BSR + sizeof(struct tramparg) - 2;
arg->tmp_stack = (char *) arg + sizeof(struct tramparg)
+ size_tramp + SIZE_TMPSTACK;
arg->mpu_type = IOCS_MPU_STAT() & 0xff;
arg->xk.image_top = buf;
arg->xk.load_addr = 0x00000000; /* XXX should not be a fixed addr */
arg->xk.text_size = hdr.a_text;
arg->xk.data_size = hdr.a_data;
arg->xk.bss_size = hdr.a_bss;
arg->xk.symbol_size = hdr.a_syms;
arg->xk.d5 = IOCS_BOOTINF(); /* unused for now */
#if 0
/* filled afterwards */
arg->xk.rootdev =
arg->xk.boothowto =
#endif
arg->xk.entry_addr = hdr.a_entry;
if (opt_v)
xwarnx("args: mpu %d, image %p, load 0x%x, entry 0x%x",
arg->mpu_type, arg->xk.image_top, arg->xk.load_addr,
arg->xk.entry_addr);
arg->mpu_type, arg->xk.sec[0].sec_image,
arg->xk.load_addr, arg->xk.entry_addr);
/*
* copy trampoline code