uboot/env/env.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2017 Google, Inc
   4 * Written by Simon Glass <sjg@chromium.org>
   5 */
   6
   7#include <common.h>
   8#include <env.h>
   9#include <env_internal.h>
  10#include <log.h>
  11#include <asm/global_data.h>
  12#include <linux/bitops.h>
  13#include <linux/bug.h>
  14
  15DECLARE_GLOBAL_DATA_PTR;
  16
  17#if defined(CONFIG_NEEDS_MANUAL_RELOC)
  18void env_fix_drivers(void)
  19{
  20        struct env_driver *drv;
  21        const int n_ents = ll_entry_count(struct env_driver, env_driver);
  22        struct env_driver *entry;
  23
  24        drv = ll_entry_start(struct env_driver, env_driver);
  25        for (entry = drv; entry != drv + n_ents; entry++) {
  26                if (entry->name)
  27                        entry->name += gd->reloc_off;
  28                if (entry->load)
  29                        entry->load += gd->reloc_off;
  30                if (entry->save)
  31                        entry->save += gd->reloc_off;
  32                if (entry->erase)
  33                        entry->erase += gd->reloc_off;
  34                if (entry->init)
  35                        entry->init += gd->reloc_off;
  36        }
  37}
  38#endif
  39
  40static struct env_driver *_env_driver_lookup(enum env_location loc)
  41{
  42        struct env_driver *drv;
  43        const int n_ents = ll_entry_count(struct env_driver, env_driver);
  44        struct env_driver *entry;
  45
  46        drv = ll_entry_start(struct env_driver, env_driver);
  47        for (entry = drv; entry != drv + n_ents; entry++) {
  48                if (loc == entry->location)
  49                        return entry;
  50        }
  51
  52        /* Not found */
  53        return NULL;
  54}
  55
  56static enum env_location env_locations[] = {
  57#ifdef CONFIG_ENV_IS_IN_EEPROM
  58        ENVL_EEPROM,
  59#endif
  60#ifdef CONFIG_ENV_IS_IN_EXT4
  61        ENVL_EXT4,
  62#endif
  63#ifdef CONFIG_ENV_IS_IN_FAT
  64        ENVL_FAT,
  65#endif
  66#ifdef CONFIG_ENV_IS_IN_FLASH
  67        ENVL_FLASH,
  68#endif
  69#ifdef CONFIG_ENV_IS_IN_MMC
  70        ENVL_MMC,
  71#endif
  72#ifdef CONFIG_ENV_IS_IN_NAND
  73        ENVL_NAND,
  74#endif
  75#ifdef CONFIG_ENV_IS_IN_NVRAM
  76        ENVL_NVRAM,
  77#endif
  78#ifdef CONFIG_ENV_IS_IN_REMOTE
  79        ENVL_REMOTE,
  80#endif
  81#ifdef CONFIG_ENV_IS_IN_SATA
  82        ENVL_ESATA,
  83#endif
  84#ifdef CONFIG_ENV_IS_IN_SPI_FLASH
  85        ENVL_SPI_FLASH,
  86#endif
  87#ifdef CONFIG_ENV_IS_IN_UBI
  88        ENVL_UBI,
  89#endif
  90#ifdef CONFIG_ENV_IS_NOWHERE
  91        ENVL_NOWHERE,
  92#endif
  93};
  94
  95static bool env_has_inited(enum env_location location)
  96{
  97        return gd->env_has_init & BIT(location);
  98}
  99
 100static void env_set_inited(enum env_location location)
 101{
 102        /*
 103         * We're using a 32-bits bitmask stored in gd (env_has_init)
 104         * using the above enum value as the bit index. We need to
 105         * make sure that we're not overflowing it.
 106         */
 107        BUILD_BUG_ON(ENVL_COUNT > BITS_PER_LONG);
 108
 109        gd->env_has_init |= BIT(location);
 110}
 111
 112/**
 113 * env_get_location() - Returns the best env location for a board
 114 * @op: operations performed on the environment
 115 * @prio: priority between the multiple environments, 0 being the
 116 *        highest priority
 117 *
 118 * This will return the preferred environment for the given priority.
 119 * This is overridable by boards if they need to.
 120 *
 121 * All implementations are free to use the operation, the priority and
 122 * any other data relevant to their choice, but must take into account
 123 * the fact that the lowest prority (0) is the most important location
 124 * in the system. The following locations should be returned by order
 125 * of descending priorities, from the highest to the lowest priority.
 126 *
 127 * Returns:
 128 * an enum env_location value on success, a negative error code otherwise
 129 */
 130__weak enum env_location env_get_location(enum env_operation op, int prio)
 131{
 132        if (prio >= ARRAY_SIZE(env_locations))
 133                return ENVL_UNKNOWN;
 134
 135        return env_locations[prio];
 136}
 137
 138
 139/**
 140 * env_driver_lookup() - Finds the most suited environment location
 141 * @op: operations performed on the environment
 142 * @prio: priority between the multiple environments, 0 being the
 143 *        highest priority
 144 *
 145 * This will try to find the available environment with the highest
 146 * priority in the system.
 147 *
 148 * Returns:
 149 * NULL on error, a pointer to a struct env_driver otherwise
 150 */
 151static struct env_driver *env_driver_lookup(enum env_operation op, int prio)
 152{
 153        enum env_location loc = env_get_location(op, prio);
 154        struct env_driver *drv;
 155
 156        if (loc == ENVL_UNKNOWN)
 157                return NULL;
 158
 159        drv = _env_driver_lookup(loc);
 160        if (!drv) {
 161                debug("%s: No environment driver for location %d\n", __func__,
 162                      loc);
 163                return NULL;
 164        }
 165
 166        return drv;
 167}
 168
 169int env_load(void)
 170{
 171        struct env_driver *drv;
 172        int best_prio = -1;
 173        int prio;
 174
 175        for (prio = 0; (drv = env_driver_lookup(ENVOP_LOAD, prio)); prio++) {
 176                int ret;
 177
 178                if (!env_has_inited(drv->location))
 179                        continue;
 180
 181                printf("Loading Environment from %s... ", drv->name);
 182                /*
 183                 * In error case, the error message must be printed during
 184                 * drv->load() in some underlying API, and it must be exactly
 185                 * one message.
 186                 */
 187                ret = drv->load();
 188                if (!ret) {
 189                        printf("OK\n");
 190                        gd->env_load_prio = prio;
 191
 192#if !CONFIG_IS_ENABLED(ENV_APPEND)
 193                        return 0;
 194#endif
 195                } else if (ret == -ENOMSG) {
 196                        /* Handle "bad CRC" case */
 197                        if (best_prio == -1)
 198                                best_prio = prio;
 199                } else {
 200                        debug("Failed (%d)\n", ret);
 201                }
 202        }
 203
 204        /*
 205         * In case of invalid environment, we set the 'default' env location
 206         * to the best choice, i.e.:
 207         *   1. Environment location with bad CRC, if such location was found
 208         *   2. Otherwise use the location with highest priority
 209         *
 210         * This way, next calls to env_save() will restore the environment
 211         * at the right place.
 212         */
 213        if (best_prio >= 0)
 214                debug("Selecting environment with bad CRC\n");
 215        else
 216                best_prio = 0;
 217
 218        gd->env_load_prio = best_prio;
 219
 220        return -ENODEV;
 221}
 222
 223int env_reload(void)
 224{
 225        struct env_driver *drv;
 226
 227        drv = env_driver_lookup(ENVOP_LOAD, gd->env_load_prio);
 228        if (drv) {
 229                int ret;
 230
 231                printf("Loading Environment from %s... ", drv->name);
 232
 233                if (!env_has_inited(drv->location)) {
 234                        printf("not initialized\n");
 235                        return -ENODEV;
 236                }
 237
 238                ret = drv->load();
 239                if (ret)
 240                        printf("Failed (%d)\n", ret);
 241                else
 242                        printf("OK\n");
 243
 244                if (!ret)
 245                        return 0;
 246        }
 247
 248        return -ENODEV;
 249}
 250
 251int env_save(void)
 252{
 253        struct env_driver *drv;
 254
 255        drv = env_driver_lookup(ENVOP_SAVE, gd->env_load_prio);
 256        if (drv) {
 257                int ret;
 258
 259                printf("Saving Environment to %s... ", drv->name);
 260                if (!drv->save) {
 261                        printf("not possible\n");
 262                        return -ENODEV;
 263                }
 264
 265                if (!env_has_inited(drv->location)) {
 266                        printf("not initialized\n");
 267                        return -ENODEV;
 268                }
 269
 270                ret = drv->save();
 271                if (ret)
 272                        printf("Failed (%d)\n", ret);
 273                else
 274                        printf("OK\n");
 275
 276                if (!ret)
 277                        return 0;
 278        }
 279
 280        return -ENODEV;
 281}
 282
 283int env_erase(void)
 284{
 285        struct env_driver *drv;
 286
 287        drv = env_driver_lookup(ENVOP_ERASE, gd->env_load_prio);
 288        if (drv) {
 289                int ret;
 290
 291                if (!drv->erase)
 292                        return -ENODEV;
 293
 294                if (!env_has_inited(drv->location))
 295                        return -ENODEV;
 296
 297                printf("Erasing Environment on %s... ", drv->name);
 298                ret = drv->erase();
 299                if (ret)
 300                        printf("Failed (%d)\n", ret);
 301                else
 302                        printf("OK\n");
 303
 304                if (!ret)
 305                        return 0;
 306        }
 307
 308        return -ENODEV;
 309}
 310
 311int env_init(void)
 312{
 313        struct env_driver *drv;
 314        int ret = -ENOENT;
 315        int prio;
 316
 317        for (prio = 0; (drv = env_driver_lookup(ENVOP_INIT, prio)); prio++) {
 318                if (!drv->init || !(ret = drv->init()))
 319                        env_set_inited(drv->location);
 320                if (ret == -ENOENT)
 321                        env_set_inited(drv->location);
 322
 323                debug("%s: Environment %s init done (ret=%d)\n", __func__,
 324                      drv->name, ret);
 325
 326                if (gd->env_valid == ENV_INVALID)
 327                        ret = -ENOENT;
 328        }
 329
 330        if (!prio)
 331                return -ENODEV;
 332
 333        if (ret == -ENOENT) {
 334                gd->env_addr = (ulong)&default_environment[0];
 335                gd->env_valid = ENV_VALID;
 336
 337                return 0;
 338        }
 339
 340        return ret;
 341}
 342
 343int env_select(const char *name)
 344{
 345        struct env_driver *drv;
 346        const int n_ents = ll_entry_count(struct env_driver, env_driver);
 347        struct env_driver *entry;
 348        int prio;
 349        bool found = false;
 350
 351        printf("Select Environment on %s: ", name);
 352
 353        /* search ENV driver by name */
 354        drv = ll_entry_start(struct env_driver, env_driver);
 355        for (entry = drv; entry != drv + n_ents; entry++) {
 356                if (!strcmp(entry->name, name)) {
 357                        found = true;
 358                        break;
 359                }
 360        }
 361
 362        if (!found) {
 363                printf("driver not found\n");
 364                return -ENODEV;
 365        }
 366
 367        /* search priority by driver */
 368        for (prio = 0; (drv = env_driver_lookup(ENVOP_INIT, prio)); prio++) {
 369                if (entry->location == env_get_location(ENVOP_LOAD, prio)) {
 370                        /* when priority change, reset the ENV flags */
 371                        if (gd->env_load_prio != prio) {
 372                                gd->env_load_prio = prio;
 373                                gd->env_valid = ENV_INVALID;
 374                                gd->flags &= ~GD_FLG_ENV_DEFAULT;
 375                        }
 376                        printf("OK\n");
 377                        return 0;
 378                }
 379        }
 380        printf("priority not found\n");
 381
 382        return -ENODEV;
 383}
 384