struct bladerf_image * bladerf_alloc_image(bladerf_image_type type, uint32_t address, uint32_t length) { struct bladerf_image *image; assert(BLADERF_IMAGE_MAGIC_LEN == (sizeof(image_magic) - 1)); /* 0xffffffff is a placeholder for images that use the format but don't * currently have an address in flash to live in */ if (address != 0xffffffff) { if (!is_page_aligned(address)) { log_debug("Address is not page-aligned: 0x%08x\n", address); return NULL; } else if (!is_page_aligned(length)) { log_debug("Length is not page-aligned: 0x%08x\n", length); return NULL; } else if (!is_valid_addr_len(address, length)) { log_debug("Invalid address=0x%08x or length=0x%08x\n", address, length); return NULL; } } image = (struct bladerf_image *)calloc(1, sizeof(*image)); if (!image) { return NULL; } if (length) { image->data = (uint8_t *)calloc(1, length); if (!image->data) { free(image); return NULL; } } memcpy(image->magic, &image_magic, BLADERF_IMAGE_MAGIC_LEN); image->version.major = 0; image->version.minor = 1; image->version.patch = 0; image->timestamp = get_timestamp(); image->address = address; image->length = length; image->type = type; return image; }
/******************************************************************************* * Generic function to load an image into the trusted RAM, * given a name, extents of free memory & whether the image should be loaded at * the bottom or top of the free memory. It updates the memory layout if the * load is successful. ******************************************************************************/ unsigned long load_image(meminfo *mem_layout, const char *image_name, unsigned int load_type, unsigned long fixed_addr) { io_dev_handle dev_handle; io_handle image_handle; void *image_spec; unsigned long temp_image_base = 0; unsigned long image_base = 0; long offset = 0; size_t image_size = 0; size_t bytes_read = 0; int io_result = IO_FAIL; assert(mem_layout != NULL); assert(image_name != NULL); /* Obtain a reference to the image by querying the platform layer */ io_result = plat_get_image_source(image_name, &dev_handle, &image_spec); if (io_result != IO_SUCCESS) { WARN("Failed to obtain reference to image '%s' (%i)\n", image_name, io_result); return 0; } /* 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 '%s' (%i)\n", image_name, io_result); return 0; } /* 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 '%s' file (%i)\n", image_name, io_result); goto fail; } /* See if we have enough space */ if (image_size > mem_layout->free_size) { WARN("Cannot load '%s' file: Not enough space.\n", image_name); dump_load_info(0, image_size, mem_layout); goto fail; } switch (load_type) { case TOP_LOAD: /* Load the image in the top of free memory */ temp_image_base = mem_layout->free_base + mem_layout->free_size; temp_image_base -= image_size; /* Page align base address and check whether the image still fits */ image_base = page_align(temp_image_base, DOWN); assert(image_base <= temp_image_base); if (image_base < mem_layout->free_base) { WARN("Cannot load '%s' file: Not enough space.\n", image_name); dump_load_info(image_base, image_size, mem_layout); goto fail; } /* Calculate the amount of extra memory used due to alignment */ offset = temp_image_base - image_base; break; case BOT_LOAD: /* Load the BL2 image in the bottom of free memory */ temp_image_base = mem_layout->free_base; image_base = page_align(temp_image_base, UP); assert(image_base >= temp_image_base); /* Page align base address and check whether the image still fits */ if (image_base + image_size > mem_layout->free_base + mem_layout->free_size) { WARN("Cannot load '%s' file: Not enough space.\n", image_name); dump_load_info(image_base, image_size, mem_layout); goto fail; } /* Calculate the amount of extra memory used due to alignment */ offset = image_base - temp_image_base; break; default: assert(0); } /* * Some images must be loaded at a fixed address, not a dynamic one. * * This has been implemented as a hack on top of the existing dynamic * loading mechanism, for the time being. If the 'fixed_addr' function * argument is different from zero, then it will force the load address. * So we still have this principle of top/bottom loading but the code * determining the load address is bypassed and the load address is * forced to the fixed one. * * This can result in quite a lot of wasted space because we still use * 1 sole meminfo structure to represent the extents of free memory, * where we should use some sort of linked list. * * E.g. we want to load BL2 at address 0x04020000, the resulting memory * layout should look as follows: * ------------ 0x04040000 * | | <- Free space (1) * |----------| * | BL2 | * |----------| 0x04020000 * | | <- Free space (2) * |----------| * | BL1 | * ------------ 0x04000000 * * But in the current hacky implementation, we'll need to specify * whether BL2 is loaded at the top or bottom of the free memory. * E.g. if BL2 is considered as top-loaded, the meminfo structure * will give the following view of the memory, hiding the chunk of * free memory above BL2: * ------------ 0x04040000 * | | * | | * | BL2 | * |----------| 0x04020000 * | | <- Free space (2) * |----------| * | BL1 | * ------------ 0x04000000 */ if (fixed_addr != 0) { /* Load the image at the given address. */ image_base = fixed_addr; /* Check whether the image fits. */ if ((image_base < mem_layout->free_base) || (image_base + image_size > mem_layout->free_base + mem_layout->free_size)) { WARN("Cannot load '%s' file: Not enough space.\n", image_name); dump_load_info(image_base, image_size, mem_layout); goto fail; } /* Check whether the fixed load address is page-aligned. */ if (!is_page_aligned(image_base)) { WARN("Cannot load '%s' file at unaligned address 0x%lx\n", image_name, fixed_addr); goto fail; } /* * Calculate the amount of extra memory used due to fixed * loading. */ if (load_type == TOP_LOAD) { unsigned long max_addr, space_used; /* * ------------ max_addr * | /wasted/ | | offset * |..........|.............................. * | image | | image_flen * |----------| fixed_addr * | | * | | * ------------ total_base */ max_addr = mem_layout->total_base + mem_layout->total_size; /* * Compute the amount of memory used by the image. * Corresponds to all space above the image load * address. */ space_used = max_addr - fixed_addr; /* * Calculate the amount of wasted memory within the * amount of memory used by the image. */ offset = space_used - image_size; } else /* BOT_LOAD */ /* * ------------ * | | * | | * |----------| * | image | * |..........| fixed_addr * | /wasted/ | | offset * ------------ total_base */ offset = fixed_addr - mem_layout->total_base; } /* 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, (void *)image_base, image_size, &bytes_read); if ((io_result != IO_SUCCESS) || (bytes_read < image_size)) { WARN("Failed to load '%s' file (%i)\n", image_name, io_result); goto fail; } /* * File has been successfully loaded. Update the free memory * data structure & flush the contents of the TZRAM so that * the next EL can see it. */ /* Update the memory contents */ flush_dcache_range(image_base, image_size); mem_layout->free_size -= image_size + offset; /* Update the base of free memory since its moved up */ if (load_type == BOT_LOAD) mem_layout->free_base += offset + image_size; exit: io_result = io_close(image_handle); /* Ignore improbable/unrecoverable error in 'close' */ /* TODO: Consider maintaining open device connection from this bootloader stage */ io_result = io_dev_close(dev_handle); /* Ignore improbable/unrecoverable error in 'dev_close' */ return image_base; fail: image_base = 0; goto exit; }
/******************************************************************************* * Generic function to load an image into the trusted RAM using semihosting * given a name, extents of free memory & whether the image should be loaded at * the bottom or top of the free memory. It updates the memory layout if the * load is successful. ******************************************************************************/ unsigned long load_image(meminfo *mem_layout, const char *image_name, unsigned int load_type, unsigned long fixed_addr) { unsigned long temp_image_base, image_base; long offset; int image_flen; /* Find the size of the image */ image_flen = semihosting_get_flen(image_name); if (image_flen < 0) { printf("ERROR: Cannot access '%s' file (%i).\r\n", image_name, image_flen); return 0; } /* See if we have enough space */ if (image_flen > mem_layout->free_size) { printf("ERROR: Cannot load '%s' file: Not enough space.\r\n", image_name); dump_load_info(0, image_flen, mem_layout); return 0; } switch (load_type) { case TOP_LOAD: /* Load the image in the top of free memory */ temp_image_base = mem_layout->free_base + mem_layout->free_size; temp_image_base -= image_flen; /* Page align base address and check whether the image still fits */ image_base = page_align(temp_image_base, DOWN); assert(image_base <= temp_image_base); if (image_base < mem_layout->free_base) { printf("ERROR: Cannot load '%s' file: Not enough space.\r\n", image_name); dump_load_info(image_base, image_flen, mem_layout); return 0; } /* Calculate the amount of extra memory used due to alignment */ offset = temp_image_base - image_base; break; case BOT_LOAD: /* Load the BL2 image in the bottom of free memory */ temp_image_base = mem_layout->free_base; image_base = page_align(temp_image_base, UP); assert(image_base >= temp_image_base); /* Page align base address and check whether the image still fits */ if (image_base + image_flen > mem_layout->free_base + mem_layout->free_size) { printf("ERROR: Cannot load '%s' file: Not enough space.\r\n", image_name); dump_load_info(image_base, image_flen, mem_layout); return 0; } /* Calculate the amount of extra memory used due to alignment */ offset = image_base - temp_image_base; break; default: assert(0); } /* * Some images must be loaded at a fixed address, not a dynamic one. * * This has been implemented as a hack on top of the existing dynamic * loading mechanism, for the time being. If the 'fixed_addr' function * argument is different from zero, then it will force the load address. * So we still have this principle of top/bottom loading but the code * determining the load address is bypassed and the load address is * forced to the fixed one. * * This can result in quite a lot of wasted space because we still use * 1 sole meminfo structure to represent the extents of free memory, * where we should use some sort of linked list. * * E.g. we want to load BL2 at address 0x04020000, the resulting memory * layout should look as follows: * ------------ 0x04040000 * | | <- Free space (1) * |----------| * | BL2 | * |----------| 0x04020000 * | | <- Free space (2) * |----------| * | BL1 | * ------------ 0x04000000 * * But in the current hacky implementation, we'll need to specify * whether BL2 is loaded at the top or bottom of the free memory. * E.g. if BL2 is considered as top-loaded, the meminfo structure * will give the following view of the memory, hiding the chunk of * free memory above BL2: * ------------ 0x04040000 * | | * | | * | BL2 | * |----------| 0x04020000 * | | <- Free space (2) * |----------| * | BL1 | * ------------ 0x04000000 */ if (fixed_addr != 0) { /* Load the image at the given address. */ image_base = fixed_addr; /* Check whether the image fits. */ if ((image_base < mem_layout->free_base) || (image_base + image_flen > mem_layout->free_base + mem_layout->free_size)) { printf("ERROR: Cannot load '%s' file: Not enough space.\r\n", image_name); dump_load_info(image_base, image_flen, mem_layout); return 0; } /* Check whether the fixed load address is page-aligned. */ if (!is_page_aligned(image_base)) { printf("ERROR: Cannot load '%s' file at unaligned address 0x%lx.\r\n", image_name, fixed_addr); return 0; } /* * Calculate the amount of extra memory used due to fixed * loading. */ if (load_type == TOP_LOAD) { unsigned long max_addr, space_used; /* * ------------ max_addr * | /wasted/ | | offset * |..........|.............................. * | image | | image_flen * |----------| fixed_addr * | | * | | * ------------ total_base */ max_addr = mem_layout->total_base + mem_layout->total_size; /* * Compute the amount of memory used by the image. * Corresponds to all space above the image load * address. */ space_used = max_addr - fixed_addr; /* * Calculate the amount of wasted memory within the * amount of memory used by the image. */ offset = space_used - image_flen; } else /* BOT_LOAD */ /* * ------------ * | | * | | * |----------| * | image | * |..........| fixed_addr * | /wasted/ | | offset * ------------ total_base */ offset = fixed_addr - mem_layout->total_base; } /* We have enough space so load the image now */ image_flen = semihosting_download_file(image_name, image_flen, (void *) image_base); if (image_flen <= 0) { printf("ERROR: Failed to load '%s' file from semihosting (%i).\r\n", image_name, image_flen); return 0; } /* * File has been successfully loaded. Update the free memory * data structure & flush the contents of the TZRAM so that * the next EL can see it. */ /* Update the memory contents */ flush_dcache_range(image_base, image_flen); mem_layout->free_size -= image_flen + offset; /* Update the base of free memory since its moved up */ if (load_type == BOT_LOAD) mem_layout->free_base += offset + image_flen; return image_base; }
/* * This reads contents of a file in pages, calling the fs-specific file read function to read-in * those pages' contents. * * Normally this is ought to be called by mm0 when a file's pages cannot be found in the page * cache. */ int generic_file_read(struct vnode *v, unsigned long pfn, unsigned long npages, void *page_buf) { BUG_ON(!is_page_aligned(page_buf)); return v->fops.read(v, pfn, npages, page_buf); }