size_t cbfs_load_and_decompress(const struct region_device *rdev, size_t offset, size_t in_size, void *buffer, size_t buffer_size, uint32_t compression) { size_t out_size; switch (compression) { case CBFS_COMPRESS_NONE: if (buffer_size < in_size) return 0; if (rdev_readat(rdev, buffer, offset, in_size) != in_size) return 0; return in_size; case CBFS_COMPRESS_LZ4: if ((ENV_BOOTBLOCK || ENV_VERSTAGE) && !IS_ENABLED(CONFIG_COMPRESS_PRERAM_STAGES)) return 0; /* Load the compressed image to the end of the available memory * area for in-place decompression. It is the responsibility of * the caller to ensure that buffer_size is large enough * (see compression.h, guaranteed by cbfstool for stages). */ void *compr_start = buffer + buffer_size - in_size; if (rdev_readat(rdev, compr_start, offset, in_size) != in_size) return 0; timestamp_add_now(TS_START_ULZ4F); out_size = ulz4fn(compr_start, in_size, buffer, buffer_size); timestamp_add_now(TS_END_ULZ4F); return out_size; case CBFS_COMPRESS_LZMA: if (ENV_BOOTBLOCK || ENV_VERSTAGE) return 0; if ((ENV_ROMSTAGE || ENV_POSTCAR) && !IS_ENABLED(CONFIG_COMPRESS_RAMSTAGE)) return 0; void *map = rdev_mmap(rdev, offset, in_size); if (map == NULL) return 0; /* Note: timestamp not useful for memory-mapped media (x86) */ timestamp_add_now(TS_START_ULZMA); out_size = ulzman(map, in_size, buffer, buffer_size); timestamp_add_now(TS_END_ULZMA); rdev_munmap(rdev, map); return out_size; default: return 0; } }
/** * Extract a node to given regions. * Returns true on error, false on success. */ static bool extract(struct region *region, struct fit_image_node *node) { void *dst = (void *)region->offset; const char *comp_name; size_t true_size = 0; switch (node->compression) { case CBFS_COMPRESS_NONE: comp_name = "Relocating uncompressed"; break; case CBFS_COMPRESS_LZMA: comp_name = "Decompressing LZMA"; break; case CBFS_COMPRESS_LZ4: comp_name = "Decompressing LZ4"; break; default: printk(BIOS_ERR, "ERROR: Unsupported compression\n"); return true; } printk(BIOS_INFO, "FIT: %s %s to %p\n", comp_name, node->name, dst); switch (node->compression) { case CBFS_COMPRESS_NONE: memcpy(dst, node->data, node->size); true_size = node->size; break; case CBFS_COMPRESS_LZMA: timestamp_add_now(TS_START_ULZMA); true_size = ulzman(node->data, node->size, dst, region->size); timestamp_add_now(TS_END_ULZMA); break; case CBFS_COMPRESS_LZ4: timestamp_add_now(TS_START_ULZ4F); true_size = ulz4fn(node->data, node->size, dst, region->size); timestamp_add_now(TS_END_ULZ4F); break; default: return true; } if (!true_size) { printk(BIOS_ERR, "ERROR: %s node failed!\n", comp_name); return true; } prog_segment_loaded(region->offset, true_size, 0); return false; }
int bootm_decomp_image(int comp, ulong load, ulong image_start, int type, void *load_buf, void *image_buf, ulong image_len, uint unc_len, ulong *load_end) { int ret = 0; *load_end = load; print_decomp_msg(comp, type, load == image_start); /* * Load the image to the right place, decompressing if needed. After * this, image_len will be set to the number of uncompressed bytes * loaded, ret will be non-zero on error. */ switch (comp) { case IH_COMP_NONE: if (load == image_start) break; if (image_len <= unc_len) memmove_wd(load_buf, image_buf, image_len, CHUNKSZ); else ret = 1; break; #ifdef CONFIG_GZIP case IH_COMP_GZIP: { ret = gunzip(load_buf, unc_len, image_buf, &image_len); break; } #endif /* CONFIG_GZIP */ #ifdef CONFIG_BZIP2 case IH_COMP_BZIP2: { uint size = unc_len; /* * If we've got less than 4 MB of malloc() space, * use slower decompression algorithm which requires * at most 2300 KB of memory. */ ret = BZ2_bzBuffToBuffDecompress(load_buf, &size, image_buf, image_len, CONFIG_SYS_MALLOC_LEN < (4096 * 1024), 0); image_len = size; break; } #endif /* CONFIG_BZIP2 */ #ifdef CONFIG_LZMA case IH_COMP_LZMA: { SizeT lzma_len = unc_len; ret = lzmaBuffToBuffDecompress(load_buf, &lzma_len, image_buf, image_len); image_len = lzma_len; break; } #endif /* CONFIG_LZMA */ #ifdef CONFIG_LZO case IH_COMP_LZO: { size_t size = unc_len; ret = lzop_decompress(image_buf, image_len, load_buf, &size); image_len = size; break; } #endif /* CONFIG_LZO */ #ifdef CONFIG_LZ4 case IH_COMP_LZ4: { size_t size = unc_len; ret = ulz4fn(image_buf, image_len, load_buf, &size); image_len = size; break; } #endif /* CONFIG_LZ4 */ default: printf("Unimplemented compression type %d\n", comp); return BOOTM_ERR_UNIMPLEMENTED; } if (ret) return handle_decomp_error(comp, image_len, unc_len, ret); *load_end = load + image_len; puts("OK\n"); return 0; }