Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F108554211
D22255.id64104.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
16 KB
Referenced Files
None
Subscribers
None
D22255.id64104.diff
View Options
Index: sys/arm64/arm64/locore.S
===================================================================
--- sys/arm64/arm64/locore.S
+++ sys/arm64/arm64/locore.S
@@ -53,6 +53,29 @@
.text
.globl _start
_start:
+#ifdef LINUX_BOOT_ABI
+ /*
+ * See Documentation/arm64/booting.txt in the Linux kernel.
+ * This is needed to boot using U-Boot's booti command.
+ */
+
+#define BOOTI_MAGIC 0x644d5241
+#define UBOOT_IMAGE_OFFSET 0
+#define UBOOT_IMAGE_SIZE _end - _start
+#define UBOOT_IMAGE_FLAGS 0
+
+ b 1f /* Executable code */
+ .long 0 /* Executable code */
+ .quad UBOOT_IMAGE_OFFSET /* Image load offset, little endian */
+ .quad UBOOT_IMAGE_SIZE /* Effective Image size, little endian */
+ .quad UBOOT_IMAGE_FLAGS /* kernel flags, little endian */
+ .quad 0 /* reserved */
+ .quad 0 /* reserved */
+ .quad 0 /* reserved */
+ .long BOOTI_MAGIC /* Magic number, little endian, "ARM\x64" */
+ .long 0 /* reserved (used for PE COFF offset) */
+1:
+#endif
/* Drop to EL1 */
bl drop_to_el1
@@ -347,15 +370,25 @@
* Build the TTBR1 maps.
*/
- /* Find the size of the kernel */
mov x6, #(KERNBASE)
- /* Find modulep - begin */
- sub x8, x0, x6
+ and x7, x0, x6
+ cmp x7, x6
+ b.eq 1f
+ /* booted from U-Boot */
+ ldr x7, .Lend
+ sub x8, x7, x6 /* kernel size = end - begin */
+ b 2f
+1:
+ /* booted from FreeBSD loader */
+ sub x8, x0, x6 /* size = modulep - begin */
/* Add two 2MiB pages for the module data and round up */
ldr x7, =(3 * L2_SIZE - 1)
add x8, x8, x7
+2:
/* Get the number of l2 pages to allocate, rounded down */
lsr x10, x8, #(L2_SHIFT)
+ /* Add 1 to get actual count */
+ add x10, x10, #1
/* Create the kernel space L2 table */
mov x6, x26
Index: sys/arm64/arm64/machdep.c
===================================================================
--- sys/arm64/arm64/machdep.c
+++ sys/arm64/arm64/machdep.c
@@ -923,6 +923,16 @@
vm_offset_t dtbp;
dtbp = MD_FETCH(kmdp, MODINFOMD_DTBP, vm_offset_t);
+
+#if defined(FDT_DTB_STATIC)
+ /*
+ * In case the device tree blob was not retrieved (from metadata) try
+ * to use the statically embedded one.
+ */
+ if (dtbp == 0)
+ dtbp = (vm_offset_t)&fdt_static_dtb;
+#endif
+
if (dtbp == (vm_offset_t)NULL) {
printf("ERROR loading DTB\n");
return;
@@ -1026,6 +1036,26 @@
}
}
+static vm_offset_t
+freebsd_parse_boot_param(struct arm64_bootparams *abp)
+{
+ vm_offset_t lastaddr;
+ void *kmdp;
+ static char *loader_envp;
+
+ preload_metadata = (caddr_t)(uintptr_t)(abp->modulep);
+ kmdp = preload_search_by_type("elf kernel");
+ if (kmdp == NULL)
+ return (0);
+
+ boothowto = MD_FETCH(kmdp, MODINFOMD_HOWTO, int);
+ loader_envp = MD_FETCH(kmdp, MODINFOMD_ENVP, char *);
+ init_static_kenv(loader_envp, 0);
+ lastaddr = MD_FETCH(kmdp, MODINFOMD_KERNEND, vm_offset_t);
+
+ return (lastaddr);
+}
+
void
initarm(struct arm64_bootparams *abp)
{
@@ -1041,27 +1071,32 @@
caddr_t kmdp;
bool valid;
- /* Set the module data location */
- preload_metadata = (caddr_t)(uintptr_t)(abp->modulep);
+ if ((abp->modulep & VM_MIN_KERNEL_ADDRESS) ==
+ VM_MIN_KERNEL_ADDRESS)
+ /* Booted from loader. */
+ lastaddr = freebsd_parse_boot_param(abp);
+#ifdef LINUX_BOOT_ABI
+ else
+ /* Booted from U-Boot. */
+ lastaddr = linux_parse_boot_param(abp);
+#endif
/* Find the kernel address */
kmdp = preload_search_by_type("elf kernel");
if (kmdp == NULL)
kmdp = preload_search_by_type("elf64 kernel");
- boothowto = MD_FETCH(kmdp, MODINFOMD_HOWTO, int);
- init_static_kenv(MD_FETCH(kmdp, MODINFOMD_ENVP, char *), 0);
link_elf_ireloc(kmdp);
#ifdef FDT
try_load_dtb(kmdp);
+#ifdef LINUX_BOOT_ABI
+ parse_bootargs(&lastaddr, abp);
+#endif
#endif
efi_systbl_phys = MD_FETCH(kmdp, MODINFOMD_FW_HANDLE, vm_paddr_t);
- /* Find the address to start allocating from */
- lastaddr = MD_FETCH(kmdp, MODINFOMD_KERNEND, vm_offset_t);
-
/* Load the physical memory ranges */
efihdr = (struct efi_map_header *)preload_search_info(kmdp,
MODINFO_METADATA | MODINFOMD_EFI_MAP);
Index: sys/arm64/arm64/machdep_boot.c
===================================================================
--- /dev/null
+++ sys/arm64/arm64/machdep_boot.c
@@ -0,0 +1,328 @@
+/*-
+ * Copyright (c) 2019 Juniper Networks, Inc
+ * Copyright (c) 2004 Olivier Houchard
+ * Copyright (c) 1994-1998 Mark Brinicombe.
+ * Copyright (c) 1994 Brini.
+ * 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 "opt_platform.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/ctype.h>
+#include <sys/linker.h>
+#include <sys/reboot.h>
+#include <sys/sysctl.h>
+
+#include <machine/cpu.h>
+#include <machine/machdep.h>
+#include <machine/metadata.h>
+#include <machine/vmparam.h>
+
+#ifdef FDT
+#include <contrib/libfdt/libfdt.h>
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/ofw_subr.h>
+#include <dev/ofw/openfirm.h>
+#include <machine/pte.h>
+#include <sys/boot.h>
+#endif
+
+#ifdef FDT
+#define PRELOAD_PUSH_VALUE(type, value) do { \
+ *(type *)(preload_ptr + preload_size) = (value); \
+ preload_size += sizeof(type); \
+} while (0)
+
+#define PRELOAD_PUSH_STRING(str) do { \
+ uint32_t ssize; \
+ ssize = strlen(str) + 1; \
+ PRELOAD_PUSH_VALUE(uint32_t, ssize); \
+ strcpy((char*)(preload_ptr + preload_size), str); \
+ preload_size += ssize; \
+ preload_size = roundup(preload_size, sizeof(u_long)); \
+} while (0)
+
+static int build_l2_block_pagetable(vm_offset_t, uint64_t,
+ struct arm64_bootparams *);
+
+#define INITRD_START "linux,initrd-start"
+#define INITRD_END "linux,initrd-end"
+#define KENV_SIZE 2048
+
+static char static_kenv[KENV_SIZE];
+static caddr_t metadata_endptr;
+#endif
+
+#define PMAP_BOOTSTRAP_PAGES 2
+
+extern vm_offset_t end;
+
+/*
+ * Fake up a boot descriptor table
+ */
+static vm_offset_t
+fake_preload_metadata(void *dtb_ptr, size_t dtb_size,
+ struct arm64_bootparams *abp)
+{
+ vm_offset_t lastaddr;
+ static char fake_preload[256];
+ caddr_t preload_ptr;
+ size_t preload_size;
+
+ preload_ptr = (caddr_t)&fake_preload[0];
+ preload_size = 0;
+
+ PRELOAD_PUSH_VALUE(uint32_t, MODINFO_NAME);
+ PRELOAD_PUSH_STRING("kernel");
+
+ PRELOAD_PUSH_VALUE(uint32_t, MODINFO_TYPE);
+ PRELOAD_PUSH_STRING("elf kernel");
+
+ PRELOAD_PUSH_VALUE(uint32_t, MODINFO_ADDR);
+ PRELOAD_PUSH_VALUE(uint32_t, sizeof(vm_offset_t));
+ PRELOAD_PUSH_VALUE(uint64_t, VM_MIN_KERNEL_ADDRESS);
+
+ PRELOAD_PUSH_VALUE(uint32_t, MODINFO_SIZE);
+ PRELOAD_PUSH_VALUE(uint32_t, sizeof(size_t));
+ PRELOAD_PUSH_VALUE(uint64_t, (size_t)(&end - VM_MIN_KERNEL_ADDRESS));
+
+ lastaddr = (vm_offset_t)&end;
+ lastaddr = roundup(lastaddr, sizeof(vm_offset_t));
+
+#ifdef FDT
+ if (dtb_ptr != NULL &&
+ (build_l2_block_pagetable(lastaddr, dtb_size, abp) == 0)) {
+ /* Copy DTB to KVA space and insert it into module chain. */
+ PRELOAD_PUSH_VALUE(uint32_t, MODINFO_METADATA | MODINFOMD_DTBP);
+ PRELOAD_PUSH_VALUE(uint32_t, sizeof(uint64_t));
+ PRELOAD_PUSH_VALUE(uint64_t, (uint64_t)lastaddr);
+ memmove((void *)lastaddr, dtb_ptr, dtb_size);
+ lastaddr += dtb_size;
+ }
+
+ lastaddr = roundup(lastaddr, sizeof(vm_offset_t));
+ /* End marker */
+ metadata_endptr = preload_ptr;
+#endif
+
+ PRELOAD_PUSH_VALUE(uint32_t, 0);
+ PRELOAD_PUSH_VALUE(uint32_t, 0);
+
+ preload_metadata = fake_preload;
+
+ return (lastaddr);
+}
+
+/*
+ * Support booting from U-Boot's booti command. If modulep (register x0)
+ * is a valid address then it is a pointer to FDT.
+ */
+vm_offset_t
+linux_parse_boot_param(struct arm64_bootparams *abp)
+{
+ uint32_t dtb_size = 0;
+ struct fdt_header *dtb_ptr = NULL;
+
+#if defined(FDT) && !defined(FDT_DTB_STATIC)
+ /* Test if modulep (x0) point to valid DTB. */
+ dtb_ptr = (struct fdt_header *)abp->modulep;
+ if (dtb_ptr && fdt_check_header(dtb_ptr) == 0)
+ dtb_size = fdt_totalsize(dtb_ptr);
+#endif
+ return (fake_preload_metadata(dtb_ptr, dtb_size, abp));
+}
+
+#ifdef FDT
+/*
+ * Builds count 2 MiB page table entries.
+ * During startup, locore.S maps kernel memory in L2 page table.
+ * Create space to copy size bytes following the kernel memory.
+ * See build_l2_block_pagetable in locore.S
+ */
+static int
+build_l2_block_pagetable(vm_offset_t lastaddr, uint64_t size,
+ struct arm64_bootparams *abp)
+{
+ vm_offset_t l2_block_entry, *l2pt_entry;
+ int32_t count_2mib;
+ volatile uint64_t output_bits;
+
+ /* Number of 2MiB pages */
+ count_2mib = ((lastaddr - KERNBASE) + size) >> L2_SHIFT;
+
+ /* All the memory must not cross a 1GiB boundary */
+ if (count_2mib >= Ln_ENTRIES) {
+ printf("%s: Adding %#lx bytes makes kernel cross 1GiB boundary\n",
+ __FUNCTION__, size);
+ return EINVAL;
+ }
+
+ /* size fits within the last 2MiB page table entry */
+ if (((lastaddr - KERNBASE) >> L2_SHIFT) == count_2mib)
+ return 0;
+
+ /* Build the L2 block entry */
+ l2_block_entry = (NORMAL_MEM << 2) | L2_BLOCK | ATTR_AF;
+#ifdef SMP
+ l2_block_entry |= ATTR_SH(ATTR_SH_IS);
+#endif
+ /* Number of 2MiB pages mapped to kernel */
+ count_2mib = (lastaddr - KERNBASE) >> L2_SHIFT;
+
+ /* Go to last L2 page table entry. Each pagetable entry is 8 bytes */
+ l2pt_entry = (vm_offset_t*)((abp->kern_l1pt - PAGE_SIZE) +
+ (count_2mib << 3));
+ output_bits = (*l2pt_entry++ >> L2_SHIFT) + 1;
+
+ /* Build count 2MiB page table entries */
+ for (count_2mib = size >> L2_SHIFT; count_2mib >= 0;
+ l2pt_entry++, output_bits++, count_2mib--)
+ *l2pt_entry = (output_bits << L2_SHIFT) | l2_block_entry;
+
+ return 0;
+}
+
+/*
+ * Align start addr to 1GiB boundary and build L1 page table entry for it.
+ * See build_l1_block_pagetable in locore.S
+ */
+static void
+build_l1_block_pagetable(vm_offset_t start, struct arm64_bootparams *abp)
+{
+ vm_offset_t l1_table_idx, l1_block_entry, phy_addr, *l1_table_entry;
+
+ /* Find the table index */
+ l1_table_idx = (start >> L1_SHIFT) & Ln_ADDR_MASK;
+
+ /* Build the L1 block entry */
+ l1_block_entry = (NORMAL_UNCACHED << 2) | L1_BLOCK | ATTR_AF;
+#ifdef SMP
+ l1_block_entry |= ATTR_SH(ATTR_SH_IS);
+#endif
+
+ /* Set the physical address */
+ phy_addr = l1_block_entry | (l1_table_idx << L1_SHIFT);
+
+ /* Index of L1 pagetable. Each pagetable entry is 8 bytes */
+ l1_table_entry = (vm_offset_t*)((abp->kern_l0pt + PAGE_SIZE) +
+ (l1_table_idx << 3));
+ *l1_table_entry = phy_addr;
+}
+
+/*
+ * Copy the initrd image passed using U-Boot's booti command into
+ * KVA space.
+ */
+static void
+linux_load_initrd(vm_offset_t *lastaddr, struct arm64_bootparams *abp)
+{
+ phandle_t chosen;
+ uint64_t initrd_start = 0, initrd_end = 0;
+ uint64_t initrd_size;
+ caddr_t preload_ptr;
+ size_t preload_size = 0;
+
+ if ((chosen = OF_finddevice("/chosen")) == -1)
+ return;
+
+ if (!(OF_hasprop(chosen, INITRD_START) &&
+ OF_hasprop(chosen, INITRD_END)))
+ return;
+
+ if ((OF_getprop(chosen, INITRD_START, &initrd_start, sizeof(uint64_t))) > 0)
+ initrd_start = fdt64_to_cpu(initrd_start);
+
+ if ((OF_getprop(chosen, INITRD_END, &initrd_end, sizeof(uint64_t))) > 0)
+ initrd_end = fdt64_to_cpu(initrd_end);
+
+ if ((initrd_size = (initrd_end - initrd_start)) <= 0)
+ return;
+
+ if (build_l2_block_pagetable(*lastaddr, initrd_size, abp) != 0)
+ return;
+
+ build_l1_block_pagetable(initrd_start, abp);
+
+ /* Copy the initrd image to virtual address space */
+ memmove((void*)(*lastaddr), (void*)initrd_start, initrd_size);
+
+ preload_ptr = metadata_endptr;
+
+ PRELOAD_PUSH_VALUE(uint32_t, MODINFO_NAME);
+ PRELOAD_PUSH_STRING("initrd");
+
+ PRELOAD_PUSH_VALUE(uint32_t, MODINFO_TYPE);
+ PRELOAD_PUSH_STRING("md_image");
+
+ PRELOAD_PUSH_VALUE(uint32_t, MODINFO_SIZE);
+ PRELOAD_PUSH_VALUE(uint32_t, sizeof(uint64_t));
+ PRELOAD_PUSH_VALUE(uint64_t, initrd_size);
+
+ PRELOAD_PUSH_VALUE(uint32_t, MODINFO_ADDR);
+ PRELOAD_PUSH_VALUE(uint32_t, sizeof(vm_offset_t));
+ PRELOAD_PUSH_VALUE(uint64_t, *lastaddr);
+
+ *lastaddr += initrd_size;
+ *lastaddr = roundup(*lastaddr, sizeof(vm_offset_t));
+
+ /* End marker */
+ metadata_endptr = preload_ptr;
+ PRELOAD_PUSH_VALUE(uint32_t, 0);
+ PRELOAD_PUSH_VALUE(uint32_t, 0);
+}
+
+/*
+ * Parse initrd image arguments, bootargs passed in FDT from U-Boot.
+ */
+void
+parse_bootargs(vm_offset_t *lastaddr, struct arm64_bootparams *abp)
+{
+
+ /*
+ * Fake metadata is used to support boot from U-Boot. Process bootargs,
+ * initrd args from FDT blob set in fake medadata.
+ */
+ if (metadata_endptr == NULL)
+ return;
+
+ /* Booted from U-Boot */
+ linux_load_initrd(lastaddr, abp);
+
+ /*
+ * L2 PTEs map addresses in order of kernel, dtb, initrd image.
+ * Add L2 pages at the end for pmap to bootstrap L2, L3 PTEs, etc.
+ */
+ build_l2_block_pagetable(*lastaddr,
+ (PMAP_BOOTSTRAP_PAGES * L2_SIZE) - 1, abp);
+
+ init_static_kenv(static_kenv, sizeof(static_kenv));
+ ofw_parse_bootargs();
+}
+#endif
Index: sys/arm64/conf/GENERIC
===================================================================
--- sys/arm64/conf/GENERIC
+++ sys/arm64/conf/GENERIC
@@ -77,6 +77,7 @@
options RCTL # Resource limits
options SMP
options INTRNG
+options LINUX_BOOT_ABI # Boot using booti command from U-Boot
# Debugging support. Always need this:
options KDB # Enable kernel debugger support.
Index: sys/arm64/include/machdep.h
===================================================================
--- sys/arm64/include/machdep.h
+++ sys/arm64/include/machdep.h
@@ -48,5 +48,9 @@
void dbg_init(void);
void initarm(struct arm64_bootparams *);
extern void (*pagezero)(void *);
+vm_offset_t linux_parse_boot_param(struct arm64_bootparams *);
+#ifdef LINUX_BOOT_ABI
+void parse_bootargs(vm_offset_t *, struct arm64_bootparams *);
+#endif
#endif /* _MACHINE_MACHDEP_H_ */
Index: sys/conf/Makefile.arm64
===================================================================
--- sys/conf/Makefile.arm64
+++ sys/conf/Makefile.arm64
@@ -31,6 +31,18 @@
CFLAGS += -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer
.endif
+SYSTEM_LD_ = ${LD} -Bdynamic -T ldscript.$M.noheader \
+ ${_LDFLAGS} --no-warn-mismatch --warn-common --export-dynamic \
+ --dynamic-linker /red/herring \
+ -o ${FULLKERNEL}.noheader -X ${SYSTEM_OBJS} vers.o
+
+SYSTEM_LD_TAIL +=;sed s/" + SIZEOF_HEADERS"// $(LDSCRIPT)\
+ >ldscript.$M.noheader;\
+ ${SYSTEM_LD_}; \
+ ${OBJCOPY} -S -O binary ${FULLKERNEL}.noheader \
+ ${KERNEL_KO}.bin; \
+ rm ${FULLKERNEL}.noheader
+
%BEFORE_DEPEND
%OBJS
Index: sys/conf/files.arm64
===================================================================
--- sys/conf/files.arm64
+++ sys/conf/files.arm64
@@ -152,6 +152,7 @@
arm64/arm64/in_cksum.c optional inet | inet6
arm64/arm64/locore.S standard no-obj
arm64/arm64/machdep.c standard
+arm64/arm64/machdep_boot.c optional linux_boot_abi
arm64/arm64/mem.c standard
arm64/arm64/memcpy.S standard
arm64/arm64/memmove.S standard
Index: sys/conf/options.arm64
===================================================================
--- sys/conf/options.arm64
+++ sys/conf/options.arm64
@@ -2,6 +2,7 @@
ARM64 opt_global.h
INTRNG opt_global.h
+LINUX_BOOT_ABI opt_global.h
SOCDEV_PA opt_global.h
SOCDEV_VA opt_global.h
THUNDERX_PASS_1_1_ERRATA opt_global.h
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Jan 27, 7:16 AM (2 h, 33 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
16188929
Default Alt Text
D22255.id64104.diff (16 KB)
Attached To
Mode
D22255: Boot arm64 kernel using booti command from U-boot.
Attached
Detach File
Event Timeline
Log In to Comment