LCOV - code coverage report
Current view: top level - external/ffspart/libflash - libffs.c (source / functions) Hit Total Coverage
Test: skiboot.info Lines: 192 430 44.7 %
Date: 2024-09-10 18:37:41 Functions: 15 28 53.6 %
Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: Apache-2.0
       2                 :            : /* Copyright 2013-2019 IBM Corp. */
       3                 :            : 
       4                 :            : #include <limits.h>
       5                 :            : #include <stdlib.h>
       6                 :            : #include <stdio.h>
       7                 :            : #include <string.h>
       8                 :            : 
       9                 :            : #ifndef __SKIBOOT__
      10                 :            : #include <sys/types.h>
      11                 :            : #include <unistd.h>
      12                 :            : #endif
      13                 :            : 
      14                 :            : #include "ffs.h"
      15                 :            : 
      16                 :            : #define __unused __attribute__((unused))
      17                 :            : #define HDR_ENTRIES_NUM 30
      18                 :            : 
      19                 :            : struct ffs_handle {
      20                 :            :         struct ffs_hdr          hdr;    /* Converted header */
      21                 :            :         uint32_t                toc_offset;
      22                 :            :         uint32_t                max_size;
      23                 :            :         /* The converted header knows how big this is */
      24                 :            :         struct __ffs_hdr *cache;
      25                 :            :         struct blocklevel_device *bl;
      26                 :            : };
      27                 :            : 
      28                 :          0 : static uint32_t ffs_checksum(void* data, size_t size)
      29                 :            : {
      30                 :          0 :         uint32_t i, csum = 0;
      31                 :            : 
      32                 :       1200 :         for (i = csum = 0; i < (size/4); i++)
      33                 :       1160 :                 csum ^= ((uint32_t *)data)[i];
      34                 :         40 :         return csum;
      35                 :            : }
      36                 :            : 
      37                 :            : /* Helper functions for typesafety and size safety */
      38                 :          6 : static uint32_t ffs_hdr_checksum(struct __ffs_hdr *hdr)
      39                 :            : {
      40                 :            :         return ffs_checksum(hdr, sizeof(struct __ffs_hdr));
      41                 :            : }
      42                 :            : 
      43                 :         34 : static uint32_t ffs_entry_checksum(struct __ffs_entry *ent)
      44                 :            : {
      45                 :          0 :         return ffs_checksum(ent, sizeof(struct __ffs_entry));
      46                 :            : }
      47                 :            : 
      48                 :          6 : static size_t ffs_hdr_raw_size(int num_entries)
      49                 :            : {
      50                 :          6 :         return sizeof(struct __ffs_hdr) + num_entries * sizeof(struct __ffs_entry);
      51                 :            : }
      52                 :            : 
      53                 :          6 : static int ffs_num_entries(struct ffs_hdr *hdr)
      54                 :            : {
      55                 :          6 :         if (hdr->count == 0)
      56                 :          0 :                 FL_DBG("%s returned zero!\n", __func__);
      57                 :          6 :         return hdr->count;
      58                 :            : }
      59                 :            : 
      60                 :          0 : static int ffs_check_convert_header(struct ffs_hdr *dst, struct __ffs_hdr *src)
      61                 :            : {
      62                 :          0 :         if (be32_to_cpu(src->magic) != FFS_MAGIC)
      63                 :            :                 return FFS_ERR_BAD_MAGIC;
      64                 :          0 :         dst->version = be32_to_cpu(src->version);
      65                 :          0 :         if (dst->version != FFS_VERSION_1)
      66                 :            :                 return FFS_ERR_BAD_VERSION;
      67                 :          0 :         if (ffs_hdr_checksum(src) != 0)
      68                 :            :                 return FFS_ERR_BAD_CKSUM;
      69                 :          0 :         if (be32_to_cpu(src->entry_size) != sizeof(struct __ffs_entry))
      70                 :            :                 return FFS_ERR_BAD_SIZE;
      71                 :          0 :         if ((be32_to_cpu(src->entry_size) * be32_to_cpu(src->entry_count)) >
      72                 :          0 :                         (be32_to_cpu(src->block_size) * be32_to_cpu(src->size)))
      73                 :            :                 return FLASH_ERR_PARM_ERROR;
      74                 :            : 
      75                 :          0 :         dst->block_size = be32_to_cpu(src->block_size);
      76                 :          0 :         dst->size = be32_to_cpu(src->size) * dst->block_size;
      77                 :          0 :         dst->block_count = be32_to_cpu(src->block_count);
      78                 :          0 :         dst->entries_size = be32_to_cpu(src->entry_count);
      79                 :            : 
      80                 :          0 :         return 0;
      81                 :            : }
      82                 :            : 
      83                 :         34 : static int ffs_entry_user_to_flash(struct ffs_hdr *hdr __unused,
      84                 :            :                 struct __ffs_entry_user *dst, struct ffs_entry_user *src)
      85                 :            : {
      86                 :         34 :         memset(dst, 0, sizeof(struct __ffs_entry_user));
      87                 :         34 :         dst->datainteg = cpu_to_be16(src->datainteg);
      88                 :         34 :         dst->vercheck = src->vercheck;
      89                 :         34 :         dst->miscflags = src->miscflags;
      90                 :            : 
      91                 :         34 :         return 0;
      92                 :            : }
      93                 :            : 
      94                 :          0 : static int ffs_entry_user_to_cpu(struct ffs_hdr *hdr __unused,
      95                 :            :                 struct ffs_entry_user *dst, struct __ffs_entry_user *src)
      96                 :            : {
      97                 :          0 :         memset(dst, 0, sizeof(struct ffs_entry_user));
      98                 :          0 :         dst->datainteg = be16_to_cpu(src->datainteg);
      99                 :          0 :         dst->vercheck = src->vercheck;
     100                 :          0 :         dst->miscflags = src->miscflags;
     101                 :            : 
     102                 :          0 :         return 0;
     103                 :            : }
     104                 :            : 
     105                 :         34 : static int ffs_entry_to_flash(struct ffs_hdr *hdr,
     106                 :            :                 struct __ffs_entry *dst, struct ffs_entry *src)
     107                 :            : {
     108                 :         34 :         int rc, index;
     109                 :            : 
     110                 :         34 :         if (!hdr || !dst || !src)
     111                 :            :                 return -1;
     112                 :            : 
     113                 :        116 :         for (index = 0; index < hdr->count && hdr->entries[index] != src; index++);
     114                 :            : 
     115                 :         34 :         if (index == hdr->count)
     116                 :            :                 return FFS_ERR_PART_NOT_FOUND;
     117                 :         34 :         index++; /* On flash indexes start at 1 */
     118                 :            :         /*
     119                 :            :          * So that the checksum gets calculated correctly at least the
     120                 :            :          * dst->checksum must be zero before calling ffs_entry_checksum()
     121                 :            :          * memset()ting the entire struct to zero is probably wise as it
     122                 :            :          * appears the reserved fields are always zero.
     123                 :            :          */
     124                 :         34 :         memset(dst, 0, sizeof(*dst));
     125                 :            : 
     126                 :         34 :         memcpy(dst->name, src->name, sizeof(dst->name));
     127                 :         34 :         dst->name[FFS_PART_NAME_MAX] = '\0';
     128                 :         34 :         dst->base = cpu_to_be32(src->base / hdr->block_size);
     129                 :         34 :         dst->size = cpu_to_be32(src->size / hdr->block_size);
     130                 :         34 :         dst->pid = cpu_to_be32(src->pid);
     131                 :         34 :         dst->id = cpu_to_be32(index);
     132                 :         34 :         dst->type = cpu_to_be32(src->type); /* TODO: Check that it is valid? */
     133                 :         34 :         dst->flags = cpu_to_be32(src->flags);
     134                 :         34 :         dst->actual = cpu_to_be32(src->actual);
     135                 :         34 :         rc = ffs_entry_user_to_flash(hdr, &dst->user, &src->user);
     136                 :         34 :         dst->checksum = ffs_entry_checksum(dst);
     137                 :            : 
     138                 :         34 :         return rc;
     139                 :            : }
     140                 :            : 
     141                 :          0 : static int ffs_entry_to_cpu(struct ffs_hdr *hdr,
     142                 :            :                 struct ffs_entry *dst, struct __ffs_entry *src)
     143                 :            : {
     144                 :          0 :         int rc;
     145                 :            : 
     146                 :          0 :         if (ffs_entry_checksum(src) != 0)
     147                 :            :                 return FFS_ERR_BAD_CKSUM;
     148                 :            : 
     149                 :          0 :         memcpy(dst->name, src->name, sizeof(dst->name));
     150                 :          0 :         dst->name[FFS_PART_NAME_MAX] = '\0';
     151                 :          0 :         dst->base = be32_to_cpu(src->base) * hdr->block_size;
     152                 :          0 :         dst->size = be32_to_cpu(src->size) * hdr->block_size;
     153                 :          0 :         dst->actual = be32_to_cpu(src->actual);
     154                 :          0 :         dst->pid = be32_to_cpu(src->pid);
     155                 :          0 :         dst->type = be32_to_cpu(src->type); /* TODO: Check that it is valid? */
     156                 :          0 :         dst->flags = be32_to_cpu(src->flags);
     157                 :          0 :         rc = ffs_entry_user_to_cpu(hdr, &dst->user, &src->user);
     158                 :            : 
     159                 :          0 :         return rc;
     160                 :            : }
     161                 :            : 
     162                 :          0 : char *ffs_entry_user_to_string(struct ffs_entry_user *user)
     163                 :            : {
     164                 :          0 :         char *ret;
     165                 :            : 
     166                 :          0 :         if (!user)
     167                 :            :                 return NULL;
     168                 :            : 
     169                 :          0 :         ret = strdup("----------");
     170                 :          0 :         if (!ret)
     171                 :            :                 return NULL;
     172                 :            : 
     173                 :          0 :         if (user->datainteg & FFS_ENRY_INTEG_ECC)
     174                 :          0 :                 ret[0] = 'E';
     175                 :            : 
     176                 :          0 :         if (user->vercheck & FFS_VERCHECK_SHA512V)
     177                 :          0 :                 ret[1] = 'L';
     178                 :            : 
     179                 :          0 :         if (user->vercheck & FFS_VERCHECK_SHA512EC)
     180                 :          0 :                 ret[2] = 'I';
     181                 :            : 
     182                 :          0 :         if (user->miscflags & FFS_MISCFLAGS_PRESERVED)
     183                 :          0 :                 ret[3] = 'P';
     184                 :            : 
     185                 :          0 :         if (user->miscflags & FFS_MISCFLAGS_READONLY)
     186                 :          0 :                 ret[4] = 'R';
     187                 :            : 
     188                 :          0 :         if (user->miscflags & FFS_MISCFLAGS_BACKUP)
     189                 :          0 :                 ret[5] = 'B';
     190                 :            : 
     191                 :          0 :         if (user->miscflags & FFS_MISCFLAGS_REPROVISION)
     192                 :          0 :                 ret[6] = 'F';
     193                 :            : 
     194                 :          0 :         if (user->miscflags & FFS_MISCFLAGS_GOLDEN)
     195                 :          0 :                 ret[7] = 'G';
     196                 :            : 
     197                 :          0 :         if (user->miscflags & FFS_MISCFLAGS_CLEARECC)
     198                 :          0 :                 ret[8] = 'C';
     199                 :            : 
     200                 :          0 :         if (user->miscflags & FFS_MISCFLAGS_VOLATILE)
     201                 :          0 :                 ret[9] = 'V';
     202                 :            : 
     203                 :            :         return ret;
     204                 :            : }
     205                 :            : 
     206                 :         28 : int ffs_string_to_entry_user(const char *flags, int nflags,
     207                 :            :                 struct ffs_entry_user *user)
     208                 :            : {
     209                 :         28 :         int i;
     210                 :            : 
     211                 :         28 :         if (!user || !flags)
     212                 :            :                 return FLASH_ERR_PARM_ERROR;
     213                 :            : 
     214                 :         28 :         memset(user, 0, sizeof(struct ffs_entry_user));
     215                 :         76 :         for (i = 0; i < nflags; i++) {
     216                 :         48 :                 switch (flags[i]) {
     217                 :         20 :                 case 'E':
     218                 :         20 :                         user->datainteg |= FFS_ENRY_INTEG_ECC;
     219                 :         20 :                         break;
     220                 :          1 :                 case 'L':
     221                 :          1 :                         user->vercheck |= FFS_VERCHECK_SHA512V;
     222                 :          1 :                         break;
     223                 :          0 :                 case 'I':
     224                 :          0 :                         user->vercheck |= FFS_VERCHECK_SHA512EC;
     225                 :          0 :                         break;
     226                 :          1 :                 case 'P':
     227                 :          1 :                         user->miscflags |= FFS_MISCFLAGS_PRESERVED;
     228                 :          1 :                         break;
     229                 :          1 :                 case 'R':
     230                 :          1 :                         user->miscflags |= FFS_MISCFLAGS_READONLY;
     231                 :          1 :                         break;
     232                 :          1 :                 case 'B':
     233                 :          1 :                         user->miscflags |= FFS_MISCFLAGS_BACKUP;
     234                 :          1 :                         break;
     235                 :         16 :                 case 'F':
     236                 :         16 :                         user->miscflags |= FFS_MISCFLAGS_REPROVISION;
     237                 :         16 :                         break;
     238                 :          0 :                 case 'G':
     239                 :          0 :                         user->miscflags |= FFS_MISCFLAGS_GOLDEN;
     240                 :          0 :                         break;
     241                 :          2 :                 case 'C':
     242                 :          2 :                         user->miscflags |= FFS_MISCFLAGS_CLEARECC;
     243                 :          2 :                         break;
     244                 :          6 :                 case 'V':
     245                 :          6 :                         user->miscflags |= FFS_MISCFLAGS_VOLATILE;
     246                 :          6 :                         break;
     247                 :          0 :                 default:
     248                 :          0 :                         FL_DBG("Unknown flag '%c'\n", flags[i]);
     249                 :            :                         return FLASH_ERR_PARM_ERROR;
     250                 :            :                 }
     251                 :            :         }
     252                 :            : 
     253                 :            :         return 0;
     254                 :            : }
     255                 :            : 
     256                 :         28 : bool has_flag(struct ffs_entry *ent, uint16_t flag)
     257                 :            : {
     258                 :         28 :         return ((ent->user.miscflags & flag) != 0);
     259                 :            : }
     260                 :            : 
     261                 :          0 : static struct ffs_entry *__ffs_entry_get(struct ffs_handle *ffs, uint32_t index)
     262                 :            : {
     263                 :          0 :         if (index >= ffs->hdr.count)
     264                 :            :                 return NULL;
     265                 :          0 :         return ffs->hdr.entries[index];
     266                 :            : }
     267                 :            : 
     268                 :          0 : struct ffs_entry *ffs_entry_get(struct ffs_handle *ffs, uint32_t index)
     269                 :            : {
     270                 :          0 :         struct ffs_entry *ret = __ffs_entry_get(ffs, index);
     271                 :          0 :         if (ret)
     272                 :          0 :                 ret->ref++;
     273                 :          0 :         return ret;
     274                 :            : }
     275                 :            : 
     276                 :         62 : struct ffs_entry *ffs_entry_put(struct ffs_entry *ent)
     277                 :            : {
     278                 :         62 :         if (!ent)
     279                 :            :                 return NULL;
     280                 :            : 
     281                 :         62 :         ent->ref--;
     282                 :         62 :         if (ent->ref == 0) {
     283                 :         34 :                 free(ent);
     284                 :         34 :                 ent = NULL;
     285                 :            :         }
     286                 :            : 
     287                 :            :         return ent;
     288                 :            : }
     289                 :            : 
     290                 :         84 : bool has_ecc(struct ffs_entry *ent)
     291                 :            : {
     292                 :         84 :         return ((ent->user.datainteg & FFS_ENRY_INTEG_ECC) != 0);
     293                 :            : }
     294                 :            : 
     295                 :          0 : int ffs_init(uint32_t offset, uint32_t max_size, struct blocklevel_device *bl,
     296                 :            :                 struct ffs_handle **ffs, bool mark_ecc)
     297                 :            : {
     298                 :          0 :         struct __ffs_hdr blank_hdr;
     299                 :          0 :         struct __ffs_hdr raw_hdr;
     300                 :          0 :         struct ffs_handle *f;
     301                 :          0 :         uint64_t total_size;
     302                 :          0 :         int rc, i;
     303                 :            : 
     304                 :          0 :         if (!ffs || !bl)
     305                 :            :                 return FLASH_ERR_PARM_ERROR;
     306                 :          0 :         *ffs = NULL;
     307                 :            : 
     308                 :          0 :         rc = blocklevel_get_info(bl, NULL, &total_size, NULL);
     309                 :          0 :         if (rc) {
     310                 :          0 :                 FL_ERR("FFS: Error %d retrieving flash info\n", rc);
     311                 :          0 :                 return rc;
     312                 :            :         }
     313                 :          0 :         if (total_size > UINT_MAX)
     314                 :            :                 return FLASH_ERR_VERIFY_FAILURE;
     315                 :          0 :         if ((offset + max_size) < offset)
     316                 :            :                 return FLASH_ERR_PARM_ERROR;
     317                 :            : 
     318                 :          0 :         if ((max_size > total_size))
     319                 :            :                 return FLASH_ERR_PARM_ERROR;
     320                 :            : 
     321                 :            :         /* Read flash header */
     322                 :          0 :         rc = blocklevel_read(bl, offset, &raw_hdr, sizeof(raw_hdr));
     323                 :          0 :         if (rc) {
     324                 :          0 :                 FL_ERR("FFS: Error %d reading flash header\n", rc);
     325                 :          0 :                 return rc;
     326                 :            :         }
     327                 :            : 
     328                 :            :         /*
     329                 :            :          * Flash controllers can get deconfigured or otherwise upset, when this
     330                 :            :          * happens they return all 0xFF bytes.
     331                 :            :          * An __ffs_hdr consisting of all 0xFF cannot be valid and it would be
     332                 :            :          * nice to drop a hint to the user to help with debugging. This will
     333                 :            :          * help quickly differentiate between flash corruption and standard
     334                 :            :          * type 'reading from the wrong place' errors vs controller errors or
     335                 :            :          * reading erased data.
     336                 :            :          */
     337                 :          0 :         memset(&blank_hdr, UINT_MAX, sizeof(struct __ffs_hdr));
     338                 :          0 :         if (memcmp(&blank_hdr, &raw_hdr, sizeof(struct __ffs_hdr)) == 0) {
     339                 :          0 :                 FL_ERR("FFS: Reading the flash has returned all 0xFF.\n");
     340                 :          0 :                 FL_ERR("     Are you reading erased flash?\n");
     341                 :          0 :                 FL_ERR("     Is something else using the flash controller?\n");
     342                 :          0 :                 return FLASH_ERR_BAD_READ;
     343                 :            :         }
     344                 :            : 
     345                 :            :         /* Allocate ffs_handle structure and start populating */
     346                 :          0 :         f = calloc(1, sizeof(*f));
     347                 :          0 :         if (!f)
     348                 :            :                 return FLASH_ERR_MALLOC_FAILED;
     349                 :            : 
     350                 :          0 :         f->toc_offset = offset;
     351                 :          0 :         f->max_size = max_size;
     352                 :          0 :         f->bl = bl;
     353                 :            : 
     354                 :            :         /* Convert and check flash header */
     355                 :          0 :         rc = ffs_check_convert_header(&f->hdr, &raw_hdr);
     356                 :          0 :         if (rc) {
     357                 :          0 :                 FL_INF("FFS: Flash header not found. Code: %d\n", rc);
     358                 :          0 :                 goto out;
     359                 :            :         }
     360                 :            : 
     361                 :            :         /* Check header is sane */
     362                 :          0 :         if ((f->hdr.block_count * f->hdr.block_size) > max_size) {
     363                 :          0 :                 rc = FLASH_ERR_PARM_ERROR;
     364                 :          0 :                 FL_ERR("FFS: Flash header exceeds max flash size\n");
     365                 :          0 :                 goto out;
     366                 :            :         }
     367                 :            : 
     368                 :          0 :         f->hdr.entries = calloc(f->hdr.entries_size, sizeof(struct ffs_entry *));
     369                 :            : 
     370                 :            :         /*
     371                 :            :          * Grab the entire partition header
     372                 :            :          */
     373                 :            :         /* Check for overflow or a silly size */
     374                 :          0 :         if (!f->hdr.size || f->hdr.size % f->hdr.block_size != 0) {
     375                 :          0 :                 rc = FLASH_ERR_MALLOC_FAILED;
     376                 :          0 :                 FL_ERR("FFS: Cache size overflow (0x%x * 0x%x)\n",
     377                 :            :                                 f->hdr.block_size, f->hdr.size);
     378                 :          0 :                 goto out;
     379                 :            :         }
     380                 :            : 
     381                 :          0 :         FL_DBG("FFS: Partition map size: 0x%x\n", f->hdr.size);
     382                 :            : 
     383                 :            :         /* Allocate cache */
     384                 :          0 :         f->cache = malloc(f->hdr.size);
     385                 :          0 :         if (!f->cache) {
     386                 :          0 :                 rc = FLASH_ERR_MALLOC_FAILED;
     387                 :          0 :                 goto out;
     388                 :            :         }
     389                 :            : 
     390                 :            :         /* Read the cached map */
     391                 :          0 :         rc = blocklevel_read(bl, offset, f->cache, f->hdr.size);
     392                 :          0 :         if (rc) {
     393                 :          0 :                 FL_ERR("FFS: Error %d reading flash partition map\n", rc);
     394                 :          0 :                 goto out;
     395                 :            :         }
     396                 :            : 
     397                 :          0 :         for (i = 0; i < f->hdr.entries_size; i++) {
     398                 :          0 :                 struct ffs_entry *ent = calloc(1, sizeof(struct ffs_entry));
     399                 :          0 :                 if (!ent) {
     400                 :          0 :                         rc = FLASH_ERR_MALLOC_FAILED;
     401                 :          0 :                         goto out;
     402                 :            :                 }
     403                 :            : 
     404                 :          0 :                 f->hdr.entries[f->hdr.count++] = ent;
     405                 :          0 :                 ent->ref = 1;
     406                 :          0 :                 rc = ffs_entry_to_cpu(&f->hdr, ent, &f->cache->entries[i]);
     407                 :          0 :                 if (rc) {
     408                 :          0 :                         FL_DBG("FFS: Failed checksum for partition %s\n",
     409                 :            :                                         f->cache->entries[i].name);
     410                 :          0 :                         goto out;
     411                 :            :                 }
     412                 :            : 
     413                 :          0 :                 if (mark_ecc && has_ecc(ent)) {
     414                 :          0 :                         rc = blocklevel_ecc_protect(bl, ent->base, ent->size);
     415                 :          0 :                         if (rc) {
     416                 :          0 :                                 FL_ERR("Failed to blocklevel_ecc_protect(0x%08x, 0x%08x)\n",
     417                 :            :                                        ent->base, ent->size);
     418                 :          0 :                                 goto out;
     419                 :            :                         }
     420                 :            :                 }
     421                 :            :         }
     422                 :            : 
     423                 :          0 : out:
     424                 :          0 :         if (rc == 0)
     425                 :          0 :                 *ffs = f;
     426                 :            :         else
     427                 :          0 :                 ffs_close(f);
     428                 :            : 
     429                 :            :         return rc;
     430                 :            : }
     431                 :            : 
     432                 :         60 : static void __hdr_free(struct ffs_hdr *hdr)
     433                 :            : {
     434                 :         60 :         int i;
     435                 :            : 
     436                 :         60 :         if (!hdr)
     437                 :            :                 return;
     438                 :            : 
     439                 :         40 :         for (i = 0; i < hdr->count; i++)
     440                 :         34 :                 ffs_entry_put(hdr->entries[i]);
     441                 :          6 :         free(hdr->entries);
     442                 :            : }
     443                 :            : 
     444                 :         60 : void ffs_hdr_free(struct ffs_hdr *hdr)
     445                 :            : {
     446                 :         60 :         __hdr_free(hdr);
     447                 :         60 :         free(hdr);
     448                 :         60 : }
     449                 :            : 
     450                 :          0 : void ffs_close(struct ffs_handle *ffs)
     451                 :            : {
     452                 :          0 :         __hdr_free(&ffs->hdr);
     453                 :            : 
     454                 :          0 :         if (ffs->cache)
     455                 :          0 :                 free(ffs->cache);
     456                 :            : 
     457                 :          0 :         free(ffs);
     458                 :          0 : }
     459                 :            : 
     460                 :          0 : int ffs_lookup_part(struct ffs_handle *ffs, const char *name,
     461                 :            :                     uint32_t *part_idx)
     462                 :            : {
     463                 :          0 :         struct ffs_entry **ents = ffs->hdr.entries;
     464                 :          0 :         int i;
     465                 :            : 
     466                 :          0 :         for (i = 0;
     467                 :          0 :                         i < ffs->hdr.count &&
     468                 :          0 :                         strncmp(name, ents[i]->name, FFS_PART_NAME_MAX);
     469                 :          0 :                         i++);
     470                 :            : 
     471                 :          0 :         if (i == ffs->hdr.count)
     472                 :            :                 return FFS_ERR_PART_NOT_FOUND;
     473                 :            : 
     474                 :          0 :         if (part_idx)
     475                 :          0 :                 *part_idx = i;
     476                 :            :         return 0;
     477                 :            : }
     478                 :            : 
     479                 :          0 : int ffs_part_info(struct ffs_handle *ffs, uint32_t part_idx,
     480                 :            :                   char **name, uint32_t *start,
     481                 :            :                   uint32_t *total_size, uint32_t *act_size, bool *ecc)
     482                 :            : {
     483                 :          0 :         struct ffs_entry *ent;
     484                 :          0 :         char *n;
     485                 :            : 
     486                 :          0 :         ent = __ffs_entry_get(ffs, part_idx);
     487                 :          0 :         if (!ent)
     488                 :            :                 return FFS_ERR_PART_NOT_FOUND;
     489                 :            : 
     490                 :          0 :         if (start)
     491                 :          0 :                 *start = ent->base;
     492                 :          0 :         if (total_size)
     493                 :          0 :                 *total_size = ent->size;
     494                 :          0 :         if (act_size)
     495                 :          0 :                 *act_size = ent->actual;
     496                 :          0 :         if (ecc)
     497                 :          0 :                 *ecc = has_ecc(ent);
     498                 :            : 
     499                 :          0 :         if (name) {
     500                 :          0 :                 n = calloc(1, FFS_PART_NAME_MAX + 1);
     501                 :          0 :                 if (!n)
     502                 :            :                         return FLASH_ERR_MALLOC_FAILED;
     503                 :          0 :                 memcpy(n, ent->name, FFS_PART_NAME_MAX);
     504                 :          0 :                 *name = n;
     505                 :            :         }
     506                 :            :         return 0;
     507                 :            : }
     508                 :            : 
     509                 :            : /*
     510                 :            :  * There are quite a few ways one might consider two ffs_handles to be the
     511                 :            :  * same. For the purposes of this function we are trying to detect a fairly
     512                 :            :  * specific scenario:
     513                 :            :  * Consecutive calls to ffs_next_side() may succeed but have gone circular.
     514                 :            :  * It is possible that the OTHER_SIDE partition in one TOC actually points
     515                 :            :  * back to the TOC to first ffs_handle.
     516                 :            :  * This function compares for this case, therefore the requirements are
     517                 :            :  * simple, the underlying blocklevel_devices must be the same along with
     518                 :            :  * the toc_offset and the max_size.
     519                 :            :  */
     520                 :          0 : bool ffs_equal(struct ffs_handle *one, struct ffs_handle *two)
     521                 :            : {
     522                 :          0 :         return (!one && !two) || (one && two && one->bl == two->bl
     523                 :            :                 && one->toc_offset == two->toc_offset
     524                 :          0 :                 && one->max_size == two->max_size);
     525                 :            : }
     526                 :            : 
     527                 :          0 : int ffs_next_side(struct ffs_handle *ffs, struct ffs_handle **new_ffs,
     528                 :            :                 bool mark_ecc)
     529                 :            : {
     530                 :          0 :         int rc;
     531                 :          0 :         uint32_t index, offset, max_size;
     532                 :            : 
     533                 :          0 :         if (!ffs || !new_ffs)
     534                 :            :                 return FLASH_ERR_PARM_ERROR;
     535                 :            : 
     536                 :          0 :         *new_ffs = NULL;
     537                 :            : 
     538                 :          0 :         rc = ffs_lookup_part(ffs, "OTHER_SIDE", &index);
     539                 :          0 :         if (rc)
     540                 :            :                 return rc;
     541                 :            : 
     542                 :          0 :         rc = ffs_part_info(ffs, index, NULL, &offset, &max_size, NULL, NULL);
     543                 :          0 :         if (rc)
     544                 :            :                 return rc;
     545                 :            : 
     546                 :          0 :         return ffs_init(offset, max_size, ffs->bl, new_ffs, mark_ecc);
     547                 :            : }
     548                 :            : 
     549                 :         28 : int ffs_entry_add(struct ffs_hdr *hdr, struct ffs_entry *entry)
     550                 :            : {
     551                 :         28 :         const char *smallest_name;
     552                 :         28 :         uint32_t smallest_base, toc_base;
     553                 :         28 :         int i;
     554                 :            : 
     555                 :         28 :         FL_DBG("LIBFFS: Adding '%s' at 0x%08x..0x%08x\n",
     556                 :            :                 entry->name, entry->base, entry->base + entry->size);
     557                 :            : 
     558                 :         28 :         if (hdr->count == 0) {
     559                 :          0 :                 FL_DBG("LIBFFS: Adding an entry to an empty header\n");
     560                 :          0 :                 hdr->entries[hdr->count++] = entry;
     561                 :            :         }
     562                 :         28 :         if (entry->base + entry->size > hdr->block_size * hdr->block_count)
     563                 :            :                 return FFS_ERR_BAD_PART_SIZE;
     564                 :            : 
     565                 :         28 :         smallest_base = entry->base;
     566                 :         28 :         smallest_name = entry->name;
     567                 :         28 :         toc_base = 0;
     568                 :            :         /*
     569                 :            :          * TODO: This may have assumed entries was sorted
     570                 :            :          */
     571                 :        110 :         for (i = 0; i < hdr->count; i++) {
     572                 :         82 :                 struct ffs_entry *ent = hdr->entries[i];
     573                 :            : 
     574                 :            :                 /* Don't allow same names to differ only by case */
     575                 :         82 :                 if (strncasecmp(entry->name, ent->name, FFS_PART_NAME_MAX) == 0)
     576                 :            :                         return FFS_ERR_BAD_PART_NAME;
     577                 :            : 
     578                 :         82 :                 if (entry->base >= ent->base && entry->base < ent->base + ent->size)
     579                 :            :                         return FFS_ERR_BAD_PART_BASE;
     580                 :            : 
     581                 :         82 :                 if (entry->base + entry->size > ent->base &&
     582                 :         82 :                                 entry->base + entry->size < ent->base + ent->size)
     583                 :            :                         return FFS_ERR_BAD_PART_SIZE;
     584                 :            : 
     585                 :         82 :                 if (entry->actual > entry->size)
     586                 :            :                         return FFS_ERR_BAD_PART_SIZE;
     587                 :            : 
     588                 :         82 :                 if (entry->pid != FFS_PID_TOPLEVEL)
     589                 :            :                         return FFS_ERR_BAD_PART_PID;
     590                 :            : 
     591                 :            :                 /* First partition is the partition table */
     592                 :         82 :                 if (i == 0) {
     593                 :            :                         toc_base = ent->base;
     594                 :            :                 } else {
     595                 :            :                         /*
     596                 :            :                          * We're looking for the partition directly
     597                 :            :                          * after the toc to make sure we don't
     598                 :            :                          * overflow onto it.
     599                 :            :                          */
     600                 :         54 :                         if (ent->base < smallest_base && ent->base > toc_base) {
     601                 :         22 :                                 smallest_base = ent->base;
     602                 :         22 :                                 smallest_name = ent->name;
     603                 :            :                         }
     604                 :            :                 }
     605                 :            :         }
     606                 :            :         /* If the smallest base is before the TOC, don't worry */
     607                 :         28 :         if (smallest_base > toc_base && (hdr->count + 1) * sizeof(struct __ffs_entry) +
     608                 :         28 :                         sizeof(struct __ffs_hdr) + toc_base > smallest_base) {
     609                 :          0 :                 fprintf(stderr, "Adding partition '%s' would cause partition '%s' at "
     610                 :            :                         "0x%08x to overlap with the header\n", entry->name, smallest_name,
     611                 :            :                         smallest_base);
     612                 :          0 :                 return FFS_ERR_BAD_PART_BASE;
     613                 :            :         }
     614                 :            : 
     615                 :         28 :         if (hdr->count == hdr->entries_size) {
     616                 :          0 :                 struct ffs_entry **old = hdr->entries;
     617                 :            : 
     618                 :          0 :                 hdr->entries = realloc(hdr->entries,
     619                 :          0 :                                 (HDR_ENTRIES_NUM + hdr->entries_size) * sizeof(struct ffs_entry *));
     620                 :          0 :                 if (!hdr->entries) {
     621                 :          0 :                         hdr->entries = old;
     622                 :          0 :                         return FLASH_ERR_MALLOC_FAILED;
     623                 :            :                 }
     624                 :          0 :                 hdr->entries_size += HDR_ENTRIES_NUM;
     625                 :            :         }
     626                 :         28 :         entry->ref++;
     627                 :         28 :         hdr->entries[hdr->count++] = entry;
     628                 :            : 
     629                 :         28 :         return 0;
     630                 :            : }
     631                 :            : 
     632                 :          6 : int ffs_hdr_finalise(struct blocklevel_device *bl, struct ffs_hdr *hdr)
     633                 :            : {
     634                 :          6 :         int num_entries, i, rc = 0;
     635                 :          6 :         struct __ffs_hdr *real_hdr;
     636                 :            : 
     637                 :          6 :         num_entries = ffs_num_entries(hdr);
     638                 :            : 
     639                 :            :         /* A TOC shouldn't have zero partitions */
     640                 :          6 :         if (num_entries == 0)
     641                 :            :                 return FFS_ERR_BAD_SIZE;
     642                 :            : 
     643                 :          6 :         real_hdr = malloc(ffs_hdr_raw_size(num_entries));
     644                 :          6 :         if (!real_hdr)
     645                 :            :                 return FLASH_ERR_MALLOC_FAILED;
     646                 :            : 
     647                 :            :         /*
     648                 :            :          * So that the checksum gets calculated correctly at least the
     649                 :            :          * real_hdr->checksum must be zero before calling ffs_hdr_checksum()
     650                 :            :          * memset()ting the entire struct to zero is probably wise as it
     651                 :            :          * appears the reserved fields are always zero.
     652                 :            :          */
     653                 :          6 :         memset(real_hdr, 0, sizeof(*real_hdr));
     654                 :            : 
     655                 :          6 :         hdr->part->size = ffs_hdr_raw_size(num_entries) + hdr->block_size;
     656                 :            :         /*
     657                 :            :          * So actual is in bytes. ffs_entry_to_flash() don't do the
     658                 :            :          * block_size division that we're relying on
     659                 :            :          */
     660                 :          6 :         hdr->part->actual = (hdr->part->size / hdr->block_size) * hdr->block_size;
     661                 :          6 :         real_hdr->magic = cpu_to_be32(FFS_MAGIC);
     662                 :          6 :         real_hdr->version = cpu_to_be32(hdr->version);
     663                 :          6 :         real_hdr->size = cpu_to_be32(hdr->part->size / hdr->block_size);
     664                 :          6 :         real_hdr->entry_size = cpu_to_be32(sizeof(struct __ffs_entry));
     665                 :          6 :         real_hdr->entry_count = cpu_to_be32(num_entries);
     666                 :          6 :         real_hdr->block_size = cpu_to_be32(hdr->block_size);
     667                 :          6 :         real_hdr->block_count = cpu_to_be32(hdr->block_count);
     668                 :          6 :         real_hdr->checksum = ffs_hdr_checksum(real_hdr);
     669                 :            : 
     670                 :         40 :         for (i = 0; i < hdr->count; i++) {
     671                 :         34 :                 rc = ffs_entry_to_flash(hdr, real_hdr->entries + i, hdr->entries[i]);
     672                 :         34 :                 if (rc) {
     673                 :          0 :                         fprintf(stderr, "Couldn't format all entries for new TOC\n");
     674                 :          0 :                         goto out;
     675                 :            :                 }
     676                 :            :         }
     677                 :            : 
     678                 :            :         /* Don't really care if this fails */
     679                 :          6 :         blocklevel_erase(bl, hdr->part->base, hdr->size);
     680                 :          6 :         rc = blocklevel_write(bl, hdr->part->base, real_hdr,
     681                 :            :                 ffs_hdr_raw_size(num_entries));
     682                 :          6 :         if (rc)
     683                 :          0 :                 goto out;
     684                 :            : 
     685                 :          6 : out:
     686                 :          6 :         free(real_hdr);
     687                 :          6 :         return rc;
     688                 :            : }
     689                 :            : 
     690                 :         28 : int ffs_entry_user_set(struct ffs_entry *ent, struct ffs_entry_user *user)
     691                 :            : {
     692                 :         28 :         if (!ent || !user)
     693                 :            :                 return -1;
     694                 :            : 
     695                 :            :         /*
     696                 :            :          * Don't allow the user to specify anything we dont't know about.
     697                 :            :          * Rationale: This is the library providing access to the FFS structures.
     698                 :            :          *   If the consumer of the library knows more about FFS structures then
     699                 :            :          *   questions need to be asked.
     700                 :            :          *   The other possibility is that they've unknowningly supplied invalid
     701                 :            :          *   flags, we should tell them.
     702                 :            :          */
     703                 :         28 :         if (user->chip)
     704                 :            :                 return -1;
     705                 :         28 :         if (user->compresstype)
     706                 :            :                 return -1;
     707                 :         28 :         if (user->datainteg & ~(FFS_ENRY_INTEG_ECC))
     708                 :            :                 return -1;
     709                 :         28 :         if (user->vercheck & ~(FFS_VERCHECK_SHA512V | FFS_VERCHECK_SHA512EC))
     710                 :            :                 return -1;
     711                 :         28 :         if (user->miscflags & ~(FFS_MISCFLAGS_PRESERVED | FFS_MISCFLAGS_BACKUP |
     712                 :            :                                 FFS_MISCFLAGS_READONLY | FFS_MISCFLAGS_REPROVISION |
     713                 :            :                                 FFS_MISCFLAGS_VOLATILE | FFS_MISCFLAGS_GOLDEN |
     714                 :            :                                 FFS_MISCFLAGS_CLEARECC))
     715                 :            :                 return -1;
     716                 :            : 
     717                 :         28 :         memcpy(&ent->user, user, sizeof(*user));
     718                 :         28 :         return 0;
     719                 :            : }
     720                 :            : 
     721                 :          0 : struct ffs_entry_user ffs_entry_user_get(struct ffs_entry *ent)
     722                 :            : {
     723                 :          0 :         struct ffs_entry_user user = { 0 };
     724                 :            : 
     725                 :          0 :         if (ent)
     726                 :          0 :                 memcpy(&user, &ent->user, sizeof(user));
     727                 :            : 
     728                 :          0 :         return user;
     729                 :            : }
     730                 :            : 
     731                 :         34 : int ffs_entry_new(const char *name, uint32_t base, uint32_t size, struct ffs_entry **r)
     732                 :            : {
     733                 :         34 :         struct ffs_entry *ret;
     734                 :            : 
     735                 :         34 :         ret = calloc(1, sizeof(*ret));
     736                 :         34 :         if (!ret)
     737                 :            :                 return FLASH_ERR_MALLOC_FAILED;
     738                 :            : 
     739                 :         34 :         strncpy(ret->name, name, FFS_PART_NAME_MAX);
     740                 :         34 :         ret->name[FFS_PART_NAME_MAX] = '\0';
     741                 :         34 :         ret->base = base;
     742                 :         34 :         ret->size = size;
     743                 :         34 :         ret->actual = size;
     744                 :         34 :         ret->pid = FFS_PID_TOPLEVEL;
     745                 :         34 :         ret->type = FFS_TYPE_DATA;
     746                 :         34 :         ret->ref = 1;
     747                 :            : 
     748                 :         34 :         *r = ret;
     749                 :         34 :         return 0;
     750                 :            : }
     751                 :            : 
     752                 :          1 : int ffs_entry_set_act_size(struct ffs_entry *ent, uint32_t actual_size)
     753                 :            : {
     754                 :          1 :         if (!ent)
     755                 :            :                 return -1;
     756                 :            : 
     757                 :          1 :         if (actual_size > ent->size)
     758                 :            :                 return FFS_ERR_BAD_PART_SIZE;
     759                 :            : 
     760                 :          1 :         ent->actual = actual_size;
     761                 :            : 
     762                 :          1 :         return 0;
     763                 :            : }
     764                 :            : 
     765                 :          6 : int ffs_hdr_new(uint32_t block_size, uint32_t block_count,
     766                 :            :                 struct ffs_entry **e, struct ffs_hdr **r)
     767                 :            : {
     768                 :          6 :         struct ffs_hdr *ret;
     769                 :          6 :         struct ffs_entry *part_table;
     770                 :          6 :         int rc;
     771                 :            : 
     772                 :          6 :         ret = calloc(1, sizeof(*ret));
     773                 :          6 :         if (!ret)
     774                 :            :                 return FLASH_ERR_MALLOC_FAILED;
     775                 :            : 
     776                 :          6 :         ret->version = FFS_VERSION_1;
     777                 :          6 :         ret->block_size = block_size;
     778                 :          6 :         ret->block_count = block_count;
     779                 :          6 :         ret->entries = calloc(HDR_ENTRIES_NUM, sizeof(struct ffs_entry *));
     780                 :          6 :         ret->entries_size = HDR_ENTRIES_NUM;
     781                 :            : 
     782                 :          6 :         if (!e || !(*e)) {
     783                 :            :                 /* Don't know how big it will be, ffs_hdr_finalise() will fix */
     784                 :          6 :                 rc = ffs_entry_new("part", 0, 0, &part_table);
     785                 :          6 :                 if (rc) {
     786                 :          0 :                         free(ret);
     787                 :          0 :                         return rc;
     788                 :            :                 }
     789                 :          6 :                 if (e)
     790                 :          0 :                         *e = part_table;
     791                 :            :         } else {
     792                 :          0 :                 part_table = *e;
     793                 :            :         }
     794                 :            : 
     795                 :            :         /* If the user still holds a ref to e, then inc the refcount */
     796                 :          6 :         if (e)
     797                 :          0 :                 part_table->ref++;
     798                 :            : 
     799                 :          6 :         ret->part = part_table;
     800                 :            : 
     801                 :          6 :         part_table->pid = FFS_PID_TOPLEVEL;
     802                 :          6 :         part_table->type = FFS_TYPE_PARTITION;
     803                 :          6 :         part_table->flags = FFS_FLAGS_PROTECTED;
     804                 :            : 
     805                 :          6 :         ret->entries[0] = part_table;
     806                 :          6 :         ret->count = 1;
     807                 :            : 
     808                 :          6 :         *r = ret;
     809                 :            : 
     810                 :          6 :         return 0;
     811                 :            : }
     812                 :            : 
     813                 :          0 : int ffs_update_act_size(struct ffs_handle *ffs, uint32_t part_idx,
     814                 :            :                         uint32_t act_size)
     815                 :            : {
     816                 :          0 :         struct ffs_entry *ent;
     817                 :          0 :         struct __ffs_entry raw_ent;
     818                 :          0 :         uint32_t offset;
     819                 :          0 :         int rc;
     820                 :            : 
     821                 :          0 :         ent = __ffs_entry_get(ffs, part_idx);
     822                 :          0 :         if (!ent) {
     823                 :          0 :                 FL_DBG("FFS: Entry not found\n");
     824                 :          0 :                 return FFS_ERR_PART_NOT_FOUND;
     825                 :            :         }
     826                 :          0 :         offset = ffs->toc_offset + ffs_hdr_raw_size(part_idx);
     827                 :          0 :         FL_DBG("FFS: part index %d at offset 0x%08x\n",
     828                 :            :                part_idx, offset);
     829                 :            : 
     830                 :          0 :         if (ent->actual == act_size) {
     831                 :          0 :                 FL_DBG("FFS: ent->actual alrady matches: 0x%08x==0x%08x\n",
     832                 :            :                        act_size, ent->actual);
     833                 :          0 :                 return 0;
     834                 :            :         }
     835                 :          0 :         ent->actual = act_size;
     836                 :            : 
     837                 :          0 :         rc = ffs_entry_to_flash(&ffs->hdr, &raw_ent, ent);
     838                 :          0 :         if (rc)
     839                 :            :                 return rc;
     840                 :            : 
     841                 :          0 :         return blocklevel_smart_write(ffs->bl, offset, &raw_ent, sizeof(struct __ffs_entry));
     842                 :            : }

Generated by: LCOV version 1.14