From fdc6e456335c5c514e10d43763bd81f0773ddfed Mon Sep 17 00:00:00 2001 From: mmel Date: Sat, 26 Mar 2016 06:55:55 +0000 Subject: [PATCH] ARM: Teach LINUX_BOOT_ABI to recognize DT blob. This allow us to boot FreeBSD kernel (using uImage encapsulation) directly from U-boot using 'bootm' command or by Android fastboot loader. For now, kernel uImage must be marked as Linux, but we can add support for FreeBSD into U-Boot later. --- sys/arm/arm/machdep.c | 41 ++++++++++++++++++++++++++++++------ sys/arm/at91/board_tsc4370.c | 2 +- sys/arm/conf/TEGRA124 | 1 + sys/arm/include/machdep.h | 3 ++- 4 files changed, 38 insertions(+), 9 deletions(-) diff --git a/sys/arm/arm/machdep.c b/sys/arm/arm/machdep.c index 1cbb4eab445b..dd4aeafd05ae 100644 --- a/sys/arm/arm/machdep.c +++ b/sys/arm/arm/machdep.c @@ -115,6 +115,7 @@ __FBSDID("$FreeBSD$"); #include #ifdef FDT +#include #include #include #endif @@ -959,7 +960,8 @@ makectx(struct trapframe *tf, struct pcb *pcb) * Fake up a boot descriptor table */ vm_offset_t -fake_preload_metadata(struct arm_boot_params *abp __unused) +fake_preload_metadata(struct arm_boot_params *abp __unused, void *dtb_ptr, + size_t dtb_size) { #ifdef DDB vm_offset_t zstart = 0, zend = 0; @@ -997,6 +999,16 @@ fake_preload_metadata(struct arm_boot_params *abp __unused) } 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)); + fake_preload[i++] = MODINFO_METADATA | MODINFOMD_DTBP; + fake_preload[i++] = sizeof(uint32_t); + fake_preload[i++] = (uint32_t)lastaddr; + memmove((void *)lastaddr, dtb_ptr, dtb_size); + lastaddr += dtb_size; + lastaddr = roundup(lastaddr, sizeof(int)); + } fake_preload[i++] = 0; fake_preload[i] = 0; preload_metadata = (void *)fake_preload; @@ -1023,20 +1035,35 @@ linux_parse_boot_param(struct arm_boot_params *abp) struct arm_lbabi_tag *walker; uint32_t revision; uint64_t serial; +#ifdef FDT + struct fdt_header *dtb_ptr; + uint32_t dtb_size; +#endif /* * Linux boot ABI: r0 = 0, r1 is the board type (!= 0) and r2 * is atags or dtb pointer. If all of these aren't satisfied, - * then punt. + * then punt. Unfortunately, it looks like DT enabled kernels + * doesn't uses board type and U-Boot delivers 0 in r1 for them. */ - if (!(abp->abp_r0 == 0 && abp->abp_r1 != 0 && abp->abp_r2 != 0)) - return 0; + if (abp->abp_r0 != 0 || abp->abp_r2 == 0) + return (0); +#ifdef FDT + /* Test if r2 point to valid DTB. */ + dtb_ptr = (struct fdt_header *)abp->abp_r2; + if (fdt_check_header(dtb_ptr) == 0) { + dtb_size = fdt_totalsize(dtb_ptr); + return (fake_preload_metadata(abp, dtb_ptr, dtb_size)); + } +#endif + /* Old, ATAG based boot must have board type set. */ + if (abp->abp_r1 == 0) + return (0); board_id = abp->abp_r1; walker = (struct arm_lbabi_tag *) (abp->abp_r2 + KERNVIRTADDR - abp->abp_physaddr); - /* xxx - Need to also look for binary device tree */ if (ATAG_TAG(walker) != ATAG_CORE) return 0; @@ -1077,7 +1104,7 @@ linux_parse_boot_param(struct arm_boot_params *abp) init_static_kenv(NULL, 0); - return fake_preload_metadata(abp); + return fake_preload_metadata(abp, NULL, 0); } #endif @@ -1135,7 +1162,7 @@ default_parse_boot_param(struct arm_boot_params *abp) return lastaddr; #endif /* Fall back to hardcoded metadata. */ - lastaddr = fake_preload_metadata(abp); + lastaddr = fake_preload_metadata(abp, NULL, 0); return lastaddr; } diff --git a/sys/arm/at91/board_tsc4370.c b/sys/arm/at91/board_tsc4370.c index 1bc0426878ba..9c0658bac387 100644 --- a/sys/arm/at91/board_tsc4370.c +++ b/sys/arm/at91/board_tsc4370.c @@ -601,7 +601,7 @@ parse_boot_param(struct arm_boot_params *abp) inkernel_bootinfo = *(struct tsc_bootinfo *)(abp->abp_r1); } - return fake_preload_metadata(abp); + return fake_preload_metadata(abp, NULL, 0); } ARM_BOARD(NONE, "TSC4370 Controller Board"); diff --git a/sys/arm/conf/TEGRA124 b/sys/arm/conf/TEGRA124 index 7323ef89616d..1b3ec3f63e53 100644 --- a/sys/arm/conf/TEGRA124 +++ b/sys/arm/conf/TEGRA124 @@ -28,6 +28,7 @@ options SCHED_ULE # ULE scheduler options PLATFORM # Platform based SoC options PLATFORM_SMP options SMP # Enable multiple cores +options LINUX_BOOT_ABI # Debugging for use in -current makeoptions DEBUG=-g # Build kernel with gdb(1) debug symbols diff --git a/sys/arm/include/machdep.h b/sys/arm/include/machdep.h index 36c2f44daed9..b156efe3c431 100644 --- a/sys/arm/include/machdep.h +++ b/sys/arm/include/machdep.h @@ -37,7 +37,8 @@ struct arm_boot_params; vm_offset_t default_parse_boot_param(struct arm_boot_params *abp); vm_offset_t freebsd_parse_boot_param(struct arm_boot_params *abp); vm_offset_t linux_parse_boot_param(struct arm_boot_params *abp); -vm_offset_t fake_preload_metadata(struct arm_boot_params *abp); +vm_offset_t fake_preload_metadata(struct arm_boot_params *abp, + void *dtb_ptr, size_t dtb_size); vm_offset_t parse_boot_param(struct arm_boot_params *abp); void arm_generic_initclocks(void);