From mboxrd@z Thu Jan 1 00:00:00 1970 Return-path: Received: from metis.ext.pengutronix.de ([2001:6f8:1178:4:290:27ff:fe1d:cc33]) by casper.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1Rb8ae-0001aU-SM for barebox@lists.infradead.org; Thu, 15 Dec 2011 10:31:12 +0000 From: Sascha Hauer Date: Thu, 15 Dec 2011 11:30:28 +0100 Message-Id: <1323945034-19687-7-git-send-email-s.hauer@pengutronix.de> In-Reply-To: <1323945034-19687-1-git-send-email-s.hauer@pengutronix.de> References: <1323945034-19687-1-git-send-email-s.hauer@pengutronix.de> List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: barebox-bounces@lists.infradead.org Errors-To: barebox-bounces+u.kleine-koenig=pengutronix.de@lists.infradead.org Subject: [PATCH 06/12] reimplement uImage code To: barebox@lists.infradead.org Provide a new API for accessing uImages which makes it easy for commands to open images, verify them, load to (free) sdram regions and show information about uImages. - We now do not load the image to malloced space anymore. - The data in the header is now stored in cpu native endianess after uimage_open which makes it easy to access the header data. - uImage can be loaded to dynamically allocated sdram regions. Signed-off-by: Sascha Hauer --- common/Makefile | 1 + common/uimage.c | 505 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ include/image.h | 30 ++++ 3 files changed, 536 insertions(+), 0 deletions(-) create mode 100644 common/uimage.c diff --git a/common/Makefile b/common/Makefile index 237c6b0..e02650b 100644 --- a/common/Makefile +++ b/common/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_CONSOLE_SIMPLE) += console_simple.o obj-$(CONFIG_DIGEST) += digest.o obj-$(CONFIG_ENVIRONMENT_VARIABLES) += env.o obj-$(CONFIG_CMD_BOOTM) += image.o +obj-$(CONFIG_CMD_BOOTM) += uimage.o obj-y += startup.o obj-y += misc.o obj-y += memsize.o diff --git a/common/uimage.c b/common/uimage.c new file mode 100644 index 0000000..28791b5 --- /dev/null +++ b/common/uimage.c @@ -0,0 +1,505 @@ +/* + * uimage.c - uimage handling code + * + * Copyright (c) 2011 Sascha Hauer , Pengutronix + * + * partly based on U-Boot uImage code + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_UIMAGE_MULTI +static inline int uimage_is_multi_image(struct uimage_handle *handle) +{ + return (handle->header.ih_type == IH_TYPE_MULTI) ? 1 : 0; +} +#else +static inline int uimage_is_multi_image(struct uimage_handle *handle) +{ + return 0; +} +#endif + +void uimage_print_contents(struct uimage_handle *handle) +{ + struct image_header *hdr = &handle->header; +#if defined(CONFIG_TIMESTAMP) + struct rtc_time tm; +#endif + printf(" Image Name: %.*s\n", IH_NMLEN, hdr->ih_name); +#if defined(CONFIG_TIMESTAMP) + printf(" Created: "); + to_tm(hdr->ih_time, &tm); + printf("%4d-%02d-%02d %2d:%02d:%02d UTC\n", + tm.tm_year, tm.tm_mon, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); +#endif +#if defined(CONFIG_CMD_BOOTM_SHOW_TYPE) + printf(" OS: %s\n", image_get_os_name(hdr->ih_os)); + printf(" Architecture: %s\n", image_get_arch_name(hdr->ih_arch)); + printf(" Type: %s\n", image_get_type_name(hdr->ih_type)); + printf(" Compression: %s\n", image_get_comp_name(hdr->ih_comp)); +#endif + printf(" Data Size: %d Bytes = %s\n", hdr->ih_size, + size_human_readable(hdr->ih_size)); + printf(" Load Address: %08x\n", hdr->ih_load); + printf(" Entry Point: %08x\n", hdr->ih_ep); + + if (uimage_is_multi_image(handle)) { + int i; + + printf(" Contents:\n"); + + for (i = 0; i < handle->nb_data_entries; i++) { + struct uimage_handle_data *data = &handle->ihd[i]; + + printf(" Image %d: %ld (%s)\n", i, + data->len, size_human_readable(data->len)); + } + } +} +EXPORT_SYMBOL(uimage_print_contents); + +size_t uimage_get_size(struct uimage_handle *handle, unsigned int image_no) +{ + if (image_no >= handle->nb_data_entries) + return -EINVAL; + + return handle->ihd[image_no].len; +} +EXPORT_SYMBOL(uimage_get_size); + +/* + * open a uimage. This will check the header contents and + * return a handle to the uImage + */ +struct uimage_handle *uimage_open(const char *filename) +{ + int fd; + uint32_t checksum; + struct uimage_handle *handle; + struct image_header *header; + int i; + int ret; + + fd = open(filename, O_RDONLY); + if (fd < 0) { + printf("could not open: %s\n", errno_str()); + return NULL; + } + + handle = xzalloc(sizeof(struct uimage_handle)); + header = &handle->header; + + if (read(fd, header, sizeof(*header)) < 0) { + printf("could not read: %s\n", errno_str()); + goto err_out; + } + + if (uimage_to_cpu(header->ih_magic) != IH_MAGIC) { + printf("Bad Magic Number\n"); + goto err_out; + } + + checksum = uimage_to_cpu(header->ih_hcrc); + header->ih_hcrc = 0; + + if (crc32(0, header, sizeof(*header)) != checksum) { + printf("Bad Header Checksum\n"); + goto err_out; + } + + /* convert header to cpu native endianess */ + header->ih_magic = uimage_to_cpu(header->ih_magic); + header->ih_hcrc = uimage_to_cpu(header->ih_hcrc); + header->ih_time = uimage_to_cpu(header->ih_time); + header->ih_size = uimage_to_cpu(header->ih_size); + header->ih_load = uimage_to_cpu(header->ih_load); + header->ih_ep = uimage_to_cpu(header->ih_ep); + header->ih_dcrc = uimage_to_cpu(header->ih_dcrc); + + if (header->ih_name[0]) { + handle->name = xzalloc(IH_NMLEN + 1); + strncpy(handle->name, header->ih_name, IH_NMLEN); + } else { + handle->name = xstrdup(filename); + } + + if (uimage_is_multi_image(handle)) { + size_t offset; + + for (i = 0; i < MAX_MULTI_IMAGE_COUNT; i++) { + u32 size; + + ret = read(fd, &size, sizeof(size)); + if (ret < 0) + goto err_out; + + if (!size) + break; + + handle->ihd[i].len = uimage_to_cpu(size); + } + + handle->nb_data_entries = i; + + /* offset of the first image in a multifile image */ + offset = 0; + + for (i = 0; i < handle->nb_data_entries; i++) { + handle->ihd[i].offset = offset; + offset += (handle->ihd[i].len + 3) & ~3; + } + + handle->data_offset = sizeof(struct image_header) + + sizeof(u32) * (handle->nb_data_entries + 1); + } else { + handle->ihd[0].offset = 0; + handle->ihd[0].len = header->ih_size; + handle->nb_data_entries = 1; + handle->data_offset = sizeof(struct image_header); + } + + /* + * fd is now at the first data word + */ + handle->fd = fd; + + return handle; +err_out: + close(fd); + free(handle); + return NULL; +} +EXPORT_SYMBOL(uimage_open); + +/* + * close a uImage previously opened with uimage_open + */ +void uimage_close(struct uimage_handle *handle) +{ + close(handle->fd); + free(handle->name); + free(handle); +} +EXPORT_SYMBOL(uimage_close); + +static int uimage_fd; + +static int uimage_fill(void *buf, unsigned int len) +{ + return read_full(uimage_fd, buf, len); +} + +static int uncompress_copy(unsigned char *inbuf_unused, int len, + int(*fill)(void*, unsigned int), + int(*flush)(void*, unsigned int), + unsigned char *outbuf_unused, + int *pos, + void(*error_fn)(char *x)) +{ + int ret; + void *buf = xmalloc(PAGE_SIZE); + + while (len) { + int now = min(len, PAGE_SIZE); + ret = fill(buf, now); + if (ret < 0) + goto err; + ret = flush(buf, now); + if (ret < 0) + goto err; + len -= now; + } + + ret = 0; +err: + free(buf); + return ret; +} + +/* + * Verify the data crc of an uImage + */ +int uimage_verify(struct uimage_handle *handle) +{ + u32 crc = 0; + int len, ret; + void *buf; + + ret = lseek(handle->fd, sizeof(struct image_header), SEEK_SET); + if (ret < 0) + return ret; + + buf = xmalloc(PAGE_SIZE); + + len = handle->header.ih_size; + while (len) { + int now = min(len, PAGE_SIZE); + ret = read(handle->fd, buf, now); + if (ret < 0) + goto err; + crc = crc32(crc, buf, now); + len -= ret; + } + + if (crc != handle->header.ih_dcrc) { + printf("Bad Data CRC: 0x%08x != 0x%08x\n", + crc, handle->header.ih_dcrc); + ret = -EINVAL; + goto err; + } + + ret = 0; +err: + free(buf); + + return ret; +} +EXPORT_SYMBOL(uimage_verify); + +/* + * Load a uimage, flushing output to flush function + */ +int uimage_load(struct uimage_handle *handle, unsigned int image_no, + int(*flush)(void*, unsigned int)) +{ + image_header_t *hdr = &handle->header; + struct uimage_handle_data *iha; + int ret; + int (*uncompress_fn)(unsigned char *inbuf, int len, + int(*fill)(void*, unsigned int), + int(*flush)(void*, unsigned int), + unsigned char *output, + int *pos, + void(*error)(char *x)); + + if (image_no >= handle->nb_data_entries) + return -EINVAL; + + iha = &handle->ihd[image_no]; + + ret = lseek(handle->fd, iha->offset + handle->data_offset, + SEEK_SET); + if (ret < 0) + return ret; + + if (hdr->ih_comp == IH_COMP_NONE) + uncompress_fn = uncompress_copy; + else + uncompress_fn = uncompress; + + uimage_fd = handle->fd; + + ret = uncompress_fn(NULL, iha->len, uimage_fill, flush, + NULL, NULL, + uncompress_err_stdout); + return ret; +} +EXPORT_SYMBOL(uimage_load); + +static void *uimage_buf; +static size_t uimage_size; +static struct resource *uimage_resource; + +static int uimage_sdram_flush(void *buf, unsigned int len) +{ + if (uimage_size + len > uimage_resource->size) { + resource_size_t start = uimage_resource->start; + resource_size_t size = uimage_resource->size + len; + release_sdram_region(uimage_resource); + + uimage_resource = request_sdram_region("uimage", + start, size); + if (!uimage_resource) { + printf("unable to request SDRAM 0x%08x-0x%08x\n", + start, start + size - 1); + return -ENOMEM; + } + } + + memcpy(uimage_buf + uimage_size, buf, len); + + uimage_size += len; + + return len; +} + +#define BUFSIZ (PAGE_SIZE * 2) + +struct resource *file_to_sdram(const char *filename, unsigned long adr) +{ + struct resource *res; + size_t size = BUFSIZ; + size_t ofs = 0; + int fd; + + fd = open(filename, O_RDONLY); + if (fd < 0) + return NULL; + + while (1) { + size_t now; + + res = request_sdram_region("image", adr, size); + if (!res) { + printf("unable to request SDRAM 0x%08lx-0x%08lx\n", + adr, adr + size - 1); + goto out; + } + + now = read_full(fd, (void *)(res->start + ofs), BUFSIZ); + if (now < 0) { + release_sdram_region(res); + res = NULL; + goto out; + } + if (now < BUFSIZ) + goto out; + + release_sdram_region(res); + + ofs += BUFSIZ; + size += BUFSIZ; + } +out: + close(fd); + + return res; +} + +/* + * Load an uImage to a dynamically allocated sdram resource. + * the resource must be freed afterwards with release_sdram_region + */ +struct resource *uimage_load_to_sdram(struct uimage_handle *handle, + int image_no, unsigned long load_address) +{ + int ret; + size_t size; + resource_size_t start = (resource_size_t)load_address; + + uimage_buf = (void *)load_address; + uimage_size = 0; + + size = uimage_get_size(handle, image_no); + if (size < 0) + return NULL; + + uimage_resource = request_sdram_region("uimage", + start, size); + if (!uimage_resource) { + printf("unable to request SDRAM 0x%08x-0x%08x\n", + start, start + size - 1); + return NULL; + } + + ret = uimage_load(handle, image_no, uimage_sdram_flush); + if (ret) { + release_sdram_region(uimage_resource); + return NULL; + } + + return uimage_resource; +} +EXPORT_SYMBOL(uimage_load_to_sdram); + +void *uimage_load_to_buf(struct uimage_handle *handle, int image_no, + size_t *outsize) +{ + u32 size; + int ret; + struct uimage_handle_data *ihd; + char ftbuf[128]; + enum filetype ft; + void *buf; + + if (image_no >= handle->nb_data_entries) + return NULL; + + ihd = &handle->ihd[image_no]; + + ret = lseek(handle->fd, ihd->offset + handle->data_offset, + SEEK_SET); + if (ret < 0) + return NULL; + + if (handle->header.ih_comp == IH_COMP_NONE) { + buf = malloc(ihd->len); + if (!buf) + return NULL; + + ret = read_full(handle->fd, buf, ihd->len); + if (ret < ihd->len) { + free(buf); + return NULL; + } + goto out; + } + + ret = read(handle->fd, ftbuf, 128); + if (ret < 0) + return NULL; + + ft = file_detect_type(ftbuf); + if ((int)ft < 0) + return NULL; + + if (ft != filetype_gzip) + return NULL; + + ret = lseek(handle->fd, ihd->offset + handle->data_offset + + ihd->len - 4, + SEEK_SET); + if (ret < 0) + return NULL; + + ret = read(handle->fd, &size, 4); + if (ret < 0) + return NULL; + + size = le32_to_cpu(size); + + ret = lseek(handle->fd, ihd->offset + handle->data_offset, + SEEK_SET); + if (ret < 0) + return NULL; + + buf = malloc(size); + ret = uncompress_fd_to_buf(handle->fd, buf, uncompress_err_stdout); + if (ret) { + free(buf); + return NULL; + } + +out: + if (outsize) + *outsize = size; + + return buf; +} diff --git a/include/image.h b/include/image.h index f3a9949..5e9b6e2 100644 --- a/include/image.h +++ b/include/image.h @@ -349,4 +349,34 @@ struct image_handle_data* gen_image_handle_data(void* data, ulong len); */ int relocate_image(struct image_handle *handle, void *load_address); +struct uimage_handle_data { + size_t offset; /* offset in the image */ + ulong len; +}; + +struct uimage_handle *uimage_open(const char *filename); +void uimage_close(struct uimage_handle *handle); +int uimage_verify(struct uimage_handle *handle); +int uimage_load(struct uimage_handle *handle, unsigned int image_no, + int(*flush)(void*, unsigned int)); +void uimage_print_contents(struct uimage_handle *handle); +size_t uimage_get_size(struct uimage_handle *handle, unsigned int image_no); +struct resource *uimage_load_to_sdram(struct uimage_handle *handle, + int image_no, unsigned long load_address); +void *uimage_load_to_buf(struct uimage_handle *handle, int image_no, + size_t *size); +struct resource *file_to_sdram(const char *filename, unsigned long adr); +#define MAX_MULTI_IMAGE_COUNT 16 + +struct uimage_handle { + struct image_header header; + char *name; + struct uimage_handle_data ihd[MAX_MULTI_IMAGE_COUNT]; + int nb_data_entries; + size_t data_offset; + int fd; +}; + +#define UIMAGE_INVALID_ADDRESS (~0) + #endif /* __IMAGE_H__ */ -- 1.7.7.3 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox