[vim3][zircon] Initial support for Zircon
Change-Id: I7d918d131f2391fd7cba36b9ac6096c3879fdbb6
diff --git a/.gitignore b/.gitignore
index ed6fb60..d59cffc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -23,6 +23,8 @@
*.tpl
*.efuse
*.encrypt
+*.bin
+*.bl2
# folder
customer/
diff --git a/arch/arm/lib/bootm.c b/arch/arm/lib/bootm.c
index 934b2b3..464252a 100644
--- a/arch/arm/lib/bootm.c
+++ b/arch/arm/lib/bootm.c
@@ -30,6 +30,10 @@
#include <asm/armv7.h>
#endif
+#if defined(CONFIG_ZIRCON_BOOT_IMAGE)
+#include <zircon/zircon.h>
+#endif
+
DECLARE_GLOBAL_DATA_PTR;
static struct tag *params;
@@ -281,10 +285,11 @@
do_nonsec_virt_switch();
gd->flags &= ~GD_FLG_SILENT;
printf("uboot time: %u us\n", get_time());
- if (images->os.arch == IH_ARCH_ARM)
+ if (images->os.arch == IH_ARCH_ARM) {
jump_to_a32_kernel(images->ep, machid, (unsigned long)images->ft_addr);
- else
+ } else {
kernel_entry(images->ft_addr, NULL, NULL, NULL);
+ }
}
#else
unsigned long machid = gd->bd->bi_arch_number;
@@ -406,3 +411,43 @@
((void (*)(void *))images->ep)(images->ft_addr);
}
#endif
+
+#if defined(CONFIG_ZIRCON_BOOT_IMAGE)
+
+#define ZIRCON_KERNEL_ALIGN 65536
+
+int do_bootm_zircon(int flag, int argc, char * const argv[],
+ bootm_headers_t *images)
+{
+ zbi_header_t* zbi = (zbi_header_t *)images->ep;
+ const zbi_header_t* kernel_hdr = &zbi[1];
+ const zbi_kernel_t* kernel = (zbi_kernel_t *)&zbi[2];
+
+ int ret = zircon_preboot(zbi);
+ if (ret < 0) {
+ printf("zircon_preboot failed\n");
+ return ret;
+ }
+
+ uint32_t zbi_len = zbi->length + sizeof(zbi_header_t);
+ uint32_t kernel_len = kernel_hdr->length + 2 * sizeof(zbi_header_t);
+
+ // If zbi_len is greater than kernel_len,
+ // then we have boot items after the kernel.
+ // In that case we must relocate the kernel after the zbi
+ if (zbi_len > kernel_len) {
+ uintptr_t dest = (ulong)zbi + zbi_len;
+ // align to 64K boundary
+ dest = (dest + ZIRCON_KERNEL_ALIGN - 1) & ~(ZIRCON_KERNEL_ALIGN - 1);
+ memcpy((void *)dest, zbi, kernel_len);
+ images->ep = dest + kernel->entry;
+ } else {
+ images->ep = (ulong)zbi + kernel->entry;
+ }
+
+ // this will pass the zbi pointer to the kernel via x0
+ images->ft_addr = (char *)zbi;
+ boot_jump_linux(images, flag);
+ return 0;
+}
+#endif
diff --git a/board/khadas/Kconfig b/board/khadas/Kconfig
index 99beaa2..979467c 100644
--- a/board/khadas/Kconfig
+++ b/board/khadas/Kconfig
@@ -10,6 +10,10 @@
bool "Support Khadas VIM3L board"
default n
+config ZIRCON_BOOT_IMAGE
+ bool "Build Zircon compatible boot image"
+ default n
+
if KHADAS_VIM
source "board/khadas/kvim/Kconfig"
endif
diff --git a/board/khadas/defconfigs/kvim3_zircon_defconfig b/board/khadas/defconfigs/kvim3_zircon_defconfig
new file mode 100644
index 0000000..2cd1803
--- /dev/null
+++ b/board/khadas/defconfigs/kvim3_zircon_defconfig
@@ -0,0 +1,7 @@
+CONFIG_ARM=y
+CONFIG_TARGET_MESON_G12B=y
+CONFIG_KHADAS_VIM3=y
+CONFIG_DM=y
+CONFIG_DM_GPIO=y
+CONFIG_AML_GPIO=y
+CONFIG_ZIRCON_BOOT_IMAGE=y
diff --git a/board/khadas/kvim3/Makefile b/board/khadas/kvim3/Makefile
index fb7f59a..0daf279 100644
--- a/board/khadas/kvim3/Makefile
+++ b/board/khadas/kvim3/Makefile
@@ -1,3 +1,4 @@
obj-y += $(BOARD).o eth_setup.o
+obj-$(CONFIG_ZIRCON_BOOT_IMAGE) += zircon.o
obj-$(CONFIG_AML_LCD) += lcd.o
diff --git a/board/khadas/kvim3/zircon.c b/board/khadas/kvim3/zircon.c
new file mode 100644
index 0000000..a3a747c
--- /dev/null
+++ b/board/khadas/kvim3/zircon.c
@@ -0,0 +1,574 @@
+/*
+ * Copyright (c) 2018 The Fuchsia Authors
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <aml_i2c.h>
+#include <asm/arch/secure_apb.h>
+#include <common.h>
+#include <part.h>
+#include <zircon/zircon.h>
+
+#define PDEV_VID_KHADAS 4
+#define PDEV_PID_VIM2 2
+#define PDEV_PID_VIM3 3
+
+#define NVRAM_LENGTH (1024 * 1024)
+
+#define CMDLINE_ENTROPY_SIZE 1024
+#define CMDLINE_ENTROPY_BITS 256 // random bits to pass to zircon.
+
+#define ENTROPY_BITS_PER_CHAR 4
+
+static char entropy_cmdline[CMDLINE_ENTROPY_SIZE] = {0};
+static const char zircon_entropy_arg[] = "kernel.entropy-mixin=";
+
+#define static_assert _Static_assert
+static_assert(CMDLINE_ENTROPY_BITS % 32 == 0,
+ "Requested entropy must be a multiple of 32");
+
+static_assert((CMDLINE_ENTROPY_BITS/ENTROPY_BITS_PER_CHAR) \
+ + sizeof(zircon_entropy_arg) < CMDLINE_ENTROPY_SIZE,
+ "Requested entropy doesn't fit in cmdline.");
+
+static const char BOOTLOADER_VERSION[] = "zircon-bootloader=0.12";
+
+
+static const zbi_cpu_config_t cpu_config = {
+ .cluster_count = 2,
+ .clusters = {
+ {
+ .cpu_count = 2,
+ },
+ {
+ .cpu_count = 4,
+ },
+ },
+};
+
+static zbi_mem_range_t mem_config[] = {
+ {
+ .type = ZBI_MEM_RANGE_RAM,
+ .length = 0x80000000,
+ },
+ {
+ .type = ZBI_MEM_RANGE_PERIPHERAL,
+ .paddr = 0xfe000000,
+ .length = 0x02000000,
+ },
+ {
+ .type = ZBI_MEM_RANGE_RESERVED,
+ .paddr = 0x07400000,
+ .length = 0x00100000,
+ },
+ {
+ .type = ZBI_MEM_RANGE_RESERVED,
+ .paddr = 0x05000000,
+ .length = 0x02300000,
+ },
+};
+
+static const dcfg_simple_t uart_driver = {
+ .mmio_phys = 0xff803000,
+ .irq = 225,
+};
+
+static const dcfg_arm_gicv2_driver_t gicv2_driver = {
+ .mmio_phys = 0xffc00000,
+ .gicd_offset = 0x1000,
+ .gicc_offset = 0x2000,
+ .gich_offset = 0x4000,
+ .gicv_offset = 0x6000,
+ .ipi_base = 5,
+};
+
+static const dcfg_arm_psci_driver_t psci_driver = {
+ .use_hvc = false,
+ .reboot_args = { 1, 0, 0 },
+ .reboot_bootloader_args = { 4, 0, 0 },
+ .reboot_recovery_args = { 2, 0, 0 },
+};
+
+static const dcfg_arm_generic_timer_driver_t timer_driver = {
+ .irq_phys = 30,
+};
+
+static const dcfg_amlogic_hdcp_driver_t hdcp_driver = {
+ .preset_phys = 0xc1104000,
+ .hiu_phys = 0xc883c000,
+ .hdmitx_phys = 0xc883a000,
+};
+
+static const zbi_platform_id_t platform_id = {
+ .vid = PDEV_VID_KHADAS,
+ .pid = PDEV_PID_VIM3,
+ .board_name = "vim3",
+};
+
+enum {
+ PART_BOOTLOADER,
+ PART_ZIRCON_A,
+ PART_ZIRCON_B,
+ PART_ZIRCON_R,
+ PART_SYS_CONFIG,
+ PART_FACTORY_CONFIG,
+ PART_FVM,
+ PART_COUNT,
+};
+
+static zbi_partition_map_t partition_map = {
+ // .block_count filled in below
+ // .block_size filled in below
+ .guid = {},
+ .partition_count = PART_COUNT,
+ .partitions = {
+ {
+ .type_guid = GUID_BOOTLOADER_VALUE,
+ .uniq_guid = {},
+ // .first_block filled in below
+ // .last_block filled in below
+ .flags = 0,
+ .name = "bootloader",
+ },
+ {
+ .type_guid = GUID_ZIRCON_A_VALUE,
+ .uniq_guid = {},
+ // .first_block filled in below
+ // .last_block filled in below
+ .flags = 0,
+ .name = "zircon-a",
+ },
+ {
+ .type_guid = GUID_ZIRCON_B_VALUE,
+ .uniq_guid = {},
+ // .first_block filled in below
+ // .last_block filled in below
+ .flags = 0,
+ .name = "zircon-b",
+ },
+ {
+ .type_guid = GUID_ZIRCON_R_VALUE,
+ .uniq_guid = {},
+ // .first_block filled in below
+ // .last_block filled in below
+ .flags = 0,
+ .name = "zircon-r",
+ },
+ {
+ .type_guid = GUID_SYS_CONFIG_VALUE,
+ .uniq_guid = {},
+ // .first_block filled in below
+ // .last_block filled in below
+ .flags = 0,
+ .name = "sys-config",
+ },
+ {
+ .type_guid = GUID_FACTORY_CONFIG_VALUE,
+ .uniq_guid = {},
+ // .first_block filled in below
+ // .last_block filled in below
+ .flags = 0,
+ .name = "factory",
+ },
+ {
+ .type_guid = GUID_FVM_VALUE,
+ .uniq_guid = {},
+ // .first_block filled in below
+ // .last_block filled in below
+ .flags = 0,
+ .name = "fvm",
+ },
+ },
+};
+
+static void add_board_info(zbi_header_t* zbi)
+{
+ zbi_board_info_t board_info = {};
+ char* s;
+ if (((s = getenv("hw_id")) != NULL) && (*s != '\0')) {
+ uint32_t hw_id = simple_strtoul(s, NULL, 16);
+ board_info.revision = hw_id;
+ } else {
+ printf("Failed to retrieve Board Revision\n");
+ }
+
+ zircon_append_boot_item(zbi, ZBI_TYPE_DRV_BOARD_INFO, 0, &board_info,
+ sizeof(board_info));
+}
+
+static void* mandatory_memset(void* dst, int c, size_t n) {
+ volatile unsigned char* out = dst;
+ size_t i = 0;
+
+ for (i = 0; i < n; ++i) {
+ out[i] = (unsigned char)c;
+ }
+ return dst;
+}
+
+// Define a cpu topology for the system that captures how all of the cores are
+// connected and grouped. Since this is a GICv2 system we include the ID for the
+// cores, especially since it is a tricky one with a gap between the little and
+// big clusters.
+static void add_cpu_topology(zbi_header_t* zbi)
+{
+ int index = 0;
+ int logical_processor = 0;
+ int big_cluster = 0, little_cluster = 0;
+ zbi_topology_node_t nodes[8];
+ little_cluster = index++;
+ nodes[little_cluster] = (zbi_topology_node_t){
+ .entity_type = ZBI_TOPOLOGY_ENTITY_CLUSTER,
+ .parent_index = ZBI_TOPOLOGY_NO_PARENT,
+ .entity = {
+ .cluster = {
+ .performance_class = 0, // low performance cluster
+ }
+ }
+ };
+ nodes[index++] = (zbi_topology_node_t){
+ .entity_type = ZBI_TOPOLOGY_ENTITY_PROCESSOR,
+ .parent_index = little_cluster,
+ .entity = {
+ .processor = {
+ .logical_ids = {logical_processor++},
+ .logical_id_count = 1,
+ .flags = ZBI_TOPOLOGY_PROCESSOR_PRIMARY,
+ .architecture = ZBI_TOPOLOGY_ARCH_ARM,
+ .architecture_info = {
+ .arm = {
+ .cluster_1_id = 0,
+ .cpu_id = 0,
+ .gic_id = 0,
+ }
+ }
+ }
+ }
+ };
+ nodes[index++] = (zbi_topology_node_t){
+ .entity_type = ZBI_TOPOLOGY_ENTITY_PROCESSOR,
+ .parent_index = little_cluster,
+ .entity = {
+ .processor = {
+ .logical_ids = {logical_processor++},
+ .logical_id_count = 1,
+ .flags = 0,
+ .architecture = ZBI_TOPOLOGY_ARCH_ARM,
+ .architecture_info = {
+ .arm = {
+ .cluster_1_id = 0,
+ .cpu_id = 1,
+ .gic_id = 1,
+ }
+ }
+ }
+ }
+ };
+ big_cluster = index++;
+ nodes[big_cluster] = (zbi_topology_node_t){
+ .entity_type = ZBI_TOPOLOGY_ENTITY_CLUSTER,
+ .parent_index = ZBI_TOPOLOGY_NO_PARENT,
+ .entity = {
+ .cluster = {
+ .performance_class = 1, // high performance cluster
+ }
+ }
+ };
+ nodes[index++] = (zbi_topology_node_t){
+ .entity_type = ZBI_TOPOLOGY_ENTITY_PROCESSOR,
+ .parent_index = big_cluster,
+ .entity = {
+ .processor = {
+ .logical_ids = {logical_processor++},
+ .logical_id_count = 1,
+ .flags = 0,
+ .architecture = ZBI_TOPOLOGY_ARCH_ARM,
+ .architecture_info = {
+ .arm = {
+ .cluster_1_id = 1,
+ .cpu_id = 0,
+ .gic_id = 4,
+ }
+ }
+ }
+ }
+ };
+ nodes[index++] = (zbi_topology_node_t){
+ .entity_type = ZBI_TOPOLOGY_ENTITY_PROCESSOR,
+ .parent_index = big_cluster,
+ .entity = {
+ .processor = {
+ .logical_ids = {logical_processor++},
+ .logical_id_count = 1,
+ .flags = 0,
+ .architecture = ZBI_TOPOLOGY_ARCH_ARM,
+ .architecture_info = {
+ .arm = {
+ .cluster_1_id = 1,
+ .cpu_id = 1,
+ .gic_id = 5,
+ }
+ }
+ }
+ }
+ };
+ nodes[index++] = (zbi_topology_node_t){
+ .entity_type = ZBI_TOPOLOGY_ENTITY_PROCESSOR,
+ .parent_index = big_cluster,
+ .entity = {
+ .processor = {
+ .logical_ids = {logical_processor++},
+ .logical_id_count = 1,
+ .flags = 0,
+ .architecture = ZBI_TOPOLOGY_ARCH_ARM,
+ .architecture_info = {
+ .arm = {
+ .cluster_1_id = 1,
+ .cpu_id = 2,
+ .gic_id = 6,
+ }
+ }
+ }
+ }
+ };
+ nodes[index++] = (zbi_topology_node_t){
+ .entity_type = ZBI_TOPOLOGY_ENTITY_PROCESSOR,
+ .parent_index = big_cluster,
+ .entity = {
+ .processor = {
+ .logical_ids = {logical_processor++},
+ .logical_id_count = 1,
+ .flags = 0,
+ .architecture = ZBI_TOPOLOGY_ARCH_ARM,
+ .architecture_info = {
+ .arm = {
+ .cluster_1_id = 1,
+ .cpu_id = 3,
+ .gic_id = 7,
+ }
+ }
+ }
+ }
+ };
+ zircon_append_boot_item(zbi, ZBI_TYPE_CPU_TOPOLOGY, sizeof(zbi_topology_node_t),
+ &nodes, sizeof(zbi_topology_node_t) * index);
+}
+
+static void add_partition_map(zbi_header_t* zbi) {
+ block_dev_desc_t* dev_desc;
+ disk_partition_t bootloader_info;
+ disk_partition_t boot_info;
+ disk_partition_t misc_info;
+ disk_partition_t recovery_info;
+ disk_partition_t tee_info;
+ //disk_partition_t crypt_info;
+ disk_partition_t system_info;
+ disk_partition_t data_info;
+
+ dev_desc = get_dev("mmc", CONFIG_FASTBOOT_FLASH_MMC_DEV);
+ if (!dev_desc || dev_desc->type == DEV_TYPE_UNKNOWN) {
+ printf("could not find MMC device for partition map\n");
+ return;
+ }
+
+ if (get_partition_info_aml_by_name(dev_desc, "bootloader", &bootloader_info)) {
+ printf("could not find bootloader partition\n");
+ return;
+ }
+ if (get_partition_info_aml_by_name(dev_desc, "boot", &boot_info)) {
+ printf("could not find boot partition\n");
+ return;
+ }
+ if (get_partition_info_aml_by_name(dev_desc, "misc", &misc_info)) {
+ printf("could not find misc partition\n");
+ return;
+ }
+ if (get_partition_info_aml_by_name(dev_desc, "recovery", &recovery_info)) {
+ printf("could not find recovery partition\n");
+ return;
+ }
+ if (get_partition_info_aml_by_name(dev_desc, "tee", &tee_info)) {
+ printf("could not find tee partition\n");
+ return;
+ }
+#if 0
+ if (get_partition_info_aml_by_name(dev_desc, "crypt", &crypt_info)) {
+ printf("could not find crypt partition\n");
+ return;
+ }
+ printf("Got crypt\n");
+#endif
+ if (get_partition_info_aml_by_name(dev_desc, "system", &system_info)) {
+ printf("could not find system partition\n");
+ return;
+ }
+ if (get_partition_info_aml_by_name(dev_desc, "data", &data_info)) {
+ printf("could not find data partition\n");
+ return;
+ }
+
+ // map bootloader partition to BOOTLOADER
+ partition_map.partitions[PART_BOOTLOADER].first_block = bootloader_info.start;
+ partition_map.partitions[PART_BOOTLOADER].last_block = bootloader_info.start +
+ bootloader_info.size - 1;
+
+ // map boot partition to ZIRCON_A
+ partition_map.partitions[PART_ZIRCON_A].first_block = boot_info.start;
+ partition_map.partitions[PART_ZIRCON_A].last_block = boot_info.start + boot_info.size - 1;
+
+ // map misc partition to ZIRCON_B
+ partition_map.partitions[PART_ZIRCON_B].first_block = misc_info.start;
+ partition_map.partitions[PART_ZIRCON_B].last_block = misc_info.start + misc_info.size - 1;
+
+ // map recovery partition to ZIRCON_R
+ partition_map.partitions[PART_ZIRCON_R].first_block = recovery_info.start;
+ partition_map.partitions[PART_ZIRCON_R].last_block = recovery_info.start +
+ recovery_info.size - 1;
+
+ // map tee partition to SYS_CONFIG
+ partition_map.partitions[PART_SYS_CONFIG].first_block = tee_info.start;
+ partition_map.partitions[PART_SYS_CONFIG].last_block = tee_info.start + tee_info.size - 1;
+#if 0
+ // map crypt partition to FACTORY_CONFIG
+ partition_map.partitions[PART_FACTORY_CONFIG].first_block = crypt_info.start;
+ partition_map.partitions[PART_FACTORY_CONFIG].last_block = crypt_info.start +
+ crypt_info.size - 1;
+#endif
+ // map system and data partitions to FVM
+ partition_map.partitions[PART_FVM].first_block = system_info.start;
+ partition_map.partitions[PART_FVM].last_block = data_info.start + data_info.size - 1;
+
+ partition_map.block_count = data_info.start + data_info.size;
+ partition_map.block_size = data_info.blksz;
+
+ zircon_append_boot_item(zbi, ZBI_TYPE_DRV_PARTITION_MAP, 0, &partition_map,
+ sizeof(zbi_partition_map_t) +
+ partition_map.partition_count * sizeof(zbi_partition_t));
+}
+
+static int hex_digit(char ch) {
+ if (ch >= '0' && ch <= '9') {
+ return ch - '0';
+ } else if (ch >= 'a' && ch <= 'f') {
+ return ch - 'a' + 10;
+ } else if (ch >= 'A' && ch <= 'F') {
+ return ch - 'A' + 10;
+ } else {
+ return -1;
+ }
+}
+
+static void add_eth_mac_address(zbi_header_t* zbi) {
+ char* str = getenv("eth_mac");
+ uint8_t addr[6];
+
+ // this would be easier with sscanf
+ int i;
+ for (i = 0; i < 6; i++) {
+ unsigned left, right;
+ if (str[0] && str[1] && (left = hex_digit(*str++)) >= 0 &&
+ (right = hex_digit(*str++)) >= 0) {
+ addr[i] = (left << 4) | right;
+ } else {
+ goto failed;
+ }
+ if (i < 5 && *str++ != ':') {
+ goto failed;
+ }
+ }
+
+ zircon_append_boot_item(zbi, ZBI_TYPE_DRV_MAC_ADDRESS, 0, addr, sizeof(addr));
+ return;
+
+failed:
+ printf("MAC address parsing failed for \"%s\"\n", getenv("eth_mac"));
+}
+
+// fills an 8 char buffer with the lowercase hex representation of the given
+// value.
+// WARNING this does not add a '\0' to the end of the buffer.
+static inline void uint32_to_hex(uint32_t val, char buf[static 8]) {
+ static const char hex[] = "0123456789abcdef";
+ int i = 0;
+
+ for (i = 7; i >= 0; i--) {
+ buf[i] = hex[val & 0xF];
+ val >>= 4;
+ }
+}
+
+// Reads a value from the userspace hardware random number generator.
+// NOTE that there is no guarantee of the quality of this rng.
+static inline uint32_t read_hw_rng(void) {
+ return readl(RNG_USR_DATA);
+}
+
+static void add_cmdline_entropy(zbi_header_t* zbi) {
+ strcpy(entropy_cmdline, zircon_entropy_arg);
+ char *entropy = entropy_cmdline + strlen(zircon_entropy_arg);
+ int i = 0;
+
+ for (i = 0; i < CMDLINE_ENTROPY_BITS; i += 32) {
+ uint32_to_hex(read_hw_rng(), entropy);
+ entropy += 8;
+ }
+ *entropy = '\0';
+
+ zircon_append_boot_item(zbi, ZBI_TYPE_CMDLINE, 0, entropy_cmdline,
+ sizeof(entropy_cmdline));
+
+ mandatory_memset(entropy_cmdline, '\0', sizeof(entropy_cmdline));
+}
+
+int zircon_preboot(zbi_header_t* zbi) {
+
+#if 0 //Deprecated cpu topology descripiton
+ zircon_append_boot_item(zbi, ZBI_TYPE_CPU_CONFIG, 0, &cpu_config,
+ sizeof(zbi_cpu_config_t) +
+ sizeof(zbi_cpu_cluster_t) * cpu_config.cluster_count);
+ printf("Appended ZBI_TYPE_CPU_CONFIG - %x\n",zbi->length);
+#endif
+ //TODO - vim3 does not define a ddr_size env variable. Since there are two
+ // variants of vim3, need to figure out how to figure this out from u-boot
+ const char* ddr_size = getenv("ddr_size");
+ if (!strcmp(ddr_size, "3")) {
+ mem_config[0].length = 0xc0000000;
+ }
+
+#if 0 //TOOD - find the nvram location in memory map
+ // allocate crashlog save area at end of RAM
+ zbi_nvram_t nvram;
+ nvram.base = mem_config[0].length - NVRAM_LENGTH;
+ nvram.length = NVRAM_LENGTH;
+ zircon_append_boot_item(zbi, ZBI_TYPE_NVRAM, 0, &nvram, sizeof(nvram));
+ printf("Appended ZBI_TYPE_NVRAM - %x\n",zbi->length);
+#endif
+ // add memory configuration
+ zircon_append_boot_item(zbi, ZBI_TYPE_MEM_CONFIG, 0, &mem_config, sizeof(mem_config));
+
+ // add kernel drivers
+ zircon_append_boot_item(zbi, ZBI_TYPE_KERNEL_DRIVER, KDRV_AMLOGIC_UART, &uart_driver,
+ sizeof(uart_driver));
+ zircon_append_boot_item(zbi, ZBI_TYPE_KERNEL_DRIVER, KDRV_ARM_GIC_V2, &gicv2_driver,
+ sizeof(gicv2_driver));
+ zircon_append_boot_item(zbi, ZBI_TYPE_KERNEL_DRIVER, KDRV_ARM_PSCI, &psci_driver,
+ sizeof(psci_driver));
+ zircon_append_boot_item(zbi, ZBI_TYPE_KERNEL_DRIVER, KDRV_ARM_GENERIC_TIMER, &timer_driver,
+ sizeof(timer_driver));
+ //zircon_append_boot_item(zbi, ZBI_TYPE_KERNEL_DRIVER, KDRV_AMLOGIC_HDCP, &hdcp_driver,
+ // sizeof(hdcp_driver));
+
+ zircon_append_boot_item(zbi, ZBI_TYPE_CMDLINE, 0, BOOTLOADER_VERSION,
+ strlen(BOOTLOADER_VERSION) + 1);
+
+ // add platform ID
+ zircon_append_boot_item(zbi, ZBI_TYPE_PLATFORM_ID, 0, &platform_id, sizeof(platform_id));
+
+ add_board_info(zbi);
+ add_cmdline_entropy(zbi);
+ add_partition_map(zbi);
+ add_cpu_topology(zbi);
+ add_eth_mac_address(zbi);
+ return 0;
+ }
diff --git a/common/Makefile b/common/Makefile
index f0a89e3..94376d2 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -303,6 +303,7 @@
endif
obj-y += image.o
obj-$(CONFIG_ANDROID_BOOT_IMAGE) += image-android.o
+obj-$(CONFIG_ZIRCON_BOOT_IMAGE) += image-zircon.o
obj-$(CONFIG_OF_LIBFDT) += image-fdt.o
obj-$(CONFIG_FIT) += image-fit.o
obj-$(CONFIG_FIT_SIGNATURE) += image-sig.o
@@ -360,4 +361,7 @@
# khadas commands
obj-$(CONFIG_KHADAS_KBI) += cmd_kbi.o
+# zircon commands
+obj-$(CONFIG_ZIRCON_BOOT_IMAGE) += cmd_zircon_bootconfig.o
+
CFLAGS_env_embedded.o := -Wa,--no-warn -DENV_CRC=$(shell tools/envcrc 2>/dev/null)
diff --git a/common/bootm.c b/common/bootm.c
index 0951804..2878311 100644
--- a/common/bootm.c
+++ b/common/bootm.c
@@ -201,6 +201,19 @@
ep_found = true;
break;
#endif
+#ifdef CONFIG_ZIRCON_BOOT_IMAGE
+ case IMAGE_FORMAT_ZIRCON:
+ images.os.type = IH_TYPE_KERNEL;
+ images.os.comp = zircon_image_get_comp(os_hdr);
+ images.os.os = IH_OS_ZIRCON;
+ images.os.end = zircon_image_get_end(os_hdr);
+ images.os.load = zircon_image_get_kload(os_hdr);
+ if (images.os.load == 0x10008000)
+ images.os.load = 0x1080000;
+ images.ep = images.os.load;
+ ep_found = true;
+ break;
+#endif
default:
puts("ERROR: unknown image format type!\n");
return 1;
@@ -669,6 +682,10 @@
blob_start, blob_end);
debug("images.os.load = 0x%lx, load_end = 0x%lx\n", load,
*load_end);
+ if (os.os == IH_OS_ZIRCON) {
+ /* no further checking is necessary */
+ return 0;
+ }
#ifndef CONFIG_ANDROID_BOOT_IMAGE
/* Check what type of image this is. */
if (images->legacy_hdr_valid) {
@@ -881,22 +898,24 @@
}
#endif
- /* Check reserved memory region */
+ if (images->os.os != IH_OS_ZIRCON) {
+ /* Check reserved memory region */
#ifdef CONFIG_CMD_RSVMEM
- ret = run_command("rsvmem check", 0);
- if (ret) {
- puts("rsvmem check failed\n");
- return ret;
- }
+ ret = run_command("rsvmem check", 0);
+ if (ret) {
+ puts("rsvmem check failed\n");
+ return ret;
+ }
#endif
#if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_LMB)
- if (!ret && (states & BOOTM_STATE_FDT)) {
- boot_fdt_add_mem_rsv_regions(&images->lmb, images->ft_addr);
- ret = boot_relocate_fdt(&images->lmb, &images->ft_addr,
- &images->ft_len);
- }
+ if (!ret && (states & BOOTM_STATE_FDT)) {
+ boot_fdt_add_mem_rsv_regions(&images->lmb, images->ft_addr);
+ ret = boot_relocate_fdt(&images->lmb, &images->ft_addr,
+ &images->ft_len);
+ }
#endif
+ }
/* From now on, we need the OS boot function */
if (ret)
@@ -1144,7 +1163,15 @@
}
#endif
}
-
+ break;
+#endif
+#ifdef CONFIG_ZIRCON_BOOT_IMAGE
+ case IMAGE_FORMAT_ZIRCON:
+ printf("## Booting Zircon Image at 0x%08lx ...\n", img_addr);
+ buf = map_sysmem(img_addr, 0);
+ if (zircon_image_get_kernel(buf, images->verify,
+ os_data, os_len))
+ return NULL;
break;
#endif
default:
diff --git a/common/bootm_os.c b/common/bootm_os.c
index 5be4467..4c04d6c 100644
--- a/common/bootm_os.c
+++ b/common/bootm_os.c
@@ -434,6 +434,9 @@
#ifdef CONFIG_INTEGRITY
[IH_OS_INTEGRITY] = do_bootm_integrity,
#endif
+#ifdef CONFIG_ZIRCON_BOOT_IMAGE
+ [IH_OS_ZIRCON] = do_bootm_zircon,
+#endif
};
/* Allow for arch specific config before we boot */
diff --git a/common/cmd_imgread.c b/common/cmd_imgread.c
index 1d685f6..e7a2001 100644
--- a/common/cmd_imgread.c
+++ b/common/cmd_imgread.c
@@ -23,6 +23,7 @@
#include <amlogic/storage_if.h>
#include <image.h>
#include <android_image.h>
+#include <zircon/image.h>
#include <asm/arch/bl31_apis.h>
#include <asm/arch/secure_apb.h>
#include <libfdt.h>
@@ -299,12 +300,18 @@
int genFmt = 0;
unsigned actualBootImgSz = 0;
unsigned dtbSz = 0;
- const char* const partName = argv[1];
+ const char* partName;
unsigned char* loadaddr = 0;
int rc = 0;
uint64_t flashReadOff = 0;
unsigned secureKernelImgSz = 0;
+ if (1 < argc) {
+ partName = argv[1];
+ } else {
+ partName = getenv("boot_part");
+ }
+
if (2 < argc) {
loadaddr = (unsigned char*)simple_strtoul(argv[2], NULL, 16);
}
@@ -330,35 +337,40 @@
}
flashReadOff += IMG_PRELOAD_SZ;
- if (!nCheckOffset)
+ genFmt = genimg_get_format(hdr_addr);
+ if (genFmt == IMAGE_FORMAT_ANDROID)
{
- genFmt = genimg_get_format(hdr_addr);
- if (IMAGE_FORMAT_ANDROID != genFmt) {
- errorP("Fmt unsupported!genFmt 0x%x != 0x%x\n", genFmt, IMAGE_FORMAT_ANDROID);
- return __LINE__;
- }
- }
-
- //Check if encrypted image
- rc = _aml_get_secure_boot_kernel_size(loadaddr, &secureKernelImgSz);
- if (rc) {
+ //Check if encrypted image
+ rc = _aml_get_secure_boot_kernel_size(loadaddr, &secureKernelImgSz);
+ if (rc) {
errorP("Fail in _aml_get_secure_boot_kernel_size, rc=%d\n", rc);
return __LINE__;
+ }
+ if (secureKernelImgSz)
+ {
+ actualBootImgSz = secureKernelImgSz;
+ MsgP("secureKernelImgSz=0x%x\n", actualBootImgSz);
+ }
+ else
+ {
+ kernel_size =(hdr_addr->kernel_size + (hdr_addr->page_size-1)+hdr_addr->page_size)&(~(hdr_addr->page_size -1));
+ ramdisk_size =(hdr_addr->ramdisk_size + (hdr_addr->page_size-1))&(~(hdr_addr->page_size -1));
+ dtbSz = hdr_addr->second_size;
+ actualBootImgSz = kernel_size + ramdisk_size + dtbSz;
+ debugP("kernel_size 0x%x, page_size 0x%x, totalSz 0x%x\n", hdr_addr->kernel_size, hdr_addr->page_size, kernel_size);
+ debugP("ramdisk_size 0x%x, totalSz 0x%x\n", hdr_addr->ramdisk_size, ramdisk_size);
+ debugP("dtbSz 0x%x, Total actualBootImgSz 0x%x\n", dtbSz, actualBootImgSz);
+ }
}
- if (secureKernelImgSz)
+ else if (genFmt == IMAGE_FORMAT_ZIRCON)
{
- actualBootImgSz = secureKernelImgSz + nCheckOffset;
- MsgP("secureKernelImgSz=0x%x\n", actualBootImgSz);
+ const zbi_header_t *zbi = (zbi_header_t*)hdr_addr;
+ actualBootImgSz = zbi->length + sizeof(*zbi);
}
else
{
- kernel_size =(hdr_addr->kernel_size + (hdr_addr->page_size-1)+hdr_addr->page_size)&(~(hdr_addr->page_size -1));
- ramdisk_size =(hdr_addr->ramdisk_size + (hdr_addr->page_size-1))&(~(hdr_addr->page_size -1));
- dtbSz = hdr_addr->second_size;
- actualBootImgSz = kernel_size + ramdisk_size + dtbSz;
- debugP("kernel_size 0x%x, page_size 0x%x, totalSz 0x%x\n", hdr_addr->kernel_size, hdr_addr->page_size, kernel_size);
- debugP("ramdisk_size 0x%x, totalSz 0x%x\n", hdr_addr->ramdisk_size, ramdisk_size);
- debugP("dtbSz 0x%x, Total actualBootImgSz 0x%x\n", dtbSz, actualBootImgSz);
+ errorP("Fmt unsupported!genFmt 0x%x != 0x%x or 0x%x\n", genFmt, IMAGE_FORMAT_ANDROID, IMAGE_FORMAT_ZIRCON);
+ return __LINE__;
}
if (actualBootImgSz > IMG_PRELOAD_SZ)
@@ -682,8 +694,8 @@
"Read the image from internal flash with actual size", //description
" argv: <imageType> <part_name> <loadaddr> \n" //usage
" - <image_type> Current support is kernel/res(ource).\n"
- "imgread kernel --- Read image in fomart IMAGE_FORMAT_ANDROID\n"
- "imgread dtb --- Read dtb in fomart IMAGE_FORMAT_ANDROID\n"
+ "imgread kernel --- Read image in format IMAGE_FORMAT_ANDROID or IMAGE_FORMAT_ZIRCON\n"
+ "imgread dtb --- Read dtb in format IMAGE_FORMAT_ANDROID\n"
"imgread res --- Read image packed by 'Amlogic resource packer'\n"
"imgread pic --- Read one picture from Amlogic logo"
" - e.g. \n"
diff --git a/common/cmd_zircon_bootconfig.c b/common/cmd_zircon_bootconfig.c
new file mode 100644
index 0000000..529b179
--- /dev/null
+++ b/common/cmd_zircon_bootconfig.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2018 The Fuchsia Authors
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common.h>
+#include <kvstore.h>
+#include <amlogic/storage_if.h>
+#include <zircon/sysconfig.h>
+
+static int do_zircon_bootconfig(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ const char* sysconfig;
+ const char* zircon_a;
+ const char* zircon_b;
+ const char* zircon_r;
+ const char* zircon_boot;
+ struct kvstore kvs;
+ int rc;
+
+ if (argc != 5) {
+ return -1;
+ }
+
+ sysconfig = argv[1];
+ zircon_a = argv[2];
+ zircon_b = argv[3];
+ zircon_r = argv[4];
+
+ uint8_t buffer[ZX_SYSCONFIG_KVSTORE_SIZE];
+
+ rc = kvs_load(&kvs, buffer, sizeof(buffer));
+ if (rc < 0) {
+ rc = store_read_ops((unsigned char*)sysconfig, buffer, ZX_SYSCONFIG_BOOT_DEFAULT_OFFSET,
+ sizeof(buffer));
+ if (rc) {
+ printf("do_sysconfig: store_read_ops failed for %s\n", sysconfig);
+ return 0;
+ }
+ rc = kvs_load(&kvs, buffer, sizeof(buffer));
+ if (rc < 0) {
+ printf("do_sysconfig: kvs_load failed for %s (%d)\n", sysconfig, rc);
+ return 0;
+ }
+ }
+
+ const char* boot_part = kvs_get(&kvs, "boot", NULL);
+ if (!boot_part) {
+ printf("boot partition not set\n");
+ return -1;
+ }
+ if (!strcmp(boot_part, "a")) {
+ zircon_boot = zircon_a;
+ } else if (!strcmp(boot_part, "b")) {
+ zircon_boot = zircon_b;
+ } else if (!strcmp(boot_part, "r")) {
+ zircon_boot = zircon_r;
+ } else {
+ printf("invalid boot partition %s, booting to recovery\n", boot_part);
+ zircon_boot = zircon_r;
+ }
+
+ printf("zircon_bootconfig setting boot_part to %s\n", zircon_boot);
+ setenv("boot_part", zircon_boot);
+
+ return 0;
+}
+
+U_BOOT_CMD(
+ zircon_bootconfig, 5, 0, do_zircon_bootconfig,
+ "sets Zircon boot partition based on information in sysconfig partition",
+ " argv: zircon_bootconfig <sysconfig partition> <Zircon-A partition> "
+ "<Zircon-B partition> <Zircon-R partition>\n"
+ " This command reads the Zircon boot configuration from partition <sysconfig partition>,\n"
+ " The environment variable \"boot_part\" is set to one of the partition names\n"
+ " <Zircon-A partition>, <Zircon-B partition> or <Zircon-R partition> based on the\n"
+ " configuration in the sysconfig partition.\n"
+);
diff --git a/common/image-zircon.c b/common/image-zircon.c
new file mode 100644
index 0000000..6aca451
--- /dev/null
+++ b/common/image-zircon.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2018 The Fuchsia Authors
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <image.h>
+#include <zircon/image.h>
+
+void zircon_append_boot_item(zbi_header_t* container, uint32_t type, uint32_t extra,
+ const void* payload, uint32_t length) {
+ zbi_header_t* dest = (zbi_header_t*)((uintptr_t)container + container->length + sizeof(zbi_header_t));
+
+ dest->type = type;
+ dest->length = length;
+ dest->extra = extra;
+ dest->flags = ZBI_FLAG_VERSION;
+ dest->reserved0 = 0;
+ dest->reserved1 = 0;
+ dest->magic = ZBI_ITEM_MAGIC;
+ dest->crc32 = ZBI_ITEM_NO_CRC32;
+
+ if (length) {
+ memcpy(dest + 1, payload, length);
+ }
+ length = ZBI_ALIGN(length + sizeof(zbi_header_t));
+ container->length += length;
+}
+
+int zircon_image_check_header(const void *hdr)
+{
+ const zbi_header_t* zbi = hdr;
+
+ return (zbi[0].type == ZBI_TYPE_CONTAINER &&
+ zbi[0].extra == ZBI_CONTAINER_MAGIC &&
+ zbi[0].magic == ZBI_ITEM_MAGIC &&
+ zbi[1].type == ZBI_TYPE_KERNEL_ARM64 &&
+ zbi[1].magic == ZBI_ITEM_MAGIC) ? 0 : -1;
+}
+
+/**
+ * zircon_image_get_kernel() - processes kernel part of Zircon bootdata
+ * @bootdata: Pointer to bootdata.
+ * @verify: Checksum verification flag. Currently unimplemented.
+ * @os_data: Pointer to a ulong variable, will hold os data start
+ * address.
+ * @os_len: Pointer to a ulong variable, will hold os data length.
+ *
+ * This function returns the os image's start address and length. Also,
+ * it appends the kernel command line to the bootargs env variable.
+ *
+ * Return: Zero, os start address and length on success,
+ * otherwise on failure.
+ */
+int zircon_image_get_kernel(const void* hdr, int verify,
+ ulong *os_data, ulong *os_len)
+{
+ if (zircon_image_check_header(hdr))
+ return -1;
+
+ const zbi_header_t* zbi = hdr;
+
+ *os_data = (ulong)zbi;
+ *os_len = zbi->length + sizeof(*zbi);
+ return 0;
+}
+
+ulong zircon_image_get_end(const void *hdr)
+{
+ const zbi_header_t* zbi = hdr;
+ return (ulong)hdr + zbi->length + sizeof(*zbi);
+}
+
+ulong zircon_image_get_kload(const void *hdr)
+{
+ return 0x1080000;
+}
+
+ulong zircon_image_get_comp(const void *hdr)
+{
+ return IH_COMP_NONE;
+}
diff --git a/common/image.c b/common/image.c
index 47d2751..6dcd160 100644
--- a/common/image.c
+++ b/common/image.c
@@ -743,6 +743,10 @@
if (android_image_check_header(img_addr) == 0)
return IMAGE_FORMAT_ANDROID;
#endif
+#ifdef CONFIG_ZIRCON_BOOT_IMAGE
+ if (zircon_image_check_header(img_addr) == 0)
+ return IMAGE_FORMAT_ZIRCON;
+#endif
return IMAGE_FORMAT_INVALID;
}
diff --git a/include/bootm.h b/include/bootm.h
index b3d1a62..1f0e8a6 100644
--- a/include/bootm.h
+++ b/include/bootm.h
@@ -36,6 +36,7 @@
bootm_headers_t *images);
extern boot_os_fn do_bootm_linux;
+extern boot_os_fn do_bootm_zircon;
int do_bootelf(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
void lynxkdi_boot(image_header_t *hdr);
diff --git a/include/image.h b/include/image.h
index 7425b14..cc0c261 100644
--- a/include/image.h
+++ b/include/image.h
@@ -152,6 +152,7 @@
#define IH_OS_INTEGRITY 21 /* INTEGRITY */
#define IH_OS_OSE 22 /* OSE */
#define IH_OS_PLAN9 23 /* Plan 9 */
+#define IH_OS_ZIRCON 24 /* Zircon */
/*
* CPU Architecture Codes (supported by Linux)
@@ -441,6 +442,7 @@
#endif
#define IMAGE_FORMAT_FIT 0x02 /* new, libfdt based format */
#define IMAGE_FORMAT_ANDROID 0x03 /* Android boot image */
+#define IMAGE_FORMAT_ZIRCON 0x04 /* Zircon boot image */
ulong genimg_get_kernel_addr_fit(char * const img_addr,
const char **fit_uname_config,
@@ -1085,4 +1087,15 @@
#endif /* CONFIG_ANDROID_BOOT_IMAGE */
+#if defined(CONFIG_ZIRCON_BOOT_IMAGE)
+struct andr_img_hdr;
+int zircon_image_check_header(const void *hdr);
+int zircon_image_get_kernel(const void* hdr, int verify,
+ ulong *os_data, ulong *os_len);
+ulong zircon_image_get_end(const void *hdr);
+ulong zircon_image_get_kload(const void *hdr);
+ulong zircon_image_get_comp(const void *hdr);
+#endif /* CONFIG_ZIRCON_BOOT_IMAGE */
+
+
#endif /* __IMAGE_H__ */
diff --git a/include/kvstore.h b/include/kvstore.h
new file mode 100644
index 0000000..af61aee
--- /dev/null
+++ b/include/kvstore.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2018 The Fuchsia Authors
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _KVSTORE_H_
+#define _KVSTORE_H_
+
+#include <common.h>
+#include <stdlib.h>
+
+typedef struct kvstore kvstore_t;
+
+#define KVS_OK 0
+#define KVS_ERR_INTERNAL -1
+#define KVS_ERR_BAD_PARAM -2
+#define KVS_ERR_OUT_OF_SPACE -3
+#define KVS_ERR_NOT_FOUND -4
+#define KVS_ERR_PARSE_HDR -5
+#define KVS_ERR_PARSE_REC -6
+#define KVS_ERR_PARSE_CRC -7
+
+// KVStore API
+// -----------
+
+// Setup a new, empty kvstore, backed by buffer.
+void kvs_init(kvstore_t* kvs, void* buffer, size_t buflen);
+
+// Initialize a kvstore (read from disk, etc), backed by buffer.
+int kvs_load(kvstore_t* kvs, void* buffer, size_t buflen);
+
+// Prepare kvstore for saving (compute checksum & update header).
+// On success kvs->data and kvs->datalen represents the data
+// to write to storage.
+int kvs_save(kvstore_t* kvs);
+
+
+// Adds a new key and value, provided there is space.
+// Does not check for duplicates.
+int kvs_addn(kvstore_t* kvs, const void* key, size_t klen,
+ const void* val, size_t vlen);
+
+// Adds a new key and value, provided there is space.
+// Does not check for duplicates.
+int kvs_add(kvstore_t* kvs, const char* key, const char* value);
+
+
+// Locates key and returns its value and OK, else NOT_FOUND
+// returned pointer is not guaranteed stable if kvstore is mutated.
+int kvs_getn(kvstore_t* kvs, const void* key, size_t klen,
+ const void** val, size_t* vlen);
+
+// Locates key and returns its value if found, otherwise returns fallback
+// returned pointer is not guaranteed stable if kvstore is mutated.
+const char* kvs_get(kvstore_t* kvs, const char* key, const char* fallback);
+
+
+// Calls func() for each key/value pair.
+// Return KVS_OK at the end, or stops and returns whatever func()
+// returned. if func returns non-zero.
+int kvs_foreach(kvstore_t* kvs, void *cookie,
+ int (*func)(void *cookie, const char* key, const char* val));
+
+
+// KVStore Wire Format and Internals
+// ---------------------------------
+
+// <header> <kventry>* [ <signature> ]
+//
+// <header> := <u64:version> <u32:flags> <u32:length> <u32:crc32> <u32:reserved>
+// <kventry> := <u8:klen> <u8:vlen> <u8[klen]:key> <u8:0> <u8[vlen]:value> <u8:0>
+// <signature> := TBD
+
+// echo -n "kvstore-version-1" | sha256sum (LSB)
+#define KVSTORE_VERSION 0x540f19caa7bf19dcUL
+
+#define KVSTORE_FLAG_SIGNED 1
+
+struct kvstore {
+ void* data;
+ size_t datalen;
+ size_t datamax;
+ size_t kvcount;
+};
+
+typedef struct kvshdr {
+ uint64_t version;
+ uint32_t flags;
+ uint32_t length;
+ uint32_t reserved;
+ uint32_t crc;
+} kvshdr_t;
+
+#endif /* _KVSTORE_H_ */
diff --git a/include/zircon/driver-config.h b/include/zircon/driver-config.h
new file mode 100644
index 0000000..b3bf01c
--- /dev/null
+++ b/include/zircon/driver-config.h
@@ -0,0 +1,77 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#pragma once
+
+// BOOTDATA_KERNEL_DRIVER bootdata types
+#define KDRV_ARM_PSCI 0x49435350 // 'PSCI'
+#define KDRV_ARM_GIC_V2 0x32434947 // 'GIC2'
+#define KDRV_ARM_GIC_V3 0x33434947 // 'GIC3'
+#define KDRV_ARM_GENERIC_TIMER 0x4D495441 // 'ATIM'
+#define KDRV_PL011_UART 0x55304C50 // 'PL0U'
+#define KDRV_AMLOGIC_UART 0x554C4D41 // 'AMLU'
+#define KDRV_NXP_IMX_UART 0x55584D49 // 'IMXU'
+#define KDRV_HISILICON_POWER 0x4F505348 // 'HSPO'
+#define KDRV_AMLOGIC_HDCP 0x484C4D41 // 'AMLH'
+
+// kernel driver struct that can be used for simple drivers
+// used by KDRV_PL011_UART, KDRV_AMLOGIC_UART and KDRV_NXP_IMX_UART
+typedef struct {
+ uint64_t mmio_phys;
+ uint32_t irq;
+} dcfg_simple_t;
+
+// for KDRV_ARM_PSCI
+typedef struct {
+ bool use_hvc;
+ uint64_t shutdown_args[3];
+ uint64_t reboot_args[3];
+ uint64_t reboot_bootloader_args[3];
+ uint64_t reboot_recovery_args[3];
+} dcfg_arm_psci_driver_t;
+
+// for KDRV_ARM_GIC_V2
+typedef struct {
+ uint64_t mmio_phys;
+ uint64_t msi_frame_phys;
+ uint64_t gicd_offset;
+ uint64_t gicc_offset;
+ uint64_t gich_offset;
+ uint64_t gicv_offset;
+ uint32_t ipi_base;
+ bool optional;
+ bool use_msi;
+} dcfg_arm_gicv2_driver_t;
+
+// for KDRV_ARM_GIC_V3
+typedef struct {
+ uint64_t mmio_phys;
+ uint64_t gicd_offset;
+ uint64_t gicr_offset;
+ uint64_t gicr_stride;
+ uint64_t mx8_gpr_phys;
+ uint32_t ipi_base;
+ bool optional;
+} dcfg_arm_gicv3_driver_t;
+
+// for KDRV_ARM_GENERIC_TIMER
+typedef struct {
+ uint32_t irq_phys;
+ uint32_t irq_virt;
+ uint32_t irq_sphys;
+ uint32_t freq_override;
+} dcfg_arm_generic_timer_driver_t;
+
+// for KDRV_HISILICON_POWER
+typedef struct {
+ uint64_t sctrl_phys;
+ uint64_t pmu_phys;
+} dcfg_hisilicon_power_driver_t;
+
+// for KDRV_AMLOGIC_HDCP
+typedef struct {
+ uint64_t preset_phys;
+ uint64_t hiu_phys;
+ uint64_t hdmitx_phys;
+} dcfg_amlogic_hdcp_driver_t;
diff --git a/include/zircon/gpt.h b/include/zircon/gpt.h
new file mode 100644
index 0000000..4d0a1aa
--- /dev/null
+++ b/include/zircon/gpt.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2018 The Fuchsia Authors
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _ZIRCON_GPT_H_
+#define _ZIRCON_GPT_H_
+
+// GUID for a system partition
+#define GUID_SYSTEM_STRING "606B000B-B7C7-4653-A7D5-B737332C899D"
+#define GUID_SYSTEM_VALUE { \
+ 0x0b, 0x00, 0x6b, 0x60, \
+ 0xc7, 0xb7, \
+ 0x53, 0x46, \
+ 0xa7, 0xd5, 0xb7, 0x37, 0x33, 0x2c, 0x89, 0x9d \
+}
+
+// GUID for a data partition
+#define GUID_DATA_STRING "08185F0C-892D-428A-A789-DBEEC8F55E6A"
+#define GUID_DATA_VALUE { \
+ 0x0c, 0x5f, 0x18, 0x08, \
+ 0x2d, 0x89, \
+ 0x8a, 0x42, \
+ 0xa7, 0x89, 0xdb, 0xee, 0xc8, 0xf5, 0x5e, 0x6a \
+}
+
+// GUID for a installer partition
+#define GUID_INSTALL_STRING "48435546-4953-2041-494E-5354414C4C52"
+#define GUID_INSTALL_VALUE { \
+ 0x46, 0x55, 0x43, 0x48, \
+ 0x53, 0x49, \
+ 0x41, 0x20, \
+ 0x49, 0x4E, 0x53, 0x54, 0x41, 0x4C, 0x4C, 0x52 \
+}
+
+#define GUID_BLOB_STRING "2967380E-134C-4CBB-B6DA-17E7CE1CA45D"
+#define GUID_BLOB_VALUE { \
+ 0x0e, 0x38, 0x67, 0x29, \
+ 0x4c, 0x13, \
+ 0xbb, 0x4c, \
+ 0xb6, 0xda, 0x17, 0xe7, 0xce, 0x1c, 0xa4, 0x5d \
+}
+
+#define GUID_FVM_STRING "41D0E340-57E3-954E-8C1E-17ECAC44CFF5"
+#define GUID_FVM_VALUE { \
+ 0x40, 0xe3, 0xd0, 0x41, \
+ 0xe3, 0x57, \
+ 0x4e, 0x95, \
+ 0x8c, 0x1e, 0x17, 0xec, 0xac, 0x44, 0xcf, 0xf5 \
+}
+
+#define GUID_ZIRCON_A_STRING "DE30CC86-1F4A-4A31-93C4-66F147D33E05"
+#define GUID_ZIRCON_A_VALUE { \
+ 0x86, 0xcc, 0x30, 0xde, \
+ 0x4a, 0x1f, \
+ 0x31, 0x4a, \
+ 0x93, 0xc4, 0x66, 0xf1, 0x47, 0xd3, 0x3e, 0x05, \
+}
+
+#define GUID_ZIRCON_B_STRING "23CC04DF-C278-4CE7-8471-897D1A4BCDF7"
+#define GUID_ZIRCON_B_VALUE { \
+ 0xdf, 0x04, 0xcc, 0x23, \
+ 0x78, 0xc2, \
+ 0xe7, 0x4c, \
+ 0x84, 0x71, 0x89, 0x7d, 0x1a, 0x4b, 0xcd, 0xf7 \
+}
+
+#define GUID_ZIRCON_R_STRING "A0E5CF57-2DEF-46BE-A80C-A2067C37CD49"
+#define GUID_ZIRCON_R_VALUE { \
+ 0x57, 0xcf, 0xe5, 0xa0, \
+ 0xef, 0x2d, \
+ 0xbe, 0x46, \
+ 0xa8, 0x0c, 0xa2, 0x06, 0x7c, 0x37, 0xcd, 0x49 \
+}
+
+#define GUID_SYS_CONFIG_STRING "4E5E989E-4C86-11E8-A15B-480FCF35F8E6"
+#define GUID_SYS_CONFIG_VALUE { \
+ 0x9e, 0x98, 0x5e, 0x4e, \
+ 0x86, 0x4c, \
+ 0xe8, 0x11, \
+ 0xa1, 0x5b, 0x48, 0x0f, 0xcf, 0x35, 0xf8, 0xe6 \
+}
+
+#define GUID_FACTORY_CONFIG_STRING "5A3A90BE-4C86-11E8-A15B-480FCF35F8E6"
+#define GUID_FACTORY_CONFIG_VALUE { \
+ 0xbe, 0x90, 0x3a, 0x5a, \
+ 0x86, 0x4c, \
+ 0xe8, 0x11, \
+ 0xa1, 0x5b, 0x48, 0x0f, 0xcf, 0x35, 0xf8, 0xe6 \
+}
+
+#define GUID_BOOTLOADER_STRING "5ECE94FE-4C86-11E8-A15B-480FCF35F8E6"
+#define GUID_BOOTLOADER_VALUE { \
+ 0xfe, 0x94, 0xce, 0x5e, \
+ 0x86, 0x4c, \
+ 0xe8, 0x11, \
+ 0xa1, 0x5b, 0x48, 0x0f, 0xcf, 0x35, 0xf8, 0xe6 \
+}
+
+#endif /* _ZIRCON_GPT_H_ */
diff --git a/include/zircon/image.h b/include/zircon/image.h
new file mode 100644
index 0000000..1fb813b
--- /dev/null
+++ b/include/zircon/image.h
@@ -0,0 +1,523 @@
+/*
+ * Copyright (c) 2018 The Fuchsia Authors
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _ZIRCON_IMAGE_H_
+#define _ZIRCON_IMAGE_H_
+// Zircon Boot Image format (ZBI).
+//
+// A Zircon Boot Image consists of a container header followed by boot
+// items. Each boot item has a header (zbi_header_t) and then a payload of
+// zbi_header_t.length bytes, which can be any size. The zbi_header_t.type
+// field indicates how to interpret the payload. Many types specify an
+// additional type-specific header that begins a variable-sized payload.
+// zbi_header_t.length does not include the zbi_header_t itself, but does
+// include any type-specific headers as part of the payload. All fields in
+// all header formats are little-endian.
+//
+// Padding bytes appear after each item as needed to align the payload size
+// up to a ZBI_ALIGNMENT (8-byte) boundary. This padding is not reflected
+// in the zbi_header_t.length value.
+//
+// A "complete" ZBI can be booted by a Zircon-compatible boot loader.
+// It contains one ZBI_TYPE_KERNEL_{ARCH} boot item that must come first,
+// followed by any number of additional boot items, which must include
+// exactly one ZBI_TYPE_STORAGE_BOOTFS item.
+//
+// A partial ZBI cannot be booted, and is only used during the build process.
+// It contains one or more boot items and can be combined with other ZBIs to
+// make a complete ZBI.
+// All items begin at an 8-byte aligned offset into the image.
+#ifdef __ASSEMBLER__
+#define ZBI_ALIGNMENT (8)
+#else
+#define ZBI_ALIGNMENT (8u)
+#endif
+// Round n up to the next 8 byte boundary
+#ifndef __ASSEMBLER__
+#ifdef __cplusplus
+constexpr
+#endif
+static inline uint32_t ZBI_ALIGN(uint32_t n) {
+ return ((n + ZBI_ALIGNMENT - 1) & -ZBI_ALIGNMENT);
+}
+#endif
+// LSW of sha256("bootdata")
+#define ZBI_CONTAINER_MAGIC (0x868cf7e6)
+// LSW of sha256("bootitem")
+#define ZBI_ITEM_MAGIC (0xb5781729)
+// This flag is always required.
+#define ZBI_FLAG_VERSION (0x00010000)
+// ZBI items with the CRC32 flag must have a valid crc32.
+// Otherwise their crc32 field must contain ZBI_ITEM_NO_CRC32
+#define ZBI_FLAG_CRC32 (0x00020000)
+// Value for zbi_header_t.crc32 when ZBI_FLAG_CRC32 is not set.
+#define ZBI_ITEM_NO_CRC32 (0x4a87e8d6)
+#ifndef __ASSEMBLER__
+// Each header must be 8-byte aligned. The length field specifies the
+// actual payload length and does not include the size of padding.
+typedef struct {
+ // ZBI_TYPE_* constant, see below.
+ uint32_t type;
+ // Size of the payload immediately following this header. This
+ // does not include the header itself nor any alignment padding
+ // after the payload.
+ uint32_t length;
+ // Type-specific extra data. Each type specifies the use of this
+ // field; see below. When not explicitly specified, it should be zero.
+ uint32_t extra;
+ // Flags for this item. This must always include ZBI_FLAG_VERSION.
+ // It should contain ZBI_FLAG_CRC32 for any item where it's feasible
+ // to compute the CRC32 at build time. Other flags are specific to
+ // each type; see below.
+ uint32_t flags;
+ // For future expansion. Set to 0.
+ uint32_t reserved0;
+ uint32_t reserved1;
+ // Must be ZBI_ITEM_MAGIC.
+ uint32_t magic;
+ // Must be the CRC32 of payload if ZBI_FLAG_CRC32 is set,
+ // otherwise must be ZBI_ITEM_NO_CRC32.
+ uint32_t crc32;
+} zbi_header_t;
+#endif
+// Be sure to add new types to ZBI_ALL_TYPES.
+#define ZBI_ALL_TYPES(macro) \
+ macro(ZBI_TYPE_CONTAINER, "CONTAINER", ".bin") \
+ macro(ZBI_TYPE_KERNEL_X64, "KERNEL_X64", ".bin") \
+ macro(ZBI_TYPE_KERNEL_ARM64, "KERNEL_ARM64", ".bin") \
+ macro(ZBI_TYPE_DISCARD, "DISCARD", ".bin") \
+ macro(ZBI_TYPE_STORAGE_RAMDISK, "RAMDISK", ".bin") \
+ macro(ZBI_TYPE_STORAGE_BOOTFS, "BOOTFS", ".bin") \
+ macro(ZBI_TYPE_STORAGE_BOOTFS_FACTORY, "BOOTFS_FACTORY", ".bin") \
+ macro(ZBI_TYPE_CMDLINE, "CMDLINE", ".txt") \
+ macro(ZBI_TYPE_CRASHLOG, "CRASHLOG", ".bin") \
+ macro(ZBI_TYPE_NVRAM, "NVRAM", ".bin") \
+ macro(ZBI_TYPE_PLATFORM_ID, "PLATFORM_ID", ".bin") \
+ macro(ZBI_TYPE_CPU_CONFIG, "CPU_CONFIG", ".bin") /* Deprecated */ \
+ macro(ZBI_TYPE_CPU_TOPOLOGY, "CPU_TOPOLOGY", ".bin") \
+ macro(ZBI_TYPE_MEM_CONFIG, "MEM_CONFIG", ".bin") \
+ macro(ZBI_TYPE_KERNEL_DRIVER, "KERNEL_DRIVER", ".bin") \
+ macro(ZBI_TYPE_ACPI_RSDP, "ACPI_RSDP", ".bin") \
+ macro(ZBI_TYPE_SMBIOS, "SMBIOS", ".bin") \
+ macro(ZBI_TYPE_EFI_MEMORY_MAP, "EFI_MEMORY_MAP", ".bin") \
+ macro(ZBI_TYPE_EFI_SYSTEM_TABLE, "EFI_SYSTEM_TABLE", ".bin") \
+ macro(ZBI_TYPE_E820_TABLE, "E820_TABLE", ".bin") \
+ macro(ZBI_TYPE_DEBUG_UART, "DEBUG_UART", ".bin") \
+ macro(ZBI_TYPE_FRAMEBUFFER, "FRAMEBUFFER", ".bin") \
+ macro(ZBI_TYPE_DRV_MAC_ADDRESS, "DRV_MAC_ADDRESS", ".bin") \
+ macro(ZBI_TYPE_DRV_PARTITION_MAP, "DRV_PARTITION_MAP", ".bin") \
+ macro(ZBI_TYPE_DRV_BOARD_PRIVATE, "DRV_BOARD_PRIVATE", ".bin") \
+ macro(ZBI_TYPE_BOOT_CONFIG, "BOOT_CONFIG", ".bin") \
+ macro(ZBI_TYPE_BOOT_VERSION, "BOOT_VERSION", ".bin")
+// Each ZBI starts with a container header.
+// length: Total size of the image after this header.
+// This includes all item headers, payloads, and padding.
+// It does not include the container header itself.
+// Must be a multiple of ZBI_ALIGNMENT.
+// extra: Must be ZBI_CONTAINER_MAGIC.
+// flags: Must be ZBI_FLAG_VERSION and no other flags.
+#define ZBI_TYPE_CONTAINER (0x544f4f42) // BOOT
+// Define a container header in assembly code. The symbol name is defined
+// as a local label; use .global symbol to make it global. The length
+// argument can use assembly label arithmetic like any immediate operand.
+#ifdef __ASSEMBLER__
+#define ZBI_CONTAINER_HEADER(symbol, length) \
+ .balign ZBI_ALIGNMENT; \
+ symbol: \
+ .int ZBI_TYPE_CONTAINER; \
+ .int (length); \
+ .int ZBI_CONTAINER_MAGIC; \
+ .int ZBI_FLAG_VERSION; \
+ .int 0; \
+ .int 0; \
+ .int ZBI_ITEM_MAGIC; \
+ .int ZBI_ITEM_NO_CRC32; \
+ .size symbol, . - symbol; \
+ .type symbol, %object
+#else
+#define ZBI_CONTAINER_HEADER(length) { \
+ ZBI_TYPE_CONTAINER, \
+ (length), \
+ ZBI_CONTAINER_MAGIC, \
+ ZBI_FLAG_VERSION, \
+ 0, \
+ 0, \
+ ZBI_ITEM_MAGIC, \
+ ZBI_ITEM_NO_CRC32, \
+}
+#endif
+// The kernel image. In a complete ZBI this item must always be first,
+// immediately after the ZBI_TYPE_CONTAINER header. The contiguous memory
+// image of the kernel is formed from the ZBI_TYPE_CONTAINER header, the
+// ZBI_TYPE_KERNEL_{ARCH} header, and the payload.
+//
+// The boot loader loads the whole image starting with the container header
+// through to the end of the kernel item's payload into contiguous physical
+// memory. It then constructs a partial ZBI elsewhere in memory, which has
+// a ZBI_TYPE_CONTAINER header of its own followed by all the other items
+// that were in the booted ZBI plus other items synthesized by the boot
+// loader to describe the machine. This partial ZBI must be placed at an
+// address (where the container header is found) that is aligned to the
+// machine's page size. The precise protocol for transferring control to
+// the kernel's entry point varies by machine.
+//
+// On all machines, the kernel requires some amount of scratch memory to be
+// available immediately after the kernel image at boot. It needs this
+// space for early setup work before it has a chance to read any memory-map
+// information from the boot loader. The `reserve_memory_size` field tells
+// the boot loader how much space after the kernel's load image it must
+// leave available for the kernel's use. The boot loader must place its
+// constructed ZBI or other reserved areas at least this many bytes after
+// the kernel image.
+//
+// x86-64
+//
+// The kernel assumes it was loaded at a fixed physical address of
+// 0x100000 (1MB). zbi_kernel_t.entry is the absolute physical address
+// of the PC location where the kernel will start.
+// TODO(SEC-31): Perhaps this will change??
+// The processor is in 64-bit mode with direct virtual to physical
+// mapping covering the physical memory where the kernel and
+// bootloader-constructed ZBI were loaded, which must be below 4GB.
+// The %rsi register (or %esi, since the high 32 bits must be zero)
+// holds the physical address of the bootloader-constructed ZBI.
+// All other registers are unspecified.
+//
+// ARM64
+//
+// zbi_kernel_t.entry is an offset from the beginning of the image
+// (i.e., the ZBI_TYPE_CONTAINER header before the ZBI_TYPE_KERNEL_ARM64
+// header) to the PC location in the image where the kernel will
+// start. The processor is in physical address mode at EL1 or
+// above. The kernel image and the bootloader-constructed ZBI each
+// can be loaded anywhere in physical memory. The x0 register
+// holds the physical address of the bootloader-constructed ZBI.
+// All other registers are unspecified.
+//
+#define ZBI_TYPE_KERNEL_PREFIX (0x004e524b) // KRN\0
+#define ZBI_TYPE_KERNEL_MASK (0x00FFFFFF)
+#define ZBI_TYPE_KERNEL_X64 (0x4c4e524b) // KRNL
+#define ZBI_TYPE_KERNEL_ARM64 (0x384e524b) // KRN8
+#define ZBI_IS_KERNEL_BOOTITEM(x) (((x) & ZBI_TYPE_KERNEL_MASK) == \
+ ZBI_TYPE_KERNEL_PREFIX)
+#ifndef __ASSEMBLER__
+typedef struct {
+ // Entry-point address. The interpretation of this differs by machine.
+ uint64_t entry;
+ // Minimum amount (in bytes) of scratch memory that the kernel requires
+ // immediately after its load image.
+ uint64_t reserve_memory_size;
+} zbi_kernel_t;
+// The whole contiguous image loaded into memory by the boot loader.
+typedef struct {
+ zbi_header_t hdr_file;
+ zbi_header_t hdr_kernel;
+ zbi_kernel_t data_kernel;
+ uint8_t contents[/*hdr_kernel.length - sizeof(zbi_kernel_t)*/];
+ // data_kernel.reserve_memory_size bytes in memory are free after contents.
+} zircon_kernel_t;
+#endif
+// A discarded item that should just be ignored. This is used for an
+// item that was already processed and should be ignored by whatever
+// stage is now looking at the ZBI. An earlier stage already "consumed"
+// this information, but avoided copying data around to remove it from
+// the ZBI item stream.
+#define ZBI_TYPE_DISCARD (0x50494b53) // SKIP
+// ZBI_TYPE_STORAGE_* types represent an image that might otherwise
+// appear on some block storage device, i.e. a RAM disk of some sort.
+// All zbi_header_t fields have the same meanings for all these types.
+// The interpretation of the payload (after possible decompression) is
+// indicated by the specific zbi_header_t.type value.
+//
+// **Note:** The ZBI_TYPE_STORAGE_* types are not a long-term stable ABI.
+// - Items of these types are always packed for a specific version of the
+// kernel and userland boot services, often in the same build that compiles
+// the kernel.
+// - These item types are **not** expected to be synthesized or
+// examined by boot loaders.
+// - New versions of the `zbi` tool will usually retain the ability to
+// read old formats and non-default switches to write old formats, for
+// diagnostic use.
+//
+// The zbi_header_t.extra field always gives the exact size of the
+// original, uncompressed payload. That equals zbi_header_t.length when
+// the payload is not compressed. If ZBI_FLAG_STORAGE_COMPRESSED is set in
+// zbi_header_t.flags, then the payload is compressed.
+//
+// **Note:** Magic-number and header bytes at the start of the compressed
+// payload indicate the compression algorithm and parameters. The set of
+// compression formats is not a long-term stable ABI.
+// - Zircon [userboot](../../../../docs/userboot.md) and core services
+// do the decompression. A given kernel build's `userboot` will usually
+// only support one particular compression format.
+// - The `zbi` tool will usually retain the ability to compress and
+// decompress for old formats, and can be used to convert between formats.
+#define ZBI_FLAG_STORAGE_COMPRESSED (0x00000001)
+// A virtual disk image. This is meant to be treated as if it were a
+// storage device. The payload (after decompression) is the contents of
+// the storage device, in whatever format that might be.
+#define ZBI_TYPE_STORAGE_RAMDISK (0x4b534452) // RDSK
+// The /boot filesystem in BOOTFS format, specified in <zircon/boot/bootfs.h>.
+// A complete ZBI must have exactly one ZBI_TYPE_STORAGE_BOOTFS item.
+// Zircon [userboot](../../../../docs/userboot.md) handles the contents
+// of this filesystem.
+#define ZBI_TYPE_STORAGE_BOOTFS (0x42534642) // BFSB
+// Device-specific factory data, stored in BOOTFS format, specified below.
+#define ZBI_TYPE_STORAGE_BOOTFS_FACTORY (0x46534642) // BFSF
+// The remaining types are used to communicate information from the boot
+// loader to the kernel. Usually these are synthesized in memory by the
+// boot loader, but they can also be included in a ZBI along with the
+// kernel and BOOTFS. Some boot loaders may set the zbi_header_t flags
+// and crc32 fields to zero, though setting them to ZBI_FLAG_VERSION and
+// ZBI_ITEM_NO_CRC32 is specified. The kernel doesn't check.
+// A kernel command line fragment, a NUL-terminated UTF-8 string.
+// Multiple ZBI_TYPE_CMDLINE items can appear. They are treated as if
+// concatenated with ' ' between each item, in the order they appear:
+// first items in the complete ZBI containing the kernel; then items in
+// the ZBI synthesized by the boot loader. The kernel interprets the
+// [whole command line](../../../../docs/kernel_cmdline.md).
+#define ZBI_TYPE_CMDLINE (0x4c444d43) // CMDL
+// The crash log from the previous boot, a UTF-8 string.
+#define ZBI_TYPE_CRASHLOG (0x4d4f4f42) // BOOM
+// Physical memory region that will persist across warm boots.
+// zbi_nvram_t gives the physical base address and length in bytes.
+#define ZBI_TYPE_NVRAM (0x4c4c564e) // NVLL
+// This reflects a typo we need to support for a while.
+#define ZBI_TYPE_NVRAM_DEPRECATED (0x4c4c5643) // CVLL
+#ifndef __ASSEMBLER__
+typedef struct {
+ uint64_t base;
+ uint64_t length;
+} zbi_nvram_t;
+#endif
+#define ZBI_BOARD_NAME_LEN 32
+// Platform ID Information.
+#define ZBI_TYPE_PLATFORM_ID (0x44494C50) // PLID
+#ifndef __ASSEMBLER__
+typedef struct {
+ uint32_t vid;
+ uint32_t pid;
+ char board_name[ZBI_BOARD_NAME_LEN];
+} zbi_platform_id_t;
+#endif
+// Board-specific information.
+#define ZBI_TYPE_DRV_BOARD_INFO (0x4953426D) // mBSI
+#ifndef __ASSEMBLER__
+typedef struct {
+ uint32_t revision;
+} zbi_board_info_t;
+#endif
+// CPU configuration, a zbi_cpu_config_t header followed by one or more
+// zbi_cpu_cluster_t entries. zbi_header_t.length must equal
+// zbi_cpu_config_t.cluster_count * sizeof(zbi_cpu_cluster_t).
+#define ZBI_TYPE_CPU_CONFIG (0x43555043) // CPUC
+#ifndef __ASSEMBLER__
+typedef struct {
+ // Number of CPU cores in the cluster.
+ uint32_t cpu_count;
+ // Reserved for future use. Set to 0.
+ uint32_t type;
+ uint32_t flags;
+ uint32_t reserved;
+} zbi_cpu_cluster_t;
+typedef struct {
+ // Number of zbi_cpu_cluster_t entries following this header.
+ uint32_t cluster_count;
+ // Reserved for future use. Set to 0.
+ uint32_t reserved[3];
+ // cluster_count entries follow.
+ zbi_cpu_cluster_t clusters[];
+} zbi_cpu_config_t;
+#endif
+#define ZBI_TYPE_CPU_TOPOLOGY (0x544F504F) // TOPO
+#ifndef __ASSEMBLER__
+#define ZBI_MAX_SMT 4
+// These are Used in the flags field of zbi_topology_processor_t.
+// This is the processor that boots the system and the last to be shutdown.
+#define ZBI_TOPOLOGY_PROCESSOR_PRIMARY 0b1
+// This is the processor that handles all interrupts, some architectures will
+// not have one.
+#define ZBI_TOPOLOGY_PROCESSOR_INTERRUPT 0b10
+#define ZBI_TOPOLOGY_NO_PARENT 0xFFFF
+typedef enum {
+ ZBI_TOPOLOGY_ARCH_UNDEFINED = 0, // Intended primarily for testing.
+ ZBI_TOPOLOGY_ARCH_X86 = 1,
+ ZBI_TOPOLOGY_ARCH_ARM = 2,
+} zbi_topology_architecture_t;
+typedef struct {
+ // Cluster ids for each level, one being closest to the cpu.
+ // These map to aff1, aff2, and aff3 values in the ARM registers.
+ uint8_t cluster_1_id;
+ uint8_t cluster_2_id;
+ uint8_t cluster_3_id;
+ // Id of the cpu inside of the bottom-most cluster, aff0 value.
+ uint8_t cpu_id;
+ // The GIC interface number for this processor.
+ // In GIC v3+ this is not necessary as the processors are addressed by their
+ // affinity routing (all cluster ids followed by cpu_id).
+ uint8_t gic_id;
+} zbi_topology_arm_info_t;
+typedef struct {
+ // Indexes here correspond to the logical_ids index for the thread.
+ uint32_t apic_ids[ZBI_MAX_SMT];
+ uint32_t apic_id_count;
+} zbi_topology_x86_info_t;
+typedef struct {
+ uint16_t logical_ids[ZBI_MAX_SMT];
+ uint8_t logical_id_count;
+ uint16_t flags;
+ // Should be one of zbi_topology_arm_info_t.
+ // If UNDEFINED then nothing will be set in arch_info.
+ uint8_t architecture;
+ union {
+ zbi_topology_arm_info_t arm;
+ zbi_topology_x86_info_t x86;
+ } architecture_info;
+} zbi_topology_processor_t;
+typedef struct {
+ // Relative performance level of this processor in the system, with 0
+ // representing the lowest performance.
+ // For example on a two cluster ARM big.LITTLE system 0 would be the little
+ // cores and 1 would represent the big cores.
+ uint8_t performance_class;
+} zbi_topology_cluster_t;
+typedef struct {
+ // Starting and ending memory addresses of this numa region.
+ uint64_t start_address;
+ uint64_t end_address;
+} zbi_topology_numa_region_t;
+typedef enum {
+ ZBI_TOPOLOGY_ENTITY_UNDEFINED = 0, // Unused default.
+ ZBI_TOPOLOGY_ENTITY_PROCESSOR = 1,
+ ZBI_TOPOLOGY_ENTITY_CLUSTER = 2,
+ ZBI_TOPOLOGY_ENTITY_CACHE = 3,
+ ZBI_TOPOLOGY_ENTITY_DIE = 4,
+ ZBI_TOPOLOGY_ENTITY_SOCKET = 5,
+ ZBI_TOPOLOGY_ENTITY_POWER_PLANE = 6,
+ ZBI_TOPOLOGY_ENTITY_NUMA_REGION = 7,
+} zbi_topology_entity_type_t;
+typedef struct {
+ // Should be one of zbi_topology_entity_type_t.
+ uint8_t entity_type;
+ uint16_t parent_index;
+ union {
+ zbi_topology_processor_t processor;
+ zbi_topology_cluster_t cluster;
+ zbi_topology_numa_region_t numa_region;
+ } entity;
+} zbi_topology_node_t;
+#endif
+// Memory configuration, one or more zbi_mem_range_t entries.
+// zbi_header_t.length is sizeof(zbi_mem_range_t) times the number of entries.
+#define ZBI_TYPE_MEM_CONFIG (0x434D454D) // MEMC
+#ifndef __ASSEMBLER__
+typedef struct {
+ uint64_t paddr;
+ uint64_t length;
+ uint32_t type;
+ uint32_t reserved;
+} zbi_mem_range_t;
+#endif
+#define ZBI_MEM_RANGE_RAM (1)
+#define ZBI_MEM_RANGE_PERIPHERAL (2)
+#define ZBI_MEM_RANGE_RESERVED (3)
+// Kernel driver configuration. The zbi_header_t.extra field gives a
+// KDRV_* type that determines the payload format.
+// See [driver-config.h](<zircon/boot/driver-config.h>) for details.
+#define ZBI_TYPE_KERNEL_DRIVER (0x5652444B) // KDRV
+// ACPI Root Table Pointer, a uint64_t physical address.
+#define ZBI_TYPE_ACPI_RSDP (0x50445352) // RSDP
+// SMBIOS entry point, a uint64_t physical address.
+#define ZBI_TYPE_SMBIOS (0x49424d53) // SMBI
+// EFI memory map, a uint64_t entry size followed by a sequence of
+// EFI memory descriptors aligned on that entry size.
+#define ZBI_TYPE_EFI_MEMORY_MAP (0x4d494645) // EFIM
+// EFI system table, a uint64_t physical address.
+#define ZBI_TYPE_EFI_SYSTEM_TABLE (0x53494645) // EFIS
+// E820 memory table, an array of e820entry_t.
+#define ZBI_TYPE_E820_TABLE (0x30323845) // E820
+/* EFI Variable for Crash Log */
+#define ZIRCON_VENDOR_GUID \
+ {0x82305eb2, 0xd39e, 0x4575, {0xa0, 0xc8, 0x6c, 0x20, 0x72, 0xd0, 0x84, 0x4c}}
+#define ZIRCON_CRASHLOG_EFIVAR \
+ { 'c', 'r', 'a', 's', 'h', 'l', 'o', 'g', 0 };
+#define ZIRCON_CRASHLOG_EFIATTR \
+ (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS)
+// Debug serial port, a zbi_uart_t entry.
+#define ZBI_TYPE_DEBUG_UART (0x54524155) // UART
+#ifndef __ASSEMBLER__
+typedef struct {
+ uint64_t base;
+ uint32_t type;
+ uint32_t irq;
+} zbi_uart_t;
+#endif
+#define ZBI_UART_NONE (0)
+#define ZBI_UART_PC_PORT (1)
+#define ZBI_UART_PC_MMIO (2)
+// Framebuffer parameters, a zbi_swfb_t entry.
+#define ZBI_TYPE_FRAMEBUFFER (0x42465753) // SWFB
+// A copy of the boot configuration stored as a kvstore
+// within the sysconfig partition.
+#define ZBI_TYPE_BOOT_CONFIG (0x47464342) // BCFG
+// A copy of the boot version stored within the sysconfig
+// partition
+#define ZBI_TYPE_BOOT_VERSION (0x53525642) // BVRS
+#ifndef __ASSEMBLER__
+typedef struct {
+ // Physical memory address.
+ uint64_t base;
+ // Pixel layout and format.
+ // See [../pixelformat.h](<zircon/pixelformat.h>).
+ uint32_t width;
+ uint32_t height;
+ uint32_t stride;
+ uint32_t format;
+} zbi_swfb_t;
+#endif
+// ZBI_TYPE_DRV_* types (LSB is 'm') contain driver metadata.
+#define ZBI_TYPE_DRV_METADATA(type) (((type) & 0xFF) == 0x6D) // 'm'
+// MAC address for Ethernet, Wifi, Bluetooth, etc. zbi_header_t.extra
+// is a board-specific index to specify which device the MAC address
+// applies to. zbi_header_t.length gives the size in bytes, which
+// varies depending on the type of address appropriate for the device.
+#define ZBI_TYPE_DRV_MAC_ADDRESS (0x43414D6D) // mMAC
+// A partition map for a storage device, a zbi_partition_map_t header
+// followed by one or more zbi_partition_t entries. zbi_header_t.extra
+// is a board-specific index to specify which device this applies to.
+#define ZBI_TYPE_DRV_PARTITION_MAP (0x5452506D) // mPRT
+#define ZBI_PARTITION_NAME_LEN (32)
+#define ZBI_PARTITION_GUID_LEN (16)
+// Private information for the board driver.
+#define ZBI_TYPE_DRV_BOARD_PRIVATE (0x524F426D) // mBOR
+#ifndef __ASSEMBLER__
+typedef struct {
+ // GUID specifying the format and use of data stored in the partition.
+ uint8_t type_guid[ZBI_PARTITION_GUID_LEN];
+ // GUID unique to this partition.
+ uint8_t uniq_guid[ZBI_PARTITION_GUID_LEN];
+ // First and last block occupied by this partition.
+ uint64_t first_block;
+ uint64_t last_block;
+ // Reserved for future use. Set to 0.
+ uint64_t flags;
+ char name[ZBI_PARTITION_NAME_LEN];
+} zbi_partition_t;
+typedef struct {
+ // Total blocks used on the device.
+ uint64_t block_count;
+ // Size of each block in bytes.
+ uint64_t block_size;
+ // Number of partitions in the map.
+ uint32_t partition_count;
+ // Reserved for future use.
+ uint32_t reserved;
+ // Device GUID.
+ uint8_t guid[ZBI_PARTITION_GUID_LEN];
+ // partition_count partition entries follow.
+ zbi_partition_t partitions[];
+} zbi_partition_map_t;
+#endif
+#endif // _ZIRCON_IMAGE_H_
\ No newline at end of file
diff --git a/include/zircon/sysconfig.h b/include/zircon/sysconfig.h
new file mode 100644
index 0000000..584e03b
--- /dev/null
+++ b/include/zircon/sysconfig.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2018 The Fuchsia Authors
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _ZIRCON_SYSCONFIG_H_
+#define _ZIRCON_SYSCONFIG_H_
+
+// Zircon sysconfig partition format
+//
+// The sysconfig partition consists of four kvstore sections, each 32K in size.
+// The sections are:
+//
+// version-a: System configuration used when booting from Zircon-A.
+//
+// version-b: System configuration used when booting from Zircon-B.
+//
+// boot-default: Default bootloader configuration.
+//
+// boot-oneshot: Bootloader configuration for one-time use.
+// If present, this overrides boot-default, and the bootloader
+// deletes this section after use.
+
+#define ZX_SYSCONFIG_KVSTORE_SIZE 32768
+#define ZX_SYSCONFIG_VERSION_A_OFFSET (0 * ZX_SYSCONFIG_KVSTORE_SIZE)
+#define ZX_SYSCONFIG_VERSION_B_OFFSET (1 * ZX_SYSCONFIG_KVSTORE_SIZE)
+#define ZX_SYSCONFIG_BOOT_DEFAULT_OFFSET (2 * ZX_SYSCONFIG_KVSTORE_SIZE)
+#define ZX_SYSCONFIG_BOOT_ONESHOT_OFFSET (3 * ZX_SYSCONFIG_KVSTORE_SIZE)
+
+#endif // _ZIRCON_SYSCONFIG_H_
diff --git a/include/zircon/zircon.h b/include/zircon/zircon.h
new file mode 100644
index 0000000..43f5d39
--- /dev/null
+++ b/include/zircon/zircon.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2018 The Fuchsia Authors
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _ZIRCON_ZIRCON_H_
+#define _ZIRCON_ZIRCON_H_
+
+#include <zircon/image.h>
+#include <zircon/driver-config.h>
+#include <zircon/gpt.h>
+
+/* called before booting to allow board specific additions to the bootdata */
+int zircon_preboot(zbi_header_t* zbi);
+
+void zircon_append_boot_item(zbi_header_t* container, uint32_t type, uint32_t extra,
+ const void* payload, uint32_t length);
+
+#endif
diff --git a/lib/Makefile b/lib/Makefile
index 181e674..ed3a314 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -71,6 +71,7 @@
obj-$(CONFIG_CMD_GPT) += uuid.o
obj-y += vsprintf.o
#obj-$(CONFIG_LIB_RAND) += rand.o
+obj-$(CONFIG_ZIRCON_BOOT_IMAGE) += kvstore.o
obj-y += libavb/
diff --git a/lib/kvstore.c b/lib/kvstore.c
new file mode 100644
index 0000000..557cffa
--- /dev/null
+++ b/lib/kvstore.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2018 The Fuchsia Authors
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <kvstore.h>
+
+// header, key, zero, value, zero
+#define RECLEN(ksz, vsz) (2 + (ksz) + 1 + (vsz) + 1)
+
+void kvs_init(kvstore_t* kvs, void* buffer, size_t buflen) {
+ kvs->data = buffer;
+ kvs->datamax = buflen;
+ kvs->kvcount = 0;
+ if (buflen < sizeof(kvshdr_t)) {
+ kvs->datalen = kvs->datamax;
+ } else {
+ kvs->datalen = sizeof(kvshdr_t);
+ }
+}
+
+int kvs_load(kvstore_t* kvs, void* buffer, size_t buflen) {
+ // initially configure kvstore as invalid to provide
+ // some protection against using after ignoring the
+ // return value of load
+ kvs->data = buffer;
+ kvs->datalen = buflen;
+ kvs->datamax = buflen;
+ kvs->kvcount = 0;
+
+ kvshdr_t hdr;
+ if (buflen < sizeof(hdr)) {
+ return KVS_ERR_BAD_PARAM;
+ }
+
+ memcpy(&hdr, buffer, sizeof(hdr));
+ if ((hdr.version != KVSTORE_VERSION) || (hdr.length < sizeof(hdr))) {
+ return KVS_ERR_PARSE_HDR;
+ }
+ if (hdr.length > buflen) {
+ return KVS_ERR_PARSE_HDR;
+ }
+ if (hdr.flags != 0) {
+ return KVS_ERR_PARSE_HDR;
+ }
+ if (hdr.reserved != 0) {
+ return KVS_ERR_PARSE_HDR;
+ }
+
+ uint32_t crc = crc32(0, buffer, sizeof(hdr) - sizeof(uint32_t));
+ crc = crc32(crc, buffer + sizeof(hdr), hdr.length - sizeof(hdr));
+ if (crc != hdr.crc) {
+ return KVS_ERR_PARSE_CRC;
+ }
+
+ size_t count = 0;
+ uint8_t *kv = buffer + sizeof(hdr);
+ uint8_t *rec = kv;
+ size_t avail = hdr.length - sizeof(hdr);
+ while (avail > 0) {
+ if (avail < 2) {
+ return KVS_ERR_PARSE_REC;
+ }
+ size_t klen = rec[0];
+ size_t vlen = rec[1];
+ size_t reclen = RECLEN(klen, vlen);
+ if (avail < reclen) {
+ return KVS_ERR_PARSE_REC;
+ }
+ if (rec[2 + klen] != 0) {
+ return KVS_ERR_PARSE_REC;
+ }
+ if (rec[2 + klen + 1 + vlen] != 0) {
+ return KVS_ERR_PARSE_REC;
+ }
+ rec += reclen;
+ avail -= reclen;
+ count++;
+ }
+
+ kvs->kvcount = count;
+ kvs->datalen = sizeof(hdr) + (rec - kv);
+ return KVS_OK;
+}
+
+int kvs_save(kvstore_t* kvs) {
+ if (kvs->datamax < sizeof(kvshdr_t)) {
+ return KVS_ERR_OUT_OF_SPACE;
+ }
+ kvshdr_t hdr;
+ hdr.version = KVSTORE_VERSION;
+ hdr.flags = 0;
+ hdr.length = kvs->datalen;
+ hdr.reserved = 0;
+ hdr.crc = crc32(0, (const void*) &hdr, sizeof(hdr) - sizeof(uint32_t));
+ hdr.crc = crc32(hdr.crc, kvs->data + sizeof(hdr), hdr.length - sizeof(hdr));
+ memcpy(kvs->data, &hdr, sizeof(hdr));
+ return KVS_OK;
+}
+
+int kvs_addn(kvstore_t* kvs, const void* key, size_t klen,
+ const void* val, size_t vlen) {
+ // ensure valid parameters
+ if ((klen == 0) || (klen > 255) || (vlen > 255)) {
+ return KVS_ERR_BAD_PARAM;
+ }
+
+ // ensure available space
+ size_t reclen = RECLEN(klen, vlen);
+ if (reclen > (kvs->datamax - kvs->datalen)) {
+ return KVS_ERR_OUT_OF_SPACE;
+ }
+
+ uint8_t* rec = kvs->data + kvs->datalen;
+ *rec++ = klen;
+ *rec++ = vlen;
+ memcpy(rec, key, klen);
+ rec += klen;
+ *rec++ = 0;
+ memcpy(rec, val, vlen);
+ rec += vlen;
+ *rec++ = 0;
+
+ kvs->datalen += reclen;
+ kvs->kvcount++;
+ return KVS_OK;
+}
+
+int kvs_add(kvstore_t* kvs, const char* key, const char* value) {
+ return kvs_addn(kvs, key, strlen(key), value, strlen(value));
+}
+
+
+int kvs_getn(kvstore_t* kvs, const void* key, size_t klen,
+ const void** val, size_t* vlen) {
+ uint8_t* rec = kvs->data + sizeof(kvshdr_t);
+ size_t count;
+ for (count = 0; count < kvs->kvcount; count++) {
+ size_t ksz = rec[0];
+ size_t vsz = rec[1];
+ if ((klen == ksz) && !memcmp(key, rec + 2, klen)) {
+ *val = rec + 2 + klen + 1;
+ if (vlen) {
+ *vlen = vsz;
+ }
+ return KVS_OK;
+ }
+ rec += RECLEN(ksz, vsz);
+ }
+ return KVS_ERR_NOT_FOUND;
+}
+
+const char* kvs_get(kvstore_t* kvs, const char* key, const char* fallback) {
+ const void* val;
+ if (kvs_getn(kvs, key, strlen(key), &val, NULL) == KVS_OK) {
+ return (const char*) val;
+ } else {
+ return fallback;
+ }
+}
+
+int kvs_foreach(kvstore_t* kvs, void *cookie,
+ int (*func)(void *cookie, const char* key, const char* val)) {
+ uint8_t* rec = kvs->data + sizeof(kvshdr_t);
+ size_t count;
+ for (count = 0; count < kvs->kvcount; count++) {
+ size_t ksz = rec[0];
+ size_t vsz = rec[1];
+ int r = func(cookie, (const char*) (rec + 2), (const char*) (rec + 2 + ksz + 1));
+ if (r != KVS_OK) {
+ return r;
+ }
+ rec += RECLEN(ksz, vsz);
+ }
+ return KVS_OK;
+}