Exemplo n.º 1
0
void
bios_addsmapdata(struct preloaded_file *kfp)
{
	int len;

	if (smapbase == 0 || smaplen == 0)
		return;
	len = smaplen * sizeof(*smapbase);
	file_addmetadata(kfp, MODINFOMD_SMAP, len, smapbase);
	/* Temporary compatability with older development kernels */
	file_addmetadata(kfp, 0x0009, len, smapbase);
}
Exemplo n.º 2
0
void
bios_addsmapdata(struct preloaded_file *kfp)
{
	size_t			size;

	if (smapbase == NULL || smaplen == 0)
		return;
	size = smaplen * sizeof(*smapbase);
	file_addmetadata(kfp, MODINFOMD_SMAP, size, smapbase);
	if (smapattr != NULL) {
		size = smaplen * sizeof(*smapattr);
		file_addmetadata(kfp, MODINFOMD_SMAP_XATTR, size, smapattr);
	}
}
Exemplo n.º 3
0
static void
bios_addsmapdata(struct preloaded_file *kfp)
{
	uint64_t lowmem, highmem;
	int smapnum, len;
	struct smap smap[3], *sm;

	CALLBACK(getmem, &lowmem, &highmem);

	sm = &smap[0];

	sm->base = 0;				/* base memory */
	sm->length = 640 * 1024;
	sm->type = SMAP_TYPE_MEMORY;
	sm++;

	sm->base = 0x100000;			/* extended memory */
	sm->length = lowmem - 0x100000;
	sm->type = SMAP_TYPE_MEMORY;
	sm++;

	smapnum = 2;

        if (highmem != 0) {
                sm->base = 4 * GB;
                sm->length = highmem;
                sm->type = SMAP_TYPE_MEMORY;
		smapnum++;
        }

        len = smapnum * sizeof (struct smap);
        file_addmetadata(kfp, MODINFOMD_SMAP, len, &smap[0]);
}
Exemplo n.º 4
0
/*
 * Load the information expected by an amd64 kernel.
 *
 * - The 'boothowto' argument is constructed
 * - The 'bootdev' argument is constructed
 * - The 'bootinfo' struct is constructed, and copied into the kernel space.
 * - The kernel environment is copied into kernel space.
 * - Module metadata are formatted and placed in kernel space.
 */
int
bi_load64(char *args, vm_offset_t *modulep, vm_offset_t *kernendp)
{
    struct preloaded_file	*xp, *kfp;
    struct userboot_devdesc	*rootdev;
    struct file_metadata	*md;
    vm_offset_t			addr;
    u_int64_t			kernend;
    u_int64_t			envp;
    vm_offset_t			size;
    char			*rootdevname;
    int				howto;

    if (!bi_checkcpu()) {
	printf("CPU doesn't support long mode\n");
	return (EINVAL);
    }

    howto = bi_getboothowto(args);

    /* 
     * Allow the environment variable 'rootdev' to override the supplied device 
     * This should perhaps go to MI code and/or have $rootdev tested/set by
     * MI code before launching the kernel.
     */
    rootdevname = getenv("rootdev");
    userboot_getdev((void **)(&rootdev), rootdevname, NULL);
    if (rootdev == NULL) {		/* bad $rootdev/$currdev */
	printf("can't determine root device\n");
	return(EINVAL);
    }

    /* Try reading the /etc/fstab file to select the root device */
    getrootmount(userboot_fmtdev((void *)rootdev));

    /* find the last module in the chain */
    addr = 0;
    for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) {
	if (addr < (xp->f_addr + xp->f_size))
	    addr = xp->f_addr + xp->f_size;
    }
    /* pad to a page boundary */
    addr = roundup(addr, PAGE_SIZE);

    /* copy our environment */
    envp = addr;
    addr = bi_copyenv(addr);

    /* pad to a page boundary */
    addr = roundup(addr, PAGE_SIZE);

    kfp = file_findfile(NULL, "elf kernel");
    if (kfp == NULL)
      kfp = file_findfile(NULL, "elf64 kernel");
    if (kfp == NULL)
	panic("can't find kernel file");
    kernend = 0;	/* fill it in later */
    file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto);
    file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp);
    file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend);
    bios_addsmapdata(kfp);

    /* Figure out the size and location of the metadata */
    *modulep = addr;
    size = bi_copymodules64(0);
    kernend = roundup(addr + size, PAGE_SIZE);
    *kernendp = kernend;

    /* patch MODINFOMD_KERNEND */
    md = file_findmetadata(kfp, MODINFOMD_KERNEND);
    bcopy(&kernend, md->md_data, sizeof kernend);

    /* copy module list and metadata */
    (void)bi_copymodules64(addr);

    return(0);
}
Exemplo n.º 5
0
/*
 * Load the information expected by a powerpc kernel.
 *
 * - The 'boothowto' argument is constructed
 * - The 'bootdev' argument is constructed
 * - The kernel environment is copied into kernel space.
 * - Module metadata are formatted and placed in kernel space.
 */
int
md_load_dual(char *args, vm_offset_t *modulep, vm_offset_t *dtb, int kern64)
{
    struct preloaded_file	*kfp;
    struct preloaded_file	*xp;
    struct file_metadata	*md;
    vm_offset_t			kernend;
    vm_offset_t			addr;
    vm_offset_t			envp;
    vm_offset_t			fdtp;
    vm_offset_t			size;
    uint64_t			scratch64;
    char			*rootdevname;
    int				howto;

    align = kern64 ? 8 : 4;
    howto = md_getboothowto(args);

    /* 
     * Allow the environment variable 'rootdev' to override the supplied device 
     * This should perhaps go to MI code and/or have $rootdev tested/set by
     * MI code before launching the kernel.
     */
    rootdevname = getenv("rootdev");
    if (rootdevname == NULL)
	    rootdevname = getenv("currdev");
    /* Try reading the /etc/fstab file to select the root device */
    getrootmount(rootdevname);

    /* find the last module in the chain */
    addr = 0;
    for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) {
	if (addr < (xp->f_addr + xp->f_size))
	    addr = xp->f_addr + xp->f_size;
    }
    /* pad to a page boundary */
    addr = roundup(addr, PAGE_SIZE);

    /* copy our environment */
    envp = addr;
    addr = md_copyenv(addr);

    /* pad to a page boundary */
    addr = roundup(addr, PAGE_SIZE);

    /* Copy out FDT */
    size = fdt_copy(addr);
    *dtb = fdtp = addr;
    addr = roundup(addr + size, PAGE_SIZE);

    kernend = 0;
    kfp = file_findfile(NULL, kern64 ? "elf64 kernel" : "elf32 kernel");
    if (kfp == NULL)
	kfp = file_findfile(NULL, "elf kernel");
    if (kfp == NULL)
	panic("can't find kernel file");
    file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto);
    if (kern64) {
	scratch64 = envp;
	file_addmetadata(kfp, MODINFOMD_ENVP, sizeof scratch64, &scratch64);
	scratch64 = fdtp;
	file_addmetadata(kfp, MODINFOMD_DTBP, sizeof scratch64, &scratch64);
	scratch64 = kernend;
	file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof scratch64, &scratch64);
    } else {
	file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp);
	file_addmetadata(kfp, MODINFOMD_DTBP, sizeof fdtp, &fdtp);
	file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend);
    }

    *modulep = addr;
    size = md_copymodules(0, kern64);
    kernend = roundup(addr + size, PAGE_SIZE);

    md = file_findmetadata(kfp, MODINFOMD_KERNEND);
    if (kern64) {
	scratch64 = kernend;
	bcopy(&scratch64, md->md_data, sizeof scratch64);
    } else {
	bcopy(&kernend, md->md_data, sizeof kernend);
    }
	
    (void)md_copymodules(addr, kern64);

    return(0);
}
Exemplo n.º 6
0
/*
 * Attempt to load the file (file) as an ELF module.  It will be stored at
 * (dest), and a pointer to a module structure describing the loaded object
 * will be saved in (result).
 */
int
__elfN(obj_loadfile)(char *filename, u_int64_t dest,
    struct preloaded_file **result)
{
	struct preloaded_file *fp, *kfp;
	struct elf_file	ef;
	Elf_Ehdr *hdr;
	int err;
	ssize_t bytes_read;

	fp = NULL;
	bzero(&ef, sizeof(struct elf_file));

	/*
	 * Open the image, read and validate the ELF header
	 */
	if (filename == NULL)	/* can't handle nameless */
		return(EFTYPE);
	if ((ef.fd = open(filename, O_RDONLY)) == -1)
		return(errno);

	hdr = &ef.hdr;
	bytes_read = read(ef.fd, hdr, sizeof(*hdr));
	if (bytes_read != sizeof(*hdr)) {
		err = EFTYPE;	/* could be EIO, but may be small file */
		goto oerr;
	}

