Index: sys/arm64/arm64/locore.S =================================================================== --- sys/arm64/arm64/locore.S +++ sys/arm64/arm64/locore.S @@ -46,6 +46,23 @@ #define NORMAL_UNCACHED 1 #define NORMAL_MEM 2 +/* U-Boot booti related constants. */ +#if defined(UBOOT_BOOT_ABI) +#define FDT_MAGIC 0xEDFE0DD0 /* FDT blob Magic */ + +#ifndef UBOOT_IMAGE_OFFSET +#define UBOOT_IMAGE_OFFSET 0 /* Image offset from start of */ +#endif /* 2 MiB page */ + +#ifndef UBOOT_IMAGE_SIZE /* Total size of image */ +#define UBOOT_IMAGE_SIZE _end - _start +#endif + +#ifndef UBOOT_IMAGE_FLAGS +#define UBOOT_IMAGE_FLAGS 0 /* LE kernel, unspecified */ +#endif /* page size */ +#endif /* defined(UBOOT_BOOT_ABI) */ + /* * We assume: * MMU on with an identity map, or off @@ -57,6 +74,21 @@ .text .globl _start _start: +#if defined(UBOOT_BOOT_ABI) + /* U-boot image header */ + b 1f /* code 0 */ + .long 0 /* code 1 */ + .quad UBOOT_IMAGE_OFFSET /* Image offset in 2 MiB page, LE */ + .quad UBOOT_IMAGE_SIZE /* Image size, LE */ + .quad UBOOT_IMAGE_FLAGS /* Flags for kernel. LE */ + .quad 0 /* Reserved */ + .quad 0 /* Reserved */ + .quad 0 /* Reserved */ + .long 0x644d5241 /* Magic "ARM\x64", LE */ + .long 0 /* Reserved for PE COFF offset*/ +1: +#endif /* defined(UBOOT_BOOT_ABI) */ + /* Drop to EL1 */ bl drop_to_el1 @@ -352,11 +384,46 @@ /* Find the size of the kernel */ mov x6, #(KERNBASE) + + /* X19 is used as 'map FDT data' flag */ + mov x19, xzr + + /* No modules or FDT pointer ? */ + cbz x0, booti_no_fdt + + /* Test if modulep points to modules descriptor or to FDT */ + ldr w8, [x0] + ldr w7, =FDT_MAGIC + cmp w7, w8 + b.eq booti_fdt + + /* Booted with modules pointer */ /* Find modulep - begin */ sub x8, x0, x6 /* Add a 2MiB page for the module data and round up */ ldr x7, =(2 * L2_SIZE - 1) add x8, x8, x7 + b common + +booti_fdt: + /* Booted by U-Boot booti with FDT data */ + /* Set 'map FDT data' flag */ + mov x19, #1 + +booti_no_fdt: + /* Booted by U-Boot booti without FTD data */ + /* Find the end - begin */ + ldr x7, .Lend + sub x8, x7, x6 + + /* + * Add one 2MiB page for copy of FDT data (maximum FDT size), + * one for metadata and round up + */ + ldr x7, =(3 * L2_SIZE - 1) + add x8, x8, x7 + +common: /* Get the number of l2 pages to allocate, rounded down */ lsr x10, x8, #(L2_SHIFT) @@ -404,7 +471,17 @@ mov x10, #1 bl build_l1_block_pagetable #endif + /* Map FDT data ? */ + cbz x19, 1f + /* Create the identity mapping for FDT data (2 MiB max) */ + mov x7, #NORMAL_UNCACHED /* Uncached as it's only needed early on */ + mov x9, x0 + mov x8, x0 /* VA start (== PA start) */ + mov x10, #1 + bl build_l1_block_pagetable + +1: /* Create the VA = PA map */ mov x7, #NORMAL_UNCACHED /* Uncached as it's only needed early on */ mov x9, x27 Index: sys/arm64/arm64/machdep.c =================================================================== --- sys/arm64/arm64/machdep.c +++ sys/arm64/arm64/machdep.c @@ -913,6 +913,15 @@ 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; @@ -923,6 +932,8 @@ if (OF_init((void *)dtbp) != 0) panic("OF_init failed with the found device tree"); + + parse_fdt_bootargs(); } #endif @@ -1032,26 +1043,20 @@ bool valid; int i; - /* Set the module data location */ - preload_metadata = (caddr_t)(uintptr_t)(abp->modulep); + /* Parse loader or FDT boot parametes. Determine last used address. */ + lastaddr = parse_boot_param(abp); /* 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); - #ifdef FDT try_load_dtb(kmdp); #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 */ physmap_idx = 0; efihdr = (struct efi_map_header *)preload_search_info(kmdp, @@ -1069,7 +1074,7 @@ } #endif - /* Print the memory map */ + /* Build the memory map */ mem_len = 0; for (i = 0; i < physmap_idx; i += 2) { dump_avail[i] = physmap[i]; Index: sys/arm64/arm64/machdep_boot.c =================================================================== --- /dev/null +++ sys/arm64/arm64/machdep_boot.c @@ -0,0 +1,273 @@ +/*- + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#ifdef FDT +#include +#endif + +#include +#include +#include +#include + +#ifdef FDT +#include +#include +#endif + +extern int *end; + +#ifdef FDT +#define CMDLINE_GUARD "FreeBSD:" +static char uboot_chosen[1024 + 1]; +#endif + +/* + * Fake up a boot descriptor table + */ + #define PRELOAD_PUSH_VALUE(type, value) do { \ + *(type *)(preload_ptr + size) = (value); \ + 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 + size), str); \ + size += ssize; \ + size = roundup(size, sizeof(u_long)); \ +} while (0) + + +/* Build minimal set of metatda. */ +static vm_offset_t +fake_preload_metadata(void *dtb_ptr, size_t dtb_size) +{ +#ifdef DDB + vm_offset_t zstart = 0, zend = 0; +#endif + vm_offset_t lastaddr; + static char fake_preload[256]; + caddr_t preload_ptr; + size_t size; + + preload_ptr = (caddr_t)&fake_preload[0]; + 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)); +#ifdef DDB + if (*(uint64_t *)VM_MIN_KERNEL_ADDRESS == MAGIC_TRAMP_NUMBER) { + PRELOAD_PUSH_VALUE(uint32_t, MODINFO_METADATA|MODINFOMD_SSYM); + PRELOAD_PUSH_VALUE(uint32_t, sizeof(vm_offset_t)); + PRELOAD_PUSH_VALUE(uint64_t, + *(uint64_t *)(VM_MIN_KERNEL_ADDRESS + 4)); + + PRELOAD_PUSH_VALUE(uint32_t, MODINFO_METADATA | MODINFOMD_ESYM); + PRELOAD_PUSH_VALUE(uint32_t, sizeof(vm_offset_t)); + PRELOAD_PUSH_VALUE(uint64_t, + *(uint64_t *)(VM_MIN_KERNEL_ADDRESS + 8)); + + lastaddr = *(uint64_t *)(VM_MIN_KERNEL_ADDRESS + 8); + zend = lastaddr; + zstart = *(uint64_t *)(VM_MIN_KERNEL_ADDRESS + 4); + db_fetch_ksymtab(zstart, zend); + } else +#endif + lastaddr = (vm_offset_t)&end; + if (dtb_ptr != NULL) { + /* Copy DTB to KVA space and insert it into module chain. */ + lastaddr = roundup(lastaddr, sizeof(int)); + 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(int)); + } + /* End marker */ + PRELOAD_PUSH_VALUE(uint32_t, 0); + PRELOAD_PUSH_VALUE(uint32_t, 0); + + preload_metadata = (caddr_t)(uintptr_t)fake_preload; + + init_static_kenv(NULL, 0); + + return (lastaddr); +} + +#ifdef FDT + +/* Convert the U-Boot command line into FreeBSD kenv and boot options. */ +static void +cmdline_set_env(char *cmdline, const char *guard) +{ + char *cmdline_next, *env; + size_t size, guard_len; + int i; + + size = strlen(cmdline); + /* Skip leading spaces. */ + for (; isspace(*cmdline) && (size > 0); cmdline++) + size--; + + /* Test and remove guard. */ + if (guard != NULL && guard[0] != '\0') { + guard_len = strlen(guard); + if (strncasecmp(cmdline, guard, guard_len) != 0) + return; + cmdline += guard_len; + size -= guard_len; + } + + /* Skip leading spaces. */ + for (; isspace(*cmdline) && (size > 0); cmdline++) + size--; + + /* Replace ',' with '\0'. */ + /* TODO: implement escaping for ',' character. */ + cmdline_next = cmdline; + while(strsep(&cmdline_next, ",") != NULL) + ; + init_static_kenv(cmdline, 0); + /* Parse boothowto. */ + for (i = 0; howto_names[i].ev != NULL; i++) { + env = kern_getenv(howto_names[i].ev); + if (env != NULL) { + if (strtoul(env, NULL, 10) != 0) + boothowto |= howto_names[i].mask; + freeenv(env); + } + } +} + +void +parse_fdt_bootargs(void) +{ + + if (fdt_get_chosen_bootargs(uboot_chosen, + sizeof(uboot_chosen) - 1) != 0) + return; + cmdline_set_env(uboot_chosen, CMDLINE_GUARD); +} + +#endif + +#if defined(UBOOT_BOOT_ABI) && defined(FDT) + +static vm_offset_t +uboot_parse_boot_param(struct arm64_bootparams *abp) +{ + struct fdt_header *dtb_ptr; + size_t dtb_size; + + if (abp->modulep == 0) + return (0); + /* Test if modulep point to valid DTB. */ + dtb_ptr = (struct fdt_header *)abp->modulep; + if (fdt_check_header(dtb_ptr) != 0) + return (0); + dtb_size = fdt_totalsize(dtb_ptr); + return (fake_preload_metadata(dtb_ptr, dtb_size)); +} + +#endif + +static vm_offset_t +freebsd_parse_boot_param(struct arm64_bootparams *abp) +{ + vm_offset_t lastaddr; + void *kmdp; + static char *loader_envp; +#ifdef DDB + vm_offset_t ksym_start; + vm_offset_t ksym_end; +#endif + + if (abp->modulep == 0) + return (0); + + 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); +#ifdef DDB + ksym_start = MD_FETCH(kmdp, MODINFOMD_SSYM, uintptr_t); + ksym_end = MD_FETCH(kmdp, MODINFOMD_ESYM, uintptr_t); + db_fetch_ksymtab(ksym_start, ksym_end); +#endif + return (lastaddr); +} + +vm_offset_t +parse_boot_param(struct arm64_bootparams *abp) +{ + vm_offset_t lastaddr; + +#if defined(UBOOT_BOOT_ABI) && defined(FDT) + lastaddr = uboot_parse_boot_param(abp); + if (lastaddr != 0) + return (lastaddr); +#endif + lastaddr = freebsd_parse_boot_param(abp); + if (lastaddr != 0) + return (lastaddr); + + /* Fall back to hardcoded metadata. */ + lastaddr = fake_preload_metadata(NULL, 0); + + return (lastaddr); +} Index: sys/arm64/include/machdep.h =================================================================== --- sys/arm64/include/machdep.h +++ sys/arm64/include/machdep.h @@ -50,6 +50,10 @@ void dbg_init(void); void initarm(struct arm64_bootparams *); +vm_offset_t parse_boot_param(struct arm64_bootparams *abp); +#ifdef FDT +void parse_fdt_bootargs(void); +#endif extern void (*pagezero)(void *); #endif /* _MACHINE_MACHDEP_H_ */ Index: sys/conf/Makefile.arm64 =================================================================== --- sys/conf/Makefile.arm64 +++ sys/conf/Makefile.arm64 @@ -27,10 +27,24 @@ INCLUDES+= -I$S/contrib/libfdt +#SYSTEM_LD:= ${SYSTEM_LD:$S/conf/ldscript.$M=ldscript.$M} +#SYSTEM_DEP:= ${SYSTEM_DEP:$S/conf/ldscript.$M=ldscript.$M} + .if !empty(DDB_ENABLED) CFLAGS += -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer .endif +SYSTEM_LD_ = ${LD} -m ${LD_EMULATION} -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 @@ -42,6 +56,7 @@ %FILES.m %CLEAN +CLEAN+= ldscript.$M ${KERNEL_KO}.bin ldscript.$M.noheader %RULES Index: sys/conf/files.arm64 =================================================================== --- sys/conf/files.arm64 +++ sys/conf/files.arm64 @@ -116,6 +116,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 standard 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 @@ -6,6 +6,7 @@ SOCDEV_VA opt_global.h THUNDERX_PASS_1_1_ERRATA opt_global.h VFP opt_global.h +UBOOT_BOOT_ABI opt_global.h # Binary compatibility COMPAT_FREEBSD32 opt_compat.h