/******************************************************************************* * Perform any BL1 specific platform actions. ******************************************************************************/ void bl1_early_platform_setup(void) { const size_t bl1_size = BL1_RAM_LIMIT - BL1_RAM_BASE; /* Initialize the console to provide early debug support */ console_init(PL011_UART2_BASE, PL011_UART2_CLK_IN_HZ, PL011_BAUDRATE); /* * Enable CCI-400 for this cluster. No need for locks as no other cpu is * active at the moment */ cci_init(CCI400_BASE, CCI400_SL_IFACE3_CLUSTER_IX, CCI400_SL_IFACE4_CLUSTER_IX); cci_enable_cluster_coherency(read_mpidr()); /* Allow BL1 to see the whole Trusted RAM */ bl1_tzram_layout.total_base = TZRAM_BASE; bl1_tzram_layout.total_size = TZRAM_SIZE; /* Calculate how much RAM BL1 is using and how much remains free */ bl1_tzram_layout.free_base = TZRAM_BASE; bl1_tzram_layout.free_size = TZRAM_SIZE; reserve_mem(&bl1_tzram_layout.free_base, &bl1_tzram_layout.free_size, BL1_RAM_BASE, bl1_size); INFO("BL1: 0x%lx - 0x%lx [size = %u]\n", BL1_RAM_BASE, BL1_RAM_LIMIT, bl1_size); }
/* * Perform any BL1 specific platform actions. */ void bl1_early_platform_setup(void) { const size_t bl1_size = BL1_RAM_LIMIT - BL1_RAM_BASE; unsigned int id, uart_base; generic_delay_timer_init(); hikey960_read_boardid(&id); if (id == 5300) uart_base = PL011_UART5_BASE; else uart_base = PL011_UART6_BASE; /* Initialize the console to provide early debug support */ console_init(uart_base, PL011_UART_CLK_IN_HZ, PL011_BAUDRATE); /* Allow BL1 to see the whole Trusted RAM */ bl1_tzram_layout.total_base = BL1_RW_BASE; bl1_tzram_layout.total_size = BL1_RW_SIZE; /* Calculate how much RAM BL1 is using and how much remains free */ bl1_tzram_layout.free_base = BL1_RW_BASE; bl1_tzram_layout.free_size = BL1_RW_SIZE; reserve_mem(&bl1_tzram_layout.free_base, &bl1_tzram_layout.free_size, BL1_RAM_BASE, bl1_size); INFO("BL1: 0x%lx - 0x%lx [size = %lu]\n", BL1_RAM_BASE, BL1_RAM_LIMIT, bl1_size); }
/******************************************************************************* * Perform any BL1 specific platform actions. ******************************************************************************/ void bl1_early_platform_setup(void) { const size_t bl1_size = BL1_RAM_LIMIT - BL1_RAM_BASE; /* Initialize the console to provide early debug support */ console_init(PLAT_QEMU_BOOT_UART_BASE, PLAT_QEMU_BOOT_UART_CLK_IN_HZ, PLAT_QEMU_CONSOLE_BAUDRATE); /* Allow BL1 to see the whole Trusted RAM */ bl1_tzram_layout.total_base = BL_RAM_BASE; bl1_tzram_layout.total_size = BL_RAM_SIZE; /* Calculate how much RAM BL1 is using and how much remains free */ bl1_tzram_layout.free_base = BL_RAM_BASE; bl1_tzram_layout.free_size = BL_RAM_SIZE; reserve_mem(&bl1_tzram_layout.free_base, &bl1_tzram_layout.free_size, BL1_RAM_BASE, bl1_size); }
void bl1_early_platform_setup(void) { /* Initialize the console to provide early debug support */ console_init(PL011_UART0_BASE, PL011_UART0_CLK_IN_HZ, PL011_BAUDRATE); /* Allow BL1 to see the whole Trusted RAM */ bl1_tzram_layout.total_base = BL_MEM_BASE; bl1_tzram_layout.total_size = BL_MEM_SIZE; /* Calculate how much RAM BL1 is using and how much remains free */ bl1_tzram_layout.free_base = BL_MEM_BASE; bl1_tzram_layout.free_size = BL_MEM_SIZE; reserve_mem(&bl1_tzram_layout.free_base, &bl1_tzram_layout.free_size, BL1_RAM_BASE, BL1_RAM_LIMIT - BL1_RAM_BASE); INFO("BL1: 0x%lx - 0x%lx [size = %zu]\n", BL1_RAM_BASE, BL1_RAM_LIMIT, BL1_RAM_LIMIT - BL1_RAM_BASE); }
/******************************************************************************* * Function that takes a memory layout into which BL2 has been loaded and * populates a new memory layout for BL2 that ensures that BL1's data sections * resident in secure RAM are not visible to BL2. ******************************************************************************/ void bl1_init_bl2_mem_layout(const meminfo_t *bl1_mem_layout, meminfo_t *bl2_mem_layout) { const size_t bl1_size = BL1_RAM_LIMIT - BL1_RAM_BASE; assert(bl1_mem_layout != NULL); assert(bl2_mem_layout != NULL); /* Check that BL1's memory is lying outside of the free memory */ assert((BL1_RAM_LIMIT <= bl1_mem_layout->free_base) || (BL1_RAM_BASE >= (bl1_mem_layout->free_base + bl1_mem_layout->free_size))); /* Remove BL1 RW data from the scope of memory visible to BL2 */ *bl2_mem_layout = *bl1_mem_layout; reserve_mem(&bl2_mem_layout->total_base, &bl2_mem_layout->total_size, BL1_RAM_BASE, bl1_size); flush_dcache_range((unsigned long)bl2_mem_layout, sizeof(meminfo_t)); }
/******************************************************************************* * Generic function to load an image at a specific address given a name and * extents of free memory. It updates the memory layout if the load is * successful, as well as the image information and the entry point information. * The caller might pass a NULL pointer for the entry point if it is not * interested in this information, e.g. because the image just needs to be * loaded in memory but won't ever be executed. * Returns 0 on success, a negative error code otherwise. ******************************************************************************/ int load_image(meminfo_t *mem_layout, unsigned int image_id, uintptr_t image_base, image_info_t *image_data, entry_point_info_t *entry_point_info) { uintptr_t dev_handle; uintptr_t image_handle; uintptr_t image_spec; size_t image_size; size_t bytes_read; int io_result = IO_FAIL; assert(mem_layout != NULL); assert(image_data != NULL); assert(image_data->h.version >= VERSION_1); /* Obtain a reference to the image by querying the platform layer */ io_result = plat_get_image_source(image_id, &dev_handle, &image_spec); if (io_result != IO_SUCCESS) { WARN("Failed to obtain reference to image id=%u (%i)\n", image_id, io_result); return io_result; } /* Attempt to access the image */ io_result = io_open(dev_handle, image_spec, &image_handle); if (io_result != IO_SUCCESS) { WARN("Failed to access image id=%u (%i)\n", image_id, io_result); return io_result; } INFO("Loading image id=%u at address 0x%lx\n", image_id, image_base); /* Find the size of the image */ io_result = io_size(image_handle, &image_size); if ((io_result != IO_SUCCESS) || (image_size == 0)) { WARN("Failed to determine the size of the image id=%u (%i)\n", image_id, io_result); goto exit; } /* Check that the memory where the image will be loaded is free */ if (!is_mem_free(mem_layout->free_base, mem_layout->free_size, image_base, image_size)) { WARN("Failed to reserve memory: 0x%lx - 0x%lx\n", image_base, image_base + image_size); dump_load_info(image_base, image_size, mem_layout); io_result = -ENOMEM; goto exit; } /* We have enough space so load the image now */ /* TODO: Consider whether to try to recover/retry a partially successful read */ io_result = io_read(image_handle, image_base, image_size, &bytes_read); if ((io_result != IO_SUCCESS) || (bytes_read < image_size)) { WARN("Failed to load image id=%u (%i)\n", image_id, io_result); goto exit; } /* * Update the memory usage info. * This is done after the actual loading so that it is not updated when * the load is unsuccessful. * If the caller does not provide an entry point, bypass the memory * reservation. */ if (entry_point_info != NULL) { reserve_mem(&mem_layout->free_base, &mem_layout->free_size, image_base, image_size); } else { INFO("Skip reserving memory: 0x%lx - 0x%lx\n", image_base, image_base + image_size); } image_data->image_base = image_base; image_data->image_size = image_size; if (entry_point_info != NULL) entry_point_info->pc = image_base; /* * File has been successfully loaded. * Flush the image in TZRAM so that the next EL can see it. */ flush_dcache_range(image_base, image_size); INFO("Image id=%u loaded: 0x%lx - 0x%lx\n", image_id, image_base, image_base + image_size); exit: io_close(image_handle); /* Ignore improbable/unrecoverable error in 'close' */ /* TODO: Consider maintaining open device connection from this bootloader stage */ io_dev_close(dev_handle); /* Ignore improbable/unrecoverable error in 'dev_close' */ return io_result; }
/******************************************************************************* * Generic function to load an image at a specific address given an image ID and * extents of free memory. * * If the load is successful then the image information is updated. * * If the entry_point_info argument is not NULL then this function also updates: * - the memory layout to mark the memory as reserved; * - the entry point information. * * The caller might pass a NULL pointer for the entry point if they are not * interested in this information. This is typically the case for non-executable * images (e.g. certificates) and executable images that won't ever be executed * on the application processor (e.g. additional microcontroller firmware). * * Returns 0 on success, a negative error code otherwise. ******************************************************************************/ int load_image(meminfo_t *mem_layout, unsigned int image_id, uintptr_t image_base, image_info_t *image_data, entry_point_info_t *entry_point_info) { uintptr_t dev_handle; uintptr_t image_handle; uintptr_t image_spec; size_t image_size; size_t bytes_read; int io_result; assert(mem_layout != NULL); assert(image_data != NULL); assert(image_data->h.version == VERSION_1); /* Obtain a reference to the image by querying the platform layer */ io_result = plat_get_image_source(image_id, &dev_handle, &image_spec); if (io_result != 0) { WARN("Failed to obtain reference to image id=%u (%i)\n", image_id, io_result); return io_result; } /* Attempt to access the image */ io_result = io_open(dev_handle, image_spec, &image_handle); if (io_result != 0) { WARN("Failed to access image id=%u (%i)\n", image_id, io_result); return io_result; } INFO("Loading image id=%u at address %p\n", image_id, (void *) image_base); /* Find the size of the image */ io_result = io_size(image_handle, &image_size); if ((io_result != 0) || (image_size == 0)) { WARN("Failed to determine the size of the image id=%u (%i)\n", image_id, io_result); goto exit; } /* Check that the memory where the image will be loaded is free */ if (!is_mem_free(mem_layout->free_base, mem_layout->free_size, image_base, image_size)) { WARN("Failed to reserve region [base = %p, size = 0x%zx]\n", (void *) image_base, image_size); dump_load_info(image_base, image_size, mem_layout); io_result = -ENOMEM; goto exit; } /* We have enough space so load the image now */ /* TODO: Consider whether to try to recover/retry a partially successful read */ io_result = io_read(image_handle, image_base, image_size, &bytes_read); if ((io_result != 0) || (bytes_read < image_size)) { WARN("Failed to load image id=%u (%i)\n", image_id, io_result); goto exit; } image_data->image_base = image_base; image_data->image_size = image_size; /* * Update the memory usage info. * This is done after the actual loading so that it is not updated when * the load is unsuccessful. * If the caller does not provide an entry point, bypass the memory * reservation. */ if (entry_point_info != NULL) { reserve_mem(&mem_layout->free_base, &mem_layout->free_size, image_base, image_size); entry_point_info->pc = image_base; } else { INFO("Skip reserving region [base = %p, size = 0x%zx]\n", (void *) image_base, image_size); } #if !TRUSTED_BOARD_BOOT /* * File has been successfully loaded. * Flush the image to main memory so that it can be executed later by * any CPU, regardless of cache and MMU state. * When TBB is enabled the image is flushed later, after image * authentication. */ flush_dcache_range(image_base, image_size); #endif /* TRUSTED_BOARD_BOOT */ INFO("Image id=%u loaded at address %p, size = 0x%zx\n", image_id, (void *) image_base, image_size); exit: io_close(image_handle); /* Ignore improbable/unrecoverable error in 'close' */ /* TODO: Consider maintaining open device connection from this bootloader stage */ io_dev_close(dev_handle); /* Ignore improbable/unrecoverable error in 'dev_close' */ return io_result; }