	/* Is it ELF? */
	if (!IS_ELF(*hdr)) {
		err = EFTYPE;
		goto oerr;
	}
	if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS ||	/* Layout ? */
	    hdr->e_ident[EI_DATA] != ELF_TARG_DATA ||
	    hdr->e_ident[EI_VERSION] != EV_CURRENT ||	/* Version ? */
	    hdr->e_version != EV_CURRENT ||
	    hdr->e_machine != ELF_TARG_MACH ||		/* Machine ? */
	    hdr->e_type != ET_REL) {
		err = EFTYPE;
		goto oerr;
	}

	if (hdr->e_shnum * hdr->e_shentsize == 0 || hdr->e_shoff == 0 ||
	    hdr->e_shentsize != sizeof(Elf_Shdr)) {
		err = EFTYPE;
		goto oerr;
	}

	kfp = file_findfile(NULL, NULL);
	if (kfp == NULL) {
		printf("elf" __XSTRING(__ELF_WORD_SIZE)
		    "_obj_loadfile: can't load module before kernel\n");
		err = EPERM;
		goto oerr;
	}
	if (strcmp(__elfN(obj_kerneltype), kfp->f_type)) {
		printf("elf" __XSTRING(__ELF_WORD_SIZE)
		    "_obj_loadfile: can't load module with kernel type '%s'\n",
		    kfp->f_type);
		err = EPERM;
		goto oerr;
	}

	if (archsw.arch_loadaddr != NULL)
		dest = archsw.arch_loadaddr(LOAD_ELF, hdr, dest);
	else
		dest = roundup(dest, PAGE_SIZE);

	/*
	 * Ok, we think we should handle this.
	 */
	fp = file_alloc();
	if (fp == NULL) {
		printf("elf" __XSTRING(__ELF_WORD_SIZE)
		    "_obj_loadfile: cannot allocate module info\n");
		err = EPERM;
		goto out;
	}
	fp->f_name = strdup(filename);
	fp->f_type = strdup(__elfN(obj_moduletype));

	printf("%s ", filename);

	fp->f_size = __elfN(obj_loadimage)(fp, &ef, dest);
	if (fp->f_size == 0 || fp->f_addr == 0)
		goto ioerr;

	/* save exec header as metadata */
	file_addmetadata(fp, MODINFOMD_ELFHDR, sizeof(*hdr), hdr);

	/* Load OK, return module pointer */
	*result = (struct preloaded_file *)fp;
	err = 0;
	goto out;

ioerr:
	err = EIO;
oerr:
	file_discard(fp);
out:
	close(ef.fd);
	if (ef.e_shdr != NULL)
		free(ef.e_shdr);

	return(err);
}
Exemplo n.º 7
0
int
__elfN(obj_parse_modmetadata)(struct preloaded_file *fp, elf_file_t ef)
{
	struct mod_metadata md;
#if defined(__i386__) && __ELF_WORD_SIZE == 64
	struct mod_metadata64 md64;
#endif
	struct mod_depend *mdepend;
	struct mod_version mver;
	char *s;
	int error, modcnt, minfolen;
	Elf_Addr v, p, p_stop;

	if (__elfN(obj_lookup_set)(fp, ef, "modmetadata_set", &p, &p_stop,
	    &modcnt) != 0)
		return 0;

	modcnt = 0;
	while (p < p_stop) {
		COPYOUT(p, &v, sizeof(v));
		error = __elfN(obj_reloc_ptr)(fp, ef, p, &v, sizeof(v));
		if (error != 0)
			return (error);
#if defined(__i386__) && __ELF_WORD_SIZE == 64
		COPYOUT(v, &md64, sizeof(md64));
		error = __elfN(obj_reloc_ptr)(fp, ef, v, &md64, sizeof(md64));
		if (error != 0)
			return (error);
		md.md_version = md64.md_version;
		md.md_type = md64.md_type;
		md.md_cval = (const char *)(uintptr_t)md64.md_cval;
		md.md_data = (void *)(uintptr_t)md64.md_data;
#else
		COPYOUT(v, &md, sizeof(md));
		error = __elfN(obj_reloc_ptr)(fp, ef, v, &md, sizeof(md));
		if (error != 0)
			return (error);
#endif
		p += sizeof(Elf_Addr);
		switch(md.md_type) {
		case MDT_DEPEND:
			s = strdupout((vm_offset_t)md.md_cval);
			minfolen = sizeof(*mdepend) + strlen(s) + 1;
			mdepend = malloc(minfolen);
			if (mdepend == NULL)
				return ENOMEM;
			COPYOUT((vm_offset_t)md.md_data, mdepend,
			    sizeof(*mdepend));
			strcpy((char*)(mdepend + 1), s);
			free(s);
			file_addmetadata(fp, MODINFOMD_DEPLIST, minfolen,
			    mdepend);
			free(mdepend);
			break;
		case MDT_VERSION:
			s = strdupout((vm_offset_t)md.md_cval);
			COPYOUT((vm_offset_t)md.md_data, &mver, sizeof(mver));
			file_addmodule(fp, s, mver.mv_version, NULL);
			free(s);
			modcnt++;
			break;
		case MDT_MODULE:
			break;
		default:
			printf("unknown type %d\n", md.md_type);
			break;
		}
	}
	return 0;
}
Exemplo n.º 8
0
/*
 * With the file (fd) open on the image, and (ehdr) containing
 * the Elf header, load the image at (off)
 */
static int
__elfN(obj_loadimage)(struct preloaded_file *fp, elf_file_t ef, u_int64_t off)
{
	Elf_Ehdr *hdr;
	Elf_Shdr *shdr, *cshdr, *lshdr;
	vm_offset_t firstaddr, lastaddr;
	int i, nsym, res, ret, shdrbytes, symstrindex;

	ret = 0;
	firstaddr = lastaddr = (vm_offset_t)off;
	hdr = &ef->hdr;
	ef->off = (vm_offset_t)off;

	/* Read in the section headers. */
	shdrbytes = hdr->e_shnum * hdr->e_shentsize;
	shdr = alloc_pread(ef->fd, (off_t)hdr->e_shoff, shdrbytes);
	if (shdr == NULL) {
		printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
		    "_obj_loadimage: read section headers failed\n");
		goto out;
	}
	ef->e_shdr = shdr;

	/*
	 * Decide where to load everything, but don't read it yet.
	 * We store the load address as a non-zero sh_addr value.
	 * Start with the code/data and bss.
	 */
	for (i = 0; i < hdr->e_shnum; i++)
		shdr[i].sh_addr = 0;
	for (i = 0; i < hdr->e_shnum; i++) {
		if (shdr[i].sh_size == 0)
			continue;
		switch (shdr[i].sh_type) {
		case SHT_PROGBITS:
		case SHT_NOBITS:
			lastaddr = roundup(lastaddr, shdr[i].sh_addralign);
			shdr[i].sh_addr = (Elf_Addr)lastaddr;
			lastaddr += shdr[i].sh_size;
			break;
		}
	}

	/* Symbols. */
	nsym = 0;
	for (i = 0; i < hdr->e_shnum; i++) {
		switch (shdr[i].sh_type) {
		case SHT_SYMTAB:
			nsym++;
			ef->symtabindex = i;
			shdr[i].sh_addr = (Elf_Addr)lastaddr;
			lastaddr += shdr[i].sh_size;
			break;
		}
	}
	if (nsym != 1) {
		printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
		    "_obj_loadimage: file has no valid symbol table\n");
		goto out;
	}
	lastaddr = roundup(lastaddr, shdr[ef->symtabindex].sh_addralign);
	shdr[ef->symtabindex].sh_addr = (Elf_Addr)lastaddr;
	lastaddr += shdr[ef->symtabindex].sh_size;

	symstrindex = shdr[ef->symtabindex].sh_link;
	if (symstrindex < 0 || symstrindex >= hdr->e_shnum ||
	    shdr[symstrindex].sh_type != SHT_STRTAB) {
		printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
		    "_obj_loadimage: file has invalid symbol strings\n");
		goto out;
	}
	lastaddr = roundup(lastaddr, shdr[symstrindex].sh_addralign);
	shdr[symstrindex].sh_addr = (Elf_Addr)lastaddr;
	lastaddr += shdr[symstrindex].sh_size;

	/* Section names. */
	if (hdr->e_shstrndx == 0 || hdr->e_shstrndx >= hdr->e_shnum ||
	    shdr[hdr->e_shstrndx].sh_type != SHT_STRTAB) {
		printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
		    "_obj_loadimage: file has no section names\n");
		goto out;
	}
	ef->shstrindex = hdr->e_shstrndx;
	lastaddr = roundup(lastaddr, shdr[ef->shstrindex].sh_addralign);
	shdr[ef->shstrindex].sh_addr = (Elf_Addr)lastaddr;
	lastaddr += shdr[ef->shstrindex].sh_size;

	/* Relocation tables. */
	for (i = 0; i < hdr->e_shnum; i++) {
		switch (shdr[i].sh_type) {
		case SHT_REL:
		case SHT_RELA:
			lastaddr = roundup(lastaddr, shdr[i].sh_addralign);
			shdr[i].sh_addr = (Elf_Addr)lastaddr;
			lastaddr += shdr[i].sh_size;
			break;
		}
	}

	/* Clear the whole area, including bss regions. */
	kern_bzero(firstaddr, lastaddr - firstaddr);

	/* Figure section with the lowest file offset we haven't loaded yet. */
	for (cshdr = NULL; /* none */; /* none */)
	{
		/*
		 * Find next section to load. The complexity of this loop is
		 * O(n^2), but with  the number of sections being typically
		 * small, we do not care.
		 */
		lshdr = cshdr;

		for (i = 0; i < hdr->e_shnum; i++) {
			if (shdr[i].sh_addr == 0 ||
			    shdr[i].sh_type == SHT_NOBITS)
				continue;
			/* Skip sections that were loaded already. */
			if (lshdr != NULL &&
			    lshdr->sh_offset >= shdr[i].sh_offset)
				continue;
			/* Find section with smallest offset. */
			if (cshdr == lshdr ||
			    cshdr->sh_offset > shdr[i].sh_offset)
				cshdr = &shdr[i];
		}

		if (cshdr == lshdr)
			break;

		if (kern_pread(ef->fd, (vm_offset_t)cshdr->sh_addr,
		    cshdr->sh_size, (off_t)cshdr->sh_offset) != 0) {
			printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
			    "_obj_loadimage: read failed\n");
			goto out;
		}
	}

	file_addmetadata(fp, MODINFOMD_SHDR, shdrbytes, shdr);

	res = __elfN(obj_parse_modmetadata)(fp, ef);
	if (res != 0)
		goto out;

	ret = lastaddr - firstaddr;
	fp->f_addr = firstaddr;

	printf("size 0x%lx at 0x%lx", (u_long)ret, (u_long)firstaddr);

out:
	printf("\n");
	return ret;
}
Exemplo n.º 9
0
/*
 * With the file (fd) open on the image, and (ehdr) containing
 * the Elf header, load the image at (off)
 */
static int
__elfN(loadimage)(struct preloaded_file *fp, elf_file_t ef, u_int64_t off)
{
    int 	i;
    u_int	j;
    Elf_Ehdr	*ehdr;
    Elf_Phdr	*phdr, *php;
    Elf_Shdr	*shdr;
    int		ret;
    vm_offset_t firstaddr;
    vm_offset_t lastaddr;
    size_t	chunk;
    ssize_t	result;
    Elf_Addr	ssym, esym;
    Elf_Dyn	*dp;
    Elf_Addr	adp;
    int		ndp;
    int		symstrindex;
    int		symtabindex;
    Elf_Size	size;
    u_int	fpcopy;

    dp = NULL;
    shdr = NULL;
    ret = 0;
    firstaddr = lastaddr = 0;
    ehdr = ef->ehdr;
    if (ef->kernel) {
#if defined(__i386__) || defined(__amd64__)
#if __ELF_WORD_SIZE == 64
	off = - (off & 0xffffffffff000000ull);/* x86_64 relocates after locore */
#else
	off = - (off & 0xff000000u);	/* i386 relocates after locore */
#endif
#elif defined(__powerpc__)
	/*
	 * On the purely virtual memory machines like e500, the kernel is
	 * linked against its final VA range, which is most often not
	 * available at the loader stage, but only after kernel initializes
	 * and completes its VM settings. In such cases we cannot use p_vaddr
	 * field directly to load ELF segments, but put them at some
	 * 'load-time' locations.
	 */
	if (off & 0xf0000000u) {
	    off = -(off & 0xf0000000u);
	    /*
	     * XXX the physical load address should not be hardcoded. Note
	     * that the Book-E kernel assumes that it's loaded at a 16MB
	     * boundary for now...
	     */
	    off += 0x01000000;
	    ehdr->e_entry += off;
#ifdef ELF_VERBOSE
	    printf("Converted entry 0x%08x\n", ehdr->e_entry);
#endif
	} else
	    off = 0;
#elif defined(__arm__)
	/*
	 * The elf headers in some kernels specify virtual addresses in all
	 * header fields.  More recently, the e_entry and p_paddr fields are the
	 * proper physical addresses.  Even when the p_paddr fields are correct,
	 * the MI code below uses the p_vaddr fields with an offset added for
	 * loading (doing so is arguably wrong).  To make loading work, we need
	 * an offset that represents the difference between physical and virtual
	 * addressing.  ARM kernels are always linked at 0xCnnnnnnn.  Depending
	 * on the headers, the offset value passed in may be physical or virtual
	 * (because it typically comes from e_entry), but we always replace
	 * whatever is passed in with the va<->pa offset.  On the other hand, we
	 * always remove the high-order part of the entry address whether it's
	 * physical or virtual, because it will be adjusted later for the actual
	 * physical entry point based on where the image gets loaded.
	 */
	off = -0xc0000000;
	ehdr->e_entry &= ~0xf0000000;
#ifdef ELF_VERBOSE
	printf("ehdr->e_entry 0x%08x, va<->pa off %llx\n", ehdr->e_entry, off);
#endif
#else
	off = 0;		/* other archs use direct mapped kernels */
#endif
	__elfN(relocation_offset) = off;
    }
    ef->off = off;

    if ((ehdr->e_phoff + ehdr->e_phnum * sizeof(*phdr)) > ef->firstlen) {
	printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadimage: program header not within first page\n");
	goto out;
    }
    phdr = (Elf_Phdr *)(ef->firstpage + ehdr->e_phoff);

    for (i = 0; i < ehdr->e_phnum; i++) {
	/* We want to load PT_LOAD segments only.. */
	if (phdr[i].p_type != PT_LOAD)
	    continue;

#ifdef ELF_VERBOSE
	printf("Segment: 0x%lx@0x%lx -> 0x%lx-0x%lx",
	    (long)phdr[i].p_filesz, (long)phdr[i].p_offset,
	    (long)(phdr[i].p_vaddr + off),
	    (long)(phdr[i].p_vaddr + off + phdr[i].p_memsz - 1));
#else
	if ((phdr[i].p_flags & PF_W) == 0) {
	    printf("text=0x%lx ", (long)phdr[i].p_filesz);
	} else {
	    printf("data=0x%lx", (long)phdr[i].p_filesz);
	    if (phdr[i].p_filesz < phdr[i].p_memsz)
		printf("+0x%lx", (long)(phdr[i].p_memsz -phdr[i].p_filesz));
	    printf(" ");
	}
#endif
	fpcopy = 0;
	if (ef->firstlen > phdr[i].p_offset) {
	    fpcopy = ef->firstlen - phdr[i].p_offset;
	    archsw.arch_copyin(ef->firstpage + phdr[i].p_offset,
			       phdr[i].p_vaddr + off, fpcopy);
	}
	if (phdr[i].p_filesz > fpcopy) {
	    if (kern_pread(ef->fd, phdr[i].p_vaddr + off + fpcopy,
		phdr[i].p_filesz - fpcopy, phdr[i].p_offset + fpcopy) != 0) {
		printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
		    "_loadimage: read failed\n");
		goto out;
	    }
	}
	/* clear space from oversized segments; eg: bss */
	if (phdr[i].p_filesz < phdr[i].p_memsz) {
#ifdef ELF_VERBOSE
	    printf(" (bss: 0x%lx-0x%lx)",
		(long)(phdr[i].p_vaddr + off + phdr[i].p_filesz),
		(long)(phdr[i].p_vaddr + off + phdr[i].p_memsz - 1));
#endif

	    kern_bzero(phdr[i].p_vaddr + off + phdr[i].p_filesz,
		phdr[i].p_memsz - phdr[i].p_filesz);
	}
#ifdef ELF_VERBOSE
	printf("\n");
#endif

	if (archsw.arch_loadseg != NULL)
	    archsw.arch_loadseg(ehdr, phdr + i, off);

	if (firstaddr == 0 || firstaddr > (phdr[i].p_vaddr + off))
	    firstaddr = phdr[i].p_vaddr + off;
	if (lastaddr == 0 || lastaddr < (phdr[i].p_vaddr + off + phdr[i].p_memsz))
	    lastaddr = phdr[i].p_vaddr + off + phdr[i].p_memsz;
    }
    lastaddr = roundup(lastaddr, sizeof(long));

    /*
     * Now grab the symbol tables.  This isn't easy if we're reading a
     * .gz file.  I think the rule is going to have to be that you must
     * strip a file to remove symbols before gzipping it so that we do not
     * try to lseek() on it.
     */
    chunk = ehdr->e_shnum * ehdr->e_shentsize;
    if (chunk == 0 || ehdr->e_shoff == 0)
	goto nosyms;
    shdr = alloc_pread(ef->fd, ehdr->e_shoff, chunk);
    if (shdr == NULL) {
	printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
	    "_loadimage: failed to read section headers");
	goto nosyms;
    }
    file_addmetadata(fp, MODINFOMD_SHDR, chunk, shdr);

    symtabindex = -1;
    symstrindex = -1;
    for (i = 0; i < ehdr->e_shnum; i++) {
	if (shdr[i].sh_type != SHT_SYMTAB)
	    continue;
	for (j = 0; j < ehdr->e_phnum; j++) {
	    if (phdr[j].p_type != PT_LOAD)
		continue;
	    if (shdr[i].sh_offset >= phdr[j].p_offset &&
		(shdr[i].sh_offset + shdr[i].sh_size <=
		 phdr[j].p_offset + phdr[j].p_filesz)) {
		shdr[i].sh_offset = 0;
		shdr[i].sh_size = 0;
		break;
	    }
	}
	if (shdr[i].sh_offset == 0 || shdr[i].sh_size == 0)
	    continue;		/* alread loaded in a PT_LOAD above */
	/* Save it for loading below */
	symtabindex = i;
	symstrindex = shdr[i].sh_link;
    }
    if (symtabindex < 0 || symstrindex < 0)
	goto nosyms;

    /* Ok, committed to a load. */
#ifndef ELF_VERBOSE
    printf("syms=[");
#endif
    ssym = lastaddr;
    for (i = symtabindex; i >= 0; i = symstrindex) {
#ifdef ELF_VERBOSE
	char	*secname;

	switch(shdr[i].sh_type) {
	    case SHT_SYMTAB:		/* Symbol table */
		secname = "symtab";
		break;
	    case SHT_STRTAB:		/* String table */
		secname = "strtab";
		break;
	    default:
		secname = "WHOA!!";
		break;
	}
#endif

	size = shdr[i].sh_size;
	archsw.arch_copyin(&size, lastaddr, sizeof(size));
	lastaddr += sizeof(size);

#ifdef ELF_VERBOSE
	printf("\n%s: 0x%jx@0x%jx -> 0x%jx-0x%jx", secname,
	    (uintmax_t)shdr[i].sh_size, (uintmax_t)shdr[i].sh_offset,
	    (uintmax_t)lastaddr, (uintmax_t)(lastaddr + shdr[i].sh_size));
#else
	if (i == symstrindex)
	    printf("+");
	printf("0x%lx+0x%lx", (long)sizeof(size), (long)size);
#endif

	if (lseek(ef->fd, (off_t)shdr[i].sh_offset, SEEK_SET) == -1) {
	    printf("\nelf" __XSTRING(__ELF_WORD_SIZE) "_loadimage: could not seek for symbols - skipped!");
	    lastaddr = ssym;
	    ssym = 0;
	    goto nosyms;
	}
	result = archsw.arch_readin(ef->fd, lastaddr, shdr[i].sh_size);
	if (result < 0 || (size_t)result != shdr[i].sh_size) {
	    printf("\nelf" __XSTRING(__ELF_WORD_SIZE) "_loadimage: could not read symbols - skipped! (%ju != %ju)", (uintmax_t)result,
		(uintmax_t)shdr[i].sh_size);
	    lastaddr = ssym;
	    ssym = 0;
	    goto nosyms;
	}
	/* Reset offsets relative to ssym */
	lastaddr += shdr[i].sh_size;
	lastaddr = roundup(lastaddr, sizeof(size));
	if (i == symtabindex)
	    symtabindex = -1;
	else if (i == symstrindex)
	    symstrindex = -1;
    }
    esym = lastaddr;
