| /* |
| * 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 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 = 4, |
| }, |
| { |
| .cpu_count = 4, |
| }, |
| }, |
| }; |
| |
| static zbi_mem_range_t mem_config[] = { |
| { |
| .type = ZBI_MEM_RANGE_RAM, |
| .length = 0x80000000, // 2GB |
| }, |
| { |
| .type = ZBI_MEM_RANGE_PERIPHERAL, |
| .paddr = 0xc0000000, |
| .length = 0x20000000, |
| }, |
| { |
| .type = ZBI_MEM_RANGE_RESERVED, |
| .paddr = 0, |
| .length = 0x001000000, |
| }, |
| { |
| .type = ZBI_MEM_RANGE_RESERVED, |
| .paddr = 0x10000000, |
| .length = 0x00200000, |
| }, |
| { |
| .type = ZBI_MEM_RANGE_RESERVED, |
| .paddr = 0x05100000, |
| .length = 0x2000000, |
| }, |
| { |
| .type = ZBI_MEM_RANGE_RESERVED, |
| .paddr = 0x7300000, |
| .length = 0x100000, |
| }, |
| { |
| .type = ZBI_MEM_RANGE_RESERVED, |
| .paddr = 0x75000000, |
| .length = 0x9000000, |
| }, |
| }; |
| |
| static const dcfg_simple_t uart_driver = { |
| .mmio_phys = 0xc81004c0, |
| .irq = 225, |
| }; |
| |
| static const dcfg_arm_gicv2_driver_t gicv2_driver = { |
| .mmio_phys = 0xc4300000, |
| .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_VIM2, |
| .board_name = "vim2", |
| }; |
| |
| 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* 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; |
| } |
| |
| 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 (get_partition_info_aml_by_name(dev_desc, "crypt", &crypt_info)) { |
| printf("could not find crypt partition\n"); |
| return; |
| } |
| 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; |
| |
| // 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; |
| |
| // 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(P_RAND64_ADDR0); |
| } |
| |
| 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) { |
| // add CPU configuration |
| 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); |
| |
| const char* ddr_size = getenv("ddr_size"); |
| if (!strcmp(ddr_size, "3")) { |
| mem_config[0].length = 0xc0000000; |
| } |
| |
| // 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)); |
| |
| // 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_cmdline_entropy(zbi); |
| add_partition_map(zbi); |
| add_eth_mac_address(zbi); |
| return 0; |
| } |