From patchwork Mon Aug 31 14:46:03 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Maxime Ripard X-Patchwork-Id: 512518 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id C61911401E7 for ; Tue, 1 Sep 2015 00:48:37 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id CD22B4B7C5; Mon, 31 Aug 2015 16:47:59 +0200 (CEST) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id vfrC85mfgoSg; Mon, 31 Aug 2015 16:47:59 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id B809B4B836; Mon, 31 Aug 2015 16:47:48 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id CB2CB4B786 for ; Mon, 31 Aug 2015 16:46:32 +0200 (CEST) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id ttXYiYz3zOj8 for ; Mon, 31 Aug 2015 16:46:32 +0200 (CEST) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from mail.free-electrons.com (down.free-electrons.com [37.187.137.238]) by theia.denx.de (Postfix) with ESMTP id 6839C4B78E for ; Mon, 31 Aug 2015 16:46:28 +0200 (CEST) Received: by mail.free-electrons.com (Postfix, from userid 110) id 1C7BE4965; Mon, 31 Aug 2015 16:46:28 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on mail.free-electrons.com X-Spam-Level: X-Spam-Status: No, score=-1.0 required=5.0 tests=ALL_TRUSTED,SHORTCIRCUIT, URIBL_BLOCKED shortcircuit=ham autolearn=disabled version=3.4.0 Received: from localhost (AToulouse-657-1-1058-12.w83-193.abo.wanadoo.fr [83.193.172.12]) by mail.free-electrons.com (Postfix) with ESMTPSA id D0BB74937; Mon, 31 Aug 2015 16:46:27 +0200 (CEST) From: Maxime Ripard To: Hans de Goede , Ian Campbell , Marek Vasut , =?UTF-8?q?=C5=81ukasz=20Majewski?= Date: Mon, 31 Aug 2015 16:46:03 +0200 Message-Id: <1441032373-16992-4-git-send-email-maxime.ripard@free-electrons.com> X-Mailer: git-send-email 2.5.0 In-Reply-To: <1441032373-16992-1-git-send-email-maxime.ripard@free-electrons.com> References: <1441032373-16992-1-git-send-email-maxime.ripard@free-electrons.com> Cc: Rob Herring , u-boot@lists.denx.de, Alexander Kaplan , Tom Rini Subject: [U-Boot] [PATCH 03/13] sparse: Refactor chunk parsing function X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.15 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" The chunk parsing code was duplicating a lot of code among the various chunk types, while all of them could be covered by generic and simple functions. Refactor the current code to reuse as much code as possible and hopefully make the chunk parsing loop more readable and concise. Signed-off-by: Maxime Ripard Reviewed-by: Tom Rini --- common/aboot.c | 351 ++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 221 insertions(+), 130 deletions(-) diff --git a/common/aboot.c b/common/aboot.c index 7f12677d13a1..65e633acfcb9 100644 --- a/common/aboot.c +++ b/common/aboot.c @@ -37,10 +37,29 @@ #include #include #include +#include #include #include #include +static unsigned int sparse_get_chunk_data_size(sparse_header_t *sparse, + chunk_header_t *chunk) +{ + return chunk->total_sz - sparse->chunk_hdr_sz; +} + +static bool sparse_chunk_has_buffer(chunk_header_t *chunk) +{ + switch (chunk->chunk_type) { + case CHUNK_TYPE_RAW: + case CHUNK_TYPE_FILL: + return true; + + default: + return false; + } +} + static sparse_header_t *sparse_parse_header(void **data) { /* Read and skip over sparse image header */ @@ -61,6 +80,173 @@ static sparse_header_t *sparse_parse_header(void **data) return sparse_header; } +static int sparse_parse_fill_chunk(sparse_header_t *sparse, + chunk_header_t *chunk) +{ + unsigned int chunk_data_sz = sparse_get_chunk_data_size(sparse, chunk); + + if (chunk_data_sz != sizeof(uint32_t)) + return -EINVAL; + + return 0; +} + +static int sparse_parse_raw_chunk(sparse_header_t *sparse, + chunk_header_t *chunk) +{ + unsigned int chunk_data_sz = sparse_get_chunk_data_size(sparse, chunk); + + /* Check if the data size is a multiple of the main block size */ + if (chunk_data_sz % sparse->blk_sz) + return -EINVAL; + + /* Check that the chunk size is consistent */ + if ((chunk_data_sz / sparse->blk_sz) != chunk->chunk_sz) + return -EINVAL; + + return 0; +} + +static chunk_header_t *sparse_parse_chunk(sparse_header_t *sparse, + void **image) +{ + chunk_header_t *chunk = (chunk_header_t *) *image; + int ret; + + debug("=== Chunk Header ===\n"); + debug("chunk_type: 0x%x\n", chunk->chunk_type); + debug("chunk_data_sz: 0x%x\n", chunk->chunk_sz); + debug("total_size: 0x%x\n", chunk->total_sz); + + switch (chunk->chunk_type) { + case CHUNK_TYPE_RAW: + ret = sparse_parse_raw_chunk(sparse, chunk); + if (ret) + return NULL; + break; + + case CHUNK_TYPE_FILL: + ret = sparse_parse_fill_chunk(sparse, chunk); + if (ret) + return NULL; + break; + + case CHUNK_TYPE_DONT_CARE: + case CHUNK_TYPE_CRC32: + debug("Ignoring chunk\n"); + break; + + default: + printf("%s: Unknown chunk type: %x\n", __func__, + chunk->chunk_type); + return NULL; + } + + *image += sparse->chunk_hdr_sz; + + return chunk; +} + +static int sparse_get_fill_buffer(sparse_header_t *sparse, + chunk_header_t *chunk, + sparse_buffer_t *buffer, + unsigned int blk_sz, + void *data) +{ + int i; + + buffer->type = CHUNK_TYPE_FILL; + + /* + * We create a buffer of one block, and ask it to be + * repeated as many times as needed. + */ + buffer->length = blk_sz; + buffer->repeat = (chunk->chunk_sz * sparse->blk_sz) / blk_sz; + + buffer->data = memalign(ARCH_DMA_MINALIGN, + ROUNDUP(blk_sz, + ARCH_DMA_MINALIGN)); + if (!buffer->data) + return -ENOMEM; + + for (i = 0; i < (buffer->length / sizeof(uint32_t)); i++) + ((uint32_t *)buffer->data)[i] = *(uint32_t *)(data); + + return 0; +} + +static int sparse_get_raw_buffer(sparse_header_t *sparse, + chunk_header_t *chunk, + sparse_buffer_t *buffer, + unsigned int blk_sz, + void *data) +{ + unsigned int chunk_data_sz = sparse_get_chunk_data_size(sparse, chunk); + + buffer->type = CHUNK_TYPE_RAW; + buffer->length = chunk_data_sz; + buffer->data = data; + buffer->repeat = 1; + + return 0; +} + +static sparse_buffer_t *sparse_get_data_buffer(sparse_header_t *sparse, + chunk_header_t *chunk, + unsigned int blk_sz, + void **image) +{ + unsigned int chunk_data_sz = sparse_get_chunk_data_size(sparse, chunk); + sparse_buffer_t *buffer; + void *data = *image; + int ret; + + *image += chunk_data_sz; + + if (!sparse_chunk_has_buffer(chunk)) + return NULL; + + buffer = calloc(sizeof(sparse_buffer_t), 1); + if (!buffer) + return NULL; + + switch(chunk->chunk_type) { + case CHUNK_TYPE_RAW: + ret = sparse_get_raw_buffer(sparse, chunk, buffer, blk_sz, + data); + if (ret) + return NULL; + break; + + case CHUNK_TYPE_FILL: + ret = sparse_get_fill_buffer(sparse, chunk, buffer, blk_sz, + data); + if (ret) + return NULL; + break; + + default: + return NULL; + } + + debug("=== Buffer ===\n"); + debug("length: 0x%x\n", buffer->length); + debug("repeat: 0x%x\n", buffer->repeat); + debug("type: 0x%x\n", buffer->type); + debug("data: 0x%p\n", buffer->data); + + return buffer; +} + +static void sparse_put_data_buffer(sparse_buffer_t *buffer) +{ + if (buffer->type == CHUNK_TYPE_FILL) + free(buffer->data); + + free(buffer); +} + void write_sparse_image(block_dev_desc_t *dev_desc, disk_partition_t *info, const char *part_name, void *data, unsigned sz) @@ -69,12 +255,10 @@ void write_sparse_image(block_dev_desc_t *dev_desc, lbaint_t blkcnt; lbaint_t blks; uint32_t bytes_written = 0; - unsigned int chunk; - unsigned int chunk_data_sz; - uint32_t *fill_buf = NULL; - uint32_t fill_val; + unsigned int chunk; sparse_header_t *sparse_header; - chunk_header_t *chunk_header; + chunk_header_t *chunk_header; + sparse_buffer_t *buffer; uint32_t total_blocks = 0; int i; @@ -97,142 +281,49 @@ void write_sparse_image(block_dev_desc_t *dev_desc, /* Start processing chunks */ blk = info->start; - for (chunk=0; chunktotal_chunks; chunk++) - { - /* Read and skip over chunk header */ - chunk_header = (chunk_header_t *) data; - data += sizeof(chunk_header_t); - - if (chunk_header->chunk_type != CHUNK_TYPE_RAW) { - debug("=== Chunk Header ===\n"); - debug("chunk_type: 0x%x\n", chunk_header->chunk_type); - debug("chunk_data_sz: 0x%x\n", chunk_header->chunk_sz); - debug("total_size: 0x%x\n", chunk_header->total_sz); + for (chunk = 0; chunk < sparse_header->total_chunks; chunk++) { + chunk_header = sparse_parse_chunk(sparse_header, &data); + if (!chunk_header) { + fastboot_fail("Unknown chunk type"); + return; } - if (sparse_header->chunk_hdr_sz > sizeof(chunk_header_t)) - { - /* - * Skip the remaining bytes in a header that is longer - * than we expected. - */ - data += (sparse_header->chunk_hdr_sz - - sizeof(chunk_header_t)); - } + /* Retrieve the buffer we're going to write */ + buffer = sparse_get_data_buffer(sparse_header, chunk_header, + info->blksz, &data); + if (!buffer) + continue; - chunk_data_sz = sparse_header->blk_sz * chunk_header->chunk_sz; - blkcnt = chunk_data_sz / info->blksz; - switch (chunk_header->chunk_type) - { - case CHUNK_TYPE_RAW: - if (chunk_header->total_sz != - (sparse_header->chunk_hdr_sz + chunk_data_sz)) - { - fastboot_fail( - "Bogus chunk size for chunk type Raw"); - return; - } + blkcnt = (buffer->length / info->blksz) * buffer->repeat; - if (blk + blkcnt > info->start + info->size) { - printf( - "%s: Request would exceed partition size!\n", - __func__); - fastboot_fail( - "Request would exceed partition size!"); - return; - } - - blks = dev_desc->block_write(dev_desc->dev, blk, blkcnt, - data); - if (blks != blkcnt) { - printf("%s: Write failed " LBAFU "\n", - __func__, blks); - fastboot_fail("flash write failure"); - return; - } - blk += blkcnt; - bytes_written += blkcnt * info->blksz; - total_blocks += chunk_header->chunk_sz; - data += chunk_data_sz; - break; - - case CHUNK_TYPE_FILL: - if (chunk_header->total_sz != - (sparse_header->chunk_hdr_sz + sizeof(uint32_t))) - { - fastboot_fail( - "Bogus chunk size for chunk type FILL"); - return; - } - - fill_buf = (uint32_t *) - memalign(ARCH_DMA_MINALIGN, - ROUNDUP(info->blksz, - ARCH_DMA_MINALIGN)); - if (!fill_buf) - { - fastboot_fail( - "Malloc failed for: CHUNK_TYPE_FILL"); - return; - } - - fill_val = *(uint32_t *)data; - data = (char *) data + sizeof(uint32_t); + if (blk + blkcnt > info->start + info->size) { + printf("%s: Request would exceed partition size!\n", + __func__); + fastboot_fail("Request would exceed partition size!"); + return; + } - for (i = 0; i < (info->blksz / sizeof(fill_val)); i++) - fill_buf[i] = fill_val; + for (i = 0; i < buffer->repeat; i++) { + unsigned int buffer_blk_cnt; + unsigned int buffer_blks; - if (blk + blkcnt > info->start + info->size) { - printf( - "%s: Request would exceed partition size!\n", - __func__); - fastboot_fail( - "Request would exceed partition size!"); - return; - } + buffer_blk_cnt = buffer->length / storage->block_sz; - for (i = 0; i < blkcnt; i++) { - blks = dev_desc->block_write(dev_desc->dev, - blk, 1, fill_buf); - if (blks != 1) { - printf( - "%s: Write failed, block # " LBAFU "\n", - __func__, blkcnt); - fastboot_fail("flash write failure"); - free(fill_buf); - return; - } - blk++; - } - bytes_written += blkcnt * info->blksz; - total_blocks += chunk_data_sz / sparse_header->blk_sz; - - free(fill_buf); - break; - - case CHUNK_TYPE_DONT_CARE: - blk += blkcnt; - total_blocks += chunk_header->chunk_sz; - break; - - case CHUNK_TYPE_CRC32: - if (chunk_header->total_sz != - sparse_header->chunk_hdr_sz) - { - fastboot_fail( - "Bogus chunk size for chunk type Dont Care"); + buffer_blks = dev_desc->block_write(dev_desc->dev, blk, + buffer_blk_cnt, buffer->data); + if (buffer_blks != buffer_blk_cnt) { + printf("%s: Write %d failed " LBAFU "\n", + __func__, i, buffer_blks); + fastboot_fail("flash write failure"); return; } - total_blocks += chunk_header->chunk_sz; - data += chunk_data_sz; - break; - default: - printf("%s: Unknown chunk type: %x\n", __func__, - chunk_header->chunk_type); - fastboot_fail("Unknown chunk type"); - return; + blk += buffer_blk_cnt; + bytes_written += buffer->length; + total_blocks += buffer_blk_cnt; } + + sparse_put_data_buffer(buffer); } debug("Wrote %d blocks, expected to write %d blocks\n",