#ifndef ELF_VERBOSE
    printf("]");
#endif

    file_addmetadata(fp, MODINFOMD_SSYM, sizeof(ssym), &ssym);
    file_addmetadata(fp, MODINFOMD_ESYM, sizeof(esym), &esym);

nosyms:
    printf("\n");

    ret = lastaddr - firstaddr;
    fp->f_addr = firstaddr;

    php = NULL;
    for (i = 0; i < ehdr->e_phnum; i++) {
	if (phdr[i].p_type == PT_DYNAMIC) {
	    php = phdr + i;
	    adp = php->p_vaddr;
	    file_addmetadata(fp, MODINFOMD_DYNAMIC, sizeof(adp), &adp);
	    break;
	}
    }

    if (php == NULL)	/* this is bad, we cannot get to symbols or _DYNAMIC */
	goto out;

    ndp = php->p_filesz / sizeof(Elf_Dyn);
    if (ndp == 0)
	goto out;
    dp = malloc(php->p_filesz);
    if (dp == NULL)
	goto out;
    archsw.arch_copyout(php->p_vaddr + off, dp, php->p_filesz);

    ef->strsz = 0;
    for (i = 0; i < ndp; i++) {
	if (dp[i].d_tag == 0)
	    break;
	switch (dp[i].d_tag) {
	case DT_HASH:
	    ef->hashtab = (Elf_Hashelt*)(uintptr_t)(dp[i].d_un.d_ptr + off);
	    break;
	case DT_STRTAB:
	    ef->strtab = (char *)(uintptr_t)(dp[i].d_un.d_ptr + off);
	    break;
	case DT_STRSZ:
	    ef->strsz = dp[i].d_un.d_val;
	    break;
	case DT_SYMTAB:
	    ef->symtab = (Elf_Sym*)(uintptr_t)(dp[i].d_un.d_ptr + off);
	    break;
	case DT_REL:
	    ef->rel = (Elf_Rel *)(uintptr_t)(dp[i].d_un.d_ptr + off);
	    break;
	case DT_RELSZ:
	    ef->relsz = dp[i].d_un.d_val;
	    break;
	case DT_RELA:
	    ef->rela = (Elf_Rela *)(uintptr_t)(dp[i].d_un.d_ptr + off);
	    break;
	case DT_RELASZ:
	    ef->relasz = dp[i].d_un.d_val;
	    break;
	default:
	    break;
	}
    }
    if (ef->hashtab == NULL || ef->symtab == NULL ||
	ef->strtab == NULL || ef->strsz == 0)
	goto out;
    COPYOUT(ef->hashtab, &ef->nbuckets, sizeof(ef->nbuckets));
    COPYOUT(ef->hashtab + 1, &ef->nchains, sizeof(ef->nchains));
    ef->buckets = ef->hashtab + 2;
    ef->chains = ef->buckets + ef->nbuckets;
    if (__elfN(parse_modmetadata)(fp, ef) == 0)
	goto out;

    if (ef->kernel)			/* kernel must not depend on anything */
	goto out;

out:
    if (dp)
	free(dp);
    if (shdr)
	free(shdr);
    return ret;
}
Exemplo n.º 10
0
static int
bi_load_efi_data(struct preloaded_file *kfp)
{
	EFI_MEMORY_DESCRIPTOR *mm;
	EFI_PHYSICAL_ADDRESS addr;
	EFI_STATUS status;
	size_t efisz;
	UINTN mmsz, pages, sz;
	UINT32 mmver;
	struct efi_map_header *efihdr;
	struct efi_fb efifb;

	if (efi_find_framebuffer(&efifb) == 0) {
		printf("EFI framebuffer information:\n");
		printf("addr, size     0x%lx, 0x%lx\n", efifb.fb_addr,
		    efifb.fb_size);
		printf("dimensions     %d x %d\n", efifb.fb_width,
		    efifb.fb_height);
		printf("stride         %d\n", efifb.fb_stride);
		printf("masks          0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
		    efifb.fb_mask_red, efifb.fb_mask_green, efifb.fb_mask_blue,
		    efifb.fb_mask_reserved);

		file_addmetadata(kfp, MODINFOMD_EFI_FB, sizeof(efifb), &efifb);
	}

	efisz = (sizeof(struct efi_map_header) + 0xf) & ~0xf;

	/*
	 * Allocate enough pages to hold the bootinfo block and the memory
	 * map EFI will return to us. The memory map has an unknown size,
	 * so we have to determine that first. Note that the AllocatePages
	 * call can itself modify the memory map, so we have to take that
	 * into account as well. The changes to the memory map are caused
	 * by splitting a range of free memory into two (AFAICT), so that
	 * one is marked as being loader data.
	 */
	sz = 0;
	BS->GetMemoryMap(&sz, NULL, &x86_efi_mapkey, &mmsz, &mmver);
	sz += mmsz;
	sz = (sz + 0xf) & ~0xf;
	pages = EFI_SIZE_TO_PAGES(sz + efisz);
	status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, pages,
	    &addr);
	if (EFI_ERROR(status)) {
		printf("%s: AllocatePages() returned 0x%lx\n", __func__,
		    (long)status);
		return (ENOMEM);
	}

	/*
	 * Read the memory map and stash it after bootinfo. Align the
	 * memory map on a 16-byte boundary (the bootinfo block is page
	 * aligned).
	 */
	efihdr = (struct efi_map_header *)addr;
	mm = (void *)((uint8_t *)efihdr + efisz);
	sz = (EFI_PAGE_SIZE * pages) - efisz;
	status = BS->GetMemoryMap(&sz, mm, &x86_efi_mapkey, &mmsz, &mmver);
	if (EFI_ERROR(status)) {
		printf("%s: GetMemoryMap() returned 0x%lx\n", __func__,
		    (long)status);
		return (EINVAL);
	}

	efihdr->memory_size = sz;
	efihdr->descriptor_size = mmsz;
	efihdr->descriptor_version = mmver;

	file_addmetadata(kfp, MODINFOMD_EFI_MAP, efisz + sz, efihdr);

	return (0);
}
Exemplo n.º 11
0
int
__elfN(parse_modmetadata)(struct preloaded_file *fp, elf_file_t ef,
    Elf_Addr p_start, Elf_Addr p_end)
{
    struct mod_metadata md;
#if (defined(__i386__) || defined(__powerpc__)) && __ELF_WORD_SIZE == 64
    struct mod_metadata64 md64;
#elif defined(__amd64__) && __ELF_WORD_SIZE == 32
    struct mod_metadata32 md32;
#endif
    struct mod_depend *mdepend;
    struct mod_version mver;
    char *s;
    int error, modcnt, minfolen;
    Elf_Addr v, p;

    modcnt = 0;
    p = p_start;
    while (p < p_end) {
	COPYOUT(p, &v, sizeof(v));
	error = __elfN(reloc_ptr)(fp, ef, p, &v, sizeof(v));
	if (error == EOPNOTSUPP)
	    v += ef->off;
	else if (error != 0)
	    return (error);
#if (defined(__i386__) || defined(__powerpc__)) && __ELF_WORD_SIZE == 64
	COPYOUT(v, &md64, sizeof(md64));
	error = __elfN(reloc_ptr)(fp, ef, v, &md64, sizeof(md64));
	if (error == EOPNOTSUPP) {
	    md64.md_cval += ef->off;
	    md64.md_data += ef->off;
	} else if (error != 0)
	    return (error);
	md.md_version = md64.md_version;
	md.md_type = md64.md_type;
	md.md_cval = (const char *)(uintptr_t)md64.md_cval;
	md.md_data = (void *)(uintptr_t)md64.md_data;
#elif defined(__amd64__) && __ELF_WORD_SIZE == 32
	COPYOUT(v, &md32, sizeof(md32));
	error = __elfN(reloc_ptr)(fp, ef, v, &md32, sizeof(md32));
	if (error == EOPNOTSUPP) {
	    md32.md_cval += ef->off;
	    md32.md_data += ef->off;
	} else if (error != 0)
	    return (error);
	md.md_version = md32.md_version;
	md.md_type = md32.md_type;
	md.md_cval = (const char *)(uintptr_t)md32.md_cval;
	md.md_data = (void *)(uintptr_t)md32.md_data;
#else
	COPYOUT(v, &md, sizeof(md));
	error = __elfN(reloc_ptr)(fp, ef, v, &md, sizeof(md));
	if (error == EOPNOTSUPP) {
	    md.md_cval += ef->off;
	    md.md_data = (void *)((uintptr_t)md.md_data + (uintptr_t)ef->off);
	} else if (error != 0)
	    return (error);
#endif
	p += sizeof(Elf_Addr);
	switch(md.md_type) {
	  case MDT_DEPEND:
	    if (ef->kernel)		/* kernel must not depend on anything */
	      break;
	    s = strdupout((vm_offset_t)md.md_cval);
	    minfolen = sizeof(*mdepend) + strlen(s) + 1;
	    mdepend = malloc(minfolen);
	    if (mdepend == NULL)
		return ENOMEM;
	    COPYOUT((vm_offset_t)md.md_data, mdepend, sizeof(*mdepend));
	    strcpy((char*)(mdepend + 1), s);
	    free(s);
	    file_addmetadata(fp, MODINFOMD_DEPLIST, minfolen, mdepend);
	    free(mdepend);
	    break;
	  case MDT_VERSION:
	    s = strdupout((vm_offset_t)md.md_cval);
	    COPYOUT((vm_offset_t)md.md_data, &mver, sizeof(mver));
	    file_addmodule(fp, s, mver.mv_version, NULL);
	    free(s);
	    modcnt++;
	    break;
	}
    }
    if (modcnt == 0) {
	s = fake_modname(fp->f_name);
	file_addmodule(fp, s, 1, NULL);
	free(s);
    }
    return 0;
}
Exemplo n.º 12
0
/*
 * With the file (fd) open on the image, and (ehdr) containing
 * the Elf header, load the image at (off)
 */
