[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;
+}