diff options
-rw-r--r-- | board/sandbox/sandbox.c | 15 | ||||
-rw-r--r-- | cmd/Kconfig | 11 | ||||
-rw-r--r-- | cmd/nvedit.c | 29 | ||||
-rw-r--r-- | configs/sandbox64_defconfig | 7 | ||||
-rw-r--r-- | configs/sandbox_defconfig | 7 | ||||
-rw-r--r-- | configs/sandbox_flattree_defconfig | 7 | ||||
-rw-r--r-- | configs/sandbox_spl_defconfig | 7 | ||||
-rw-r--r-- | env/Kconfig | 19 | ||||
-rw-r--r-- | env/common.c | 16 | ||||
-rw-r--r-- | env/eeprom.c | 2 | ||||
-rw-r--r-- | env/env.c | 82 | ||||
-rw-r--r-- | env/ext4.c | 54 | ||||
-rw-r--r-- | env/fat.c | 2 | ||||
-rw-r--r-- | env/flags.c | 66 | ||||
-rw-r--r-- | env/flash.c | 2 | ||||
-rw-r--r-- | env/mmc.c | 4 | ||||
-rw-r--r-- | env/nand.c | 4 | ||||
-rw-r--r-- | env/nowhere.c | 17 | ||||
-rw-r--r-- | env/nvram.c | 2 | ||||
-rw-r--r-- | env/onenand.c | 2 | ||||
-rw-r--r-- | env/remote.c | 2 | ||||
-rw-r--r-- | env/sata.c | 2 | ||||
-rw-r--r-- | env/sf.c | 6 | ||||
-rw-r--r-- | env/ubi.c | 4 | ||||
-rw-r--r-- | include/env.h | 22 | ||||
-rw-r--r-- | include/env_flags.h | 6 | ||||
-rw-r--r-- | include/env_internal.h | 23 | ||||
-rw-r--r-- | include/search.h | 2 | ||||
-rw-r--r-- | lib/hashtable.c | 9 | ||||
-rw-r--r-- | test/py/tests/test_efi_loader.py | 2 | ||||
-rw-r--r-- | test/py/tests/test_efi_selftest.py | 2 | ||||
-rw-r--r-- | test/py/tests/test_env.py | 113 | ||||
-rw-r--r-- | tools/env/fw_env.c | 24 |
33 files changed, 507 insertions, 65 deletions
diff --git a/board/sandbox/sandbox.c b/board/sandbox/sandbox.c index c1317a8ca3..937ce28411 100644 --- a/board/sandbox/sandbox.c +++ b/board/sandbox/sandbox.c @@ -7,6 +7,7 @@ #include <cpu_func.h> #include <cros_ec.h> #include <dm.h> +#include <env_internal.h> #include <init.h> #include <led.h> #include <os.h> @@ -44,6 +45,20 @@ unsigned long timer_read_counter(void) } #endif +/* specific order for sandbox: nowhere is the first value, used by default */ +static enum env_location env_locations[] = { + ENVL_NOWHERE, + ENVL_EXT4, +}; + +enum env_location env_get_location(enum env_operation op, int prio) +{ + if (prio >= ARRAY_SIZE(env_locations)) + return ENVL_UNKNOWN; + + return env_locations[prio]; +} + int dram_init(void) { gd->ram_size = CONFIG_SYS_SDRAM_SIZE; diff --git a/cmd/Kconfig b/cmd/Kconfig index bea2ddf830..d7136b0e79 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -604,6 +604,17 @@ config CMD_NVEDIT_INFO [-q] : quiet output The result of multiple evaluations will be combined with AND. +config CMD_NVEDIT_LOAD + bool "env load" + help + Load all environment variables from the compiled-in persistent + storage. + +config CMD_NVEDIT_SELECT + bool "env select" + help + Select the compiled-in persistent storage of environment variables. + endmenu menu "Memory commands" diff --git a/cmd/nvedit.c b/cmd/nvedit.c index acd9f82667..d188c6aa6b 100644 --- a/cmd/nvedit.c +++ b/cmd/nvedit.c @@ -794,6 +794,23 @@ U_BOOT_CMD( ); #endif #endif + +#if defined(CONFIG_CMD_NVEDIT_LOAD) +static int do_env_load(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + return env_reload() ? 1 : 0; +} +#endif + +#if defined(CONFIG_CMD_NVEDIT_SELECT) +static int do_env_select(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + return env_select(argv[1]) ? 1 : 0; +} +#endif + #endif /* CONFIG_SPL_BUILD */ int env_match(uchar *s1, int i2) @@ -1347,6 +1364,9 @@ static struct cmd_tbl cmd_env_sub[] = { #if defined(CONFIG_CMD_NVEDIT_INFO) U_BOOT_CMD_MKENT(info, 3, 0, do_env_info, "", ""), #endif +#if defined(CONFIG_CMD_NVEDIT_LOAD) + U_BOOT_CMD_MKENT(load, 1, 0, do_env_load, "", ""), +#endif U_BOOT_CMD_MKENT(print, CONFIG_SYS_MAXARGS, 1, do_env_print, "", ""), #if defined(CONFIG_CMD_RUN) U_BOOT_CMD_MKENT(run, CONFIG_SYS_MAXARGS, 1, do_run, "", ""), @@ -1357,6 +1377,9 @@ static struct cmd_tbl cmd_env_sub[] = { U_BOOT_CMD_MKENT(erase, 1, 0, do_env_erase, "", ""), #endif #endif +#if defined(CONFIG_CMD_NVEDIT_SELECT) + U_BOOT_CMD_MKENT(select, 2, 0, do_env_select, "", ""), +#endif U_BOOT_CMD_MKENT(set, CONFIG_SYS_MAXARGS, 0, do_env_set, "", ""), #if defined(CONFIG_CMD_ENV_EXISTS) U_BOOT_CMD_MKENT(exists, 2, 0, do_env_exists, "", ""), @@ -1442,6 +1465,12 @@ static char env_help_text[] = "env erase - erase environment\n" #endif #endif +#if defined(CONFIG_CMD_NVEDIT_LOAD) + "env load - load environment\n" +#endif +#if defined(CONFIG_CMD_NVEDIT_SELECT) + "env select [target] - select environment target\n" +#endif #if defined(CONFIG_CMD_NVEDIT_EFI) "env set -e [-nv][-bs][-rt][-at][-a][-i addr,size][-v] name [arg ...]\n" " - set UEFI variable; unset if '-i' or 'arg' not specified\n" diff --git a/configs/sandbox64_defconfig b/configs/sandbox64_defconfig index e8a1d57285..1228c49727 100644 --- a/configs/sandbox64_defconfig +++ b/configs/sandbox64_defconfig @@ -27,10 +27,13 @@ CONFIG_CMD_BOOTEFI_HELLO=y # CONFIG_CMD_ELF is not set CONFIG_CMD_ASKENV=y CONFIG_CMD_GREPENV=y +CONFIG_CMD_ERASEENV=y CONFIG_CMD_ENV_CALLBACK=y CONFIG_CMD_ENV_FLAGS=y CONFIG_CMD_NVEDIT_EFI=y CONFIG_CMD_NVEDIT_INFO=y +CONFIG_CMD_NVEDIT_LOAD=y +CONFIG_CMD_NVEDIT_SELECT=y CONFIG_LOOPW=y CONFIG_CMD_MD5SUM=y CONFIG_CMD_MEMINFO=y @@ -83,6 +86,10 @@ CONFIG_OF_CONTROL=y CONFIG_OF_LIVE=y CONFIG_OF_HOSTFILE=y CONFIG_BOOTP_SEND_HOSTNAME=y +CONFIG_ENV_IS_NOWHERE=y +CONFIG_ENV_IS_IN_EXT4=y +CONFIG_ENV_EXT4_INTERFACE="host" +CONFIG_ENV_EXT4_DEVICE_AND_PART="0:0" CONFIG_NETCONSOLE=y CONFIG_IP_DEFRAG=y CONFIG_REGMAP=y diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index 5bb44c780f..f4f97f34ff 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -32,10 +32,13 @@ CONFIG_CMD_ABOOTIMG=y # CONFIG_CMD_ELF is not set CONFIG_CMD_ASKENV=y CONFIG_CMD_GREPENV=y +CONFIG_CMD_ERASEENV=y CONFIG_CMD_ENV_CALLBACK=y CONFIG_CMD_ENV_FLAGS=y CONFIG_CMD_NVEDIT_EFI=y CONFIG_CMD_NVEDIT_INFO=y +CONFIG_CMD_NVEDIT_LOAD=y +CONFIG_CMD_NVEDIT_SELECT=y CONFIG_LOOPW=y CONFIG_CMD_MD5SUM=y CONFIG_CMD_MEMINFO=y @@ -94,6 +97,10 @@ CONFIG_OF_CONTROL=y CONFIG_OF_LIVE=y CONFIG_OF_HOSTFILE=y CONFIG_BOOTP_SEND_HOSTNAME=y +CONFIG_ENV_IS_NOWHERE=y +CONFIG_ENV_IS_IN_EXT4=y +CONFIG_ENV_EXT4_INTERFACE="host" +CONFIG_ENV_EXT4_DEVICE_AND_PART="0:0" CONFIG_NETCONSOLE=y CONFIG_IP_DEFRAG=y CONFIG_REGMAP=y diff --git a/configs/sandbox_flattree_defconfig b/configs/sandbox_flattree_defconfig index 4b28b8e71c..78d732d0bc 100644 --- a/configs/sandbox_flattree_defconfig +++ b/configs/sandbox_flattree_defconfig @@ -24,7 +24,10 @@ CONFIG_CMD_BOOTEFI_HELLO=y # CONFIG_CMD_ELF is not set CONFIG_CMD_ASKENV=y CONFIG_CMD_GREPENV=y +CONFIG_CMD_ERASEENV=y CONFIG_CMD_NVEDIT_INFO=y +CONFIG_CMD_NVEDIT_LOAD=y +CONFIG_CMD_NVEDIT_SELECT=y CONFIG_LOOPW=y CONFIG_CMD_MD5SUM=y CONFIG_CMD_MEMINFO=y @@ -66,6 +69,10 @@ CONFIG_AMIGA_PARTITION=y CONFIG_OF_CONTROL=y CONFIG_OF_HOSTFILE=y CONFIG_BOOTP_SEND_HOSTNAME=y +CONFIG_ENV_IS_NOWHERE=y +CONFIG_ENV_IS_IN_EXT4=y +CONFIG_ENV_EXT4_INTERFACE="host" +CONFIG_ENV_EXT4_DEVICE_AND_PART="0:0" CONFIG_NETCONSOLE=y CONFIG_IP_DEFRAG=y CONFIG_REGMAP=y diff --git a/configs/sandbox_spl_defconfig b/configs/sandbox_spl_defconfig index 4549a81ff0..b846487f23 100644 --- a/configs/sandbox_spl_defconfig +++ b/configs/sandbox_spl_defconfig @@ -34,9 +34,12 @@ CONFIG_CMD_BOOTEFI_HELLO=y # CONFIG_CMD_ELF is not set CONFIG_CMD_ASKENV=y CONFIG_CMD_GREPENV=y +CONFIG_CMD_ERASEENV=y CONFIG_CMD_ENV_CALLBACK=y CONFIG_CMD_ENV_FLAGS=y CONFIG_CMD_NVEDIT_INFO=y +CONFIG_CMD_NVEDIT_LOAD=y +CONFIG_CMD_NVEDIT_SELECT=y CONFIG_LOOPW=y CONFIG_CMD_MD5SUM=y CONFIG_CMD_MEMINFO=y @@ -83,6 +86,10 @@ CONFIG_SPL_OF_CONTROL=y CONFIG_OF_HOSTFILE=y CONFIG_SPL_OF_PLATDATA=y CONFIG_BOOTP_SEND_HOSTNAME=y +CONFIG_ENV_IS_NOWHERE=y +CONFIG_ENV_IS_IN_EXT4=y +CONFIG_ENV_EXT4_INTERFACE="host" +CONFIG_ENV_EXT4_DEVICE_AND_PART="0:0" CONFIG_NETCONSOLE=y CONFIG_IP_DEFRAG=y CONFIG_SPL_DM=y diff --git a/env/Kconfig b/env/Kconfig index 4113628f49..5d0a8ecea0 100644 --- a/env/Kconfig +++ b/env/Kconfig @@ -479,7 +479,7 @@ config ENV_EXT4_DEVICE_AND_PART config ENV_EXT4_FILE string "Name of the EXT4 file to use for the environment" depends on ENV_IS_IN_EXT4 - default "uboot.env" + default "/uboot.env" help It's a string of the EXT4 file name. This file use to store the environment (explicit path to the file) @@ -614,6 +614,23 @@ config DELAY_ENVIRONMENT later by U-Boot code. With CONFIG_OF_CONTROL this is instead controlled by the value of /config/load-environment. +config ENV_APPEND + bool "Always append the environment with new data" + default n + help + If defined, the environment hash table is only ever appended with new + data, but the existing hash table can never be dropped and reloaded + with newly imported data. This may be used in combination with static + flags to e.g. to protect variables which must not be modified. + +config ENV_WRITEABLE_LIST + bool "Permit write access only to listed variables" + default n + help + If defined, only environment variables which explicitly set the 'w' + writeable flag can be written and modified at runtime. No variables + can be otherwise created, written or imported into the environment. + config ENV_ACCESS_IGNORE_FORCE bool "Block forced environment operations" default n diff --git a/env/common.c b/env/common.c index 088b2aebb4..ed18378000 100644 --- a/env/common.c +++ b/env/common.c @@ -81,6 +81,7 @@ void env_set_default(const char *s, int flags) debug("Using default environment\n"); } + flags |= H_DEFAULT; if (himport_r(&env_htab, (char *)default_environment, sizeof(default_environment), '\0', flags, 0, 0, NULL) == 0) @@ -99,7 +100,7 @@ int env_set_default_vars(int nvars, char * const vars[], int flags) * Special use-case: import from default environment * (and use \0 as a separator) */ - flags |= H_NOCLEAR; + flags |= H_NOCLEAR | H_DEFAULT; return himport_r(&env_htab, (const char *)default_environment, sizeof(default_environment), '\0', flags, 0, nvars, vars); @@ -109,7 +110,7 @@ int env_set_default_vars(int nvars, char * const vars[], int flags) * Check if CRC is valid and (if yes) import the environment. * Note that "buf" may or may not be aligned. */ -int env_import(const char *buf, int check) +int env_import(const char *buf, int check, int flags) { env_t *ep = (env_t *)buf; @@ -124,7 +125,7 @@ int env_import(const char *buf, int check) } } - if (himport_r(&env_htab, (char *)ep->data, ENV_SIZE, '\0', 0, 0, + if (himport_r(&env_htab, (char *)ep->data, ENV_SIZE, '\0', flags, 0, 0, NULL)) { gd->flags |= GD_FLG_ENV_READY; return 0; @@ -141,7 +142,8 @@ int env_import(const char *buf, int check) static unsigned char env_flags; int env_import_redund(const char *buf1, int buf1_read_fail, - const char *buf2, int buf2_read_fail) + const char *buf2, int buf2_read_fail, + int flags) { int crc1_ok, crc2_ok; env_t *ep, *tmp_env1, *tmp_env2; @@ -161,10 +163,10 @@ int env_import_redund(const char *buf1, int buf1_read_fail, return -EIO; } else if (!buf1_read_fail && buf2_read_fail) { gd->env_valid = ENV_VALID; - return env_import((char *)tmp_env1, 1); + return env_import((char *)tmp_env1, 1, flags); } else if (buf1_read_fail && !buf2_read_fail) { gd->env_valid = ENV_REDUND; - return env_import((char *)tmp_env2, 1); + return env_import((char *)tmp_env2, 1, flags); } crc1_ok = crc32(0, tmp_env1->data, ENV_SIZE) == @@ -199,7 +201,7 @@ int env_import_redund(const char *buf1, int buf1_read_fail, ep = tmp_env2; env_flags = ep->flags; - return env_import((char *)ep, 0); + return env_import((char *)ep, 0, flags); } #endif /* CONFIG_SYS_REDUNDAND_ENVIRONMENT */ diff --git a/env/eeprom.c b/env/eeprom.c index e8126cfe39..e300470ad0 100644 --- a/env/eeprom.c +++ b/env/eeprom.c @@ -188,7 +188,7 @@ static int env_eeprom_load(void) eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR, off, (uchar *)buf_env, CONFIG_ENV_SIZE); - return env_import(buf_env, 1); + return env_import(buf_env, 1, H_EXTERNAL); } static int env_eeprom_save(void) @@ -131,8 +131,6 @@ __weak enum env_location env_get_location(enum env_operation op, int prio) if (prio >= ARRAY_SIZE(env_locations)) return ENVL_UNKNOWN; - gd->env_load_prio = prio; - return env_locations[prio]; } @@ -189,9 +187,6 @@ int env_load(void) for (prio = 0; (drv = env_driver_lookup(ENVOP_LOAD, prio)); prio++) { int ret; - if (!drv->load) - continue; - if (!env_has_inited(drv->location)) continue; @@ -204,7 +199,11 @@ int env_load(void) ret = drv->load(); if (!ret) { printf("OK\n"); + gd->env_load_prio = prio; + +#if !CONFIG_IS_ENABLED(ENV_APPEND) return 0; +#endif } else if (ret == -ENOMSG) { /* Handle "bad CRC" case */ if (best_prio == -1) @@ -227,7 +226,36 @@ int env_load(void) debug("Selecting environment with bad CRC\n"); else best_prio = 0; - env_get_location(ENVOP_LOAD, best_prio); + + gd->env_load_prio = best_prio; + + return -ENODEV; +} + +int env_reload(void) +{ + struct env_driver *drv; + + drv = env_driver_lookup(ENVOP_LOAD, gd->env_load_prio); + if (drv) { + int ret; + + printf("Loading Environment from %s... ", drv->name); + + if (!env_has_inited(drv->location)) { + printf("not initialized\n"); + return -ENODEV; + } + + ret = drv->load(); + if (ret) + printf("Failed (%d)\n", ret); + else + printf("OK\n"); + + if (!ret) + return 0; + } return -ENODEV; } @@ -318,3 +346,45 @@ int env_init(void) return ret; } + +int env_select(const char *name) +{ + struct env_driver *drv; + const int n_ents = ll_entry_count(struct env_driver, env_driver); + struct env_driver *entry; + int prio; + bool found = false; + + printf("Select Environment on %s: ", name); + + /* search ENV driver by name */ + drv = ll_entry_start(struct env_driver, env_driver); + for (entry = drv; entry != drv + n_ents; entry++) { + if (!strcmp(entry->name, name)) { + found = true; + break; + } + } + + if (!found) { + printf("driver not found\n"); + return -ENODEV; + } + + /* search priority by driver */ + for (prio = 0; (drv = env_driver_lookup(ENVOP_INIT, prio)); prio++) { + if (entry->location == env_get_location(ENVOP_LOAD, prio)) { + /* when priority change, reset the ENV flags */ + if (gd->env_load_prio != prio) { + gd->env_load_prio = prio; + gd->env_valid = ENV_INVALID; + gd->flags &= ~GD_FLG_ENV_DEFAULT; + } + printf("OK\n"); + return 0; + } + } + printf("priority not found\n"); + + return -ENODEV; +} diff --git a/env/ext4.c b/env/ext4.c index 8e90bb71b7..f823b69409 100644 --- a/env/ext4.c +++ b/env/ext4.c @@ -32,6 +32,8 @@ #include <ext4fs.h> #include <mmc.h> +DECLARE_GLOBAL_DATA_PTR; + __weak const char *env_ext4_get_intf(void) { return (const char *)CONFIG_ENV_EXT4_INTERFACE; @@ -42,9 +44,8 @@ __weak const char *env_ext4_get_dev_part(void) return (const char *)CONFIG_ENV_EXT4_DEVICE_AND_PART; } -static int env_ext4_save(void) +static int env_ext4_save_buffer(env_t *env_new) { - env_t env_new; struct blk_desc *dev_desc = NULL; struct disk_partition info; int dev, part; @@ -52,10 +53,6 @@ static int env_ext4_save(void) const char *ifname = env_ext4_get_intf(); const char *dev_and_part = env_ext4_get_dev_part(); - err = env_export(&env_new); - if (err) - return err; - part = blk_get_device_part_str(ifname, dev_and_part, &dev_desc, &info, 1); if (part < 0) @@ -70,7 +67,7 @@ static int env_ext4_save(void) return 1; } - err = ext4fs_write(CONFIG_ENV_EXT4_FILE, (void *)&env_new, + err = ext4fs_write(CONFIG_ENV_EXT4_FILE, (void *)env_new, sizeof(env_t), FILETYPE_REG); ext4fs_close(); @@ -80,7 +77,42 @@ static int env_ext4_save(void) return 1; } + return 0; +} + +static int env_ext4_save(void) +{ + env_t env_new; + int err; + + err = env_export(&env_new); + if (err) + return err; + + err = env_ext4_save_buffer(&env_new); + if (err) + return err; + + gd->env_valid = ENV_VALID; puts("done\n"); + + return 0; +} + +static int env_ext4_erase(void) +{ + env_t env_new; + int err; + + memset(&env_new, 0, sizeof(env_t)); + + err = env_ext4_save_buffer(&env_new); + if (err) + return err; + + gd->env_valid = ENV_INVALID; + puts("done\n"); + return 0; } @@ -124,7 +156,11 @@ static int env_ext4_load(void) goto err_env_relocate; } - return env_import(buf, 1); + err = env_import(buf, 1, H_EXTERNAL); + if (!err) + gd->env_valid = ENV_VALID; + + return err; err_env_relocate: env_set_default(NULL, 0); @@ -137,4 +173,6 @@ U_BOOT_ENV_LOCATION(ext4) = { ENV_NAME("EXT4") .load = env_ext4_load, .save = ENV_SAVE_PTR(env_ext4_save), + .erase = CONFIG_IS_ENABLED(CMD_ERASEENV) ? env_ext4_erase : + NULL, }; @@ -144,7 +144,7 @@ static int env_fat_load(void) goto err_env_relocate; } - return env_import(buf, 1); + return env_import(buf, 1, H_EXTERNAL); err_env_relocate: env_set_default(NULL, 0); diff --git a/env/flags.c b/env/flags.c index b88fe7ba9c..df4aed26b2 100644 --- a/env/flags.c +++ b/env/flags.c @@ -28,8 +28,15 @@ #define ENV_FLAGS_NET_VARTYPE_REPS "" #endif +#ifdef CONFIG_ENV_WRITEABLE_LIST +#define ENV_FLAGS_WRITEABLE_VARACCESS_REPS "w" +#else +#define ENV_FLAGS_WRITEABLE_VARACCESS_REPS "" +#endif + static const char env_flags_vartype_rep[] = "sdxb" ENV_FLAGS_NET_VARTYPE_REPS; -static const char env_flags_varaccess_rep[] = "aroc"; +static const char env_flags_varaccess_rep[] = + "aroc" ENV_FLAGS_WRITEABLE_VARACCESS_REPS; static const int env_flags_varaccess_mask[] = { 0, ENV_FLAGS_VARACCESS_PREVENT_DELETE | @@ -38,7 +45,11 @@ static const int env_flags_varaccess_mask[] = { ENV_FLAGS_VARACCESS_PREVENT_DELETE | ENV_FLAGS_VARACCESS_PREVENT_OVERWR, ENV_FLAGS_VARACCESS_PREVENT_DELETE | - ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR}; + ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR, +#ifdef CONFIG_ENV_WRITEABLE_LIST + ENV_FLAGS_VARACCESS_WRITEABLE, +#endif + }; #ifdef CONFIG_CMD_ENV_FLAGS static const char * const env_flags_vartype_names[] = { @@ -56,6 +67,9 @@ static const char * const env_flags_varaccess_names[] = { "read-only", "write-once", "change-default", +#ifdef CONFIG_ENV_WRITEABLE_LIST + "writeable", +#endif }; /* @@ -130,21 +144,25 @@ enum env_flags_vartype env_flags_parse_vartype(const char *flags) */ enum env_flags_varaccess env_flags_parse_varaccess(const char *flags) { + enum env_flags_varaccess va_default = env_flags_varaccess_any; + enum env_flags_varaccess va; char *access; if (strlen(flags) <= ENV_FLAGS_VARACCESS_LOC) - return env_flags_varaccess_any; + return va_default; access = strchr(env_flags_varaccess_rep, flags[ENV_FLAGS_VARACCESS_LOC]); - if (access != NULL) - return (enum env_flags_varaccess) + if (access != NULL) { + va = (enum env_flags_varaccess) (access - &env_flags_varaccess_rep[0]); + return va; + } printf("## Warning: Unknown environment variable access method '%c'\n", flags[ENV_FLAGS_VARACCESS_LOC]); - return env_flags_varaccess_any; + return va_default; } /* @@ -152,17 +170,21 @@ enum env_flags_varaccess env_flags_parse_varaccess(const char *flags) */ enum env_flags_varaccess env_flags_parse_varaccess_from_binflags(int binflags) { + enum env_flags_varaccess va_default = env_flags_varaccess_any; + enum env_flags_varaccess va; int i; for (i = 0; i < ARRAY_SIZE(env_flags_varaccess_mask); i++) if (env_flags_varaccess_mask[i] == - (binflags & ENV_FLAGS_VARACCESS_BIN_MASK)) - return (enum env_flags_varaccess)i; + (binflags & ENV_FLAGS_VARACCESS_BIN_MASK)) { + va = (enum env_flags_varaccess)i; + return va; + } printf("Warning: Non-standard access flags. (0x%x)\n", binflags & ENV_FLAGS_VARACCESS_BIN_MASK); - return env_flags_varaccess_any; + return va_default; } static inline int is_hex_prefix(const char *value) @@ -326,13 +348,14 @@ enum env_flags_vartype env_flags_get_type(const char *name) enum env_flags_varaccess env_flags_get_varaccess(const char *name) { const char *flags_list = env_get(ENV_FLAGS_VAR); + enum env_flags_varaccess va_default = env_flags_varaccess_any; char flags[ENV_FLAGS_ATTR_MAX_LEN + 1]; if (env_flags_lookup(flags_list, name, flags)) - return env_flags_varaccess_any; + return va_default; if (strlen(flags) <= ENV_FLAGS_VARACCESS_LOC) - return env_flags_varaccess_any; + return va_default; return env_flags_parse_varaccess(flags); } @@ -426,7 +449,11 @@ void env_flags_init(struct env_entry *var_entry) int ret = 1; if (first_call) { +#ifdef CONFIG_ENV_WRITEABLE_LIST + flags_list = ENV_FLAGS_LIST_STATIC; +#else flags_list = env_get(ENV_FLAGS_VAR); +#endif first_call = 0; } /* look in the ".flags" and static for a reference to this variable */ @@ -523,9 +550,24 @@ int env_flags_validate(const struct env_entry *item, const char *newval, } /* check for access permission */ +#ifdef CONFIG_ENV_WRITEABLE_LIST + if (flag & H_DEFAULT) + return 0; /* Default env is always OK */ + + /* + * External writeable variables can be overwritten by external env, + * anything else can not be overwritten by external env. + */ + if ((flag & H_EXTERNAL) && + !(item->flags & ENV_FLAGS_VARACCESS_WRITEABLE)) + return 1; +#endif + #ifndef CONFIG_ENV_ACCESS_IGNORE_FORCE - if (flag & H_FORCE) + if (flag & H_FORCE) { + printf("## Error: Can't force access to \"%s\"\n", name); return 0; + } #endif switch (op) { case env_op_delete: diff --git a/env/flash.c b/env/flash.c index 3198147c38..722d5adf8b 100644 --- a/env/flash.c +++ b/env/flash.c @@ -351,7 +351,7 @@ static int env_flash_load(void) "reading environment; recovered successfully\n\n"); #endif /* CONFIG_ENV_ADDR_REDUND */ - return env_import((char *)flash_addr, 1); + return env_import((char *)flash_addr, 1, H_EXTERNAL); } #endif /* LOADENV */ @@ -338,7 +338,7 @@ static int env_mmc_load(void) read2_fail = read_env(mmc, CONFIG_ENV_SIZE, offset2, tmp_env2); ret = env_import_redund((char *)tmp_env1, read1_fail, (char *)tmp_env2, - read2_fail); + read2_fail, H_EXTERNAL); fini: fini_mmc_for_env(mmc); @@ -380,7 +380,7 @@ static int env_mmc_load(void) goto fini; } - ret = env_import(buf, 1); + ret = env_import(buf, 1, H_EXTERNAL); if (!ret) { ep = (env_t *)buf; gd->env_addr = (ulong)&ep->data; diff --git a/env/nand.c b/env/nand.c index 8b0027d304..0d7ee19bc2 100644 --- a/env/nand.c +++ b/env/nand.c @@ -331,7 +331,7 @@ static int env_nand_load(void) read2_fail = readenv(CONFIG_ENV_OFFSET_REDUND, (u_char *) tmp_env2); ret = env_import_redund((char *)tmp_env1, read1_fail, (char *)tmp_env2, - read2_fail); + read2_fail, H_EXTERNAL); done: free(tmp_env1); @@ -372,7 +372,7 @@ static int env_nand_load(void) return -EIO; } - return env_import(buf, 1); + return env_import(buf, 1, H_EXTERNAL); #endif /* ! ENV_IS_EMBEDDED */ return 0; diff --git a/env/nowhere.c b/env/nowhere.c index f5b0a17652..d33fdf27d0 100644 --- a/env/nowhere.c +++ b/env/nowhere.c @@ -27,8 +27,25 @@ static int env_nowhere_init(void) return 0; } +static int env_nowhere_load(void) +{ + /* + * for SPL, set env_valid = ENV_INVALID is enougth as env_get_char() + * return the default env if env_get is used + * and SPL don't used env_import to reduce its size + * For U-Boot proper, import the default environment to allow reload. + */ + if (!IS_ENABLED(CONFIG_SPL_BUILD)) + env_set_default(NULL, 0); + + gd->env_valid = ENV_INVALID; + + return 0; +} + U_BOOT_ENV_LOCATION(nowhere) = { .location = ENVL_NOWHERE, .init = env_nowhere_init, + .load = env_nowhere_load, ENV_NAME("nowhere") }; diff --git a/env/nvram.c b/env/nvram.c index 1a9fcf1c06..7c8ea26f96 100644 --- a/env/nvram.c +++ b/env/nvram.c @@ -64,7 +64,7 @@ static int env_nvram_load(void) #else memcpy(buf, (void *)CONFIG_ENV_ADDR, CONFIG_ENV_SIZE); #endif - return env_import(buf, 1); + return env_import(buf, 1, H_EXTERNAL); } static int env_nvram_save(void) diff --git a/env/onenand.c b/env/onenand.c index dfd4e939f8..a2477cef9b 100644 --- a/env/onenand.c +++ b/env/onenand.c @@ -55,7 +55,7 @@ static int env_onenand_load(void) mtd->writesize = MAX_ONENAND_PAGESIZE; #endif /* !ENV_IS_EMBEDDED */ - rc = env_import(buf, 1); + rc = env_import(buf, 1, H_EXTERNAL); if (!rc) gd->env_valid = ENV_VALID; diff --git a/env/remote.c b/env/remote.c index e3f0608b16..d93a137376 100644 --- a/env/remote.c +++ b/env/remote.c @@ -45,7 +45,7 @@ static int env_remote_save(void) static int env_remote_load(void) { #ifndef ENV_IS_EMBEDDED - return env_import((char *)env_ptr, 1); + return env_import((char *)env_ptr, 1, H_EXTERNAL); #endif return 0; diff --git a/env/sata.c b/env/sata.c index 8bfcc94306..9442cfcaf3 100644 --- a/env/sata.c +++ b/env/sata.c @@ -111,7 +111,7 @@ static void env_sata_load(void) return -EIO; } - return env_import(buf, 1); + return env_import(buf, 1, H_EXTERNAL); } U_BOOT_ENV_LOCATION(sata) = { @@ -172,7 +172,7 @@ static int env_sf_load(void) CONFIG_ENV_SIZE, tmp_env2); ret = env_import_redund((char *)tmp_env1, read1_fail, (char *)tmp_env2, - read2_fail); + read2_fail, H_EXTERNAL); spi_flash_free(env_flash); env_flash = NULL; @@ -265,7 +265,7 @@ static int env_sf_load(void) goto err_read; } - ret = env_import(buf, 1); + ret = env_import(buf, 1, H_EXTERNAL); if (!ret) gd->env_valid = ENV_VALID; @@ -305,7 +305,7 @@ static int env_sf_init(void) U_BOOT_ENV_LOCATION(sf) = { .location = ENVL_SPI_FLASH, - ENV_NAME("SPI Flash") + ENV_NAME("SPIFlash") .load = env_sf_load, .save = CONFIG_IS_ENABLED(SAVEENV) ? ENV_SAVE_PTR(env_sf_save) : NULL, #if defined(INITENV) && (CONFIG_ENV_ADDR != 0x0) @@ -141,7 +141,7 @@ static int env_ubi_load(void) CONFIG_ENV_UBI_PART, CONFIG_ENV_UBI_VOLUME_REDUND); return env_import_redund((char *)tmp_env1, read1_fail, (char *)tmp_env2, - read2_fail); + read2_fail, H_EXTERNAL); } #else /* ! CONFIG_SYS_REDUNDAND_ENVIRONMENT */ static int env_ubi_load(void) @@ -172,7 +172,7 @@ static int env_ubi_load(void) return -EIO; } - return env_import(buf, 1); + return env_import(buf, 1, H_EXTERNAL); } #endif /* CONFIG_SYS_REDUNDAND_ENVIRONMENT */ diff --git a/include/env.h b/include/env.h index d6c2d751d6..af405955b0 100644 --- a/include/env.h +++ b/include/env.h @@ -266,6 +266,13 @@ int env_set_default_vars(int nvars, char *const vars[], int flags); int env_load(void); /** + * env_reload() - Re-Load the environment from current storage + * + * @return 0 if OK, -ve on error + */ +int env_reload(void); + +/** * env_save() - Save the environment to storage * * @return 0 if OK, -ve on error @@ -280,6 +287,13 @@ int env_save(void); int env_erase(void); /** + * env_select() - Select the environment storage + * + * @return 0 if OK, -ve on error + */ +int env_select(const char *name); + +/** * env_import() - Import from a binary representation into hash table * * This imports the environment from a buffer. The format for each variable is @@ -288,10 +302,11 @@ int env_erase(void); * @buf: Buffer containing the environment (struct environemnt_s *) * @check: non-zero to check the CRC at the start of the environment, 0 to * ignore it + * @flags: Flags controlling matching (H_... - see search.h) * @return 0 if imported successfully, -ENOMSG if the CRC was bad, -EIO if * something else went wrong */ -int env_import(const char *buf, int check); +int env_import(const char *buf, int check, int flags); /** * env_export() - Export the environment to a buffer @@ -310,10 +325,12 @@ int env_export(struct environment_s *env_out); * @buf1_read_fail: 0 if buf1 is valid, non-zero if invalid * @buf2: Second environment (struct environemnt_s *) * @buf2_read_fail: 0 if buf2 is valid, non-zero if invalid + * @flags: Flags controlling matching (H_... - see search.h) * @return 0 if OK, -EIO if no environment is valid, -ENOMSG if the CRC was bad */ int env_import_redund(const char *buf1, int buf1_read_fail, - const char *buf2, int buf2_read_fail); + const char *buf2, int buf2_read_fail, + int flags); /** * env_get_default() - Look up a variable from the default environment @@ -342,5 +359,4 @@ int env_get_char(int index); * This is used for those unfortunate archs with crappy toolchains */ void env_reloc(void); - #endif diff --git a/include/env_flags.h b/include/env_flags.h index 725841a891..313cb8c49a 100644 --- a/include/env_flags.h +++ b/include/env_flags.h @@ -24,6 +24,9 @@ enum env_flags_varaccess { env_flags_varaccess_readonly, env_flags_varaccess_writeonce, env_flags_varaccess_changedefault, +#ifdef CONFIG_ENV_WRITEABLE_LIST + env_flags_varaccess_writeable, +#endif env_flags_varaccess_end }; @@ -173,6 +176,7 @@ int env_flags_validate(const struct env_entry *item, const char *newval, #define ENV_FLAGS_VARACCESS_PREVENT_CREATE 0x00000010 #define ENV_FLAGS_VARACCESS_PREVENT_OVERWR 0x00000020 #define ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR 0x00000040 -#define ENV_FLAGS_VARACCESS_BIN_MASK 0x00000078 +#define ENV_FLAGS_VARACCESS_WRITEABLE 0x00000080 +#define ENV_FLAGS_VARACCESS_BIN_MASK 0x000000f8 #endif /* __ENV_FLAGS_H__ */ diff --git a/include/env_internal.h b/include/env_internal.h index 66550434c3..b26dc6239c 100644 --- a/include/env_internal.h +++ b/include/env_internal.h @@ -154,8 +154,7 @@ struct env_driver { /** * load() - Load the environment from storage * - * This method is optional. If not provided, no environment will be - * loaded. + * This method is required for loading environment * * @return 0 if OK, -ve on error */ @@ -212,6 +211,26 @@ struct env_driver { extern struct hsearch_data env_htab; /** + * env_ext4_get_intf() - Provide the interface for env in EXT4 + * + * It is a weak function allowing board to overidde the default interface for + * U-Boot env in EXT4: CONFIG_ENV_EXT4_INTERFACE + * + * @return string of interface, empty if not supported + */ +const char *env_ext4_get_intf(void); + +/** + * env_ext4_get_dev_part() - Provide the device and partition for env in EXT4 + * + * It is a weak function allowing board to overidde the default device and + * partition used for U-Boot env in EXT4: CONFIG_ENV_EXT4_DEVICE_AND_PART + * + * @return string of device and partition + */ +const char *env_ext4_get_dev_part(void); + +/** * env_get_location()- Provide the best location for the U-Boot environment * * It is a weak function allowing board to overidde the environment location diff --git a/include/search.h b/include/search.h index bca36d3abc..e56843c26f 100644 --- a/include/search.h +++ b/include/search.h @@ -112,5 +112,7 @@ int hwalk_r(struct hsearch_data *htab, #define H_MATCH_METHOD (H_MATCH_IDENT | H_MATCH_SUBSTR | H_MATCH_REGEX) #define H_PROGRAMMATIC (1 << 9) /* indicate that an import is from env_set() */ #define H_ORIGIN_FLAGS (H_INTERACTIVE | H_PROGRAMMATIC) +#define H_DEFAULT (1 << 10) /* indicate that an import is default env */ +#define H_EXTERNAL (1 << 11) /* indicate that an import is external env */ #endif /* _SEARCH_H_ */ diff --git a/lib/hashtable.c b/lib/hashtable.c index 7b6781bc35..4a8c50b4b8 100644 --- a/lib/hashtable.c +++ b/lib/hashtable.c @@ -826,6 +826,10 @@ int himport_r(struct hsearch_data *htab, if (nvars) memcpy(localvars, vars, sizeof(vars[0]) * nvars); +#if CONFIG_IS_ENABLED(ENV_APPEND) + flag |= H_NOCLEAR; +#endif + if ((flag & H_NOCLEAR) == 0 && !nvars) { /* Destroy old hash table if one exists */ debug("Destroy Hash Table: %p table = %p\n", htab, @@ -946,9 +950,12 @@ int himport_r(struct hsearch_data *htab, e.data = value; hsearch_r(e, ENV_ENTER, &rv, htab, flag); - if (rv == NULL) +#if !CONFIG_IS_ENABLED(ENV_WRITEABLE_LIST) + if (rv == NULL) { printf("himport_r: can't insert \"%s=%s\" into hash table\n", name, value); + } +#endif debug("INSERT: table %p, filled %d/%d rv %p ==> name=\"%s\" value=\"%s\"\n", htab, htab->filled, htab->size, diff --git a/test/py/tests/test_efi_loader.py b/test/py/tests/test_efi_loader.py index ca68626cec..fc8d6b8655 100644 --- a/test/py/tests/test_efi_loader.py +++ b/test/py/tests/test_efi_loader.py @@ -199,6 +199,6 @@ def test_efi_grub_net(u_boot_console): # Then exit cleanly u_boot_console.wait_for('grub>') u_boot_console.run_command('exit', wait_for_prompt=False, wait_for_echo=False) - u_boot_console.wait_for('=>') + u_boot_console.wait_for(u_boot_console.prompt) # And give us our U-Boot prompt back u_boot_console.run_command('') diff --git a/test/py/tests/test_efi_selftest.py b/test/py/tests/test_efi_selftest.py index 971c9f6053..9b520c2070 100644 --- a/test/py/tests/test_efi_selftest.py +++ b/test/py/tests/test_efi_selftest.py @@ -36,7 +36,7 @@ def test_efi_selftest_device_tree(u_boot_console): output = u_boot_console.run_command('bootefi selftest') assert '\'device tree\'' in output u_boot_console.run_command(cmd='setenv efi_selftest device tree') - u_boot_console.run_command(cmd='setenv -f serial# Testing DT') + u_boot_console.run_command(cmd='setenv serial# Testing DT') u_boot_console.run_command(cmd='bootefi selftest ${fdtcontroladdr}', wait_for_prompt=False) m = u_boot_console.p.expect(['serial-number: Testing DT', 'U-Boot']) if m != 0: diff --git a/test/py/tests/test_env.py b/test/py/tests/test_env.py index a64aaa9bc5..86ec1b36d3 100644 --- a/test/py/tests/test_env.py +++ b/test/py/tests/test_env.py @@ -4,6 +4,10 @@ # Test operation of shell commands relating to environment variables. +import os +import os.path +from subprocess import call, check_call, CalledProcessError + import pytest import u_boot_utils @@ -374,7 +378,6 @@ def test_env_info(state_test_env): @pytest.mark.buildconfigspec('cmd_nvedit_info') @pytest.mark.buildconfigspec('cmd_echo') def test_env_info_sandbox(state_test_env): - """Test 'env info' command result with several options on sandbox with a known ENV configuration: ready & default & persistent """ @@ -399,3 +402,111 @@ def test_env_info_sandbox(state_test_env): response = c.run_command('env info -d -p -q') response = c.run_command('echo $?') assert response == "1" + +def mk_env_ext4(state_test_env): + + """Create a empty ext4 file system volume.""" + c = state_test_env.u_boot_console + filename = 'env.ext4.img' + persistent = c.config.persistent_data_dir + '/' + filename + fs_img = c.config.result_dir + '/' + filename + + if os.path.exists(persistent): + c.log.action('Disk image file ' + persistent + ' already exists') + else: + try: + u_boot_utils.run_and_log(c, 'dd if=/dev/zero of=%s bs=1M count=16' % persistent) + u_boot_utils.run_and_log(c, 'mkfs.ext4 -O ^metadata_csum %s' % persistent) + except CalledProcessError: + call('rm -f %s' % persistent, shell=True) + raise + + u_boot_utils.run_and_log(c, ['cp', '-f', persistent, fs_img]) + return fs_img + +@pytest.mark.boardspec('sandbox') +@pytest.mark.buildconfigspec('cmd_echo') +@pytest.mark.buildconfigspec('cmd_nvedit_info') +@pytest.mark.buildconfigspec('cmd_nvedit_load') +@pytest.mark.buildconfigspec('cmd_nvedit_select') +@pytest.mark.buildconfigspec('env_is_in_ext4') +def test_env_ext4(state_test_env): + + """Test ENV in EXT4 on sandbox.""" + c = state_test_env.u_boot_console + fs_img = '' + try: + fs_img = mk_env_ext4(state_test_env) + + c.run_command('host bind 0 %s' % fs_img) + + response = c.run_command('ext4ls host 0:0') + assert 'uboot.env' not in response + + # force env location: EXT4 (prio 1 in sandbox) + response = c.run_command('env select EXT4') + assert 'Select Environment on EXT4: OK' in response + + response = c.run_command('env save') + assert 'Saving Environment to EXT4' in response + + response = c.run_command('env load') + assert 'Loading Environment from EXT4... OK' in response + + response = c.run_command('ext4ls host 0:0') + assert '8192 uboot.env' in response + + response = c.run_command('env info') + assert 'env_valid = valid' in response + assert 'env_ready = true' in response + assert 'env_use_default = false' in response + + response = c.run_command('env info -p -d') + assert 'Environment was loaded from persistent storage' in response + assert 'Environment can be persisted' in response + + response = c.run_command('env info -d -q') + assert response == "" + response = c.run_command('echo $?') + assert response == "1" + + response = c.run_command('env info -p -q') + assert response == "" + response = c.run_command('echo $?') + assert response == "0" + + response = c.run_command('env erase') + assert 'OK' in response + + response = c.run_command('env load') + assert 'Loading Environment from EXT4... ' in response + assert 'bad CRC, using default environment' in response + + response = c.run_command('env info') + assert 'env_valid = invalid' in response + assert 'env_ready = true' in response + assert 'env_use_default = true' in response + + response = c.run_command('env info -p -d') + assert 'Default environment is used' in response + assert 'Environment can be persisted' in response + + # restore env location: NOWHERE (prio 0 in sandbox) + response = c.run_command('env select nowhere') + assert 'Select Environment on nowhere: OK' in response + + response = c.run_command('env load') + assert 'Loading Environment from nowhere... OK' in response + + response = c.run_command('env info') + assert 'env_valid = invalid' in response + assert 'env_ready = true' in response + assert 'env_use_default = true' in response + + response = c.run_command('env info -p -d') + assert 'Default environment is used' in response + assert 'Environment cannot be persisted' in response + + finally: + if fs_img: + call('rm -f %s' % fs_img, shell=True) diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c index c6378ecf34..3ab1ae69c7 100644 --- a/tools/env/fw_env.c +++ b/tools/env/fw_env.c @@ -995,6 +995,7 @@ static int flash_write_buf(int dev, int fd, void *buf, size_t count) of the data */ loff_t blockstart; /* running start of the current block - MEMGETBADBLOCK needs 64 bits */ + int was_locked; /* flash lock flag */ int rc; /* @@ -1080,6 +1081,12 @@ static int flash_write_buf(int dev, int fd, void *buf, size_t count) } erase.length = erasesize; + if (DEVTYPE(dev) != MTD_ABSENT) { + was_locked = ioctl(fd, MEMISLOCKED, &erase); + /* treat any errors as unlocked flash */ + if (was_locked < 0) + was_locked = 0; + } /* This only runs once on NOR flash and SPI-dataflash */ while (processed < write_total) { @@ -1099,7 +1106,8 @@ static int flash_write_buf(int dev, int fd, void *buf, size_t count) if (DEVTYPE(dev) != MTD_ABSENT) { erase.start = blockstart; - ioctl(fd, MEMUNLOCK, &erase); + if (was_locked) + ioctl(fd, MEMUNLOCK, &erase); /* These do not need an explicit erase cycle */ if (DEVTYPE(dev) != MTD_DATAFLASH) if (ioctl(fd, MEMERASE, &erase) != 0) { @@ -1127,8 +1135,10 @@ static int flash_write_buf(int dev, int fd, void *buf, size_t count) return -1; } - if (DEVTYPE(dev) != MTD_ABSENT) - ioctl(fd, MEMLOCK, &erase); + if (DEVTYPE(dev) != MTD_ABSENT) { + if (was_locked) + ioctl(fd, MEMLOCK, &erase); + } processed += erasesize; block_seek = 0; @@ -1149,7 +1159,9 @@ static int flash_flag_obsolete(int dev, int fd, off_t offset) int rc; struct erase_info_user erase; char tmp = ENV_REDUND_OBSOLETE; + int was_locked; /* flash lock flag */ + was_locked = ioctl(fd, MEMISLOCKED, &erase); erase.start = DEVOFFSET(dev); erase.length = DEVESIZE(dev); /* This relies on the fact, that ENV_REDUND_OBSOLETE == 0 */ @@ -1159,9 +1171,11 @@ static int flash_flag_obsolete(int dev, int fd, off_t offset) DEVNAME(dev)); return rc; } - ioctl(fd, MEMUNLOCK, &erase); + if (was_locked) + ioctl(fd, MEMUNLOCK, &erase); rc = write(fd, &tmp, sizeof(tmp)); - ioctl(fd, MEMLOCK, &erase); + if (was_locked) + ioctl(fd, MEMLOCK, &erase); if (rc < 0) perror("Could not set obsolete flag"); |