summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/boot/arm/uboot/Makefile40
-rw-r--r--sys/boot/arm/uboot/ldscript.arm18
-rw-r--r--sys/boot/arm/uboot/start.S48
-rw-r--r--sys/boot/common/load_elf.c86
-rw-r--r--sys/boot/common/self_reloc.c123
-rw-r--r--sys/boot/uboot/common/main.c9
-rw-r--r--sys/boot/uboot/lib/copy.c113
-rw-r--r--sys/boot/uboot/lib/elf_freebsd.c2
-rw-r--r--sys/boot/uboot/lib/libuboot.h5
9 files changed, 347 insertions, 97 deletions
diff --git a/sys/boot/arm/uboot/Makefile b/sys/boot/arm/uboot/Makefile
index 8f718be..b4c5463 100644
--- a/sys/boot/arm/uboot/Makefile
+++ b/sys/boot/arm/uboot/Makefile
@@ -2,7 +2,8 @@
.include <bsd.own.mk>
-PROG= ubldr
+FILES= ubldr ubldr.bin
+
NEWVERSWHAT= "U-Boot loader" ${MACHINE_ARCH}
BINDIR?= /boot
INSTALLFLAGS= -b
@@ -12,7 +13,7 @@ WARNS?= 1
UBLDR_LOADADDR?= 0x1000000
# Architecture-specific loader code
-SRCS= start.S conf.c vers.c
+SRCS= start.S conf.c self_reloc.c vers.c
.if !defined(LOADER_NO_DISK_SUPPORT)
LOADER_DISK_SUPPORT?= yes
@@ -93,9 +94,7 @@ CLEANFILES+= vers.c loader.help
CFLAGS+= -ffreestanding -msoft-float
-LDFLAGS= -nostdlib -static
-LDFLAGS+= -T ldscript.generated
-LDFLAGS+= -T ${.CURDIR}/ldscript.${MACHINE_CPUARCH}
+LDFLAGS= -nostdlib -static -T ${.CURDIR}/ldscript.${MACHINE_CPUARCH}
# Pull in common loader code
.PATH: ${.CURDIR}/../../uboot/common
@@ -116,6 +115,8 @@ NO_WERROR.clang=
DPADD= ${LIBFICL} ${LIBUBOOT} ${LIBFDT} ${LIBUBOOT_FDT} ${LIBSTAND}
LDADD= ${LIBFICL} ${LIBUBOOT} ${LIBFDT} ${LIBUBOOT_FDT} -lstand
+OBJS+= ${SRCS:N*.h:R:S/$/.o/g}
+
vers.c: ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version
sh ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version ${NEWVERSWHAT}
@@ -123,17 +124,24 @@ loader.help: help.common help.uboot ${.CURDIR}/../../fdt/help.fdt
cat ${.ALLSRC} | \
awk -f ${.CURDIR}/../../common/merge_help.awk > ${.TARGET}
-${PROG}: ldscript.generated ${.CURDIR}/ldscript.${MACHINE_CPUARCH}
-
-ldscript.generated::
- rm -f ldscript.generated.tmp
- echo "UBLDR_LOADADDR = ${UBLDR_LOADADDR};" >ldscript.generated.tmp
- if diff ldscript.generated ldscript.generated.tmp > /dev/null; then \
- true; \
- else \
- rm -f ldscript.generated; \
- mv ldscript.generated.tmp ldscript.generated; \
- fi
+ldscript.abs:
+ echo "UBLDR_LOADADDR = ${UBLDR_LOADADDR};" >${.TARGET}
+
+ldscript.pie:
+ echo "UBLDR_LOADADDR = 0;" >${.TARGET}
+
+ubldr: ${OBJS} ldscript.abs ${.CURDIR}/ldscript.${MACHINE_CPUARCH} ${DPADD}
+ ${CC} ${CFLAGS} -T ldscript.abs ${LDFLAGS} \
+ -o ${.TARGET} ${OBJS} ${LDADD}
+
+ubldr.pie: ${OBJS} ldscript.pie ${.CURDIR}/ldscript.${MACHINE_CPUARCH} ${DPADD}
+ ${CC} ${CFLAGS} -T ldscript.pie ${LDFLAGS} -pie -Wl,-Bsymbolic \
+ -o ${.TARGET} ${OBJS} ${LDADD}
+
+ubldr.bin: ubldr.pie
+ ${OBJCOPY} -S -O binary ubldr.pie ${.TARGET}
+
+CLEANFILES+= ldscript.abs ldscript.pie ubldr ubldr.pie ubldr.bin
.if !defined(LOADER_ONLY)
.PATH: ${.CURDIR}/../../forth
diff --git a/sys/boot/arm/uboot/ldscript.arm b/sys/boot/arm/uboot/ldscript.arm
index b3be119..1eb10a8 100644
--- a/sys/boot/arm/uboot/ldscript.arm
+++ b/sys/boot/arm/uboot/ldscript.arm
@@ -6,6 +6,15 @@ SECTIONS
{
/* Read-only sections, merged into text segment: */
. = UBLDR_LOADADDR + SIZEOF_HEADERS;
+ .text :
+ {
+ *(.text)
+ /* .gnu.warning sections are handled specially by elf32.em. */
+ *(.gnu.warning)
+ *(.gnu.linkonce.t*)
+ } =0
+ _etext = .;
+ PROVIDE (etext = .);
.interp : { *(.interp) }
.hash : { *(.hash) }
.dynsym : { *(.dynsym) }
@@ -32,15 +41,6 @@ SECTIONS
.rela.sbss : { *(.rela.sbss) }
.rela.sdata2 : { *(.rela.sdata2) }
.rela.sbss2 : { *(.rela.sbss2) }
- .text :
- {
- *(.text)
- /* .gnu.warning sections are handled specially by elf32.em. */
- *(.gnu.warning)
- *(.gnu.linkonce.t*)
- } =0
- _etext = .;
- PROVIDE (etext = .);
.init : { *(.init) } =0
.fini : { *(.fini) } =0
.rodata : { *(.rodata) *(.gnu.linkonce.r*) }
diff --git a/sys/boot/arm/uboot/start.S b/sys/boot/arm/uboot/start.S
index 6e8f117..1ef21f3 100644
--- a/sys/boot/arm/uboot/start.S
+++ b/sys/boot/arm/uboot/start.S
@@ -29,12 +29,38 @@
#include <machine/asm.h>
#include <machine/armreg.h>
+ .text
+ .extern _C_LABEL(self_reloc), _C_LABEL(main)
+ .weak _DYNAMIC
+
/*
* Entry point to the loader that U-Boot passes control to.
*/
- .text
.globl _start
_start:
+
+#ifdef _ARM_ARCH_6
+ mrc p15, 0, ip, c1, c0, 0
+ orr ip, ip, #(CPU_CONTROL_UNAL_ENABLE)
+ orr ip, ip, #(CPU_CONTROL_AFLT_ENABLE)
+ mcr p15, 0, ip, c1, c0, 0
+#endif
+ /*
+ * Do self-relocation when the weak external symbol _DYNAMIC is non-NULL.
+ * When linked as a dynamic relocatable file, the linker automatically
+ * defines _DYNAMIC with a value that is the offset of the dynamic
+ * relocation info section.
+ * Note that we're still on u-boot's stack here, but the self_reloc
+ * code uses only a couple dozen bytes of stack space.
+ */
+ adr ip, .here_off /* .here_off is a symbol whose value */
+ ldr r0, [ip] /* is its own offset in the text seg. */
+ sub r0, ip, r0 /* Get its pc-relative address and */
+ ldr r1, .dynamic_off /* subtract its value and we get */
+ teq r1, #0 /* r0 = physaddr we were loaded at. */
+ addne r1, r1, r0 /* r1 = dynamic section physaddr. */
+ blne _C_LABEL(self_reloc) /* Do reloc if _DYNAMIC is non-NULL. */
+
/* Hint where to look for the API signature */
ldr ip, =uboot_address
str sp, [ip]
@@ -44,16 +70,20 @@ _start:
str r8, [ip, #0]
str r9, [ip, #4]
-#ifdef _ARM_ARCH_6
- mrc p15, 0, r2, c1, c0, 0
- orr r2, r2, #(CPU_CONTROL_UNAL_ENABLE)
- orr r2, r2, #(CPU_CONTROL_AFLT_ENABLE)
- mcr p15, 0, r2, c1, c0, 0
-#endif
-
- /* Start loader */
+ /*
+ * Start loader. This is basically a tail-recursion call; if main()
+ * returns, it returns to u-boot (which reports the value returned r0).
+ */
b main
+ /*
+ * Data for self-relocation, in the text segment for pc-rel access.
+ */
+.here_off:
+ .word .
+.dynamic_off:
+ .word _DYNAMIC
+
/*
* syscall()
*/
diff --git a/sys/boot/common/load_elf.c b/sys/boot/common/load_elf.c
index 672c566..edbad05 100644
--- a/sys/boot/common/load_elf.c
+++ b/sys/boot/common/load_elf.c
@@ -141,22 +141,15 @@ __elfN(loadfile)(char *filename, u_int64_t dest, struct preloaded_file **result)
* 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) {
+#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");
@@ -164,16 +157,39 @@ __elfN(loadfile)(char *filename, u_int64_t dest, struct preloaded_file **result)
goto oerr;
}
/*
- * Calculate destination address based on kernel entrypoint
+ * 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.
*/
- dest = (ehdr->e_entry & ~PAGE_MASK);
- if (dest == 0) {
+#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 (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;
@@ -259,7 +275,7 @@ __elfN(loadimage)(struct preloaded_file *fp, elf_file_t ef, u_int64_t off)
ret = 0;
firstaddr = lastaddr = 0;
ehdr = ef->ehdr;
- if (ef->kernel) {
+ if (ehdr->e_type == ET_EXEC) {
#if defined(__i386__) || defined(__amd64__)
#if __ELF_WORD_SIZE == 64
off = - (off & 0xffffffffff000000ull);/* x86_64 relocates after locore */
@@ -291,32 +307,30 @@ __elfN(loadimage)(struct preloaded_file *fp, elf_file_t ef, u_int64_t off)
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.
+ * 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.
*/
- off = -0xc0000000;
- ehdr->e_entry &= ~0xf0000000;
+ 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
- __elfN(relocation_offset) = off;
}
ef->off = off;
+ 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;
diff --git a/sys/boot/common/self_reloc.c b/sys/boot/common/self_reloc.c
new file mode 100644
index 0000000..9864a48
--- /dev/null
+++ b/sys/boot/common/self_reloc.c
@@ -0,0 +1,123 @@
+/*-
+ * Copyright (c) 2008-2010 Rui Paulo <rpaulo@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <elf.h>
+#include <bootstrap.h>
+
+#if defined(__aarch64__)
+#define ElfW_Rel Elf64_Rela
+#define ElfW_Dyn Elf64_Dyn
+#define ELFW_R_TYPE ELF64_R_TYPE
+#define ELF_RELA
+#elif defined(__arm__) || defined(__i386__)
+#define ElfW_Rel Elf32_Rel
+#define ElfW_Dyn Elf32_Dyn
+#define ELFW_R_TYPE ELF32_R_TYPE
+#elif defined(__amd64__)
+#define ElfW_Rel Elf64_Rel
+#define ElfW_Dyn Elf64_Dyn
+#define ELFW_R_TYPE ELF64_R_TYPE
+#else
+#error architecture not supported
+#endif
+#if defined(__aarch64__)
+#define RELOC_TYPE_NONE R_AARCH64_NONE
+#define RELOC_TYPE_RELATIVE R_AARCH64_RELATIVE
+#elif defined(__amd64__)
+#define RELOC_TYPE_NONE R_X86_64_NONE
+#define RELOC_TYPE_RELATIVE R_X86_64_RELATIVE
+#elif defined(__arm__)
+#define RELOC_TYPE_NONE R_ARM_NONE
+#define RELOC_TYPE_RELATIVE R_ARM_RELATIVE
+#elif defined(__i386__)
+#define RELOC_TYPE_NONE R_386_NONE
+#define RELOC_TYPE_RELATIVE R_386_RELATIVE
+#endif
+
+/*
+ * A simple elf relocator.
+ */
+void
+self_reloc(Elf_Addr baseaddr, ElfW_Dyn *dynamic)
+{
+ Elf_Word relsz, relent;
+ Elf_Addr *newaddr;
+ ElfW_Rel *rel;
+ ElfW_Dyn *dynp;
+
+ /*
+ * Find the relocation address, its size and the relocation entry.
+ */
+ relsz = 0;
+ relent = 0;
+ for (dynp = dynamic; dynp->d_tag != DT_NULL; dynp++) {
+ switch (dynp->d_tag) {
+ case DT_REL:
+ case DT_RELA:
+ rel = (ElfW_Rel *)(dynp->d_un.d_ptr + baseaddr);
+ break;
+ case DT_RELSZ:
+ case DT_RELASZ:
+ relsz = dynp->d_un.d_val;
+ break;
+ case DT_RELENT:
+ case DT_RELAENT:
+ relent = dynp->d_un.d_val;
+ break;
+ default:
+ break;
+ }
+ }
+
+ /*
+ * Perform the actual relocation.
+ */
+ for (; relsz > 0; relsz -= relent) {
+ switch (ELFW_R_TYPE(rel->r_info)) {
+ case RELOC_TYPE_NONE:
+ /* No relocation needs be performed. */
+ break;
+
+ case RELOC_TYPE_RELATIVE:
+ /* Address relative to the base address. */
+ newaddr = (Elf_Addr *)(rel->r_offset + baseaddr);
+ *newaddr += baseaddr;
+ /* Add the addend when the ABI uses them */
+#ifdef ELF_RELA
+ *newaddr += rel->r_addend;
+#endif
+ break;
+ default:
+ /* XXX: do we need other relocations ? */
+ break;
+ }
+ rel = (ElfW_Rel *) ((caddr_t) rel + relent);
+ }
+}
diff --git a/sys/boot/uboot/common/main.c b/sys/boot/uboot/common/main.c
index 919b541..b830354 100644
--- a/sys/boot/uboot/common/main.c
+++ b/sys/boot/uboot/common/main.c
@@ -28,6 +28,7 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include <sys/param.h>
#include <stand.h>
@@ -44,6 +45,9 @@ struct uboot_devdesc currdev;
struct arch_switch archsw; /* MI/MD interface boundary */
int devs_no;
+uintptr_t uboot_heap_start;
+uintptr_t uboot_heap_end;
+
struct device_type {
const char *name;
int type;
@@ -414,7 +418,9 @@ main(void)
* Initialise the heap as early as possible. Once this is done,
* alloc() is usable. The stack is buried inside us, so this is safe.
*/
- setheap((void *)end, (void *)(end + 512 * 1024));
+ uboot_heap_start = round_page((uintptr_t)end);
+ uboot_heap_end = uboot_heap_start + 512 * 1024;
+ setheap((void *)uboot_heap_start, (void *)uboot_heap_end);
/*
* Set up console.
@@ -487,6 +493,7 @@ main(void)
setenv("LINES", "24", 1); /* optional */
setenv("prompt", "loader>", 1);
+ archsw.arch_loadaddr = uboot_loadaddr;
archsw.arch_getdev = uboot_getdev;
archsw.arch_copyin = uboot_copyin;
archsw.arch_copyout = uboot_copyout;
diff --git a/sys/boot/uboot/lib/copy.c b/sys/boot/uboot/lib/copy.c
index 3adf7eb..bb658e3 100644
--- a/sys/boot/uboot/lib/copy.c
+++ b/sys/boot/uboot/lib/copy.c
@@ -27,66 +27,131 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include <sys/param.h>
#include <stand.h>
#include <stdint.h>
#include "api_public.h"
#include "glue.h"
+#include "libuboot.h"
/*
* MD primitives supporting placement of module data
*/
-void *
-uboot_vm_translate(vm_offset_t o) {
+#ifdef __arm__
+#define KERN_ALIGN (2 * 1024 * 1024)
+#else
+#define KERN_ALIGN PAGE_SIZE
+#endif
+
+/*
+ * Avoid low memory, u-boot puts things like args and dtb blobs there.
+ */
+#define KERN_MINADDR max(KERN_ALIGN, (1024 * 1024))
+
+extern void _start(void); /* ubldr entry point address. */
+
+/*
+ * This is called for every object loaded (kernel, module, dtb file, etc). The
+ * expected return value is the next address at or after the given addr which is
+ * appropriate for loading the given object described by type and data. On each
+ * call the addr is the next address following the previously loaded object.
+ *
+ * The first call is for loading the kernel, and the addr argument will be zero,
+ * and we search for a big block of ram to load the kernel and modules.
+ *
+ * On subsequent calls the addr will be non-zero, and we just round it up so
+ * that each object begins on a page boundary.
+ */
+uint64_t
+uboot_loadaddr(u_int type, void *data, uint64_t addr)
+{
struct sys_info *si;
- static uintptr_t start = 0;
- static size_t size = 0;
+ uintptr_t sblock, eblock, subldr, eubldr;
+ uintptr_t biggest_block, this_block;
+ size_t biggest_size, this_size;
int i;
+ char * envstr;
+
+ if (addr == 0) {
+ /*
+ * If the loader_kernaddr environment variable is set, blindly
+ * honor it. It had better be right. We force interpretation
+ * of the value in base-16 regardless of any leading 0x prefix,
+ * because that's the U-Boot convention.
+ */
+ envstr = ub_env_get("loader_kernaddr");
+ if (envstr != NULL)
+ return (strtoul(envstr, NULL, 16));
- if (size == 0) {
+ /*
+ * Find addr/size of largest DRAM block. Carve our own address
+ * range out of the block, because loading the kernel over the
+ * top ourself is a poor memory-conservation strategy. Avoid
+ * memory at beginning of the first block of physical ram,
+ * since u-boot likes to pass args and data there. Assume that
+ * u-boot has moved itself to the very top of ram and
+ * optimistically assume that we won't run into it up there.
+ */
if ((si = ub_get_sys_info()) == NULL)
panic("could not retrieve system info");
- /* Find start/size of largest DRAM block. */
+ biggest_block = 0;
+ biggest_size = 0;
+ subldr = rounddown2((uintptr_t)_start, KERN_ALIGN);
+ eubldr = roundup2(uboot_heap_end, KERN_ALIGN);
for (i = 0; i < si->mr_no; i++) {
- if (si->mr[i].flags == MR_ATTR_DRAM
- && si->mr[i].size > size) {
- start = si->mr[i].start;
- size = si->mr[i].size;
+ if (si->mr[i].flags != MR_ATTR_DRAM)
+ continue;
+ sblock = roundup2(si->mr[i].start, KERN_ALIGN);
+ eblock = rounddown2(si->mr[i].start + si->mr[i].size,
+ KERN_ALIGN);
+ if (biggest_size == 0)
+ sblock += KERN_MINADDR;
+ if (subldr >= sblock && subldr < eblock) {
+ if (subldr - sblock > eblock - eubldr) {
+ this_block = sblock;
+ this_size = subldr - sblock;
+ } else {
+ this_block = eubldr;
+ this_size = eblock - eubldr;
+ }
+ }
+ if (biggest_size < this_size) {
+ biggest_block = this_block;
+ biggest_size = this_size;
}
}
-
- if (size <= 0)
- panic("No suitable DRAM?\n");
- /*
- printf("Loading into memory region 0x%08X-0x%08X (%d MiB)\n",
- start, start + size, size / 1024 / 1024);
- */
+ if (biggest_size == 0)
+ panic("Not enough DRAM to load kernel\n");
+#if 0
+ printf("Loading kernel into region 0x%08x-0x%08x (%u MiB)\n",
+ biggest_block, biggest_block + biggest_size - 1,
+ biggest_size / 1024 / 1024);
+#endif
+ return (biggest_block);
}
- if (o > size)
- panic("Address offset 0x%08jX bigger than size 0x%08X\n",
- (intmax_t)o, size);
- return (void *)(start + o);
+ return roundup2(addr, PAGE_SIZE);
}
ssize_t
uboot_copyin(const void *src, vm_offset_t dest, const size_t len)
{
- bcopy(src, uboot_vm_translate(dest), len);
+ bcopy(src, (void *)dest, len);
return (len);
}
ssize_t
uboot_copyout(const vm_offset_t src, void *dest, const size_t len)
{
- bcopy(uboot_vm_translate(src), dest, len);
+ bcopy((void *)src, dest, len);
return (len);
}
ssize_t
uboot_readin(const int fd, vm_offset_t dest, const size_t len)
{
- return (read(fd, uboot_vm_translate(dest), len));
+ return (read(fd, (void *)dest, len));
}
diff --git a/sys/boot/uboot/lib/elf_freebsd.c b/sys/boot/uboot/lib/elf_freebsd.c
index 6b828d3..b72d07c 100644
--- a/sys/boot/uboot/lib/elf_freebsd.c
+++ b/sys/boot/uboot/lib/elf_freebsd.c
@@ -80,7 +80,7 @@ __elfN(uboot_exec)(struct preloaded_file *fp)
if ((error = md_load(fp->f_args, &mdp)) != 0)
return (error);
- entry = uboot_vm_translate(e->e_entry);
+ entry = (void *)e->e_entry;
printf("Kernel entry at 0x%x...\n", (unsigned)entry);
dev_cleanup();
diff --git a/sys/boot/uboot/lib/libuboot.h b/sys/boot/uboot/lib/libuboot.h
index 79005f2..e4201d8 100644
--- a/sys/boot/uboot/lib/libuboot.h
+++ b/sys/boot/uboot/lib/libuboot.h
@@ -57,7 +57,10 @@ extern int devs_no;
extern struct netif_driver uboot_net;
extern struct devsw uboot_storage;
-void *uboot_vm_translate(vm_offset_t);
+extern uintptr_t uboot_heap_start;
+extern uintptr_t uboot_heap_end;
+
+uint64_t uboot_loadaddr(u_int type, void *data, uint64_t addr);
ssize_t uboot_copyin(const void *src, vm_offset_t dest, const size_t len);
ssize_t uboot_copyout(const vm_offset_t src, void *dest, const size_t len);
ssize_t uboot_readin(const int fd, vm_offset_t dest, const size_t len);
OpenPOWER on IntegriCloud