LCOV - code coverage report
Current view: top level - external/pflash - pflash.c (source / functions) Hit Total Coverage
Test: skiboot.info Lines: 450 760 59.2 %
Date: 2024-01-02 21:04:04 Functions: 12 16 75.0 %
Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
       2                 :            : /*
       3                 :            :  * Display progress bars, while also writing whole or part
       4                 :            :  * of flash.
       5                 :            :  *
       6                 :            :  * Copyright 2013-2019 IBM Corp.
       7                 :            :  */
       8                 :            : 
       9                 :            : #define _GNU_SOURCE
      10                 :            : 
      11                 :            : #include <stdio.h>
      12                 :            : #include <stdlib.h>
      13                 :            : #include <string.h>
      14                 :            : #include <fcntl.h>
      15                 :            : #include <sys/mman.h>
      16                 :            : #include <sys/types.h>
      17                 :            : #include <sys/stat.h>
      18                 :            : #include <unistd.h>
      19                 :            : #include <byteswap.h>
      20                 :            : #include <stdint.h>
      21                 :            : #include <stdbool.h>
      22                 :            : #include <getopt.h>
      23                 :            : #include <limits.h>
      24                 :            : #include <arpa/inet.h>
      25                 :            : #include <assert.h>
      26                 :            : #include <inttypes.h>
      27                 :            : 
      28                 :            : #include <libflash/libflash.h>
      29                 :            : #include <libflash/libffs.h>
      30                 :            : #include <libflash/blocklevel.h>
      31                 :            : #include <libflash/ecc.h>
      32                 :            : #include <common/arch_flash.h>
      33                 :            : #include "progress.h"
      34                 :            : 
      35                 :            : #define __aligned(x)                    __attribute__((aligned(x)))
      36                 :            : 
      37                 :            : struct flash_details {
      38                 :            :         struct blocklevel_device *bl;
      39                 :            :         int need_relock;
      40                 :            :         const char *name;
      41                 :            :         uint64_t toc;
      42                 :            :         uint64_t total_size;
      43                 :            :         uint32_t erase_granule;
      44                 :            :         bool mark_ecc;
      45                 :            : };
      46                 :            : 
      47                 :            : /* Full pflash version number (possibly includes gitid). */
      48                 :            : extern const char version[];
      49                 :            : 
      50                 :            : const char *flashfilename = NULL;
      51                 :            : static bool must_confirm = true;
      52                 :            : static bool dummy_run;
      53                 :            : static bool bmc_flash;
      54                 :            : 
      55                 :            : #define FILE_BUF_SIZE   0x10000
      56                 :            : static uint8_t file_buf[FILE_BUF_SIZE] __aligned(0x1000);
      57                 :            : 
      58                 :         12 : static bool check_confirm(void)
      59                 :            : {
      60                 :         12 :         char yes[8], *p;
      61                 :            : 
      62                 :         12 :         if (!must_confirm)
      63                 :            :                 return true;
      64                 :            : 
      65                 :         16 :         printf("WARNING ! This will modify your %s flash chip content !\n",
      66                 :          8 :                bmc_flash ? "BMC" : "HOST");
      67                 :          8 :         printf("Enter \"yes\" to confirm:");
      68                 :          8 :         memset(yes, 0, sizeof(yes));
      69                 :          8 :         if (!fgets(yes, 7, stdin))
      70                 :            :                 return false;
      71                 :          8 :         p = strchr(yes, 10);
      72                 :          8 :         if (p)
      73                 :          8 :                 *p = 0;
      74                 :          8 :         p = strchr(yes, 13);
      75                 :          8 :         if (p)
      76                 :          0 :                 *p = 0;
      77                 :          8 :         if (strcmp(yes, "yes")) {
      78                 :          0 :                 printf("Operation cancelled !\n");
      79                 :          0 :                 return false;
      80                 :            :         }
      81                 :          8 :         must_confirm = false;
      82                 :          8 :         return true;
      83                 :            : }
      84                 :            : 
      85                 :          2 : static uint32_t print_ffs_info(struct ffs_handle *ffsh, uint32_t toc)
      86                 :            : {
      87                 :          2 :         struct ffs_entry *ent;
      88                 :          2 :         uint32_t next_toc = toc;
      89                 :          2 :         int rc;
      90                 :          2 :         int i;
      91                 :            : 
      92                 :          2 :         printf("\n");
      93                 :          2 :         printf("TOC@0x%08x Partitions:\n", toc);
      94                 :          2 :         printf("-----------\n");
      95                 :            : 
      96                 :          2 :         for (i = 0;; i++) {
      97                 :         16 :                 uint32_t start, size, act, end;
      98                 :         16 :                 struct ffs_entry_user user;
      99                 :         16 :                 char *name = NULL, *flags;
     100                 :            : 
     101                 :         16 :                 rc = ffs_part_info(ffsh, i, &name, &start, &size, &act, NULL);
     102                 :         16 :                 if (rc == FFS_ERR_PART_NOT_FOUND)
     103                 :            :                         break;
     104                 :            : 
     105                 :         14 :                 ent = ffs_entry_get(ffsh, i);
     106                 :         14 :                 if (rc || !ent) {
     107                 :          0 :                         fprintf(stderr, "Error %d scanning partitions\n",
     108                 :            :                                         !ent ? FFS_ERR_PART_NOT_FOUND : rc);
     109                 :          0 :                     goto out;
     110                 :            :                 }
     111                 :            : 
     112                 :         14 :                 user = ffs_entry_user_get(ent);
     113                 :         14 :                 ffs_entry_put(ent);
     114                 :         14 :                 flags = ffs_entry_user_to_string(&user);
     115                 :         14 :                 if (!flags)
     116                 :          0 :                         goto out;
     117                 :            : 
     118                 :         14 :                 end = start + size;
     119                 :         14 :                 printf("ID=%02d %15s 0x%08x..0x%08x (actual=0x%08x) [%s]\n",
     120                 :            :                                 i, name, start, end, act, flags);
     121                 :            : 
     122                 :         14 :                 if (strcmp(name, "OTHER_SIDE") == 0)
     123                 :          0 :                         next_toc = start;
     124                 :            : 
     125                 :         14 :                 free(flags);
     126                 :         14 : out:
     127                 :         14 :                 free(name);
     128                 :            :         }
     129                 :            : 
     130                 :          2 :         return next_toc;
     131                 :            : }
     132                 :            : 
     133                 :         18 : static struct ffs_handle *open_ffs(struct flash_details *flash)
     134                 :            : {
     135                 :         18 :         struct ffs_handle *ffsh;
     136                 :         18 :         int rc;
     137                 :            : 
     138                 :         36 :         rc = ffs_init(flash->toc, flash->total_size,
     139                 :         18 :                         flash->bl, &ffsh, flash->mark_ecc);
     140                 :         18 :         if (rc) {
     141                 :          0 :                 fprintf(stderr, "Error %d opening ffs !\n", rc);
     142                 :          0 :                 if (flash->toc) {
     143                 :          0 :                         fprintf(stderr, "You specified 0x%" PRIx64 " as the libffs TOC\n"
     144                 :            :                                         "Looks like it doesn't exist\n", flash->toc);
     145                 :          0 :                         return NULL;
     146                 :            :                 }
     147                 :            :         }
     148                 :            : 
     149                 :         18 :         return ffsh;
     150                 :            : }
     151                 :            : 
     152                 :          2 : static void print_flash_info(struct flash_details *flash)
     153                 :            : {
     154                 :          2 :         struct ffs_handle *ffsh;
     155                 :          2 :         uint32_t next_toc;
     156                 :          2 :         uint32_t toc;
     157                 :            : 
     158                 :          2 :         printf("Flash info:\n");
     159                 :          2 :         printf("-----------\n");
     160                 :          2 :         printf("Name          = %s\n", flash->name);
     161                 :          4 :         printf("Total size    = %" PRIu64 "MB\t Flags E:ECC, P:PRESERVED, R:READONLY, "
     162                 :          2 :                         "B:BACKUP\n", flash->total_size >> 20);
     163                 :          4 :         printf("Erase granule = %2d%-13sF:REPROVISION, V:VOLATILE, C:CLEARECC\n",
     164                 :          2 :                         flash->erase_granule >> 10, "KB");
     165                 :            : 
     166                 :          2 :         if (bmc_flash)
     167                 :            :                 return;
     168                 :            : 
     169                 :          2 :         toc = flash->toc;
     170                 :            : 
     171                 :          2 :         ffsh = open_ffs(flash);
     172                 :          2 :         if (!ffsh)
     173                 :            :                 return;
     174                 :            : 
     175                 :          2 :         next_toc = print_ffs_info(ffsh, toc);
     176                 :          2 :         ffs_close(ffsh);
     177                 :          2 :         while(next_toc != toc) {
     178                 :          0 :                 struct ffs_handle *next_ffsh;
     179                 :            : 
     180                 :          0 :                 flash->toc = next_toc;
     181                 :          0 :                 next_ffsh = open_ffs(flash);
     182                 :          0 :                 if (!next_ffsh)
     183                 :            :                         break;
     184                 :          0 :                 next_toc = print_ffs_info(next_ffsh, next_toc);
     185                 :          0 :                 ffs_close(next_ffsh);
     186                 :            :         }
     187                 :          2 :         flash->toc = toc;
     188                 :            : }
     189                 :            : 
     190                 :         16 : static struct ffs_handle *open_partition(struct flash_details *flash,
     191                 :            :                 const char *name, uint32_t *index)
     192                 :            : {
     193                 :         16 :         struct ffs_handle *ffsh;
     194                 :         16 :         int rc;
     195                 :            : 
     196                 :         16 :         ffsh = open_ffs(flash);
     197                 :         16 :         if (!ffsh)
     198                 :            :                 return NULL;
     199                 :            : 
     200                 :         16 :         if (!name)
     201                 :            :                 /* Just open the FFS */
     202                 :            :                 return ffsh;
     203                 :            : 
     204                 :            :         /* Find partition */
     205                 :          4 :         rc = ffs_lookup_part(ffsh, name, index);
     206                 :          4 :         if (rc == FFS_ERR_PART_NOT_FOUND) {
     207                 :          0 :                 fprintf(stderr, "Partition '%s' not found !\n", name);
     208                 :          0 :                 goto out;
     209                 :            :         }
     210                 :          4 :         if (rc) {
     211                 :          0 :                 fprintf(stderr, "Error %d looking for partition '%s' !\n",
     212                 :            :                         rc, name);
     213                 :          0 :                 goto out;
     214                 :            :         }
     215                 :            :         return ffsh;
     216                 :          0 : out:
     217                 :          0 :         ffs_close(ffsh);
     218                 :          0 :         return NULL;
     219                 :            : }
     220                 :            : 
     221                 :         16 : static struct ffs_handle *lookup_partition_at_toc(struct flash_details *flash,
     222                 :            :                 const char *name, uint32_t *index)
     223                 :            : {
     224                 :         16 :         return open_partition(flash, name, index);
     225                 :            : }
     226                 :            : 
     227                 :         16 : static struct ffs_handle *lookup_partition_at_side(struct flash_details *flash,
     228                 :            :                 int side, const char *name, uint32_t *index)
     229                 :            : {
     230                 :         16 :         uint32_t toc = 0;
     231                 :         16 :         int rc;
     232                 :            : 
     233                 :         16 :         if (side == 1) {
     234                 :          0 :                 struct ffs_handle *ffsh;
     235                 :          0 :                 uint32_t side_index;
     236                 :            : 
     237                 :          0 :                 ffsh = open_partition(flash, "OTHER_SIDE", &side_index);
     238                 :          0 :                 if (!ffsh)
     239                 :          0 :                         return NULL;
     240                 :            : 
     241                 :            :                 /* Just need to know where it starts */
     242                 :          0 :                 rc = ffs_part_info(ffsh, side_index, NULL, &toc, NULL, NULL, NULL);
     243                 :          0 :                 ffs_close(ffsh);
     244                 :          0 :                 if (rc)
     245                 :            :                         return NULL;
     246                 :            :         }
     247                 :            : 
     248                 :         16 :         flash->toc = toc;
     249                 :         16 :         return lookup_partition_at_toc(flash, name, index);
     250                 :            : }
     251                 :            : 
     252                 :          2 : static int erase_chip(struct flash_details *flash)
     253                 :            : {
     254                 :          2 :         bool confirm;
     255                 :          2 :         int rc;
     256                 :          2 :         uint64_t pos;
     257                 :            : 
     258                 :          2 :         printf("About to erase chip !\n");
     259                 :          2 :         confirm = check_confirm();
     260                 :          2 :         if (!confirm)
     261                 :            :                 return 1;
     262                 :            : 
     263                 :          2 :         printf("Erasing... (may take a while)\n");
     264                 :          2 :         fflush(stdout);
     265                 :            : 
     266                 :          2 :         if (dummy_run) {
     267                 :          0 :                 printf("skipped (dummy)\n");
     268                 :          0 :                 return 1;
     269                 :            :         }
     270                 :            : 
     271                 :            :         /*
     272                 :            :          * We could use arch_flash_erase_chip() here BUT everyone really
     273                 :            :          * likes the progress bars.
     274                 :            :          * Lets do an erase block at a time erase then...
     275                 :            :          */
     276                 :          2 :         progress_init(flash->total_size);
     277                 :       5124 :         for (pos = 0; pos < flash->total_size; pos += flash->erase_granule) {
     278                 :       5120 :                 rc = blocklevel_erase(flash->bl, pos, flash->erase_granule);
     279                 :       5120 :                 if (rc)
     280                 :            :                         break;
     281                 :       5120 :                 progress_tick(pos);
     282                 :            :         }
     283                 :          2 :         progress_end();
     284                 :          2 :         if (rc) {
     285                 :          0 :                 fprintf(stderr, "Error %d erasing chip\n", rc);
     286                 :          0 :                 return rc;
     287                 :            :         }
     288                 :            : 
     289                 :          2 :         printf("done !\n");
     290                 :          2 :         return 0;
     291                 :            : }
     292                 :            : 
     293                 :          6 : static int erase_range(struct flash_details *flash,
     294                 :            :                 uint32_t start, uint32_t size, bool will_program,
     295                 :            :                 struct ffs_handle *ffsh, int ffs_index)
     296                 :            : {
     297                 :          6 :         uint32_t done = 0, erase_mask = flash->erase_granule - 1;
     298                 :          6 :         struct ffs_entry *toc;
     299                 :          6 :         bool confirm;
     300                 :          6 :         int rc;
     301                 :            : 
     302                 :          6 :         printf("About to erase 0x%08x..0x%08x !\n", start, start + size);
     303                 :          6 :         confirm = check_confirm();
     304                 :          6 :         if (!confirm)
     305                 :            :                 return 1;
     306                 :            : 
     307                 :          6 :         if (dummy_run) {
     308                 :          0 :                 printf("skipped (dummy)\n");
     309                 :          0 :                 return 1;
     310                 :            :         }
     311                 :            : 
     312                 :          6 :         printf("Erasing...\n");
     313                 :            :         /*
     314                 :            :          * blocklevel_smart_erase() can do the entire thing in one call
     315                 :            :          * BUT everyone really likes progress bars so break stuff up
     316                 :            :          */
     317                 :          6 :         progress_init(size);
     318                 :          6 :         if (start & erase_mask) {
     319                 :            :                 /*
     320                 :            :                  * Align to next erase block, or just do the entire
     321                 :            :                  * thing if we fit within one erase block
     322                 :            :                  */
     323                 :          0 :                 uint32_t first_size = MIN(size, (flash->erase_granule - (start & erase_mask)));
     324                 :            : 
     325                 :          0 :                 rc = blocklevel_smart_erase(flash->bl, start, first_size);
     326                 :          0 :                 if (rc) {
     327                 :          0 :                         fprintf(stderr, "Failed to blocklevel_smart_erase(): %d\n", rc);
     328                 :          0 :                         return 1;
     329                 :            :                 }
     330                 :          0 :                 size -= first_size;
     331                 :          0 :                 done = first_size;
     332                 :          0 :                 start += first_size;
     333                 :            :         }
     334                 :          6 :         progress_tick(done);
     335                 :       1542 :         while (size & ~(erase_mask)) {
     336                 :       1536 :                 rc = blocklevel_smart_erase(flash->bl, start, flash->erase_granule);
     337                 :       1536 :                 if (rc) {
     338                 :          0 :                         fprintf(stderr, "Failed to blocklevel_smart_erase(): %d\n", rc);
     339                 :          0 :                         return 1;
     340                 :            :                 }
     341                 :       1536 :                 start += flash->erase_granule;
     342                 :       1536 :                 size -= flash->erase_granule;
     343                 :       1536 :                 done += flash->erase_granule;
     344                 :       1536 :                 progress_tick(done);
     345                 :            :         }
     346                 :          6 :         if (size) {
     347                 :          0 :                 rc = blocklevel_smart_erase(flash->bl, start, size);
     348                 :          0 :                 if (rc) {
     349                 :          0 :                         fprintf(stderr, "Failed to blocklevel_smart_erase(): %d\n", rc);
     350                 :          0 :                         return 1;
     351                 :            :                 }
     352                 :          0 :                 done += size;
     353                 :          0 :                 progress_tick(done);
     354                 :            :         }
     355                 :          6 :         progress_end();
     356                 :            : 
     357                 :          6 :         if (!ffsh)
     358                 :            :                 return 0;
     359                 :            : 
     360                 :            :         /* If this is a flash partition, mark it empty if we aren't
     361                 :            :          * going to program over it as well
     362                 :            :          */
     363                 :          4 :         toc = ffs_entry_get(ffsh, 0);
     364                 :          4 :         if (toc) {
     365                 :          4 :                 struct ffs_entry_user user;
     366                 :          4 :                 bool rw_toc;
     367                 :            : 
     368                 :          4 :                 user = ffs_entry_user_get(toc);
     369                 :          4 :                 rw_toc = !(user.miscflags & FFS_MISCFLAGS_READONLY);
     370                 :          4 :                 if (ffs_index >= 0 && !will_program && rw_toc) {
     371                 :          2 :                         printf("Updating actual size in partition header...\n");
     372                 :          2 :                         ffs_update_act_size(ffsh, ffs_index, 0);
     373                 :            :                 }
     374                 :            :         }
     375                 :            : 
     376                 :            :         return 0;
     377                 :            : }
     378                 :            : 
     379                 :          0 : static int set_ecc(struct flash_details *flash, uint32_t start, uint32_t size)
     380                 :            : {
     381                 :          0 :         uint32_t i = start + 8;
     382                 :          0 :         uint8_t ecc = 0;
     383                 :          0 :         bool confirm;
     384                 :          0 :         int rc;
     385                 :            : 
     386                 :          0 :         printf("About to erase and set ECC bits in region 0x%08x to 0x%08x\n", start, start + size);
     387                 :          0 :         confirm = check_confirm();
     388                 :          0 :         if (!confirm)
     389                 :            :                 return 1;
     390                 :            : 
     391                 :          0 :         rc = erase_range(flash, start, size, true, NULL, 0);
     392                 :          0 :         if (rc) {
     393                 :          0 :                 fprintf(stderr, "Couldn't erase region to mark with ECC\n");
     394                 :          0 :                 return rc;
     395                 :            :         }
     396                 :            : 
     397                 :          0 :         printf("Programming ECC bits...\n");
     398                 :          0 :         progress_init(size);
     399                 :          0 :         while (i < start + size) {
     400                 :          0 :                 rc = blocklevel_write(flash->bl, i, &ecc, sizeof(ecc));
     401                 :          0 :                 if (rc) {
     402                 :          0 :                         fprintf(stderr, "\nError setting ECC byte at 0x%08x\n", i);
     403                 :          0 :                         return rc;
     404                 :            :                 }
     405                 :          0 :                 i += 9;
     406                 :          0 :                 progress_tick(i - start);
     407                 :            :         }
     408                 :          0 :         progress_end();
     409                 :          0 :         return 0;
     410                 :            : }
     411                 :            : 
     412                 :          4 : static int program_file(struct blocklevel_device *bl,
     413                 :            :                 const char *file, uint32_t start, uint32_t size,
     414                 :            :                 struct ffs_handle *ffsh, int ffs_index)
     415                 :            : {
     416                 :          4 :         uint32_t actual_size = 0;
     417                 :          4 :         struct ffs_entry *toc;
     418                 :          4 :         int fd, rc = 0;
     419                 :          4 :         bool confirm;
     420                 :            : 
     421                 :          4 :         fd = open(file, O_RDONLY);
     422                 :          4 :         if (fd == -1) {
     423                 :          0 :                 perror("Failed to open file");
     424                 :          0 :                 return 1;
     425                 :            :         }
     426                 :          4 :         printf("About to program \"%s\" at 0x%08x..0x%08x !\n",
     427                 :            :                file, start, start + size);
     428                 :          4 :         confirm = check_confirm();
     429                 :          4 :         if (!confirm) {
     430                 :          0 :                 rc = 1;
     431                 :          0 :                 goto out;
     432                 :            :         }
     433                 :            : 
     434                 :          4 :         if (dummy_run) {
     435                 :          0 :                 printf("skipped (dummy)\n");
     436                 :          0 :                 rc = 1;
     437                 :          0 :                 goto out;
     438                 :            :         }
     439                 :            : 
     440                 :          4 :         printf("Programming & Verifying...\n");
     441                 :          4 :         progress_init(size);
     442                 :          8 :         while(size) {
     443                 :          4 :                 ssize_t len;
     444                 :            : 
     445                 :          4 :                 len = read(fd, file_buf, FILE_BUF_SIZE);
     446                 :          4 :                 if (len < 0) {
     447                 :          0 :                         perror("Error reading file");
     448                 :          0 :                         rc = 1;
     449                 :          0 :                         goto out;
     450                 :            :                 }
     451                 :          4 :                 if (len == 0)
     452                 :            :                         break;
     453                 :          4 :                 if (len > size)
     454                 :            :                         len = size;
     455                 :          4 :                 size -= len;
     456                 :          4 :                 actual_size += len;
     457                 :          4 :                 rc = blocklevel_write(bl, start, file_buf, len);
     458                 :          4 :                 if (rc) {
     459                 :          0 :                         if (rc == FLASH_ERR_VERIFY_FAILURE)
     460                 :          0 :                                 fprintf(stderr, "Verification failed for"
     461                 :            :                                         " chunk at 0x%08x\n", start);
     462                 :            :                         else
     463                 :          0 :                                 fprintf(stderr, "Flash write error %d for"
     464                 :            :                                         " chunk at 0x%08x\n", rc, start);
     465                 :          0 :                         goto out;
     466                 :            :                 }
     467                 :          4 :                 start += len;
     468                 :          4 :                 progress_tick(actual_size);
     469                 :            :         }
     470                 :          4 :         progress_end();
     471                 :            : 
     472                 :          4 :         if (!ffsh)
     473                 :          2 :                 goto out;
     474                 :            : 
     475                 :            :         /* If this is a flash partition, adjust its size */
     476                 :          2 :         toc = ffs_entry_get(ffsh, 0);
     477                 :          2 :         if (toc) {
     478                 :          2 :                 struct ffs_entry_user user;
     479                 :          2 :                 bool rw_toc;
     480                 :            : 
     481                 :          2 :                 user = ffs_entry_user_get(toc);
     482                 :          2 :                 rw_toc = !(user.miscflags & FFS_MISCFLAGS_READONLY);
     483                 :          2 :                 if (ffs_index >= 0 && rw_toc) {
     484                 :          2 :                         printf("Updating actual size in partition header...\n");
     485                 :          2 :                         ffs_update_act_size(ffsh, ffs_index, actual_size);
     486                 :            :                 }
     487                 :            :         }
     488                 :          0 : out:
     489                 :          4 :         close(fd);
     490                 :          4 :         return rc;
     491                 :            : }
     492                 :            : 
     493                 :          0 : static int do_read_file(struct blocklevel_device *bl, const char *file,
     494                 :            :                 uint32_t start, uint32_t size, uint32_t skip_size)
     495                 :            : {
     496                 :          0 :         int fd, rc = 0;
     497                 :          0 :         uint32_t done = 0;
     498                 :            : 
     499                 :          0 :         fd = open(file, O_WRONLY | O_TRUNC | O_CREAT, 00666);
     500                 :          0 :         if (fd == -1) {
     501                 :          0 :                 perror("Failed to open file");
     502                 :          0 :                 return 1;
     503                 :            :         }
     504                 :          0 :         start += skip_size;
     505                 :          0 :         size -= skip_size;
     506                 :            : 
     507                 :          0 :         printf("Reading to \"%s\" from 0x%08x..0x%08x !\n",
     508                 :            :                file, start, start + size);
     509                 :            : 
     510                 :          0 :         progress_init(size);
     511                 :          0 :         while(size) {
     512                 :          0 :                 ssize_t len;
     513                 :            : 
     514                 :          0 :                 len = size > FILE_BUF_SIZE ? FILE_BUF_SIZE : size;
     515                 :          0 :                 rc = blocklevel_read(bl, start, file_buf, len);
     516                 :          0 :                 if (rc) {
     517                 :          0 :                         fprintf(stderr, "Flash read error %d for"
     518                 :            :                                 " chunk at 0x%08x\n", rc, start);
     519                 :            :                         break;
     520                 :            :                 }
     521                 :          0 :                 rc = write(fd, file_buf, len);
     522                 :            :                 /*
     523                 :            :                  * zero isn't strictly an error.
     524                 :            :                  * Treat it as such so we can be sure we'lre always
     525                 :            :                  * making forward progress.
     526                 :            :                  */
     527                 :          0 :                 if (rc <= 0) {
     528                 :          0 :                         perror("Error writing file");
     529                 :          0 :                         break;
     530                 :            :                 }
     531                 :          0 :                 start += rc;
     532                 :          0 :                 size -= rc;
     533                 :          0 :                 done += rc;
     534                 :          0 :                 progress_tick(done);
     535                 :            :         }
     536                 :          0 :         progress_end();
     537                 :          0 :         close(fd);
     538                 :          0 :         return size ? rc : 0;
     539                 :            : }
     540                 :            : 
     541                 :          0 : static int enable_4B_addresses(struct blocklevel_device *bl)
     542                 :            : {
     543                 :          0 :         int rc;
     544                 :            : 
     545                 :          0 :         printf("Switching to 4-bytes address mode\n");
     546                 :            : 
     547                 :          0 :         rc = arch_flash_4b_mode(bl, true);
     548                 :          0 :         if (rc) {
     549                 :          0 :                 if (rc == -1) {
     550                 :          0 :                         fprintf(stderr, "Switching address mode not available on this architecture\n");
     551                 :            :                 } else {
     552                 :          0 :                         fprintf(stderr, "Error %d enabling 4b mode\n", rc);
     553                 :            :                 }
     554                 :            :         }
     555                 :            : 
     556                 :          0 :         return rc;
     557                 :            : }
     558                 :            : 
     559                 :          0 : static int disable_4B_addresses(struct blocklevel_device *bl)
     560                 :            : {
     561                 :          0 :         int rc;
     562                 :            : 
     563                 :          0 :         printf("Switching to 3-bytes address mode\n");
     564                 :            : 
     565                 :          0 :         rc = arch_flash_4b_mode(bl, false);
     566                 :          0 :         if (rc) {
     567                 :          0 :                 if (rc == -1) {
     568                 :          0 :                         fprintf(stderr, "Switching address mode not available on this architecture\n");
     569                 :            :                 } else {
     570                 :          0 :                         fprintf(stderr, "Error %d enabling 4b mode\n", rc);
     571                 :            :                 }
     572                 :            :         }
     573                 :            : 
     574                 :          0 :         return rc;
     575                 :            : }
     576                 :            : 
     577                 :         12 : static void print_partition_detail(struct ffs_handle *ffsh, uint32_t part_id)
     578                 :            : {
     579                 :         12 :         uint32_t start, size, act, end;
     580                 :         12 :         char *ent_name = NULL, *flags;
     581                 :         12 :         struct ffs_entry *ent;
     582                 :         12 :         int rc, l;
     583                 :            : 
     584                 :         12 :         rc = ffs_part_info(ffsh, part_id, &ent_name, &start, &size,
     585                 :            :                         &act, NULL);
     586                 :         12 :         if (rc) {
     587                 :          0 :                 fprintf(stderr, "Partition with ID %d doesn't exist error: %d\n",
     588                 :            :                                 part_id, rc);
     589                 :          0 :                 goto out;
     590                 :            :         }
     591                 :            : 
     592                 :         12 :         ent = ffs_entry_get(ffsh, part_id);
     593                 :         12 :         if (!ent) {
     594                 :          0 :                 rc = FFS_ERR_PART_NOT_FOUND;
     595                 :          0 :                 fprintf(stderr, "Couldn't open partition entry\n");
     596                 :          0 :                 goto out;
     597                 :            :         }
     598                 :            : 
     599                 :         12 :         printf("Detailed partition information\n");
     600                 :         12 :         end = start + size;
     601                 :         12 :         printf("Name:\n");
     602                 :         12 :         printf("%s (ID=%02d)\n\n", ent_name, part_id);
     603                 :         12 :         printf("%-10s  %-10s  %-10s\n", "Start", "End", "Actual");
     604                 :         12 :         printf("0x%08x  0x%08x  0x%08x\n\n", start, end, act);
     605                 :            : 
     606                 :         12 :         printf("Flags:\n");
     607                 :            : 
     608                 :         82 :         l = asprintf(&flags, "%s%s%s%s%s%s%s", has_ecc(ent) ? "ECC [E]\n" : "",
     609                 :         12 :                         has_flag(ent, FFS_MISCFLAGS_PRESERVED) ? "PRESERVED [P]\n" : "",
     610                 :         12 :                         has_flag(ent, FFS_MISCFLAGS_READONLY) ? "READONLY [R]\n" : "",
     611                 :         12 :                         has_flag(ent, FFS_MISCFLAGS_BACKUP) ? "BACKUP [B]\n" : "",
     612                 :         12 :                         has_flag(ent, FFS_MISCFLAGS_REPROVISION) ?
     613                 :            :                                         "REPROVISION [F]\n" : "",
     614                 :         12 :                         has_flag(ent, FFS_MISCFLAGS_VOLATILE) ? "VOLATILE [V]\n" : "",
     615                 :         12 :                         has_flag(ent, FFS_MISCFLAGS_CLEARECC) ? "CLEARECC [C]\n" : "");
     616                 :         12 :         ffs_entry_put(ent);
     617                 :         12 :         if (l < 0) {
     618                 :          0 :                 fprintf(stderr, "Memory allocation failure printing flags!\n");
     619                 :          0 :                 goto out;
     620                 :            :         }
     621                 :            : 
     622                 :         12 :         printf("%s", flags);
     623                 :         12 :         free(flags);
     624                 :            : 
     625                 :         12 : out:
     626                 :         12 :         free(ent_name);
     627                 :         12 : }
     628                 :            : 
     629                 :          4 : static void print_version(void)
     630                 :            : {
     631                 :          4 :         printf("Open-Power Flash tool %s\n", version);
     632                 :          4 : }
     633                 :            : 
     634                 :          4 : static void print_help(const char *pname)
     635                 :            : {
     636                 :          4 :         printf("Usage: %s [options] commands...\n\n", pname);
     637                 :          4 :         printf(" Options:\n");
     638                 :          4 :         printf("\t-a address, --address=address\n");
     639                 :          4 :         printf("\t\tSpecify the start address for erasing, reading\n");
     640                 :          4 :         printf("\t\tor flashing\n\n");
     641                 :          4 :         printf("\t-s size, --size=size\n");
     642                 :          4 :         printf("\t\tSpecify the size in bytes for erasing, reading\n");
     643                 :          4 :         printf("\t\tor flashing\n\n");
     644                 :          4 :         printf("\t-P part_name, --partition=part_name\n");
     645                 :          4 :         printf("\t\tSpecify the partition whose content is to be erased\n");
     646                 :          4 :         printf("\t\tprogrammed or read. This is an alternative to -a and -s\n");
     647                 :          4 :         printf("\t\tif both -P and -s are specified, the smallest of the\n");
     648                 :          4 :         printf("\t\ttwo will be used\n\n");
     649                 :          4 :         printf("\t-f, --force\n");
     650                 :          4 :         printf("\t\tDon't ask for confirmation before erasing or flashing\n\n");
     651                 :          4 :         printf("\t-d, --dummy\n");
     652                 :          4 :         printf("\t\tDon't write to flash\n\n");
     653                 :          4 :         printf("\t--direct\n");
     654                 :          4 :         printf("\t\tBypass all safety provided to you by the kernel driver\n");
     655                 :          4 :         printf("\t\tand use the flash driver built into pflash.\n");
     656                 :          4 :         printf("\t\tIf you have mtd devices and you use this command, the\n");
     657                 :          4 :         printf("\t\tsystem may become unstable.\n");
     658                 :          4 :         printf("\t\tIf you are reading this sentence then this flag is not\n");
     659                 :          4 :         printf("\t\twhat you want! Using this feature without knowing\n");
     660                 :          4 :         printf("\t\twhat it does can and likely will result in a bricked\n");
     661                 :          4 :         printf("\t\tmachine\n\n");
     662                 :          4 :         printf("\t-b, --bmc\n");
     663                 :          4 :         printf("\t\tTarget BMC flash instead of host flash.\n");
     664                 :          4 :         printf("\t\tNote: This carries a high chance of bricking your BMC if you\n");
     665                 :          4 :         printf("\t\tdon't know what you're doing. Consider --mtd to be safe(r)\n\n");
     666                 :          4 :         printf("\t-F filename, --flash-file filename\n");
     667                 :          4 :         printf("\t\tTarget filename instead of actual flash.\n\n");
     668                 :          4 :         printf("\t-S, --side\n");
     669                 :          4 :         printf("\t\tSide of the flash on which to operate, 0 (default) or 1\n\n");
     670                 :          4 :         printf("\t--skip=N\n");
     671                 :          4 :         printf("\t\tSkip N number of bytes from the start when reading\n\n");
     672                 :          4 :         printf("\t-T, --toc\n");
     673                 :          4 :         printf("\t\tlibffs TOC on which to operate, defaults to 0.\n");
     674                 :          4 :         printf("\t\tleading 0x is required for interpretation of a hex value\n\n");
     675                 :          4 :         printf("\t-g\n");
     676                 :          4 :         printf("\t\tEnable verbose libflash debugging\n\n");
     677                 :          4 :         printf(" Commands:\n");
     678                 :          4 :         printf("\t-4, --enable-4B\n");
     679                 :          4 :         printf("\t\tSwitch the flash and controller to 4-bytes address\n");
     680                 :          4 :         printf("\t\tmode (no confirmation needed).\n\n");
     681                 :          4 :         printf("\t-3, --disable-4B\n");
     682                 :          4 :         printf("\t\tSwitch the flash and controller to 3-bytes address\n");
     683                 :          4 :         printf("\t\tmode (no confirmation needed).\n\n");
     684                 :          4 :         printf("\t-r file, --read=file\n");
     685                 :          4 :         printf("\t\tRead flash content from address into file, use -s\n");
     686                 :          4 :         printf("\t\tto specify the size to read (or it will use the source\n");
     687                 :          4 :         printf("\t\tfile size if used in conjunction with -p and -s is not\n");
     688                 :          4 :         printf("\t\tspecified). When using -r together with -e or -p, the\n");
     689                 :          4 :         printf("\t\tread will be performed first\n\n");
     690                 :          4 :         printf("\t-E, --erase-all\n");
     691                 :          4 :         printf("\t\tErase entire flash chip\n");
     692                 :          4 :         printf("\t\t(Not supported on all chips/controllers)\n\n");
     693                 :          4 :         printf("\t-e, --erase\n");
     694                 :          4 :         printf("\t\tErase the specified region. If size or address are not\n");
     695                 :          4 :         printf("\t\tspecified, but \'--program\' is used, then the file\n");
     696                 :          4 :         printf("\t\tsize will be used (rounded to an erase block) and the\n");
     697                 :          4 :         printf("\t\taddress defaults to 0.\n\n");
     698                 :          4 :         printf("\t-p file, --program=file\n");
     699                 :          4 :         printf("\t\tWill program the file to flash. If the address is not\n");
     700                 :          4 :         printf("\t\tspecified, it will use 0. If the size is not specified\n");
     701                 :          4 :         printf("\t\tit will use the file size. Otherwise it will limit to\n");
     702                 :          4 :         printf("\t\tthe specified size (whatever is smaller). If used in\n");
     703                 :          4 :         printf("\t\tconjunction with any erase command, the erase will\n");
     704                 :          4 :         printf("\t\ttake place first.\n\n");
     705                 :          4 :         printf("\t-t, --tune\n");
     706                 :          4 :         printf("\t\tJust tune the flash controller & access size\n");
     707                 :          4 :         printf("\t\tMust be used in conjuction with --direct\n");
     708                 :          4 :         printf("\t\t(Implicit for all other operations)\n\n");
     709                 :          4 :         printf("\t-c --clear\n");
     710                 :          4 :         printf("\t\tUsed to ECC clear a partition of the flash\n");
     711                 :          4 :         printf("\t\tMust be used in conjunction with -P. Will erase the\n");
     712                 :          4 :         printf("\t\tpartition and then set all the ECC bits as they should be\n\n");
     713                 :          4 :         printf("\t-9 --ecc\n");
     714                 :          4 :         printf("\t\tEncode/Decode ECC where specified in the FFS header.\n");
     715                 :          4 :         printf("\t\tThis 9 byte ECC method is used for some OpenPOWER\n");
     716                 :          4 :         printf("\t\tpartitions.\n");
     717                 :          4 :         printf("\t-i, --info\n");
     718                 :          4 :         printf("\t\tDisplay some information about the flash.\n\n");
     719                 :          4 :         printf("\t--detail\n");
     720                 :          4 :         printf("\t\tDisplays detailed info about a particular partition.\n");
     721                 :          4 :         printf("\t\tAccepts a numeric partition or can be used in conjuction\n");
     722                 :          4 :         printf("\t\twith the -P flag.\n\n");
     723                 :          4 :         printf("\t-h, --help\n");
     724                 :          4 :         printf("\t\tThis message.\n\n");
     725                 :          4 : }
     726                 :            : 
     727                 :         26 : int main(int argc, char *argv[])
     728                 :            : {
     729                 :         26 :         const char *pname = argv[0];
     730                 :         26 :         struct flash_details flash = { 0 };
     731                 :         26 :         static struct ffs_handle *ffsh = NULL;
     732                 :         26 :         uint32_t ffs_index;
     733                 :         26 :         uint32_t address = 0, read_size = 0, detail_id = UINT_MAX;
     734                 :         26 :         uint32_t write_size = 0, write_size_minus_ecc = 0;
     735                 :         26 :         bool erase = false, do_clear = false;
     736                 :         26 :         bool program = false, erase_all = false, info = false, do_read = false;
     737                 :         26 :         bool enable_4B = false, disable_4B = false;
     738                 :         26 :         bool show_help = false, show_version = false;
     739                 :         26 :         bool no_action = false, tune = false;
     740                 :         26 :         char *write_file = NULL, *read_file = NULL, *part_name = NULL;
     741                 :         26 :         bool ffs_toc_seen = false, direct = false, print_detail = false;
     742                 :         26 :         int flash_side = 0, skip_size = 0;
     743                 :         26 :         int rc = 0;
     744                 :            : 
     745                 :         66 :         while(1) {
     746                 :         92 :                 struct option long_opts[] = {
     747                 :            :                         {"address",   required_argument,      NULL,   'a'},
     748                 :            :                         {"size",      required_argument,      NULL,   's'},
     749                 :            :                         {"partition", required_argument,      NULL,   'P'},
     750                 :            :                         {"bmc",               no_argument,            NULL,   'b'},
     751                 :            :                         {"direct",    no_argument,            NULL,   'D'},
     752                 :            :                         {"enable-4B", no_argument,            NULL,   '4'},
     753                 :            :                         {"disable-4B",        no_argument,            NULL,   '3'},
     754                 :            :                         {"read",      required_argument,      NULL,   'r'},
     755                 :            :                         {"erase-all", no_argument,            NULL,   'E'},
     756                 :            :                         {"erase",     no_argument,            NULL,   'e'},
     757                 :            :                         {"program",   required_argument,      NULL,   'p'},
     758                 :            :                         {"force",     no_argument,            NULL,   'f'},
     759                 :            :                         {"flash-file",        required_argument,      NULL,   'F'},
     760                 :            :                         {"info",      no_argument,            NULL,   'i'},
     761                 :            :                         {"detail",  optional_argument,  NULL,   'm'},
     762                 :            :                         {"tune",      no_argument,            NULL,   't'},
     763                 :            :                         {"dummy",     no_argument,            NULL,   'd'},
     764                 :            :                         {"help",      no_argument,            NULL,   'h'},
     765                 :            :                         {"version",   no_argument,            NULL,   'v'},
     766                 :            :                         {"debug",     no_argument,            NULL,   'g'},
     767                 :            :                         {"side",      required_argument,      NULL,   'S'},
     768                 :            :                         {"skip",      required_argument,      NULL,   'k'},
     769                 :            :                         {"toc",               required_argument,      NULL,   'T'},
     770                 :            :                         {"clear",   no_argument,        NULL,   'c'},
     771                 :            :                         {"ecc",         no_argument,            NULL,   '9'},
     772                 :            :                         {NULL,      0,                  NULL,    0 }
     773                 :            :                 };
     774                 :         92 :                 int c, oidx = 0;
     775                 :            : 
     776                 :         92 :                 c = getopt_long(argc, argv, "+:a:s:P:r:43Eep:fdihvbtgS:T:c9F:",
     777                 :            :                                 long_opts, &oidx);
     778                 :         92 :                 if (c == -1)
     779                 :            :                         break;
     780                 :         66 :                 switch(c) {
     781                 :          4 :                         char *endptr;
     782                 :            : 
     783                 :          4 :                 case 'a':
     784                 :          4 :                         address = strtoul(optarg, &endptr, 0);
     785                 :          4 :                         if (*endptr != '\0') {
     786                 :          2 :                                 rc = 1;
     787                 :          2 :                                 no_action = true;
     788                 :            :                         }
     789                 :         66 :                         break;
     790                 :          4 :                 case 's':
     791                 :          4 :                         read_size = write_size = strtoul(optarg, &endptr, 0);
     792                 :          4 :                         if (*endptr != '\0') {
     793                 :          2 :                                 rc = 1;
     794                 :          2 :                                 no_action = true;
     795                 :            :                         }
     796                 :            :                         break;
     797                 :          4 :                 case 'P':
     798                 :          4 :                         free(part_name);
     799                 :          4 :                         part_name = strdup(optarg);
     800                 :          4 :                         break;
     801                 :            :                 case '4':
     802                 :            :                         enable_4B = true;
     803                 :            :                         break;
     804                 :          0 :                 case '3':
     805                 :          0 :                         disable_4B = true;
     806                 :          0 :                         break;
     807                 :          0 :                 case 'r':
     808                 :          0 :                         if (!optarg)
     809                 :            :                                 break;
     810                 :          0 :                         do_read = true;
     811                 :          0 :                         free(read_file);
     812                 :          0 :                         read_file = strdup(optarg);
     813                 :          0 :                         break;
     814                 :          2 :                 case 'E':
     815                 :          2 :                         erase_all = erase = true;
     816                 :          2 :                         break;
     817                 :          8 :                 case 'e':
     818                 :          8 :                         erase = true;
     819                 :          8 :                         break;
     820                 :          0 :                 case 'D':
     821                 :          0 :                         direct = true;
     822                 :          0 :                         break;
     823                 :          4 :                 case 'p':
     824                 :          4 :                         if (!optarg)
     825                 :            :                                 break;
     826                 :          4 :                         program = true;
     827                 :          4 :                         free(write_file);
     828                 :          4 :                         write_file = strdup(optarg);
     829                 :          4 :                         break;
     830                 :          0 :                 case 'f':
     831                 :          0 :                         must_confirm = false;
     832                 :          0 :                         break;
     833                 :         24 :                 case 'F':
     834                 :         24 :                         flashfilename = optarg;
     835                 :         24 :                         break;
     836                 :          0 :                 case 'd':
     837                 :          0 :                         must_confirm = false;
     838                 :          0 :                         dummy_run = true;
     839                 :          0 :                         break;
     840                 :          2 :                 case 'i':
     841                 :          2 :                         info = true;
     842                 :          2 :                         break;
     843                 :          0 :                 case 'b':
     844                 :          0 :                         bmc_flash = true;
     845                 :          0 :                         break;
     846                 :          0 :                 case 't':
     847                 :          0 :                         tune = true;
     848                 :          0 :                         break;
     849                 :          0 :                 case 'v':
     850                 :          0 :                         show_version = true;
     851                 :          0 :                         break;
     852                 :          2 :                 case 'h':
     853                 :          2 :                         show_help = show_version = true;
     854                 :          2 :                         break;
     855                 :          0 :                 case 'g':
     856                 :          0 :                         libflash_debug = true;
     857                 :          0 :                         break;
     858                 :          0 :                 case 'S':
     859                 :          0 :                         flash_side = atoi(optarg);
     860                 :          0 :                         break;
     861                 :          0 :                 case 'k':
     862                 :          0 :                         skip_size = strtoul(optarg, &endptr, 0);
     863                 :          0 :                         if (*endptr != '\0') {
     864                 :          0 :                                 rc = 1;
     865                 :          0 :                                 no_action = true;
     866                 :            :                         }
     867                 :            :                         break;
     868                 :          0 :                 case 'T':
     869                 :          0 :                         if (!optarg)
     870                 :            :                                 break;
     871                 :          0 :                         ffs_toc_seen = true;
     872                 :          0 :                         flash.toc = strtoul(optarg, &endptr, 0);
     873                 :          0 :                         if (*endptr != '\0') {
     874                 :          0 :                                 rc = 1;
     875                 :          0 :                                 no_action = true;
     876                 :            :                         }
     877                 :            :                         break;
     878                 :          0 :                 case 'c':
     879                 :          0 :                         do_clear = true;
     880                 :          0 :                         break;
     881                 :         12 :                 case 'm':
     882                 :         12 :                         print_detail = true;
     883                 :         12 :                         if (optarg) {
     884                 :         12 :                                 detail_id = strtoul(optarg, &endptr, 0);
     885                 :         12 :                                 if (*endptr != '\0') {
     886                 :          0 :                                         rc = 1;
     887                 :          0 :                                         no_action = true;
     888                 :            :                                 }
     889                 :            :                         }
     890                 :            :                         break;
     891                 :          0 :                 case '9':
     892                 :          0 :                         flash.mark_ecc = true;
     893                 :          0 :                         break;
     894                 :          0 :                 case ':':
     895                 :          0 :                         fprintf(stderr, "Unrecognised option \"%s\" to '%c'\n", optarg, optopt);
     896                 :          0 :                         no_action = true;
     897                 :          0 :                         break;
     898                 :          0 :                 case '?':
     899                 :          0 :                         fprintf(stderr, "Unrecognised option '%c'\n", optopt);
     900                 :          0 :                         no_action = true;
     901                 :          0 :                         break;
     902                 :          0 :                 default:
     903                 :          0 :                         fprintf(stderr , "Encountered unknown error parsing options\n");
     904                 :          0 :                         no_action = true;
     905                 :            :                 }
     906                 :            :         }
     907                 :            : 
     908                 :         26 :         if (optind < argc) {
     909                 :            :                 /*
     910                 :            :                  * It appears not everything passed to pflash was an option, best to
     911                 :            :                  * not continue
     912                 :            :                  */
     913                 :          0 :                 while (optind < argc)
     914                 :          0 :                         fprintf(stderr, "Unrecognised option or argument \"%s\"\n", argv[optind++]);
     915                 :            : 
     916                 :            :                 no_action = true;
     917                 :            :         }
     918                 :            : 
     919                 :            :         /* Check if we need to access the flash at all (which will
     920                 :            :          * also tune them as a side effect
     921                 :            :          */
     922                 :         26 :         no_action = no_action || (!erase && !program && !info && !do_read &&
     923                 :         14 :                 !enable_4B && !disable_4B && !tune && !do_clear && !print_detail);
     924                 :            : 
     925                 :            :         /* Nothing to do, if we didn't already, print usage */
     926                 :         26 :         if (no_action && !show_version)
     927                 :            :                 show_help = show_version = true;
     928                 :            : 
     929                 :         24 :         if (show_version)
     930                 :          4 :                 print_version();
     931                 :         26 :         if (show_help)
     932                 :          4 :                 print_help(pname);
     933                 :            : 
     934                 :         26 :         if (no_action)
     935                 :          4 :                 goto out;
     936                 :            : 
     937                 :            :         /* --enable-4B and --disable-4B are mutually exclusive */
     938                 :         22 :         if (enable_4B && disable_4B) {
     939                 :          0 :                 fprintf(stderr, "--enable-4B and --disable-4B are mutually"
     940                 :            :                         " exclusive !\n");
     941                 :          0 :                 rc = 1;
     942                 :          0 :                 goto out;
     943                 :            :         }
     944                 :            : 
     945                 :            :         /* 4B not supported on BMC flash */
     946                 :         22 :         if (enable_4B && bmc_flash) {
     947                 :          0 :                 fprintf(stderr, "--enable-4B not supported on BMC flash !\n");
     948                 :          0 :                 rc = 1;
     949                 :          0 :                 goto out;;
     950                 :            :         }
     951                 :            : 
     952                 :            :         /* partitions not supported on BMC flash */
     953                 :         22 :         if (part_name && bmc_flash) {
     954                 :          0 :                 fprintf(stderr, "--partition not supported on BMC flash !\n");
     955                 :          0 :                 rc = 1;
     956                 :          0 :                 goto out;
     957                 :            :         }
     958                 :            : 
     959                 :         22 :         if (print_detail && ((detail_id == UINT_MAX && !part_name)
     960                 :         12 :                         || (detail_id != UINT_MAX && part_name))) {
     961                 :          0 :                 fprintf(stderr, "--detail requires either a partition id or\n");
     962                 :          0 :                 fprintf(stderr, "a partition name with -P\n");
     963                 :            :         }
     964                 :            : 
     965                 :            :         /* part-name and erase-all make no sense together */
     966                 :         22 :         if (part_name && erase_all) {
     967                 :          0 :                 fprintf(stderr, "--partition and --erase-all are mutually"
     968                 :            :                         " exclusive !\n");
     969                 :          0 :                 rc = 1;
     970                 :          0 :                 goto out;
     971                 :            :         }
     972                 :            : 
     973                 :            :         /* Read command should always come with a file */
     974                 :         22 :         if (do_read && !read_file) {
     975                 :          0 :                 fprintf(stderr, "Read with no file specified !\n");
     976                 :          0 :                 rc = 1;
     977                 :          0 :                 goto out;
     978                 :            :         }
     979                 :            : 
     980                 :            :         /* Skip only supported on read */
     981                 :         22 :         if (skip_size && !do_read) {
     982                 :          0 :                 fprintf(stderr, "--skip requires a --read command !\n");
     983                 :          0 :                 rc = 1;
     984                 :          0 :                 goto out;
     985                 :            :         }
     986                 :            : 
     987                 :            :         /* Program command should always come with a file */
     988                 :         22 :         if (program && !write_file) {
     989                 :          0 :                 fprintf(stderr, "Program with no file specified !\n");
     990                 :          0 :                 rc = 1;
     991                 :          0 :                 goto out;
     992                 :            :         }
     993                 :            : 
     994                 :            :         /* If both partition and address specified, error out */
     995                 :         22 :         if (address && part_name) {
     996                 :          0 :                 fprintf(stderr, "Specify partition or address, not both !\n");
     997                 :          0 :                 rc = 1;
     998                 :          0 :                 goto out;
     999                 :            :         }
    1000                 :            : 
    1001                 :         22 :         if (do_clear && !part_name) {
    1002                 :          0 :                 fprintf(stderr, "--clear only supported on a partition name\n");
    1003                 :          0 :                 rc = 1;
    1004                 :          0 :                 goto out;
    1005                 :            :         }
    1006                 :            : 
    1007                 :            :         /* Explicitly only support two sides */
    1008                 :         22 :         if (flash_side != 0 && flash_side != 1) {
    1009                 :          0 :                 fprintf(stderr, "Unexpected value for --side '%d'\n", flash_side);
    1010                 :          0 :                 rc = 1;
    1011                 :          0 :                 goto out;
    1012                 :            :         }
    1013                 :            : 
    1014                 :         22 :         if (ffs_toc_seen && flash_side) {
    1015                 :          0 :                 fprintf(stderr, "--toc and --side are exclusive");
    1016                 :          0 :                 rc = 1;
    1017                 :          0 :                 goto out;
    1018                 :            :         }
    1019                 :            : 
    1020                 :         22 :         if (flashfilename && bmc_flash) {
    1021                 :          0 :                 fprintf(stderr, "Filename or bmc flash but not both\n");
    1022                 :          0 :                 rc = 1;
    1023                 :          0 :                 goto out;
    1024                 :            :         }
    1025                 :            : 
    1026                 :         22 :         if (flashfilename && direct) {
    1027                 :          0 :                 fprintf(stderr, "Filename or direct access but not both\n");
    1028                 :          0 :                 rc = 1;
    1029                 :          0 :                 goto out;
    1030                 :            :         }
    1031                 :            : 
    1032                 :         22 :         if (tune && !direct) {
    1033                 :          0 :                 fprintf(stderr, "It doesn't make sense to --tune without --direct\n");
    1034                 :          0 :                 rc = 1;
    1035                 :          0 :                 goto out;
    1036                 :            :         }
    1037                 :            : 
    1038                 :         22 :         if (direct) {
    1039                 :            :                 /* If -t is passed, then print a nice message */
    1040                 :          0 :                 if (tune)
    1041                 :          0 :                         printf("Flash and controller tuned\n");
    1042                 :            : 
    1043                 :          0 :                 if (arch_flash_access(NULL, bmc_flash ? BMC_DIRECT : PNOR_DIRECT) == ACCESS_INVAL) {
    1044                 :          0 :                         fprintf(stderr, "Can't access %s flash directly on this architecture\n",
    1045                 :          0 :                                 bmc_flash ? "BMC" : "PNOR");
    1046                 :          0 :                         rc = 1;
    1047                 :          0 :                         goto out;
    1048                 :            :                 }
    1049                 :         22 :         } else if (!flashfilename) {
    1050                 :          0 :                 if (arch_flash_access(NULL, bmc_flash ? BMC_MTD : PNOR_MTD) == ACCESS_INVAL) {
    1051                 :          0 :                         fprintf(stderr, "Can't access %s flash through MTD on this system\n",
    1052                 :          0 :                                 bmc_flash ? "BMC" : "PNOR");
    1053                 :          0 :                         rc = 1;
    1054                 :          0 :                         goto out;
    1055                 :            :                 }
    1056                 :            :         }
    1057                 :            : 
    1058                 :         22 :         if (arch_flash_init(&flash.bl, flashfilename, true)) {
    1059                 :          0 :                 fprintf(stderr, "Couldn't initialise architecture flash structures\n");
    1060                 :          0 :                 rc = 1;
    1061                 :          0 :                 goto out;
    1062                 :            :         }
    1063                 :            : 
    1064                 :         22 :         rc = blocklevel_get_info(flash.bl, &flash.name,
    1065                 :            :                             &flash.total_size, &flash.erase_granule);
    1066                 :         22 :         if (rc) {
    1067                 :          0 :                 fprintf(stderr, "Error %d getting flash info\n", rc);
    1068                 :          0 :                 rc = 1;
    1069                 :          0 :                 goto close;
    1070                 :            :         }
    1071                 :            : 
    1072                 :            :         /* If file specified but not size, get size from file */
    1073                 :         22 :         if (write_file && !write_size) {
    1074                 :          2 :                 struct stat stbuf;
    1075                 :            : 
    1076                 :          2 :                 if (stat(write_file, &stbuf)) {
    1077                 :          0 :                         perror("Failed to get file size");
    1078                 :          0 :                         rc = 1;
    1079                 :          0 :                         goto close;
    1080                 :            :                 }
    1081                 :          2 :                 write_size = stbuf.st_size;
    1082                 :            :         }
    1083                 :            : 
    1084                 :            :         /* Only take ECC into account under some conditions later */
    1085                 :         22 :         write_size_minus_ecc = write_size;
    1086                 :            : 
    1087                 :            :         /* If read specified and no read_size, use flash size */
    1088                 :         22 :         if (do_read && !read_size && !part_name)
    1089                 :          0 :                 read_size = flash.total_size;
    1090                 :            : 
    1091                 :            :         /* We have a partition, adjust read/write size if needed */
    1092                 :         22 :         if (part_name || print_detail) {
    1093                 :         16 :                 uint32_t pstart, pmaxsz, pactsize;
    1094                 :         16 :                 bool ecc, confirm;
    1095                 :            : 
    1096                 :         16 :                 if (ffs_toc_seen)
    1097                 :          0 :                         ffsh = lookup_partition_at_toc(&flash,
    1098                 :            :                                         part_name, &ffs_index);
    1099                 :            :                 else
    1100                 :         16 :                         ffsh = lookup_partition_at_side(&flash, flash_side,
    1101                 :            :                                         part_name, &ffs_index);
    1102                 :         16 :                 if (!ffsh)
    1103                 :          0 :                         goto close;
    1104                 :            : 
    1105                 :         16 :                 if (!part_name)
    1106                 :         12 :                         ffs_index = detail_id;
    1107                 :            : 
    1108                 :         16 :                 rc = ffs_part_info(ffsh, ffs_index, NULL,
    1109                 :            :                                    &pstart, &pmaxsz, &pactsize, &ecc);
    1110                 :         16 :                 if (rc) {
    1111                 :          0 :                         fprintf(stderr,"Failed to get partition info\n");
    1112                 :          0 :                         goto close;
    1113                 :            :                 }
    1114                 :            : 
    1115                 :         16 :                 if (!ecc && do_clear) {
    1116                 :          0 :                         fprintf(stderr, "The partition on which to do --clear "
    1117                 :            :                                         "does not have ECC, are you sure?\n");
    1118                 :          0 :                         confirm = check_confirm();
    1119                 :          0 :                         if (!confirm) {
    1120                 :          0 :                                 rc = 1;
    1121                 :          0 :                                 goto close;
    1122                 :            :                         }
    1123                 :            :                         /* Still confirm later on */
    1124                 :          0 :                         must_confirm = true;
    1125                 :            :                 }
    1126                 :            : 
    1127                 :            :                 /* Read size is obtained from partition "actual" size */
    1128                 :         16 :                 if (!read_size)
    1129                 :         16 :                         read_size = pactsize;
    1130                 :            :                 /* If we're decoding ecc and partition is ECC'd, then adjust */
    1131                 :         16 :                 if (ecc && flash.mark_ecc)
    1132                 :          0 :                         read_size = ecc_buffer_size_minus_ecc(read_size);
    1133                 :            : 
    1134                 :            :                 /* Write size is max size of partition */
    1135                 :         16 :                 if (!write_size)
    1136                 :         14 :                         write_size = pmaxsz;
    1137                 :            : 
    1138                 :            :                 /* But write size can take into account ECC as well */
    1139                 :         16 :                 if (ecc && flash.mark_ecc)
    1140                 :          0 :                         write_size_minus_ecc = ecc_buffer_size_minus_ecc(write_size);
    1141                 :            :                 else
    1142                 :            :                         write_size_minus_ecc = write_size;
    1143                 :            : 
    1144                 :            :                 /* Crop write size to partition size if --force was passed */
    1145                 :         16 :                 if ((write_size_minus_ecc > pmaxsz) && !must_confirm) {
    1146                 :          0 :                         printf("WARNING: Size (%d bytes) larger than partition"
    1147                 :            :                                " (%d bytes), cropping to fit\n",
    1148                 :            :                                write_size, pmaxsz);
    1149                 :          0 :                         write_size = pmaxsz;
    1150                 :         16 :                 } else if (write_size_minus_ecc > pmaxsz) {
    1151                 :          0 :                         printf("ERROR: Size (%d bytes) larger than partition"
    1152                 :            :                                " (%d bytes). Use --force to force\n",
    1153                 :            :                                write_size, pmaxsz);
    1154                 :          0 :                         goto close;
    1155                 :            :                 }
    1156                 :            : 
    1157                 :            :                 /* Set address */
    1158                 :         16 :                 address = pstart;
    1159                 :          6 :         } else if (erase) {
    1160                 :          4 :                 if ((address | write_size) & (flash.erase_granule - 1)) {
    1161                 :          0 :                         if (must_confirm) {
    1162                 :          0 :                                 printf("ERROR: Erase at 0x%08x for 0x%08x isn't erase block aligned\n",
    1163                 :            :                                                 address, write_size);
    1164                 :          0 :                                 printf("Use --force to force\n");
    1165                 :          0 :                                 goto close;
    1166                 :            :                         } else {
    1167                 :          0 :                                 printf("WARNING: Erase at 0x%08x for 0x%08x isn't erase block aligned\n",
    1168                 :            :                                                 address, write_size);
    1169                 :            :                         }
    1170                 :            :                 }
    1171                 :            :         }
    1172                 :            : 
    1173                 :            :         /* Process commands */
    1174                 :            : 
    1175                 :            :         /* Both enable and disable can't be set (we've checked) */
    1176                 :         22 :         if (enable_4B)
    1177                 :          0 :                 rc = enable_4B_addresses(flash.bl);
    1178                 :         22 :         if (disable_4B)
    1179                 :          0 :                 rc = disable_4B_addresses(flash.bl);
    1180                 :         22 :         if (rc)
    1181                 :          0 :                 goto close;
    1182                 :            : 
    1183                 :         22 :         if (info) {
    1184                 :            :                 /*
    1185                 :            :                  * Don't pass through modfied TOC value if the modification was done
    1186                 :            :                  * because of --size, but still respect if it came from --toc (we
    1187                 :            :                  * assume the user knows what they're doing in that case)
    1188                 :            :                  */
    1189                 :          2 :                 print_flash_info(&flash);
    1190                 :            :         }
    1191                 :            : 
    1192                 :         22 :         if (print_detail)
    1193                 :         12 :                 print_partition_detail(ffsh, ffs_index);
    1194                 :            : 
    1195                 :            :         /* Unlock flash (PNOR only) */
    1196                 :         22 :         if ((erase || program || do_clear) && !bmc_flash && !flashfilename) {
    1197                 :          0 :                 flash.need_relock = arch_flash_set_wrprotect(flash.bl, false);
    1198                 :          0 :                 if (flash.need_relock == -1) {
    1199                 :          0 :                         fprintf(stderr, "Architecture doesn't support write protection on flash\n");
    1200                 :          0 :                         flash.need_relock = 0;
    1201                 :          0 :                         goto close;
    1202                 :            :                 }
    1203                 :            :         }
    1204                 :         22 :         rc = 0;
    1205                 :         22 :         if (do_read)
    1206                 :          0 :                 rc = do_read_file(flash.bl, read_file, address, read_size, skip_size);
    1207                 :         22 :         if (!rc && erase_all)
    1208                 :          2 :                 rc = erase_chip(&flash);
    1209                 :         20 :         else if (!rc && erase)
    1210                 :          6 :                 rc = erase_range(&flash, address, write_size,
    1211                 :            :                                 program, ffsh, ffs_index);
    1212                 :         22 :         if (!rc && program)
    1213                 :          4 :                 rc = program_file(flash.bl, write_file, address, write_size_minus_ecc,
    1214                 :            :                                 ffsh, ffs_index);
    1215                 :         22 :         if (!rc && do_clear)
    1216                 :          0 :                 rc = set_ecc(&flash, address, write_size);
    1217                 :            : 
    1218                 :         22 : close:
    1219                 :         22 :         if (flash.need_relock)
    1220                 :          0 :                 arch_flash_set_wrprotect(flash.bl, 1);
    1221                 :         22 :         arch_flash_close(flash.bl, flashfilename);
    1222                 :         22 :         if (ffsh)
    1223                 :         16 :                 ffs_close(ffsh);
    1224                 :          6 : out:
    1225                 :         26 :         free(part_name);
    1226                 :         26 :         free(read_file);
    1227                 :         26 :         free(write_file);
    1228                 :            : 
    1229                 :         26 :         return rc;
    1230                 :            : }

Generated by: LCOV version 1.14