static int
__elfN(loadimage)(struct preloaded_file *fp, elf_file_t ef, u_int64_t off)
{
    int 	i;
    u_int	j;
    Elf_Ehdr	*ehdr;
    Elf_Phdr	*phdr, *php;
    Elf_Shdr	*shdr;
    char	*shstr;
    int		ret;
    vm_offset_t firstaddr;
    vm_offset_t lastaddr;
    size_t	chunk;
    ssize_t	result;
    Elf_Addr	ssym, esym;
    Elf_Dyn	*dp;
    Elf_Addr	adp;
    Elf_Addr	ctors;
    int		ndp;
    int		symstrindex;
    int		symtabindex;
    Elf_Size	size;
    u_int	fpcopy;
    Elf_Sym	sym;
    Elf_Addr	p_start, p_end;

    dp = NULL;
    shdr = NULL;
    ret = 0;
    firstaddr = lastaddr = 0;
    ehdr = ef->ehdr;
    if (ehdr->e_type == ET_EXEC) {
#if defined(__i386__) || defined(__amd64__)
#if __ELF_WORD_SIZE == 64
	off = - (off & 0xffffffffff000000ull);/* x86_64 relocates after locore */
#else
	off = - (off & 0xff000000u);	/* i386 relocates after locore */
#endif
#elif defined(__powerpc__)
	/*
	 * On the purely virtual memory machines like e500, the kernel is
	 * linked against its final VA range, which is most often not
	 * available at the loader stage, but only after kernel initializes
	 * and completes its VM settings. In such cases we cannot use p_vaddr
	 * field directly to load ELF segments, but put them at some
	 * 'load-time' locations.
	 */
	if (off & 0xf0000000u) {
	    off = -(off & 0xf0000000u);
	    /*
	     * XXX the physical load address should not be hardcoded. Note
	     * that the Book-E kernel assumes that it's loaded at a 16MB
	     * boundary for now...
	     */
	    off += 0x01000000;
	    ehdr->e_entry += off;
#ifdef ELF_VERBOSE
	    printf("Converted entry 0x%08x\n", ehdr->e_entry);
#endif
	} else
	    off = 0;
#elif defined(__arm__) && !defined(EFI)
	/*
	 * The elf headers in arm kernels specify virtual addresses in all
	 * header fields, even the ones that should be physical addresses.
	 * We assume the entry point is in the first page, and masking the page
	 * offset will leave us with the virtual address the kernel was linked
	 * at.  We subtract that from the load offset, making 'off' into the
	 * value which, when added to a virtual address in an elf header,
	 * translates it to a physical address.  We do the va->pa conversion on
	 * the entry point address in the header now, so that later we can
	 * launch the kernel by just jumping to that address.
	 *
	 * When booting from UEFI the copyin and copyout functions handle
	 * adjusting the location relative to the first virtual address.
	 * Because of this there is no need to adjust the offset or entry
	 * point address as these will both be handled by the efi code.
	 */
	off -= ehdr->e_entry & ~PAGE_MASK;
	ehdr->e_entry += off;
#ifdef ELF_VERBOSE
	printf("ehdr->e_entry 0x%08x, va<->pa off %llx\n", ehdr->e_entry, off);
#endif
#else
	off = 0;		/* other archs use direct mapped kernels */
#endif
    }
    ef->off = off;

    if (ehdr->e_ident[EI_OSABI] == ELFOSABI_SOLARIS) {
	/* use entry address from header */
	fp->f_addr = ehdr->e_entry;
    }

    if (ef->kernel)
	__elfN(relocation_offset) = off;

    if ((ehdr->e_phoff + ehdr->e_phnum * sizeof(*phdr)) > ef->firstlen) {
	printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadimage: program header not within first page\n");
	goto out;
    }
    phdr = (Elf_Phdr *)(ef->firstpage + ehdr->e_phoff);

    for (i = 0; i < ehdr->e_phnum; i++) {
	/* We want to load PT_LOAD segments only.. */
	if (phdr[i].p_type != PT_LOAD)
	    continue;

#ifdef ELF_VERBOSE
	if (ehdr->e_ident[EI_OSABI] == ELFOSABI_SOLARIS) {
	    printf("Segment: 0x%lx@0x%lx -> 0x%lx-0x%lx",
		(long)phdr[i].p_filesz, (long)phdr[i].p_offset,
		(long)(phdr[i].p_paddr + off),
		(long)(phdr[i].p_paddr + off + phdr[i].p_memsz - 1));
	} else {
	    printf("Segment: 0x%lx@0x%lx -> 0x%lx-0x%lx",
		(long)phdr[i].p_filesz, (long)phdr[i].p_offset,
		(long)(phdr[i].p_vaddr + off),
		(long)(phdr[i].p_vaddr + off + phdr[i].p_memsz - 1));
	}
#else
	if ((phdr[i].p_flags & PF_W) == 0) {
	    printf("text=0x%lx ", (long)phdr[i].p_filesz);
	} else {
	    printf("data=0x%lx", (long)phdr[i].p_filesz);
	    if (phdr[i].p_filesz < phdr[i].p_memsz)
		printf("+0x%lx", (long)(phdr[i].p_memsz -phdr[i].p_filesz));
	    printf(" ");
	}
#endif
	fpcopy = 0;
	if (ef->firstlen > phdr[i].p_offset) {
	    fpcopy = ef->firstlen - phdr[i].p_offset;
	    if (ehdr->e_ident[EI_OSABI] == ELFOSABI_SOLARIS) {
		archsw.arch_copyin(ef->firstpage + phdr[i].p_offset,
		    phdr[i].p_paddr + off, fpcopy);
	    } else {
		archsw.arch_copyin(ef->firstpage + phdr[i].p_offset,
		    phdr[i].p_vaddr + off, fpcopy);
	    }
	}
	if (phdr[i].p_filesz > fpcopy) {
	    if (ehdr->e_ident[EI_OSABI] == ELFOSABI_SOLARIS) {
		if (kern_pread(ef->fd, phdr[i].p_paddr + off + fpcopy,
		    phdr[i].p_filesz - fpcopy,
		    phdr[i].p_offset + fpcopy) != 0) {
			printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
			    "_loadimage: read failed\n");
			goto out;
		}
	    } else {
		if (kern_pread(ef->fd, phdr[i].p_vaddr + off + fpcopy,
		    phdr[i].p_filesz - fpcopy,
		    phdr[i].p_offset + fpcopy) != 0) {
			printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
			    "_loadimage: read failed\n");
			goto out;
		}
	    }
	}
	/* clear space from oversized segments; eg: bss */
	if (phdr[i].p_filesz < phdr[i].p_memsz) {
#ifdef ELF_VERBOSE
	    if (ehdr->e_ident[EI_OSABI] == ELFOSABI_SOLARIS) {
		printf(" (bss: 0x%lx-0x%lx)",
		    (long)(phdr[i].p_paddr + off + phdr[i].p_filesz),
		    (long)(phdr[i].p_paddr + off + phdr[i].p_memsz - 1));
	    } else {
		printf(" (bss: 0x%lx-0x%lx)",
		    (long)(phdr[i].p_vaddr + off + phdr[i].p_filesz),
		    (long)(phdr[i].p_vaddr + off + phdr[i].p_memsz - 1));
	    }
#endif

	    if (ehdr->e_ident[EI_OSABI] == ELFOSABI_SOLARIS) {
		kern_bzero(phdr[i].p_paddr + off + phdr[i].p_filesz,
		    phdr[i].p_memsz - phdr[i].p_filesz);
	    } else {
		kern_bzero(phdr[i].p_vaddr + off + phdr[i].p_filesz,
		    phdr[i].p_memsz - phdr[i].p_filesz);
	    }
	}
#ifdef ELF_VERBOSE
	printf("\n");
#endif

	if (archsw.arch_loadseg != NULL)
	    archsw.arch_loadseg(ehdr, phdr + i, off);

	if (ehdr->e_ident[EI_OSABI] == ELFOSABI_SOLARIS) {
		if (firstaddr == 0 || firstaddr > (phdr[i].p_paddr + off))
		    firstaddr = phdr[i].p_paddr + off;
		if (lastaddr == 0 ||
		    lastaddr < (phdr[i].p_paddr + off + phdr[i].p_memsz))
		    lastaddr = phdr[i].p_paddr + off + phdr[i].p_memsz;
	} else {
		if (firstaddr == 0 || firstaddr > (phdr[i].p_vaddr + off))
		    firstaddr = phdr[i].p_vaddr + off;
		if (lastaddr == 0 ||
		    lastaddr < (phdr[i].p_vaddr + off + phdr[i].p_memsz))
		    lastaddr = phdr[i].p_vaddr + off + phdr[i].p_memsz;
	}
    }
    lastaddr = roundup(lastaddr, sizeof(long));

    /*
     * Get the section headers.  We need this for finding the .ctors
     * section as well as for loading any symbols.  Both may be hard
     * to do if reading from a .gz file as it involves seeking.  I
     * think the rule is going to have to be that you must strip a
     * file to remove symbols before gzipping it.
     */
    chunk = ehdr->e_shnum * ehdr->e_shentsize;
    if (chunk == 0 || ehdr->e_shoff == 0)
	goto nosyms;
    shdr = alloc_pread(ef->fd, ehdr->e_shoff, chunk);
    if (shdr == NULL) {
	printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
	    "_loadimage: failed to read section headers");
	goto nosyms;
    }
    file_addmetadata(fp, MODINFOMD_SHDR, chunk, shdr);

    /*
     * Read the section string table and look for the .ctors section.
     * We need to tell the kernel where it is so that it can call the
     * ctors.
     */
    chunk = shdr[ehdr->e_shstrndx].sh_size;
    if (chunk) {
	shstr = alloc_pread(ef->fd, shdr[ehdr->e_shstrndx].sh_offset, chunk);
	if (shstr) {
	    for (i = 0; i < ehdr->e_shnum; i++) {
		if (strcmp(shstr + shdr[i].sh_name, ".ctors") != 0)
		    continue;
		ctors = shdr[i].sh_addr;
		file_addmetadata(fp, MODINFOMD_CTORS_ADDR, sizeof(ctors),
		    &ctors);
		size = shdr[i].sh_size;
		file_addmetadata(fp, MODINFOMD_CTORS_SIZE, sizeof(size),
		    &size);
		break;
	    }
	    free(shstr);
	}
    }

    /*
     * Now load any symbols.
     */
    symtabindex = -1;
    symstrindex = -1;
    for (i = 0; i < ehdr->e_shnum; i++) {
	if (shdr[i].sh_type != SHT_SYMTAB)
	    continue;
	for (j = 0; j < ehdr->e_phnum; j++) {
	    if (phdr[j].p_type != PT_LOAD)
		continue;
	    if (shdr[i].sh_offset >= phdr[j].p_offset &&
		(shdr[i].sh_offset + shdr[i].sh_size <=
		 phdr[j].p_offset + phdr[j].p_filesz)) {
		shdr[i].sh_offset = 0;
		shdr[i].sh_size = 0;
		break;
	    }
	}
	if (shdr[i].sh_offset == 0 || shdr[i].sh_size == 0)
	    continue;		/* alread loaded in a PT_LOAD above */
	/* Save it for loading below */
	symtabindex = i;
	symstrindex = shdr[i].sh_link;
    }
    if (symtabindex < 0 || symstrindex < 0)
	goto nosyms;

    /* Ok, committed to a load. */
#ifndef ELF_VERBOSE
    printf("syms=[");
#endif
    ssym = lastaddr;
    for (i = symtabindex; i >= 0; i = symstrindex) {
#ifdef ELF_VERBOSE
	char	*secname;

	switch(shdr[i].sh_type) {
	    case SHT_SYMTAB:		/* Symbol table */
		secname = "symtab";
		break;
	    case SHT_STRTAB:		/* String table */
		secname = "strtab";
		break;
	    default:
		secname = "WHOA!!";
		break;
	}
#endif

	size = shdr[i].sh_size;
	archsw.arch_copyin(&size, lastaddr, sizeof(size));
	lastaddr += sizeof(size);

#ifdef ELF_VERBOSE
	printf("\n%s: 0x%jx@0x%jx -> 0x%jx-0x%jx", secname,
	    (uintmax_t)shdr[i].sh_size, (uintmax_t)shdr[i].sh_offset,
	    (uintmax_t)lastaddr, (uintmax_t)(lastaddr + shdr[i].sh_size));
#else
	if (i == symstrindex)
	    printf("+");
	printf("0x%lx+0x%lx", (long)sizeof(size), (long)size);
#endif

	if (lseek(ef->fd, (off_t)shdr[i].sh_offset, SEEK_SET) == -1) {
	    printf("\nelf" __XSTRING(__ELF_WORD_SIZE) "_loadimage: could not seek for symbols - skipped!");
	    lastaddr = ssym;
	    ssym = 0;
	    goto nosyms;
	}
	result = archsw.arch_readin(ef->fd, lastaddr, shdr[i].sh_size);
	if (result < 0 || (size_t)result != shdr[i].sh_size) {
	    printf("\nelf" __XSTRING(__ELF_WORD_SIZE) "_loadimage: could not read symbols - skipped! (%ju != %ju)", (uintmax_t)result,
		(uintmax_t)shdr[i].sh_size);
	    lastaddr = ssym;
	    ssym = 0;
	    goto nosyms;
	}
	/* Reset offsets relative to ssym */
	lastaddr += shdr[i].sh_size;
	lastaddr = roundup(lastaddr, sizeof(size));
	if (i == symtabindex)
	    symtabindex = -1;
	else if (i == symstrindex)
	    symstrindex = -1;
    }
    esym = lastaddr;
#ifndef ELF_VERBOSE
    printf("]");
#endif

    file_addmetadata(fp, MODINFOMD_SSYM, sizeof(ssym), &ssym);
    file_addmetadata(fp, MODINFOMD_ESYM, sizeof(esym), &esym);

nosyms:
    printf("\n");

    ret = lastaddr - firstaddr;
    if (ehdr->e_ident[EI_OSABI] != ELFOSABI_SOLARIS)
	fp->f_addr = firstaddr;

    php = NULL;
    for (i = 0; i < ehdr->e_phnum; i++) {
	if (phdr[i].p_type == PT_DYNAMIC) {
	    php = phdr + i;
	    adp = php->p_vaddr;
	    file_addmetadata(fp, MODINFOMD_DYNAMIC, sizeof(adp), &adp);
	    break;
	}
    }

    if (php == NULL)	/* this is bad, we cannot get to symbols or _DYNAMIC */
	goto out;

    ndp = php->p_filesz / sizeof(Elf_Dyn);
    if (ndp == 0)
	goto out;
    dp = malloc(php->p_filesz);
    if (dp == NULL)
	goto out;
    if (ehdr->e_ident[EI_OSABI] == ELFOSABI_SOLARIS)
	archsw.arch_copyout(php->p_paddr + off, dp, php->p_filesz);
    else
	archsw.arch_copyout(php->p_vaddr + off, dp, php->p_filesz);

    ef->strsz = 0;
    for (i = 0; i < ndp; i++) {
	if (dp[i].d_tag == 0)
	    break;
	switch (dp[i].d_tag) {
	case DT_HASH:
	    ef->hashtab = (Elf_Hashelt*)(uintptr_t)(dp[i].d_un.d_ptr + off);
	    break;
	case DT_STRTAB:
	    ef->strtab = (char *)(uintptr_t)(dp[i].d_un.d_ptr + off);
	    break;
	case DT_STRSZ:
	    ef->strsz = dp[i].d_un.d_val;
	    break;
	case DT_SYMTAB:
	    ef->symtab = (Elf_Sym*)(uintptr_t)(dp[i].d_un.d_ptr + off);
	    break;
	case DT_REL:
	    ef->rel = (Elf_Rel *)(uintptr_t)(dp[i].d_un.d_ptr + off);
	    break;
	case DT_RELSZ:
	    ef->relsz = dp[i].d_un.d_val;
	    break;
	case DT_RELA:
	    ef->rela = (Elf_Rela *)(uintptr_t)(dp[i].d_un.d_ptr + off);
	    break;
	case DT_RELASZ:
	    ef->relasz = dp[i].d_un.d_val;
	    break;
	default:
	    break;
	}
    }
    if (ef->hashtab == NULL || ef->symtab == NULL ||
	ef->strtab == NULL || ef->strsz == 0)
	goto out;
    COPYOUT(ef->hashtab, &ef->nbuckets, sizeof(ef->nbuckets));
    COPYOUT(ef->hashtab + 1, &ef->nchains, sizeof(ef->nchains));
    ef->buckets = ef->hashtab + 2;
    ef->chains = ef->buckets + ef->nbuckets;

    if (__elfN(lookup_symbol)(fp, ef, "__start_set_modmetadata_set", &sym) != 0)
	return 0;
    p_start = sym.st_value + ef->off;
    if (__elfN(lookup_symbol)(fp, ef, "__stop_set_modmetadata_set", &sym) != 0)
	return ENOENT;
    p_end = sym.st_value + ef->off;

    if (__elfN(parse_modmetadata)(fp, ef, p_start, p_end) == 0)
	goto out;

    if (ef->kernel)			/* kernel must not depend on anything */
	goto out;

out:
    if (dp)
	free(dp);
    if (shdr)
	free(shdr);
    return ret;
}
Exemplo n.º 13
0
int
__elfN(loadfile_raw)(char *filename, u_int64_t dest,
    struct preloaded_file **result, int multiboot)
{
    struct preloaded_file	*fp, *kfp;
    struct elf_file		ef;
    Elf_Ehdr 			*ehdr;
    int				err;

    fp = NULL;
    bzero(&ef, sizeof(struct elf_file));
    ef.fd = -1;

    err = __elfN(load_elf_header)(filename, &ef);
    if (err != 0)
    	return (err);

    ehdr = ef.ehdr;

    /*
     * Check to see what sort of module we are.
     */
    kfp = file_findfile(NULL, __elfN(kerneltype));
#ifdef __powerpc__
    /*
     * Kernels can be ET_DYN, so just assume the first loaded object is the
     * kernel. This assumption will be checked later.
     */
    if (kfp == NULL)
        ef.kernel = 1;
#endif
    if (ef.kernel || ehdr->e_type == ET_EXEC) {
	/* Looks like a kernel */
	if (kfp != NULL) {
	    printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: kernel already loaded\n");
	    err = EPERM;
	    goto oerr;
	}
	/* 
	 * Calculate destination address based on kernel entrypoint.
	 *
	 * For ARM, the destination address is independent of any values in the
	 * elf header (an ARM kernel can be loaded at any 2MB boundary), so we
	 * leave dest set to the value calculated by archsw.arch_loadaddr() and
	 * passed in to this function.
	 */
#ifndef __arm__
        if (ehdr->e_type == ET_EXEC)
	    dest = (ehdr->e_entry & ~PAGE_MASK);
#endif
	if ((ehdr->e_entry & ~PAGE_MASK) == 0) {
	    printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: not a kernel (maybe static binary?)\n");
	    err = EPERM;
	    goto oerr;
	}
	ef.kernel = 1;

    } else if (ehdr->e_type == ET_DYN) {
	/* Looks like a kld module */
	if (multiboot != 0) {
		printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: can't load module as multiboot\n");
		err = EPERM;
		goto oerr;
	}
	if (kfp == NULL) {
	    printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: can't load module before kernel\n");
	    err = EPERM;
	    goto oerr;
	}
	if (strcmp(__elfN(kerneltype), kfp->f_type)) {
	    printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: can't load module with kernel type '%s'\n", kfp->f_type);
	    err = EPERM;
	    goto oerr;
	}
	/* Looks OK, got ahead */
	ef.kernel = 0;

    } else {
	err = EFTYPE;
	goto oerr;
    }

    if (archsw.arch_loadaddr != NULL)
	dest = archsw.arch_loadaddr(LOAD_ELF, ehdr, dest);
    else
	dest = roundup(dest, PAGE_SIZE);

    /* 
     * Ok, we think we should handle this.
     */
    fp = file_alloc();
    if (fp == NULL) {
	    printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: cannot allocate module info\n");
	    err = EPERM;
	    goto out;
    }
    if (ef.kernel == 1 && multiboot == 0)
	setenv("kernelname", filename, 1);
    fp->f_name = strdup(filename);
    if (multiboot == 0)
    	fp->f_type = strdup(ef.kernel ?
    	    __elfN(kerneltype) : __elfN(moduletype));
    else
    	fp->f_type = strdup("elf multiboot kernel");

#ifdef ELF_VERBOSE
    if (ef.kernel)
	printf("%s entry at 0x%jx\n", filename, (uintmax_t)ehdr->e_entry);
#else
    printf("%s ", filename);
#endif

    fp->f_size = __elfN(loadimage)(fp, &ef, dest);
    if (fp->f_size == 0 || fp->f_addr == 0)
	goto ioerr;

    /* save exec header as metadata */
    file_addmetadata(fp, MODINFOMD_ELFHDR, sizeof(*ehdr), ehdr);

    /* Load OK, return module pointer */
    *result = (struct preloaded_file *)fp;
    err = 0;
    goto out;
    
 ioerr:
    err = EIO;
 oerr:
    file_discard(fp);
 out:
    if (ef.firstpage)
	free(ef.firstpage);
    if (ef.fd != -1)
    	close(ef.fd);
    return(err);
}
Exemplo n.º 14
0
/*
 * Attempt to load the file (file) as an ELF module.  It will be stored at
 * (dest), and a pointer to a module structure describing the loaded object
 * will be saved in (result).
 */
int
__elfN(loadfile)(char *filename, u_int64_t dest, struct preloaded_file **result)
{
    struct preloaded_file	*fp, *kfp;
    struct elf_file		ef;
    Elf_Ehdr 			*ehdr;
    int				err;
    ssize_t			bytes_read;

    fp = NULL;
    bzero(&ef, sizeof(struct elf_file));

    /*
     * Open the image, read and validate the ELF header 
     */
    if (filename == NULL)	/* can't handle nameless */
	return(EFTYPE);
    if ((ef.fd = open(filename, O_RDONLY)) == -1)
	return(errno);
    ef.firstpage = malloc(PAGE_SIZE);
    if (ef.firstpage == NULL) {
	close(ef.fd);
	return(ENOMEM);
    }
    bytes_read = read(ef.fd, ef.firstpage, PAGE_SIZE);
    ef.firstlen = (size_t)bytes_read;
    if (bytes_read < 0 || ef.firstlen <= sizeof(Elf_Ehdr)) {
	err = EFTYPE;		/* could be EIO, but may be small file */
	goto oerr;
    }
    ehdr = ef.ehdr = (Elf_Ehdr *)ef.firstpage;

    /* Is it ELF? */
    if (!IS_ELF(*ehdr)) {
	err = EFTYPE;
	goto oerr;
    }
    if (ehdr->e_ident[EI_CLASS] != ELF_TARG_CLASS ||	/* Layout ? */
	ehdr->e_ident[EI_DATA] != ELF_TARG_DATA ||
	ehdr->e_ident[EI_VERSION] != EV_CURRENT ||	/* Version ? */
	ehdr->e_version != EV_CURRENT ||
	ehdr->e_machine != ELF_TARG_MACH) {		/* Machine ? */
	err = EFTYPE;
	goto oerr;
    }


    /*
     * Check to see what sort of module we are.
     */
    kfp = file_findfile(NULL, NULL);
    if (ehdr->e_type == ET_DYN) {
	/* Looks like a kld module */
	if (kfp == NULL) {
	    printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: can't load module before kernel\n");
	    err = EPERM;
	    goto oerr;
	}
	if (strcmp(__elfN(kerneltype), kfp->f_type)) {
	    printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: can't load module with kernel type '%s'\n", kfp->f_type);
	    err = EPERM;
	    goto oerr;
	}
	/* Looks OK, got ahead */
	ef.kernel = 0;

    } else if (ehdr->e_type == ET_EXEC) {
	/* Looks like a kernel */
	if (kfp != NULL) {
	    printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: kernel already loaded\n");
	    err = EPERM;
	    goto oerr;
	}
	/* 
	 * Calculate destination address based on kernel entrypoint 	
	 */
	dest = (ehdr->e_entry & ~PAGE_MASK);
	if (dest == 0) {
	    printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: not a kernel (maybe static binary?)\n");
	    err = EPERM;
	    goto oerr;
	}
	ef.kernel = 1;

    } else {
	err = EFTYPE;
	goto oerr;
    }

    if (archsw.arch_loadaddr != NULL)
	dest = archsw.arch_loadaddr(LOAD_ELF, ehdr, dest);
    else
	dest = roundup(dest, PAGE_SIZE);

    /* 
     * Ok, we think we should handle this.
     */
    fp = file_alloc();
    if (fp == NULL) {
	    printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: cannot allocate module info\n");
	    err = EPERM;
	    goto out;
    }
    if (ef.kernel)
	setenv("kernelname", filename, 1);
    fp->f_name = strdup(filename);
    fp->f_type = strdup(ef.kernel ? __elfN(kerneltype) : __elfN(moduletype));

#ifdef ELF_VERBOSE
    if (ef.kernel)
	printf("%s entry at 0x%jx\n", filename, (uintmax_t)ehdr->e_entry);
#else
    printf("%s ", filename);
#endif

    fp->f_size = __elfN(loadimage)(fp, &ef, dest);
    if (fp->f_size == 0 || fp->f_addr == 0)
	goto ioerr;

    /* save exec header as metadata */
    file_addmetadata(fp, MODINFOMD_ELFHDR, sizeof(*ehdr), ehdr);

    /* Load OK, return module pointer */
    *result = (struct preloaded_file *)fp;
    err = 0;
    goto out;
    
 ioerr:
    err = EIO;
 oerr:
    file_discard(fp);
 out:
    if (ef.firstpage)
	free(ef.firstpage);
    close(ef.fd);
    return(err);
}
Exemplo n.º 15
0
/*
 * Load the information expected by an i386 kernel.
 *
 * - The 'boothowto' argument is constructed
 * - The 'bootdev' argument is constructed
 * - The 'bootinfo' struct is constructed, and copied into the kernel space.
 * - The kernel environment is copied into kernel space.
 * - Module metadata are formatted and placed in kernel space.
 */
int
bi_load32(char *args, int *howtop, int *bootdevp, vm_offset_t *bip, vm_offset_t *modulep, vm_offset_t *kernendp)
{
    struct preloaded_file	*xp, *kfp;
    struct i386_devdesc		*rootdev;
    struct file_metadata	*md;
    vm_offset_t			addr;
    vm_offset_t			kernend;
    vm_offset_t			envp;
    vm_offset_t			size;
    vm_offset_t			ssym, esym;
    char			*rootdevname;
    int				bootdevnr, i, howto;
    char			*kernelname;
    const char			*kernelpath;

    howto = bi_getboothowto(args);

    /* 
     * Allow the environment variable 'rootdev' to override the supplied device 
     * This should perhaps go to MI code and/or have $rootdev tested/set by
     * MI code before launching the kernel.
     */
    rootdevname = getenv("rootdev");
    i386_getdev((void **)(&rootdev), rootdevname, NULL);
    if (rootdev == NULL) {		/* bad $rootdev/$currdev */
	printf("can't determine root device\n");
	return(EINVAL);
    }

    /* Try reading the /etc/fstab file to select the root device */
    getrootmount(i386_fmtdev(rootdev));

    /* Do legacy rootdev guessing */

    /* XXX - use a default bootdev of 0.  Is this ok??? */
    bootdevnr = 0;

    switch(rootdev->d_type) {
    case DEVT_CD:
	    /* Pass in BIOS device number. */
	    bi.bi_bios_dev = bc_unit2bios(rootdev->d_kind.bioscd.unit);
	    bootdevnr = bc_getdev(rootdev);
	    break;

    case DEVT_DISK:
	/* pass in the BIOS device number of the current disk */
	bi.bi_bios_dev = bd_unit2bios(rootdev->d_kind.biosdisk.unit);
	bootdevnr = bd_getdev(rootdev);
	break;

    case DEVT_NET:
	    break;
	    
    default:
	printf("WARNING - don't know how to boot from device type %d\n", rootdev->d_type);
    }
    if (bootdevnr == -1) {
	printf("root device %s invalid\n", i386_fmtdev(rootdev));
	return (EINVAL);
    }
    free(rootdev);

    /* find the last module in the chain */
    addr = 0;
    for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) {
	if (addr < (xp->f_addr + xp->f_size))
	    addr = xp->f_addr + xp->f_size;
    }
    /* pad to a page boundary */
    addr = roundup(addr, PAGE_SIZE);

    /* copy our environment */
    envp = addr;
    addr = bi_copyenv(addr);

    /* pad to a page boundary */
    addr = roundup(addr, PAGE_SIZE);

    kfp = file_findfile(NULL, "elf kernel");
    if (kfp == NULL)
      kfp = file_findfile(NULL, "elf32 kernel");
    if (kfp == NULL)
	panic("can't find kernel file");
    kernend = 0;	/* fill it in later */
    file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto);
    file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp);
    file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend);
    bios_addsmapdata(kfp);

    /* Figure out the size and location of the metadata */
    *modulep = addr;
    size = bi_copymodules32(0);
    kernend = roundup(addr + size, PAGE_SIZE);
    *kernendp = kernend;

    /* patch MODINFOMD_KERNEND */
    md = file_findmetadata(kfp, MODINFOMD_KERNEND);
    bcopy(&kernend, md->md_data, sizeof kernend);

    /* copy module list and metadata */
    (void)bi_copymodules32(addr);

    ssym = esym = 0;
    md = file_findmetadata(kfp, MODINFOMD_SSYM);
    if (md != NULL)
	ssym = *((vm_offset_t *)&(md->md_data));
    md = file_findmetadata(kfp, MODINFOMD_ESYM);
    if (md != NULL)
	esym = *((vm_offset_t *)&(md->md_data));
    if (ssym == 0 || esym == 0)
	ssym = esym = 0;		/* sanity */

    /* legacy bootinfo structure */
    kernelname = getenv("kernelname");
    i386_getdev(NULL, kernelname, &kernelpath);
    bi.bi_version = BOOTINFO_VERSION;
    bi.bi_kernelname = 0;		/* XXX char * -> kernel name */
    bi.bi_nfs_diskless = 0;		/* struct nfs_diskless * */
    bi.bi_n_bios_used = 0;		/* XXX would have to hook biosdisk driver for these */
    for (i = 0; i < N_BIOS_GEOM; i++)
        bi.bi_bios_geom[i] = bd_getbigeom(i);
    bi.bi_size = sizeof(bi);
    bi.bi_memsizes_valid = 1;
    bi.bi_basemem = bios_basemem / 1024;
    bi.bi_extmem = bios_extmem / 1024;
    bi.bi_envp = envp;
    bi.bi_modulep = *modulep;
    bi.bi_kernend = kernend;
    bi.bi_kernelname = VTOP(kernelpath);
    bi.bi_symtab = ssym;       /* XXX this is only the primary kernel symtab */
    bi.bi_esymtab = esym;

    /* legacy boot arguments */
    *howtop = howto | RB_BOOTINFO;
    *bootdevp = bootdevnr;
    *bip = VTOP(&bi);

    return(0);
}
Exemplo n.º 16
0
/*
 * Load the information expected by a sparc64 kernel.
 *
 * - The 'boothowto' argument is constructed
 * - The 'bootdev' argument is constructed
 * - The kernel environment is copied into kernel space.
 * - Module metadata are formatted and placed in kernel space.
 */
int
md_load(char *args, vm_offset_t *modulep, vm_offset_t *dtbp)
{
    struct preloaded_file	*kfp;
    struct preloaded_file	*xp;
    struct file_metadata	*md;
    vm_offset_t			kernend;
    vm_offset_t			addr;
    vm_offset_t			envp;
    vm_offset_t			size;
    char			*rootdevname;
    int				howto;

    howto = md_getboothowto(args);
    *dtbp = 0;

    /*
     * Allow the environment variable 'rootdev' to override the supplied device
     * This should perhaps go to MI code and/or have $rootdev tested/set by
     * MI code before launching the kernel.
     */
    if ((rootdevname = getenv("rootdev")) == NULL)
        rootdevname = getenv("currdev");
    getrootmount(rootdevname);

    /* find the last module in the chain */
    addr = 0;
    for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) {
        if (addr < (xp->f_addr + xp->f_size))
            addr = xp->f_addr + xp->f_size;
    }
    /* pad to a page boundary */
    addr = roundup(addr, PAGE_SIZE);

    /* copy our environment */
    envp = addr;
    addr = md_copyenv(addr);

    /* pad to a page boundary */
    addr = roundup(addr, PAGE_SIZE);

    kernend = 0;
    kfp = file_findfile(NULL, "elf64 kernel");
    if (kfp == NULL)
        kfp = file_findfile(NULL, "elf kernel");
    if (kfp == NULL)
        panic("can't find kernel file");
    file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto);
    file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp);
    file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend);
    file_addmetadata(kfp, MODINFOMD_DTLB_SLOTS, sizeof dtlb_slot, &dtlb_slot);
    file_addmetadata(kfp, MODINFOMD_ITLB_SLOTS, sizeof itlb_slot, &itlb_slot);
    file_addmetadata(kfp, MODINFOMD_DTLB,
                     dtlb_slot * sizeof(*dtlb_store), dtlb_store);
    file_addmetadata(kfp, MODINFOMD_ITLB,
                     itlb_slot * sizeof(*itlb_store), itlb_store);

    *modulep = addr;
    size = md_copymodules(0);
    kernend = roundup(addr + size, PAGE_SIZE);

    md = file_findmetadata(kfp, MODINFOMD_KERNEND);
    bcopy(&kernend, md->md_data, sizeof kernend);

    (void)md_copymodules(addr);

    return(0);
}
Exemplo n.º 17
0
/*
 * Load the information expected by a kernel.
 *
 * - The 'boothowto' argument is constructed
 * - The 'bootdev' argument is constructed
 * - The kernel environment is copied into kernel space.
 * - Module metadata are formatted and placed in kernel space.
 */
int
md_load(char *args, vm_offset_t *modulep)
{
	struct preloaded_file	*kfp, *bfp;
	struct preloaded_file	*xp;
	struct file_metadata	*md;
	struct bootinfo		*bip;
	vm_offset_t		kernend;
	vm_offset_t		addr;
	vm_offset_t		envp;
	vm_offset_t		size;
	vm_offset_t		vaddr;
	vm_offset_t		dtbp;
	char			*rootdevname;
	int			howto;
	int			i;

	/*
	 * These metadata addreses must be converted for kernel after
	 * relocation.
	 */
	uint32_t		mdt[] = {
	    MODINFOMD_SSYM, MODINFOMD_ESYM, MODINFOMD_KERNEND,
	    MODINFOMD_ENVP,
#if defined(LOADER_FDT_SUPPORT)
	    MODINFOMD_DTBP
#endif
	};

	howto = md_getboothowto(args);

	/*
	 * Allow the environment variable 'rootdev' to override the supplied
	 * device. This should perhaps go to MI code and/or have $rootdev
	 * tested/set by MI code before launching the kernel.
	 */
	rootdevname = getenv("rootdev");
	if (rootdevname == NULL)
		rootdevname = getenv("currdev");
	/* Try reading the /etc/fstab file to select the root device */
	getrootmount(rootdevname);

	/* Find the last module in the chain */
	addr = 0;
	for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) {
		if (addr < (xp->f_addr + xp->f_size))
			addr = xp->f_addr + xp->f_size;
	}
	/* Pad to a page boundary */
	addr = roundup(addr, PAGE_SIZE);

	/* Copy our environment */
	envp = addr;
	addr = md_copyenv(addr);

	/* Pad to a page boundary */
	addr = roundup(addr, PAGE_SIZE);

	kernend = 0;
	kfp = file_findfile(NULL, "elf32 kernel");
	if (kfp == NULL)
		kfp = file_findfile(NULL, "elf kernel");
	if (kfp == NULL)
		panic("can't find kernel file");
	file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto);
	file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp);

#if defined(LOADER_FDT_SUPPORT)
	/* Handle device tree blob */
	dtbp = fdt_fixup();
	if (dtbp != 0)
		file_addmetadata(kfp, MODINFOMD_DTBP, sizeof dtbp, &dtbp);
	else
		pager_output("WARNING! Trying to fire up the kernel, but no "
		    "device tree blob found!\n");
#endif

	file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend);

	/* Figure out the size and location of the metadata */
	*modulep = addr;
	size = md_copymodules(0);
	kernend = roundup(addr + size, PAGE_SIZE);

	/* Provide MODINFOMD_KERNEND */
	md = file_findmetadata(kfp, MODINFOMD_KERNEND);
	bcopy(&kernend, md->md_data, sizeof kernend);

	/* Convert addresses to the final VA */
	*modulep -= __elfN(relocation_offset);

	for (i = 0; i < sizeof mdt / sizeof mdt[0]; i++) {
		md = file_findmetadata(kfp, mdt[i]);
		if (md) {
			bcopy(md->md_data, &vaddr, sizeof vaddr);
			vaddr -= __elfN(relocation_offset);
			bcopy(&vaddr, md->md_data, sizeof vaddr);
		}
	}

	/* Only now copy actual modules and metadata */
	(void)md_copymodules(addr);

	return (0);
}