summaryrefslogtreecommitdiffstats
path: root/sys/mips/mips/elf_trampoline.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/mips/mips/elf_trampoline.c')
-rw-r--r--sys/mips/mips/elf_trampoline.c133
1 files changed, 133 insertions, 0 deletions
diff --git a/sys/mips/mips/elf_trampoline.c b/sys/mips/mips/elf_trampoline.c
new file mode 100644
index 0000000..0f2ccc9
--- /dev/null
+++ b/sys/mips/mips/elf_trampoline.c
@@ -0,0 +1,133 @@
+/*-
+ * Copyright (c) 2005 Olivier Houchard. 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 ``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 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 <machine/asm.h>
+#include <sys/param.h>
+#include <sys/elf32.h>
+#include <sys/inflate.h>
+#include <machine/elf.h>
+#include <machine/cpufunc.h>
+#include <machine/stdarg.h>
+
+/*
+ * Since we are compiled outside of the normal kernel build process, we
+ * need to include opt_global.h manually.
+ */
+#include "opt_global.h"
+#include "opt_kernname.h"
+
+extern char kernel_start[];
+extern char kernel_end[];
+
+static __inline void *
+memcpy(void *dst, const void *src, int len)
+{
+ const char *s = src;
+ char *d = dst;
+
+ while (len) {
+ if (0 && len >= 4 && !((vm_offset_t)d & 3) &&
+ !((vm_offset_t)s & 3)) {
+ *(uint32_t *)d = *(uint32_t *)s;
+ s += 4;
+ d += 4;
+ len -= 4;
+ } else {
+ *d++ = *s++;
+ len--;
+ }
+ }
+ return (dst);
+}
+
+static __inline void
+bzero(void *addr, int count)
+{
+ char *tmp = (char *)addr;
+
+ while (count > 0) {
+ if (count >= 4 && !((vm_offset_t)tmp & 3)) {
+ *(uint32_t *)tmp = 0;
+ tmp += 4;
+ count -= 4;
+ } else {
+ *tmp = 0;
+ tmp++;
+ count--;
+ }
+ }
+}
+
+/*
+ * Relocate PT_LOAD segements of kernel ELF image to their respective
+ * virtual addresses and return entry point
+ */
+void *
+load_kernel(void * kstart)
+{
+ Elf32_Ehdr *eh;
+ Elf32_Phdr phdr[64] /* XXX */;
+ int i;
+ void *entry_point;
+
+ eh = (Elf32_Ehdr *)kstart;
+ entry_point = (void*)eh->e_entry;
+ memcpy(phdr, (void *)(kstart + eh->e_phoff ),
+ eh->e_phnum * sizeof(phdr[0]));
+
+ for (i = 0; i < eh->e_phnum; i++) {
+ volatile char c;
+
+ if (phdr[i].p_type != PT_LOAD)
+ continue;
+
+ memcpy((void *)(phdr[i].p_vaddr),
+ (void*)(kstart + phdr[i].p_offset), phdr[i].p_filesz);
+ /* Clean space from oversized segments, eg: bss. */
+ if (phdr[i].p_filesz < phdr[i].p_memsz)
+ bzero((void *)(phdr[i].p_vaddr + phdr[i].p_filesz),
+ phdr[i].p_memsz - phdr[i].p_filesz);
+ }
+
+ return entry_point;
+}
+
+void
+_startC(register_t a0, register_t a1, register_t a2, register_t a3)
+{
+ unsigned int * code;
+ int i;
+ void (*entry_point)(register_t, register_t, register_t, register_t);
+
+ /*
+ * Relocate segment to the predefined memory location
+ * Most likely it will be KSEG0/KSEG1 address
+ */
+ entry_point = load_kernel(kernel_start);
+
+ /* Pass saved registers to original _start */
+ entry_point(a0, a1, a2, a3);
+}
OpenPOWER on IntegriCloud