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.
This commit is contained in:
mmel 2016-03-26 06:55:55 +00:00
parent 991d92a87e
commit fdc6e45633
4 changed files with 38 additions and 9 deletions

View File

@ -115,6 +115,7 @@ __FBSDID("$FreeBSD$");
#include <machine/sysarch.h> #include <machine/sysarch.h>
#ifdef FDT #ifdef FDT
#include <contrib/libfdt/libfdt.h>
#include <dev/fdt/fdt_common.h> #include <dev/fdt/fdt_common.h>
#include <dev/ofw/openfirm.h> #include <dev/ofw/openfirm.h>
#endif #endif
@ -959,7 +960,8 @@ makectx(struct trapframe *tf, struct pcb *pcb)
* Fake up a boot descriptor table * Fake up a boot descriptor table
*/ */
vm_offset_t 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 #ifdef DDB
vm_offset_t zstart = 0, zend = 0; vm_offset_t zstart = 0, zend = 0;
@ -997,6 +999,16 @@ fake_preload_metadata(struct arm_boot_params *abp __unused)
} else } else
#endif #endif
lastaddr = (vm_offset_t)&end; 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;
fake_preload[i] = 0; fake_preload[i] = 0;
preload_metadata = (void *)fake_preload; preload_metadata = (void *)fake_preload;
@ -1023,20 +1035,35 @@ linux_parse_boot_param(struct arm_boot_params *abp)
struct arm_lbabi_tag *walker; struct arm_lbabi_tag *walker;
uint32_t revision; uint32_t revision;
uint64_t serial; 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 * 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, * 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)) if (abp->abp_r0 != 0 || abp->abp_r2 == 0)
return 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; board_id = abp->abp_r1;
walker = (struct arm_lbabi_tag *) walker = (struct arm_lbabi_tag *)
(abp->abp_r2 + KERNVIRTADDR - abp->abp_physaddr); (abp->abp_r2 + KERNVIRTADDR - abp->abp_physaddr);
/* xxx - Need to also look for binary device tree */
if (ATAG_TAG(walker) != ATAG_CORE) if (ATAG_TAG(walker) != ATAG_CORE)
return 0; return 0;
@ -1077,7 +1104,7 @@ linux_parse_boot_param(struct arm_boot_params *abp)
init_static_kenv(NULL, 0); init_static_kenv(NULL, 0);
return fake_preload_metadata(abp); return fake_preload_metadata(abp, NULL, 0);
} }
#endif #endif
@ -1135,7 +1162,7 @@ default_parse_boot_param(struct arm_boot_params *abp)
return lastaddr; return lastaddr;
#endif #endif
/* Fall back to hardcoded metadata. */ /* Fall back to hardcoded metadata. */
lastaddr = fake_preload_metadata(abp); lastaddr = fake_preload_metadata(abp, NULL, 0);
return lastaddr; return lastaddr;
} }

View File

@ -601,7 +601,7 @@ parse_boot_param(struct arm_boot_params *abp)
inkernel_bootinfo = *(struct tsc_bootinfo *)(abp->abp_r1); 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"); ARM_BOARD(NONE, "TSC4370 Controller Board");

View File

@ -28,6 +28,7 @@ options SCHED_ULE # ULE scheduler
options PLATFORM # Platform based SoC options PLATFORM # Platform based SoC
options PLATFORM_SMP options PLATFORM_SMP
options SMP # Enable multiple cores options SMP # Enable multiple cores
options LINUX_BOOT_ABI
# Debugging for use in -current # Debugging for use in -current
makeoptions DEBUG=-g # Build kernel with gdb(1) debug symbols makeoptions DEBUG=-g # Build kernel with gdb(1) debug symbols

View File

@ -37,7 +37,8 @@ struct arm_boot_params;
vm_offset_t default_parse_boot_param(struct arm_boot_params *abp); 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 freebsd_parse_boot_param(struct arm_boot_params *abp);
vm_offset_t linux_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); vm_offset_t parse_boot_param(struct arm_boot_params *abp);
void arm_generic_initclocks(void); void arm_generic_initclocks(void);