From patchwork Fri Mar 17 05:13:05 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cyril Bur X-Patchwork-Id: 740169 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [103.22.144.68]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3vkv5l1lq5z9ryZ for ; Fri, 17 Mar 2017 16:28:59 +1100 (AEDT) Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 3vkv5l0ypKzDrL7 for ; Fri, 17 Mar 2017 16:28:59 +1100 (AEDT) X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Received: from mx0a-001b2d01.pphosted.com (mx0a-001b2d01.pphosted.com [148.163.156.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 3vktqZ1cTmzDqrq for ; Fri, 17 Mar 2017 16:16:42 +1100 (AEDT) Received: from pps.filterd (m0098404.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.20/8.16.0.20) with SMTP id v2H5DlgL052402 for ; Fri, 17 Mar 2017 01:16:36 -0400 Received: from e23smtp09.au.ibm.com (e23smtp09.au.ibm.com [202.81.31.142]) by mx0a-001b2d01.pphosted.com with ESMTP id 297x6aj3yb-1 (version=TLSv1.2 cipher=AES256-SHA bits=256 verify=NOT) for ; Fri, 17 Mar 2017 01:16:35 -0400 Received: from localhost by e23smtp09.au.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Fri, 17 Mar 2017 15:16:32 +1000 Received: from d23relay07.au.ibm.com (202.81.31.226) by e23smtp09.au.ibm.com (202.81.31.206) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Fri, 17 Mar 2017 15:16:30 +1000 Received: from d23av01.au.ibm.com (d23av01.au.ibm.com [9.190.234.96]) by d23relay07.au.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id v2H5GMhF26148898 for ; Fri, 17 Mar 2017 16:16:30 +1100 Received: from d23av01.au.ibm.com (localhost [127.0.0.1]) by d23av01.au.ibm.com (8.14.4/8.14.4/NCO v10.0 AVout) with ESMTP id v2H5FvPe030991 for ; Fri, 17 Mar 2017 16:15:57 +1100 Received: from ozlabs.au.ibm.com (ozlabs.au.ibm.com [9.192.253.14]) by d23av01.au.ibm.com (8.14.4/8.14.4/NCO v10.0 AVin) with ESMTP id v2H5FvCt030481; Fri, 17 Mar 2017 16:15:57 +1100 Received: from camb691.ozlabs.ibm.com (haven.au.ibm.com [9.192.254.114]) (using TLSv1.2 with cipher DHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ozlabs.au.ibm.com (Postfix) with ESMTPSA id DD705A01C7; Fri, 17 Mar 2017 16:15:32 +1100 (AEDT) From: Cyril Bur To: skiboot@lists.ozlabs.org Date: Fri, 17 Mar 2017 16:13:05 +1100 X-Mailer: git-send-email 2.12.0 In-Reply-To: <20170317051309.16899-1-cyril.bur@au1.ibm.com> References: <20170317051309.16899-1-cyril.bur@au1.ibm.com> X-TM-AS-MML: disable x-cbid: 17031705-0052-0000-0000-00000225A17B X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 17031705-0053-0000-0000-000007FC9EF0 Message-Id: <20170317051309.16899-2-cyril.bur@au1.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:, , definitions=2017-03-17_04:, , signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 spamscore=0 suspectscore=4 malwarescore=0 phishscore=0 adultscore=0 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1702020001 definitions=main-1703170044 Subject: [Skiboot] [PATCH 1/5] libflash/libffs: Rework libffs X-BeenThere: skiboot@lists.ozlabs.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Mailing list for skiboot development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Skiboot" This patch attempts a rework of libffs to prepare it for future changes. Firstly the types are split in two: 1. Packed, big endian structures used to map exactly how the data is on flash. 2. CPU endian, sane valued, not packed structures used to manipulate FFS data. Secondly: The packed struct can use BE types so that in future tools like sparse can be run over the code to check for endian conversion bugs. Thirdly: defines of sizeof(struct ...) were removed for clarity. Finally: For ease of manipulation, the in memory FFS structures contain a linked list of entries as this will make addition and removal operations much easier. This patch should be invisible to consumers of libffs. Signed-off-by: Cyril Bur --- libflash/ffs.h | 155 +++++++++++++++--------- libflash/libffs.c | 356 ++++++++++++++++++++++++++++++++---------------------- libflash/libffs.h | 57 ++++++++- 3 files changed, 368 insertions(+), 200 deletions(-) diff --git a/libflash/ffs.h b/libflash/ffs.h index 5cb6778c..64e5e6a1 100644 --- a/libflash/ffs.h +++ b/libflash/ffs.h @@ -25,11 +25,16 @@ #define __FFS_H__ /* Pull in the correct header depending on what is being built */ -#if defined(__KERNEL__) +#ifndef __SKIBOOT__ #include #else #include #endif +#include +#include +#include + +#include "libffs.h" /* The version of this partition implementation */ #define FFS_VERSION_1 1 @@ -37,44 +42,22 @@ /* Magic number for the partition header (ASCII 'PART') */ #define FFS_MAGIC 0x50415254 -/* The maximum length of the partition name */ -#define PART_NAME_MAX 15 - -/* - * Sizes of the data structures - */ -#define FFS_HDR_SIZE sizeof(struct ffs_hdr) -#define FFS_ENTRY_SIZE sizeof(struct ffs_entry) - -/* - * Sizes of the data structures w/o checksum - */ -#define FFS_HDR_SIZE_CSUM (FFS_HDR_SIZE - sizeof(uint32_t)) -#define FFS_ENTRY_SIZE_CSUM (FFS_ENTRY_SIZE - sizeof(uint32_t)) - /* pid of logical partitions/containers */ #define FFS_PID_TOPLEVEL 0xFFFFFFFF /* * Type of image contained w/in partition */ -enum type { +enum ffs_type { FFS_TYPE_DATA = 1, FFS_TYPE_LOGICAL = 2, FFS_TYPE_PARTITION = 3, }; -/* - * Flag bit definitions - */ -#define FFS_FLAGS_PROTECTED 0x0001 -#define FFS_FLAGS_U_BOOT_ENV 0x0002 - -/* Data integrity flags */ -#define FFS_ENRY_INTEG_ECC 0x8000 - /** - * struct ffs_entry_user - User data enties + * struct __ffs_entry_user - On flash user data entries + * + * Represents the on flash layout of FFS structures * * @chip: Chip Select (0,1) * @compressType: Compression Indication/alg (0=not compressed) @@ -84,18 +67,22 @@ enum type { * @freeMisc[2]: Unused Miscellaneious Info * @freeUser[14]: Unused User Data */ -struct ffs_entry_user { - uint8_t chip; - uint8_t compresstype; - uint16_t datainteg; - uint8_t vercheck; - uint8_t miscflags; - uint8_t freemisc[2]; - uint32_t reserved[14]; -}; +struct __ffs_entry_user { + uint8_t chip; + uint8_t compresstype; + be16 datainteg; + uint8_t vercheck; + uint8_t miscflags; + uint8_t freemisc[2]; + be32 reserved[14]; +} __attribute__ ((packed)); /** - * struct ffs_entry - Partition entry + * struct __ffs_entry - On flash partition entry + * + * Represents the on flash layout of FFS structures + * Note: Unlike the in memory structures base and size of the entry are in + * units of block_size and the actual size is in bytes * * @name: Opaque null terminated string * @base: Starting offset of partition in flash (in hdr.block_size) @@ -109,22 +96,54 @@ struct ffs_entry_user { * @user: User data (optional) * @checksum: Partition entry checksum (includes all above) */ +struct __ffs_entry { + char name[FFS_PART_NAME_MAX + 1]; + be32 base; + be32 size; + be32 pid; + be32 id; + be32 type; + be32 flags; + be32 actual; + be32 resvd[4]; + struct __ffs_entry_user user; + /* The checksum is actually endian agnostic */ + uint32_t checksum; +} __attribute__ ((packed)); + +/** + * struct ffs_entry - Partition entry + * + * Useable in memory representation of a struct __ffs_entry + * Note: Unlike the on flash structure, all sizes here are in bytes! + * + * @name: Opaque null terminated string + * @base: Starting offset of partition in flash (in bytes) + * @size: Partition size (in bytes) + * @actual: Actual partition size (in bytes) + * @pid: Parent partition entry (FFS_PID_TOPLEVEL for toplevel) + * @type: Describe type of partition + * @flags: Partition attributes (optional) + * @user: User data (optional) + */ struct ffs_entry { - char name[PART_NAME_MAX + 1]; + char name[FFS_PART_NAME_MAX + 1]; uint32_t base; uint32_t size; + uint32_t actual; uint32_t pid; - uint32_t id; - uint32_t type; + enum ffs_type type; uint32_t flags; - uint32_t actual; - uint32_t resvd[4]; struct ffs_entry_user user; - uint32_t checksum; -} __attribute__ ((packed)); + struct list_node list; +}; + /** - * struct ffs_hdr - FSP Flash Structure header + * struct __ffs_hdr - On flash FSP Flash Structure header + * + * Represents the on flash layout of FFS structures + * Note: Beware that the size of the partition table is in units of block_size * * @magic: Eye catcher/corruption detector * @version: Version of the structure @@ -133,22 +152,44 @@ struct ffs_entry { * @entry_count: Number of struct ffs_entry elements in @entries array * @block_size: Size of block on device (in bytes) * @block_count: Number of blocks on device - * @resvd: Reserved words for future use + * @resvd[4]: Reserved words for future use * @checksum: Header checksum * @entries: Pointer to array of partition entries */ -struct ffs_hdr { - uint32_t magic; - uint32_t version; - uint32_t size; - uint32_t entry_size; - uint32_t entry_count; - uint32_t block_size; - uint32_t block_count; - uint32_t resvd[4]; - uint32_t checksum; - struct ffs_entry entries[]; +struct __ffs_hdr { + be32 magic; + be32 version; + be32 size; + be32 entry_size; + be32 entry_count; + be32 block_size; + be32 block_count; + be32 resvd[4]; + /* The checksum is actually endian agnostic */ + uint32_t checksum; + struct __ffs_entry entries[]; } __attribute__ ((packed)); +/** + * struct ffs_hdr - FSP Flash Structure header + * + * Useable in memory representation of a struct __ffs_hdr + * Note: All sizes here are in bytes + * + * @version: Version of the structure + * @size: Size of partition table (in bytes) + * @block_size: Size of block on device (in bytes) + * @block_count: Number of blocks on device. + * @backup The backup partition + * @side The ffs header for the other side + * @entries: List of partition entries + */ +struct ffs_hdr { + uint32_t version; + uint32_t size; + uint32_t block_size; + uint32_t block_count; + struct list_head entries; +}; #endif /* __FFS_H__ */ diff --git a/libflash/libffs.c b/libflash/libffs.c index 96b7c557..d2d77638 100644 --- a/libflash/libffs.c +++ b/libflash/libffs.c @@ -23,24 +23,26 @@ #ifndef __SKIBOOT__ #include #include +#else +static void *calloc(size_t num, size_t size) +{ + void *ptr = malloc(num * size); + if (ptr) + memset(ptr, 0, num * size); + return ptr; +} #endif -#include +#include "ffs.h" -#include "libffs.h" - -enum ffs_type { - ffs_type_flash, - ffs_type_image, -}; +#define __unused __attribute__((unused)) struct ffs_handle { struct ffs_hdr hdr; /* Converted header */ - enum ffs_type type; uint32_t toc_offset; uint32_t max_size; - void *cache; - uint32_t cached_size; + /* The converted header knows how big this is */ + struct __ffs_hdr *cache; struct blocklevel_device *bl; }; @@ -53,30 +55,153 @@ static uint32_t ffs_checksum(void* data, size_t size) return csum; } -static int ffs_check_convert_header(struct ffs_hdr *dst, struct ffs_hdr *src) +/* Helper functions for typesafety and size safety */ +static uint32_t ffs_hdr_checksum(struct __ffs_hdr *hdr) +{ + return ffs_checksum(hdr, sizeof(struct __ffs_hdr)); +} + +static uint32_t ffs_entry_checksum(struct __ffs_entry *ent) +{ + return ffs_checksum(ent, sizeof(struct __ffs_entry)); +} + +__unused static int ffs_num_entries(struct ffs_hdr *hdr) +{ + struct ffs_entry *ent; + int num_entries = 0; + list_for_each(&hdr->entries, ent, list) + num_entries++; + if (num_entries == 0) + FL_DBG("%s returned zero!\n", __func__); + return num_entries; +} + +__unused static size_t ffs_hdr_raw_size(int num_entries) { - dst->magic = be32_to_cpu(src->magic); - if (dst->magic != FFS_MAGIC) + return sizeof(struct __ffs_hdr) + num_entries * sizeof(struct __ffs_entry); +} + +static int ffs_check_convert_header(struct ffs_hdr *dst, struct __ffs_hdr *src) +{ + if (be32_to_cpu(src->magic) != FFS_MAGIC) return FFS_ERR_BAD_MAGIC; dst->version = be32_to_cpu(src->version); if (dst->version != FFS_VERSION_1) return FFS_ERR_BAD_VERSION; - if (ffs_checksum(src, FFS_HDR_SIZE) != 0) + if (ffs_hdr_checksum(src) != 0) return FFS_ERR_BAD_CKSUM; - dst->size = be32_to_cpu(src->size); - dst->entry_size = be32_to_cpu(src->entry_size); - dst->entry_count = be32_to_cpu(src->entry_count); + if (be32_to_cpu(src->entry_size) != sizeof(struct __ffs_entry)) + return FFS_ERR_BAD_SIZE; + if ((be32_to_cpu(src->entry_size) * be32_to_cpu(src->entry_count)) > + (be32_to_cpu(src->block_size) * be32_to_cpu(src->size))) + return FLASH_ERR_PARM_ERROR; + dst->block_size = be32_to_cpu(src->block_size); + dst->size = be32_to_cpu(src->size) * dst->block_size; dst->block_count = be32_to_cpu(src->block_count); return 0; } +static int ffs_entry_user_to_flash(struct __ffs_entry_user *dst, + struct ffs_entry_user *src) +{ + memset(dst, 0, sizeof(struct __ffs_entry_user)); + dst->datainteg = cpu_to_be16(src->datainteg); + dst->vercheck = src->vercheck; + dst->miscflags = src->miscflags; + + return 0; +} + +static int ffs_entry_user_to_cpu(struct ffs_entry_user *dst, + struct __ffs_entry_user *src) +{ + memset(dst, 0, sizeof(struct ffs_entry_user)); + dst->datainteg = be16_to_cpu(src->datainteg); + dst->vercheck = src->vercheck; + dst->miscflags = src->miscflags; + + return 0; +} + +static int ffs_entry_to_flash(struct ffs_hdr *hdr, + struct __ffs_entry *dst, struct ffs_entry *src) +{ + int rc, index = 1; /* On flash indexes start at 1 */ + struct ffs_entry *ent = NULL; + + if (!hdr || !dst || !src) + return -1; + + list_for_each(&hdr->entries, ent, list) { + if (ent == src) + break; + index++; + } + + if (!ent) + return FFS_ERR_PART_NOT_FOUND; + + memcpy(dst->name, src->name, sizeof(dst->name)); + dst->name[FFS_PART_NAME_MAX] = '\0'; + dst->base = cpu_to_be32(src->base / hdr->block_size); + dst->size = cpu_to_be32(src->size / hdr->block_size); + dst->pid = cpu_to_be32(src->pid); + dst->id = cpu_to_be32(index); + dst->type = cpu_to_be32(src->type); /* TODO: Check that it is valid? */ + dst->flags = cpu_to_be32(src->flags); + dst->actual = cpu_to_be32(src->actual); + rc = ffs_entry_user_to_flash(&dst->user, &src->user); + dst->checksum = ffs_entry_checksum(dst); + + return rc; +} + +static int ffs_entry_to_cpu(struct ffs_hdr *hdr, + struct ffs_entry *dst, struct __ffs_entry *src) +{ + int rc; + + if (ffs_entry_checksum(src) != 0) + return FFS_ERR_BAD_CKSUM; + + memcpy(dst->name, src->name, sizeof(dst->name)); + dst->name[FFS_PART_NAME_MAX] = '\0'; + dst->base = be32_to_cpu(src->base) * hdr->block_size; + dst->size = be32_to_cpu(src->size) * hdr->block_size; + dst->actual = be32_to_cpu(src->actual); + dst->pid = be32_to_cpu(src->pid); + dst->type = be32_to_cpu(src->type); /* TODO: Check that it is valid? */ + dst->flags = be32_to_cpu(src->flags); + rc = ffs_entry_user_to_cpu(&dst->user, &src->user); + + return rc; +} + +static struct ffs_entry *ffs_get_part(struct ffs_handle *ffs, uint32_t index) +{ + int i = 0; + struct ffs_entry *ent = NULL; + + list_for_each(&ffs->hdr.entries, ent, list) + if (i++ == index) + break; + + return ent; +} + +bool has_ecc(struct ffs_entry *ent) +{ + return ((ent->user.datainteg & FFS_ENRY_INTEG_ECC) != 0); +} + int ffs_init(uint32_t offset, uint32_t max_size, struct blocklevel_device *bl, struct ffs_handle **ffs, bool mark_ecc) { - struct ffs_hdr hdr; - struct ffs_hdr blank_hdr; + struct __ffs_hdr blank_hdr; + struct __ffs_hdr raw_hdr; struct ffs_handle *f; uint64_t total_size; int rc, i; @@ -99,7 +224,7 @@ int ffs_init(uint32_t offset, uint32_t max_size, struct blocklevel_device *bl, return FLASH_ERR_PARM_ERROR; /* Read flash header */ - rc = blocklevel_read(bl, offset, &hdr, sizeof(hdr)); + rc = blocklevel_read(bl, offset, &raw_hdr, sizeof(raw_hdr)); if (rc) { FL_ERR("FFS: Error %d reading flash header\n", rc); return rc; @@ -108,209 +233,159 @@ int ffs_init(uint32_t offset, uint32_t max_size, struct blocklevel_device *bl, /* * Flash controllers can get deconfigured or otherwise upset, when this * happens they return all 0xFF bytes. - * An ffs_hdr consisting of all 0xFF cannot be valid and it would be + * An __ffs_hdr consisting of all 0xFF cannot be valid and it would be * nice to drop a hint to the user to help with debugging. This will * help quickly differentiate between flash corruption and standard * type 'reading from the wrong place' errors vs controller errors or * reading erased data. */ - memset(&blank_hdr, UINT_MAX, sizeof(struct ffs_hdr)); - if (memcmp(&blank_hdr, &hdr, sizeof(struct ffs_hdr)) == 0) { + memset(&blank_hdr, UINT_MAX, sizeof(struct __ffs_hdr)); + if (memcmp(&blank_hdr, &raw_hdr, sizeof(struct __ffs_hdr)) == 0) { FL_ERR("FFS: Reading the flash has returned all 0xFF.\n"); - FL_ERR("Are you reading erased flash?\n"); - FL_ERR("Is something else using the flash controller?\n"); + FL_ERR(" Are you reading erased flash?\n"); + FL_ERR(" Is something else using the flash controller?\n"); return FLASH_ERR_BAD_READ; } /* Allocate ffs_handle structure and start populating */ - f = malloc(sizeof(*f)); + f = calloc(1, sizeof(*f)); if (!f) return FLASH_ERR_MALLOC_FAILED; - memset(f, 0, sizeof(*f)); f->toc_offset = offset; f->max_size = max_size; f->bl = bl; /* Convert and check flash header */ - rc = ffs_check_convert_header(&f->hdr, &hdr); + rc = ffs_check_convert_header(&f->hdr, &raw_hdr); if (rc) { FL_INF("FFS: Flash header not found. Code: %d\n", rc); goto out; } /* Check header is sane */ - if ((f->hdr.block_size * f->hdr.size) > max_size) { + if ((f->hdr.block_count * f->hdr.block_size) > max_size) { rc = FLASH_ERR_PARM_ERROR; FL_ERR("FFS: Flash header exceeds max flash size\n"); goto out; } - if ((f->hdr.entry_size * f->hdr.entry_count) > - (f->hdr.block_size * f->hdr.size)) { - rc = FLASH_ERR_PARM_ERROR; - FL_ERR("FFS: Flash header entries exceeds available blocks\n"); - goto out; - } - /* - * Decide how much of the image to grab to get the whole - * partition map. + * Grab the entire partition header */ - f->cached_size = f->hdr.block_size * f->hdr.size; /* Check for overflow or a silly size */ - if (!f->hdr.size || f->cached_size / f->hdr.size != f->hdr.block_size) { - rc= FLASH_ERR_MALLOC_FAILED; + if (!f->hdr.size || f->hdr.size % f->hdr.block_size != 0) { + rc = FLASH_ERR_MALLOC_FAILED; FL_ERR("FFS: Cache size overflow (0x%x * 0x%x)\n", f->hdr.block_size, f->hdr.size); goto out; } - FL_DBG("FFS: Partition map size: 0x%x\n", f->cached_size); + FL_DBG("FFS: Partition map size: 0x%x\n", f->hdr.size); /* Allocate cache */ - f->cache = malloc(f->cached_size); + f->cache = malloc(f->hdr.size); if (!f->cache) { rc = FLASH_ERR_MALLOC_FAILED; goto out; } /* Read the cached map */ - rc = blocklevel_read(bl, offset, f->cache, f->cached_size); + rc = blocklevel_read(bl, offset, f->cache, f->hdr.size); if (rc) { FL_ERR("FFS: Error %d reading flash partition map\n", rc); goto out; } - if (mark_ecc) { - uint32_t start, total_size; - bool ecc; - for (i = 0; i < f->hdr.entry_count; i++) { - rc = ffs_part_info(f, i, NULL, &start, &total_size, - NULL, &ecc); + list_head_init(&f->hdr.entries); + for (i = 0; i < be32_to_cpu(raw_hdr.entry_count); i++) { + struct ffs_entry *ent = calloc(1, sizeof(struct ffs_entry)); + if (!ent) { + rc = FLASH_ERR_MALLOC_FAILED; + goto out; + } + + list_add_tail(&f->hdr.entries, &ent->list); + rc = ffs_entry_to_cpu(&f->hdr, ent, &f->cache->entries[i]); + if (rc) + goto out; + + if (mark_ecc && has_ecc(ent)) { + rc = blocklevel_ecc_protect(bl, ent->base, ent->size); if (rc) { - FL_ERR("FFS: Failed to read ffs partition %d\n", - i); + FL_ERR("Failed to blocklevel_ecc_protect(0x%08x, 0x%08x)\n", + ent->base, ent->size); goto out; } - if (ecc) { - rc = blocklevel_ecc_protect(bl, start, total_size); - if (rc) { - FL_ERR("FFS: Failed to blocklevel_ecc_protect(0x%08x, 0x%08x)\n", - start, total_size); - goto out; - } - } /* ecc */ - } /* for */ + } } out: if (rc == 0) *ffs = f; else - free(f); + ffs_close(f); return rc; } void ffs_close(struct ffs_handle *ffs) { - if (ffs->cache) - free(ffs->cache); - free(ffs); -} + struct ffs_entry *ent, *next; -static struct ffs_entry *ffs_get_part(struct ffs_handle *ffs, uint32_t index, - uint32_t *out_offset) -{ - uint32_t esize = ffs->hdr.entry_size; - uint32_t offset = FFS_HDR_SIZE + index * esize; - - if (index > ffs->hdr.entry_count) - return NULL; - if (out_offset) - *out_offset = ffs->toc_offset + offset; - return (struct ffs_entry *)(ffs->cache + offset); -} + list_for_each_safe(&ffs->hdr.entries, ent, next, list) { + list_del(&ent->list); + free(ent); + } -static int ffs_check_convert_entry(struct ffs_entry *dst, struct ffs_entry *src) -{ - if (ffs_checksum(src, FFS_ENTRY_SIZE) != 0) - return FFS_ERR_BAD_CKSUM; - memcpy(dst->name, src->name, sizeof(dst->name)); - dst->base = be32_to_cpu(src->base); - dst->size = be32_to_cpu(src->size); - dst->pid = be32_to_cpu(src->pid); - dst->id = be32_to_cpu(src->id); - dst->type = be32_to_cpu(src->type); - dst->flags = be32_to_cpu(src->flags); - dst->actual = be32_to_cpu(src->actual); - dst->user.datainteg = be16_to_cpu(src->user.datainteg); + if (ffs->cache) + free(ffs->cache); - return 0; + free(ffs); } int ffs_lookup_part(struct ffs_handle *ffs, const char *name, uint32_t *part_idx) { - struct ffs_entry ent; - uint32_t i; - int rc; + int i = 0; + struct ffs_entry *ent = NULL; - /* Lookup the requested partition */ - for (i = 0; i < ffs->hdr.entry_count; i++) { - struct ffs_entry *src_ent = ffs_get_part(ffs, i, NULL); - rc = ffs_check_convert_entry(&ent, src_ent); - if (rc) { - FL_ERR("FFS: Bad entry %d in partition map\n", i); - continue; - } - if (!strncmp(name, ent.name, sizeof(ent.name))) + list_for_each(&ffs->hdr.entries, ent, list) { + if (!strncmp(name, ent->name, sizeof(ent->name))) break; + i++; } - if (i >= ffs->hdr.entry_count) - return FFS_ERR_PART_NOT_FOUND; + if (part_idx) *part_idx = i; - return 0; + return ent ? 0 : FFS_ERR_PART_NOT_FOUND; } int ffs_part_info(struct ffs_handle *ffs, uint32_t part_idx, char **name, uint32_t *start, uint32_t *total_size, uint32_t *act_size, bool *ecc) { - struct ffs_entry *raw_ent; - struct ffs_entry ent; + struct ffs_entry *ent; char *n; - int rc; - if (part_idx >= ffs->hdr.entry_count) + ent = ffs_get_part(ffs, part_idx); + if (!ent) return FFS_ERR_PART_NOT_FOUND; - raw_ent = ffs_get_part(ffs, part_idx, NULL); - if (!raw_ent) - return FFS_ERR_PART_NOT_FOUND; - - rc = ffs_check_convert_entry(&ent, raw_ent); - if (rc) { - FL_ERR("FFS: Bad entry %d in partition map\n", part_idx); - return rc; - } if (start) - *start = ent.base * ffs->hdr.block_size; + *start = ent->base; if (total_size) - *total_size = ent.size * ffs->hdr.block_size; + *total_size = ent->size; if (act_size) - *act_size = ent.actual; + *act_size = ent->actual; if (ecc) - *ecc = ((ent.user.datainteg & FFS_ENRY_INTEG_ECC) != 0); + *ecc = has_ecc(ent); if (name) { - n = malloc(PART_NAME_MAX + 1); + n = calloc(1, FFS_PART_NAME_MAX + 1); if (!n) return FLASH_ERR_MALLOC_FAILED; - memset(n, 0, PART_NAME_MAX + 1); - strncpy(n, ent.name, PART_NAME_MAX); + strncpy(n, ent->name, FFS_PART_NAME_MAX); *name = n; } return 0; @@ -360,33 +435,30 @@ int ffs_update_act_size(struct ffs_handle *ffs, uint32_t part_idx, uint32_t act_size) { struct ffs_entry *ent; + struct __ffs_entry raw_ent; uint32_t offset; + int rc; - if (part_idx >= ffs->hdr.entry_count) { - FL_DBG("FFS: Entry out of bound\n"); - return FFS_ERR_PART_NOT_FOUND; - } - - ent = ffs_get_part(ffs, part_idx, &offset); + ent = ffs_get_part(ffs, part_idx); if (!ent) { FL_DBG("FFS: Entry not found\n"); return FFS_ERR_PART_NOT_FOUND; } + offset = ent->base; FL_DBG("FFS: part index %d at offset 0x%08x\n", part_idx, offset); - /* - * NOTE: We are accessing the unconverted ffs_entry from the PNOR here - * (since we are going to write it back) so we need to be endian safe. - */ - if (ent->actual == cpu_to_be32(act_size)) { + if (ent->actual == act_size) { FL_DBG("FFS: ent->actual alrady matches: 0x%08x==0x%08x\n", - cpu_to_be32(act_size), ent->actual); + act_size, ent->actual); return 0; } - ent->actual = cpu_to_be32(act_size); - ent->checksum = ffs_checksum(ent, FFS_ENTRY_SIZE_CSUM); + ent->actual = act_size; + + rc = ffs_entry_to_flash(&ffs->hdr, &raw_ent, ent); + if (rc) + return rc; - return blocklevel_smart_write(ffs->bl, offset, ent, FFS_ENTRY_SIZE); + return blocklevel_smart_write(ffs->bl, offset, &raw_ent, sizeof(struct __ffs_entry)); } diff --git a/libflash/libffs.h b/libflash/libffs.h index a9ff5746..09769618 100644 --- a/libflash/libffs.h +++ b/libflash/libffs.h @@ -17,11 +17,30 @@ #define __LIBFFS_H #include -#include #include /* FFS handle, opaque */ struct ffs_handle; +struct ffs_entry; + +/** + * struct ffs_entry_user - User data entries + * + * Usable in memory representation of a struct __ffs_entry_user + * + * @chip: Chip Select (0,1) + * @compressType: Compression Indication/alg (0=not compressed) + * @dataInteg: Indicates Data Integrity mechanism + * @verCheck: Indicates Version check type + * @miscFlags: Misc Partition related Flags + */ +struct ffs_entry_user { + uint8_t chip; + uint8_t compresstype; + uint16_t datainteg; + uint8_t vercheck; + uint8_t miscflags; +}; /* Error codes: * @@ -34,6 +53,42 @@ struct ffs_handle; #define FFS_ERR_BAD_CKSUM 102 #define FFS_ERR_PART_NOT_FOUND 103 #define FFS_ERR_BAD_ECC 104 +#define FFS_ERR_BAD_SIZE 105 +#define FFS_ERR_BAD_PART_NAME 106 +#define FFS_ERR_BAD_PART_BASE 107 +#define FFS_ERR_BAD_PART_SIZE 108 +#define FFS_ERR_BAD_PART_PID 109 + +/* The maximum length of the partition name */ +#define FFS_PART_NAME_MAX 15 +/* Old version of the name DEPRECATED */ +#define PART_NAME_MAX 15 + +/* + * Flag bit definitions + */ +#define FFS_FLAGS_PROTECTED 0x0001 +#define FFS_FLAGS_U_BOOT_ENV 0x0002 + +/* Data integrity flags */ +#define FFS_ENRY_INTEG_ECC 0x8000 + +/* + * User verCheck definitions + */ +#define FFS_VERCHECK_SHA512V 0x80 +#define FFS_VERCHECK_SHA512EC 0x40 + +/* + * User miscFlags + */ +#define FFS_MISCFLAGS_PRESERVED 0x80 +#define FFS_MISCFLAGS_READONLY 0x40 +#define FFS_MISCFLAGS_BACKUP 0x20 +#define FFS_MISCFLAGS_REPROVISION 0x10 + + +bool has_ecc(struct ffs_entry *ent); /* Init */