GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)

This commit is contained in:
lai
2026-09-06 03:52:57 +08:00
commit b1928b41c0
21813 changed files with 4413081 additions and 0 deletions
+699
View File
@@ -0,0 +1,699 @@
menu "Environment"
config ENV_IS_NOWHERE
bool "Environment is not stored"
default y if !ENV_IS_IN_EEPROM && !ENV_IS_IN_EXT4 && \
!ENV_IS_IN_FAT && !ENV_IS_IN_FLASH && \
!ENV_IS_IN_MMC && !ENV_IS_IN_NAND && \
!ENV_IS_IN_NVRAM && !ENV_IS_IN_ONENAND && \
!ENV_IS_IN_REMOTE && !ENV_IS_IN_SPI_FLASH && \
!ENV_IS_IN_UBI
help
Define this if you don't want to or can't have an environment stored
on a storage medium. In this case the environment will still exist
while U-Boot is running, but once U-Boot exits it will not be
stored. U-Boot will therefore always start up with a default
environment.
config ENV_IS_IN_EEPROM
bool "Environment in EEPROM"
depends on !CHAIN_OF_TRUST
help
Use this if you have an EEPROM or similar serial access
device and a driver for it.
- CONFIG_ENV_OFFSET:
- CONFIG_ENV_SIZE:
These two #defines specify the offset and size of the
environment area within the total memory of your EEPROM.
Note that we consider the length of the address field to
still be one byte because the extra address bits are hidden
in the chip address.
- CONFIG_ENV_EEPROM_IS_ON_I2C
define this, if you have I2C and SPI activated, and your
EEPROM, which holds the environment, is on the I2C bus.
- CONFIG_I2C_ENV_EEPROM_BUS
if you have an Environment on an EEPROM reached over
I2C muxes, you can define here, how to reach this
EEPROM. For example:
#define CONFIG_I2C_ENV_EEPROM_BUS 1
EEPROM which holds the environment, is reached over
a pca9547 i2c mux with address 0x70, channel 3.
config ENV_IS_IN_FAT
bool "Environment is in a FAT filesystem"
depends on !CHAIN_OF_TRUST
default y if ARCH_BCM283X
default y if ARCH_SUNXI && MMC
default y if MMC_OMAP_HS && TI_COMMON_CMD_OPTIONS
select FS_FAT
select FAT_WRITE
help
Define this if you want to use the FAT file system for the environment.
config ENV_IS_IN_EXT4
bool "Environment is in a EXT4 filesystem"
depends on !CHAIN_OF_TRUST
select EXT4_WRITE
help
Define this if you want to use the EXT4 file system for the environment.
config ENV_IS_IN_FLASH
bool "Environment in flash memory"
depends on !CHAIN_OF_TRUST
default y if ARCH_CINTEGRATOR
default y if ARCH_INTEGRATOR_CP
default y if M548x || M547x || M5282 || MCF547x_8x
default y if MCF532x || MCF52x2
default y if MPC86xx || MPC83xx
default y if ARCH_MPC8572 || ARCH_MPC8548 || ARCH_MPC8641
default y if SH && !CPU_SH4
help
Define this if you have a flash device which you want to use for the
environment.
a) The environment occupies one whole flash sector, which is
"embedded" in the text segment with the U-Boot code. This
happens usually with "bottom boot sector" or "top boot
sector" type flash chips, which have several smaller
sectors at the start or the end. For instance, such a
layout can have sector sizes of 8, 2x4, 16, Nx32 kB. In
such a case you would place the environment in one of the
4 kB sectors - with U-Boot code before and after it. With
"top boot sector" type flash chips, you would put the
environment in one of the last sectors, leaving a gap
between U-Boot and the environment.
CONFIG_ENV_OFFSET:
Offset of environment data (variable area) to the
beginning of flash memory; for instance, with bottom boot
type flash chips the second sector can be used: the offset
for this sector is given here.
CONFIG_ENV_OFFSET is used relative to CONFIG_SYS_FLASH_BASE.
CONFIG_ENV_ADDR:
This is just another way to specify the start address of
the flash sector containing the environment (instead of
CONFIG_ENV_OFFSET).
CONFIG_ENV_SECT_SIZE:
Size of the sector containing the environment.
b) Sometimes flash chips have few, equal sized, BIG sectors.
In such a case you don't want to spend a whole sector for
the environment.
CONFIG_ENV_SIZE:
If you use this in combination with CONFIG_ENV_IS_IN_FLASH
and CONFIG_ENV_SECT_SIZE, you can specify to use only a part
of this flash sector for the environment. This saves
memory for the RAM copy of the environment.
It may also save flash memory if you decide to use this
when your environment is "embedded" within U-Boot code,
since then the remainder of the flash sector could be used
for U-Boot code. It should be pointed out that this is
STRONGLY DISCOURAGED from a robustness point of view:
updating the environment in flash makes it always
necessary to erase the WHOLE sector. If something goes
wrong before the contents has been restored from a copy in
RAM, your target system will be dead.
CONFIG_ENV_ADDR_REDUND
These settings describe a second storage area used to hold
a redundant copy of the environment data, so that there is
a valid backup copy in case there is a power failure during
a "saveenv" operation.
BE CAREFUL! Any changes to the flash layout, and some changes to the
source code will make it necessary to adapt <board>/u-boot.lds*
accordingly!
config ENV_IS_IN_MMC
bool "Environment in an MMC device"
depends on !CHAIN_OF_TRUST
depends on MMC
default y if ARCH_EXYNOS4
default y if MX6SX || MX7D
default y if TEGRA30 || TEGRA124
default y if TEGRA_ARMV8_COMMON
help
Define this if you have an MMC device which you want to use for the
environment.
CONFIG_SYS_MMC_ENV_DEV:
Specifies which MMC device the environment is stored in.
CONFIG_SYS_MMC_ENV_PART (optional):
Specifies which MMC partition the environment is stored in. If not
set, defaults to partition 0, the user area. Common values might be
1 (first MMC boot partition), 2 (second MMC boot partition).
CONFIG_ENV_OFFSET:
CONFIG_ENV_SIZE:
These two #defines specify the offset and size of the environment
area within the specified MMC device.
If offset is positive (the usual case), it is treated as relative to
the start of the MMC partition. If offset is negative, it is treated
as relative to the end of the MMC partition. This can be useful if
your board may be fitted with different MMC devices, which have
different sizes for the MMC partitions, and you always want the
environment placed at the very end of the partition, to leave the
maximum possible space before it, to store other data.
These two values are in units of bytes, but must be aligned to an
MMC sector boundary.
CONFIG_ENV_OFFSET_REDUND (optional):
Specifies a second storage area, of CONFIG_ENV_SIZE size, used to
hold a redundant copy of the environment data. This provides a
valid backup copy in case the other copy is corrupted, e.g. due
to a power failure during a "saveenv" operation.
This value may also be positive or negative; this is handled in the
same way as CONFIG_ENV_OFFSET.
This value is also in units of bytes, but must also be aligned to
an MMC sector boundary.
config ENV_IS_IN_NAND
bool "Environment in a NAND device"
depends on !CHAIN_OF_TRUST
help
Define this if you have a NAND device which you want to use for the
environment.
- CONFIG_ENV_OFFSET:
- CONFIG_ENV_SIZE:
These two #defines specify the offset and size of the environment
area within the first NAND device. CONFIG_ENV_OFFSET must be
aligned to an erase block boundary.
- CONFIG_ENV_OFFSET_REDUND (optional):
This setting describes a second storage area of CONFIG_ENV_SIZE
size used to hold a redundant copy of the environment data, so
that there is a valid backup copy in case there is a power failure
during a "saveenv" operation. CONFIG_ENV_OFFSET_REDUND must be
aligned to an erase block boundary.
- CONFIG_ENV_RANGE (optional):
Specifies the length of the region in which the environment
can be written. This should be a multiple of the NAND device's
block size. Specifying a range with more erase blocks than
are needed to hold CONFIG_ENV_SIZE allows bad blocks within
the range to be avoided.
- CONFIG_ENV_OFFSET_OOB (optional):
Enables support for dynamically retrieving the offset of the
environment from block zero's out-of-band data. The
"nand env.oob" command can be used to record this offset.
Currently, CONFIG_ENV_OFFSET_REDUND is not supported when
using CONFIG_ENV_OFFSET_OOB.
config ENV_IS_IN_NVRAM
bool "Environment in a non-volatile RAM"
depends on !CHAIN_OF_TRUST
help
Define this if you have some non-volatile memory device
(NVRAM, battery buffered SRAM) which you want to use for the
environment.
- CONFIG_ENV_ADDR:
- CONFIG_ENV_SIZE:
These two #defines are used to determine the memory area you
want to use for environment. It is assumed that this memory
can just be read and written to, without any special
provision.
config ENV_IS_IN_ONENAND
bool "Environment is in OneNAND"
depends on !CHAIN_OF_TRUST
help
Define this if you want to put your local device's environment in
OneNAND.
- CONFIG_ENV_ADDR:
- CONFIG_ENV_SIZE:
These two #defines are used to determine the device range you
want to use for environment. It is assumed that this memory
can just be read and written to, without any special
provision.
config ENV_IS_IN_REMOTE
bool "Environment is in remote memory space"
depends on !CHAIN_OF_TRUST
help
Define this if you have a remote memory space which you
want to use for the local device's environment.
- CONFIG_ENV_ADDR:
- CONFIG_ENV_SIZE:
These two #defines specify the address and size of the
environment area within the remote memory space. The
local device can get the environment from remote memory
space by SRIO or PCIE links.
config ENV_IS_IN_SPI_FLASH
bool "Environment is in SPI flash"
depends on !CHAIN_OF_TRUST && SPI || FMC
default y if ARMADA_XP
default y if INTEL_BAYTRAIL
default y if INTEL_BRASWELL
default y if INTEL_BROADWELL
default y if NORTHBRIDGE_INTEL_IVYBRIDGE
default y if INTEL_QUARK
default y if INTEL_QUEENSBAY
help
Define this if you have a SPI Flash memory device which you
want to use for the environment.
- CONFIG_ENV_OFFSET:
- CONFIG_ENV_SIZE:
These two #defines specify the offset and size of the
environment area within the SPI Flash. CONFIG_ENV_OFFSET must be
aligned to an erase sector boundary.
- CONFIG_ENV_SECT_SIZE:
Define the SPI flash's sector size.
- CONFIG_ENV_OFFSET_REDUND (optional):
This setting describes a second storage area of CONFIG_ENV_SIZE
size used to hold a redundant copy of the environment data, so
that there is a valid backup copy in case there is a power failure
during a "saveenv" operation. CONFIG_ENV_OFFSET_REDUND must be
aligned to an erase sector boundary.
config USE_ENV_SPI_BUS
bool "SPI flash bus for environment"
depends on ENV_IS_IN_SPI_FLASH
help
Force the SPI bus for environment.
If not defined, use CONFIG_SF_DEFAULT_BUS.
config ENV_SPI_BUS
int "Value of SPI flash bus for environment"
depends on USE_ENV_SPI_BUS
help
Value the SPI bus and chip select for environment.
config USE_ENV_SPI_CS
bool "SPI flash chip select for environment"
depends on ENV_IS_IN_SPI_FLASH
help
Force the SPI chip select for environment.
If not defined, use CONFIG_SF_DEFAULT_CS.
config ENV_SPI_CS
int "Value of SPI flash chip select for environment"
depends on USE_ENV_SPI_CS
help
Value of the SPI chip select for environment.
config USE_ENV_SPI_MAX_HZ
bool "SPI flash max frequency for environment"
depends on ENV_IS_IN_SPI_FLASH
help
Force the SPI max work clock for environment.
If not defined, use CONFIG_SF_DEFAULT_SPEED.
config ENV_SPI_MAX_HZ
int "Value of SPI flash max frequency for environment"
depends on USE_ENV_SPI_MAX_HZ
help
Value of the SPI max work clock for environment.
config USE_ENV_SPI_MODE
bool "SPI flash mode for environment"
depends on ENV_IS_IN_SPI_FLASH
help
Force the SPI work mode for environment.
config ENV_SPI_MODE
hex "Value of SPI flash work mode for environment"
depends on USE_ENV_SPI_MODE
help
Value of the SPI work mode for environment.
See include/spi.h for value.
config ENV_IS_IN_UBI
bool "Environment in a UBI volume"
depends on !CHAIN_OF_TRUST
depends on MTD_UBI
depends on CMD_UBI
help
Define this if you have an UBI volume that you want to use for the
environment. This has the benefit of wear-leveling the environment
accesses, which is important on NAND.
- CONFIG_ENV_UBI_PART:
Define this to a string that is the mtd partition containing the UBI.
- CONFIG_ENV_UBI_VOLUME:
Define this to the name of the volume that you want to store the
environment in.
- CONFIG_ENV_UBI_VOLUME_REDUND:
Define this to the name of another volume to store a second copy of
the environment in. This will enable redundant environments in UBI.
It is assumed that both volumes are in the same MTD partition.
config SYS_REDUNDAND_ENVIRONMENT
bool "Enable redundant environment support"
depends on ENV_IS_IN_EEPROM || ENV_IS_IN_FLASH || ENV_IS_IN_MMC || \
ENV_IS_IN_NAND || ENV_IS_IN_SPI_FLASH || ENV_IS_IN_UBI
help
Normally, the environemt is stored in a single location. By
selecting this option, you can then define where to hold a redundant
copy of the environment data, so that there is a valid backup copy in
case there is a power failure during a "saveenv" operation.
config ENV_FAT_INTERFACE
string "Name of the block device for the environment"
depends on ENV_IS_IN_FAT
default "mmc" if ARCH_SUNXI
default "mmc" if TI_COMMON_CMD_OPTIONS || ARCH_ZYNQMP || ARCH_AT91
help
Define this to a string that is the name of the block device.
config ENV_FAT_DEVICE_AND_PART
string "Device and partition for where to store the environemt in FAT"
depends on ENV_IS_IN_FAT
default "0:1" if TI_COMMON_CMD_OPTIONS
default "0:auto" if ARCH_ZYNQMP
default "0:auto" if ARCH_SUNXI && MMC_SUNXI_SLOT_EXTRA = -1
default "1:auto" if ARCH_SUNXI && MMC_SUNXI_SLOT_EXTRA != -1
default "0" if ARCH_AT91
help
Define this to a string to specify the partition of the device. It can
be as following:
"D:P", "D:0", "D", "D:" or "D:auto" (D, P are integers. And P >= 1)
- "D:P": device D partition P. Error occurs if device D has no
partition table.
- "D:0": device D.
- "D" or "D:": device D partition 1 if device D has partition
table, or the whole device D if has no partition
table.
- "D:auto": first partition in device D with bootable flag set.
If none, first valid partition in device D. If no
partition table then means device D.
config ENV_FAT_FILE
string "Name of the FAT file to use for the environment"
depends on ENV_IS_IN_FAT
default "uboot.env"
help
It's a string of the FAT file name. This file use to store the
environment.
config ENV_EXT4_INTERFACE
string "Name of the block device for the environment"
depends on ENV_IS_IN_EXT4
help
Define this to a string that is the name of the block device.
config ENV_EXT4_DEVICE_AND_PART
string "Device and partition for where to store the environemt in EXT4"
depends on ENV_IS_IN_EXT4
help
Define this to a string to specify the partition of the device. It can
be as following:
"D:P", "D:0", "D", "D:" or "D:auto" (D, P are integers. And P >= 1)
- "D:P": device D partition P. Error occurs if device D has no
partition table.
- "D:0": device D.
- "D" or "D:": device D partition 1 if device D has partition
table, or the whole device D if has no partition
table.
- "D:auto": first partition in device D with bootable flag set.
If none, first valid partition in device D. If no
partition table then means device D.
config ENV_EXT4_FILE
string "Name of the EXT4 file to use for the environment"
depends on ENV_IS_IN_EXT4
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)
config ENV_ADDR
hex "Environment address"
depends on ENV_IS_IN_FLASH || ENV_IS_IN_NVRAM || ENV_IS_IN_ONENAND || \
ENV_IS_IN_REMOTE || ENV_IS_IN_SPI_FLASH
default 0x0 if ENV_IS_IN_SPI_FLASH
help
Offset from the start of the device (or partition)
config ENV_ADDR_REDUND
hex "Redundant environment address"
depends on ENV_IS_IN_FLASH && SYS_REDUNDAND_ENVIRONMENT
help
Offset from the start of the device (or partition) of the redundant
environment location.
config ENV_OFFSET
hex "Environment offset"
depends on ENV_IS_IN_EEPROM || ENV_IS_IN_MMC || ENV_IS_IN_NAND || \
ENV_IS_IN_SPI_FLASH
default 0x3f8000 if ARCH_ROCKCHIP
default 0x88000 if ARCH_SUNXI
default 0xE0000 if ARCH_ZYNQ
default 0x1E00000 if ARCH_ZYNQMP
default 0x7F40000 if ARCH_VERSAL
default 0 if ARC
default 0x140000 if ARCH_AT91
default 0x260000 if ARCH_OMAP2PLUS
help
Offset from the start of the device (or partition)
config ENV_OFFSET_REDUND
hex "Redundant environment offset"
depends on (ENV_IS_IN_EEPROM || ENV_IS_IN_MMC || ENV_IS_IN_NAND || \
ENV_IS_IN_SPI_FLASH) && SYS_REDUNDAND_ENVIRONMENT
help
Offset from the start of the device (or partition) of the redundant
environment location.
config ENV_SIZE
hex "Environment Size"
default 0x40000 if ENV_IS_IN_SPI_FLASH && ARCH_ZYNQMP
default 0x20000 if ARCH_SUNXI || ARCH_ZYNQ || ARCH_OMAP2PLUS || ARCH_AT91
default 0x8000 if ARCH_ROCKCHIP || ARCH_ZYNQMP || ARCH_VERSAL
default 0x4000 if ARC
default 0x1f000
help
Size of the environment storage area
config ENV_SECT_SIZE
hex "Environment Sector-Size"
depends on ENV_IS_IN_FLASH || ENV_IS_IN_SPI_FLASH
default 0x40000 if ARCH_ZYNQMP || ARCH_VERSAL
default 0x20000 if ARCH_ZYNQ || ARCH_OMAP2PLUS || ARCH_AT91
help
Size of the sector containing the environment.
config ENV_UBI_PART
string "UBI partition name"
depends on ENV_IS_IN_UBI
help
MTD partition containing the UBI device
config ENV_UBI_VOLUME
string "UBI volume name"
depends on ENV_IS_IN_UBI
help
Name of the volume that you want to store the environment in.
config ENV_UBI_VOLUME_REDUND
string "UBI redundant volume name"
depends on ENV_IS_IN_UBI && SYS_REDUNDAND_ENVIRONMENT
help
Name of the redundant volume that you want to store the environment in.
config ENV_UBI_VID_OFFSET
int "ubi environment VID offset"
depends on ENV_IS_IN_UBI
default 0
help
UBI VID offset for environment. If 0, no custom VID offset is used.
config SYS_RELOC_GD_ENV_ADDR
bool "Relocate gd->en_addr"
help
Relocate the early env_addr pointer so we know it is not inside
the binary. Some systems need this and for the rest, it doesn't hurt.
config USE_DEFAULT_ENV_FILE
bool "Create default environment from file"
help
Normally, the default environment is automatically generated
based on the settings of various CONFIG_* options, as well
as the CONFIG_EXTRA_ENV_SETTINGS. By selecting this option,
you can instead define the entire default environment in an
external file.
config DEFAULT_ENV_FILE
string "Path to default environment file"
depends on USE_DEFAULT_ENV_FILE
help
The path containing the default environment. The format is
the same as accepted by the mkenvimage tool: lines
containing key=value pairs, blank lines and lines beginning
with # are ignored.
config ENV_VARS_UBOOT_RUNTIME_CONFIG
bool "Add run-time information to the environment"
help
Enable this in order to add variables describing certain
run-time determined information about the hardware to the
environment. These will be named board_name, board_rev.
if SPL_ENV_SUPPORT
config SPL_ENV_IS_NOWHERE
bool "SPL Environment is not stored"
default y if ENV_IS_NOWHERE
help
Similar to ENV_IS_NOWHERE, used for SPL environment.
config SPL_ENV_IS_IN_MMC
bool "SPL Environment in an MMC device"
depends on !SPL_ENV_IS_NOWHERE
depends on ENV_IS_IN_MMC
default y
help
Similar to ENV_IS_IN_MMC, used for SPL environment.
config SPL_ENV_IS_IN_FAT
bool "SPL Environment is in a FAT filesystem"
depends on !SPL_ENV_IS_NOWHERE
depends on ENV_IS_IN_FAT
default y
help
Similar to ENV_IS_IN_FAT, used for SPL environment.
config SPL_ENV_IS_IN_EXT4
bool "SPL Environment is in a EXT4 filesystem"
depends on !SPL_ENV_IS_NOWHERE
depends on ENV_IS_IN_EXT4
default y
help
Similar to ENV_IS_IN_EXT4, used for SPL environment.
config SPL_ENV_IS_IN_NAND
bool "SPL Environment in a NAND device"
depends on !SPL_ENV_IS_NOWHERE
depends on ENV_IS_IN_NAND
default y
help
Similar to ENV_IS_IN_NAND, used for SPL environment.
config SPL_ENV_IS_IN_SPI_FLASH
bool "SPL Environment is in SPI flash"
depends on !SPL_ENV_IS_NOWHERE
depends on ENV_IS_IN_SPI_FLASH
default y
help
Similar to ENV_IS_IN_SPI_FLASH, used for SPL environment.
config SPL_ENV_IS_IN_FLASH
bool "SPL Environment in flash memory"
depends on !SPL_ENV_IS_NOWHERE
depends on ENV_IS_IN_FLASH
default y
help
Similar to ENV_IS_IN_FLASH, used for SPL environment.
endif
if TPL_ENV_SUPPORT
config TPL_ENV_IS_NOWHERE
bool "TPL Environment is not stored"
default y if ENV_IS_NOWHERE
help
Similar to ENV_IS_NOWHERE, used for TPL environment.
config TPL_ENV_IS_IN_MMC
bool "TPL Environment in an MMC device"
depends on !TPL_ENV_IS_NOWHERE
depends on ENV_IS_IN_MMC
default y
help
Similar to ENV_IS_IN_MMC, used for TPL environment.
config TPL_ENV_IS_IN_FAT
bool "TPL Environment is in a FAT filesystem"
depends on !TPL_ENV_IS_NOWHERE
depends on ENV_IS_IN_FAT
default y
help
Similar to ENV_IS_IN_FAT, used for TPL environment.
config TPL_ENV_IS_IN_EXT4
bool "TPL Environment is in a EXT4 filesystem"
depends on !TPL_ENV_IS_NOWHERE
depends on ENV_IS_IN_EXT4
default y
help
Similar to ENV_IS_IN_EXT4, used for TPL environment.
config TPL_ENV_IS_IN_NAND
bool "TPL Environment in a NAND device"
depends on !TPL_ENV_IS_NOWHERE
depends on ENV_IS_IN_NAND
default y
help
Similar to ENV_IS_IN_NAND, used for TPL environment.
config TPL_ENV_IS_IN_SPI_FLASH
bool "TPL Environment is in SPI flash"
depends on !TPL_ENV_IS_NOWHERE
depends on ENV_IS_IN_SPI_FLASH
default y
help
Similar to ENV_IS_IN_SPI_FLASH, used for TPL environment.
config TPL_ENV_IS_IN_FLASH
bool "TPL Environment in flash memory"
depends on !TPL_ENV_IS_NOWHERE
depends on ENV_IS_IN_FLASH
default y
help
Similar to ENV_IS_IN_FLASH, used for TPL environment.
endif
endmenu
+36
View File
@@ -0,0 +1,36 @@
# SPDX-License-Identifier: GPL-2.0+
#
# (C) Copyright 2004-2006
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
obj-y += common.o env.o
ifndef CONFIG_SPL_BUILD
obj-y += attr.o
obj-y += callback.o
obj-y += flags.o
obj-$(CONFIG_ENV_IS_IN_EEPROM) += eeprom.o
extra-$(CONFIG_ENV_IS_EMBEDDED) += embedded.o
obj-$(CONFIG_ENV_IS_IN_EEPROM) += embedded.o
extra-$(CONFIG_ENV_IS_IN_FLASH) += embedded.o
obj-$(CONFIG_ENV_IS_IN_NVRAM) += embedded.o
obj-$(CONFIG_ENV_IS_IN_NVRAM) += nvram.o
obj-$(CONFIG_ENV_IS_IN_ONENAND) += onenand.o
obj-$(CONFIG_ENV_IS_IN_SATA) += sata.o
obj-$(CONFIG_ENV_IS_IN_REMOTE) += remote.o
obj-$(CONFIG_ENV_IS_IN_UBI) += ubi.o
else
obj-$(CONFIG_$(SPL_TPL_)ENV_SUPPORT) += attr.o
obj-$(CONFIG_$(SPL_TPL_)ENV_SUPPORT) += flags.o
obj-$(CONFIG_$(SPL_TPL_)ENV_SUPPORT) += callback.o
endif
obj-$(CONFIG_$(SPL_TPL_)ENV_IS_NOWHERE) += nowhere.o
obj-$(CONFIG_$(SPL_TPL_)ENV_IS_IN_MMC) += mmc.o
obj-$(CONFIG_$(SPL_TPL_)ENV_IS_IN_FAT) += fat.o
obj-$(CONFIG_$(SPL_TPL_)ENV_IS_IN_EXT4) += ext4.o
obj-$(CONFIG_$(SPL_TPL_)ENV_IS_IN_NAND) += nand.o
obj-$(CONFIG_$(SPL_TPL_)ENV_IS_IN_SPI_FLASH) += sf.o
obj-$(CONFIG_$(SPL_TPL_)ENV_IS_IN_FLASH) += flash.o
CFLAGS_embedded.o := -Wa,--no-warn -DENV_CRC=$(shell tools/envcrc 2>/dev/null)
+309
View File
@@ -0,0 +1,309 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2012
* Joe Hershberger, National Instruments, joe.hershberger@ni.com
*/
#ifdef USE_HOSTCC /* Eliminate "ANSI does not permit..." warnings */
#include <stdint.h>
#include <stdio.h>
#include <linux/linux_string.h>
#else
#include <common.h>
#include <slre.h>
#endif
#include <env_attr.h>
#include <errno.h>
#include <linux/string.h>
#include <malloc.h>
/*
* Iterate through the whole list calling the callback for each found element.
* "attr_list" takes the form:
* attributes = [^,:\s]*
* entry = name[:attributes]
* list = entry[,list]
*/
int env_attr_walk(const char *attr_list,
int (*callback)(const char *name, const char *attributes, void *priv),
void *priv)
{
const char *entry, *entry_end;
char *name, *attributes;
if (!attr_list)
/* list not found */
return 1;
entry = attr_list;
do {
char *entry_cpy = NULL;
entry_end = strchr(entry, ENV_ATTR_LIST_DELIM);
/* check if this is the last entry in the list */
if (entry_end == NULL) {
int entry_len = strlen(entry);
if (entry_len) {
/*
* allocate memory to copy the entry into since
* we will need to inject '\0' chars and squash
* white-space before calling the callback
*/
entry_cpy = malloc(entry_len + 1);
if (entry_cpy)
/* copy the rest of the list */
strcpy(entry_cpy, entry);
else
return -ENOMEM;
}
} else {
int entry_len = entry_end - entry;
if (entry_len) {
/*
* allocate memory to copy the entry into since
* we will need to inject '\0' chars and squash
* white-space before calling the callback
*/
entry_cpy = malloc(entry_len + 1);
if (entry_cpy) {
/* copy just this entry and null term */
strncpy(entry_cpy, entry, entry_len);
entry_cpy[entry_len] = '\0';
} else
return -ENOMEM;
}
}
/* check if there is anything to process (e.g. not ",,,") */
if (entry_cpy != NULL) {
attributes = strchr(entry_cpy, ENV_ATTR_SEP);
/* check if there is a ':' */
if (attributes != NULL) {
/* replace the ':' with '\0' to term name */
*attributes++ = '\0';
/* remove white-space from attributes */
attributes = strim(attributes);
}
/* remove white-space from name */
name = strim(entry_cpy);
/* only call the callback if there is a name */
if (strlen(name) != 0) {
int retval = 0;
retval = callback(name, attributes, priv);
if (retval) {
free(entry_cpy);
return retval;
}
}
}
free(entry_cpy);
entry = entry_end + 1;
} while (entry_end != NULL);
return 0;
}
#if defined(CONFIG_REGEX)
struct regex_callback_priv {
const char *searched_for;
char *regex;
char *attributes;
};
static int regex_callback(const char *name, const char *attributes, void *priv)
{
int retval = 0;
struct regex_callback_priv *cbp = (struct regex_callback_priv *)priv;
struct slre slre;
char regex[strlen(name) + 3];
/* Require the whole string to be described by the regex */
sprintf(regex, "^%s$", name);
if (slre_compile(&slre, regex)) {
struct cap caps[slre.num_caps + 2];
if (slre_match(&slre, cbp->searched_for,
strlen(cbp->searched_for), caps)) {
free(cbp->regex);
if (!attributes) {
retval = -EINVAL;
goto done;
}
cbp->regex = malloc(strlen(regex) + 1);
if (cbp->regex) {
strcpy(cbp->regex, regex);
} else {
retval = -ENOMEM;
goto done;
}
free(cbp->attributes);
cbp->attributes = malloc(strlen(attributes) + 1);
if (cbp->attributes) {
strcpy(cbp->attributes, attributes);
} else {
retval = -ENOMEM;
free(cbp->regex);
cbp->regex = NULL;
goto done;
}
}
} else {
printf("Error compiling regex: %s\n", slre.err_str);
retval = -EINVAL;
}
done:
return retval;
}
/*
* Retrieve the attributes string associated with a single name in the list
* There is no protection on attributes being too small for the value
*/
int env_attr_lookup(const char *attr_list, const char *name, char *attributes)
{
if (!attributes)
/* bad parameter */
return -EINVAL;
if (!attr_list)
/* list not found */
return -EINVAL;
struct regex_callback_priv priv;
int retval;
priv.searched_for = name;
priv.regex = NULL;
priv.attributes = NULL;
retval = env_attr_walk(attr_list, regex_callback, &priv);
if (retval)
return retval; /* error */
if (priv.regex) {
strcpy(attributes, priv.attributes);
free(priv.attributes);
free(priv.regex);
/* success */
return 0;
}
return -ENOENT; /* not found in list */
}
#else
/*
* Search for the last exactly matching name in an attribute list
*/
static int reverse_name_search(const char *searched, const char *search_for,
const char **result)
{
int result_size = 0;
const char *cur_searched = searched;
if (result)
*result = NULL;
if (*search_for == '\0') {
if (result)
*result = searched;
return strlen(searched);
}
for (;;) {
const char *match = strstr(cur_searched, search_for);
const char *prevch;
const char *nextch;
/* Stop looking if no new match is found */
if (match == NULL)
break;
prevch = match - 1;
nextch = match + strlen(search_for);
/* Skip spaces */
while (*prevch == ' ' && prevch >= searched)
prevch--;
while (*nextch == ' ')
nextch++;
/* Start looking past the current match so last is found */
cur_searched = match + 1;
/* Check for an exact match */
if (match != searched &&
*prevch != ENV_ATTR_LIST_DELIM &&
prevch != searched - 1)
continue;
if (*nextch != ENV_ATTR_SEP &&
*nextch != ENV_ATTR_LIST_DELIM &&
*nextch != '\0')
continue;
if (result)
*result = match;
result_size = strlen(search_for);
}
return result_size;
}
/*
* Retrieve the attributes string associated with a single name in the list
* There is no protection on attributes being too small for the value
*/
int env_attr_lookup(const char *attr_list, const char *name, char *attributes)
{
const char *entry = NULL;
int entry_len;
if (!attributes)
/* bad parameter */
return -EINVAL;
if (!attr_list)
/* list not found */
return -EINVAL;
entry_len = reverse_name_search(attr_list, name, &entry);
if (entry != NULL) {
int len;
/* skip the name */
entry += entry_len;
/* skip spaces */
while (*entry == ' ')
entry++;
if (*entry != ENV_ATTR_SEP)
len = 0;
else {
const char *delim;
static const char delims[] = {
ENV_ATTR_LIST_DELIM, ' ', '\0'};
/* skip the attr sep */
entry += 1;
/* skip spaces */
while (*entry == ' ')
entry++;
delim = strpbrk(entry, delims);
if (delim == NULL)
len = strlen(entry);
else
len = delim - entry;
memcpy(attributes, entry, len);
}
attributes[len] = '\0';
/* success */
return 0;
}
/* not found in list */
return -ENOENT;
}
#endif
+136
View File
@@ -0,0 +1,136 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2012
* Joe Hershberger, National Instruments, joe.hershberger@ni.com
*/
#include <common.h>
#include <env.h>
#include <env_internal.h>
#if defined(CONFIG_NEEDS_MANUAL_RELOC)
DECLARE_GLOBAL_DATA_PTR;
#endif
/*
* Look up a callback function pointer by name
*/
static struct env_clbk_tbl *find_env_callback(const char *name)
{
struct env_clbk_tbl *clbkp;
int i;
int num_callbacks = ll_entry_count(struct env_clbk_tbl, env_clbk);
if (name == NULL)
return NULL;
/* look up the callback in the linker-list */
for (i = 0, clbkp = ll_entry_start(struct env_clbk_tbl, env_clbk);
i < num_callbacks;
i++, clbkp++) {
if (strcmp(name, clbkp->name) == 0)
return clbkp;
}
return NULL;
}
static int first_call = 1;
static const char *callback_list;
/*
* Look for a possible callback for a newly added variable
* This is called specifically when the variable did not exist in the hash
* previously, so the blanket update did not find this variable.
*/
void env_callback_init(struct env_entry *var_entry)
{
const char *var_name = var_entry->key;
char callback_name[256] = "";
struct env_clbk_tbl *clbkp;
int ret = 1;
if (first_call) {
callback_list = env_get(ENV_CALLBACK_VAR);
first_call = 0;
}
/* look in the ".callbacks" var for a reference to this variable */
if (callback_list != NULL)
ret = env_attr_lookup(callback_list, var_name, callback_name);
/* only if not found there, look in the static list */
if (ret)
ret = env_attr_lookup(ENV_CALLBACK_LIST_STATIC, var_name,
callback_name);
/* if an association was found, set the callback pointer */
if (!ret && strlen(callback_name)) {
clbkp = find_env_callback(callback_name);
if (clbkp != NULL)
#if defined(CONFIG_NEEDS_MANUAL_RELOC)
var_entry->callback = clbkp->callback + gd->reloc_off;
#else
var_entry->callback = clbkp->callback;
#endif
}
}
/*
* Called on each existing env var prior to the blanket update since removing
* a callback association should remove its callback.
*/
static int clear_callback(struct env_entry *entry)
{
entry->callback = NULL;
return 0;
}
/*
* Call for each element in the list that associates variables to callbacks
*/
static int set_callback(const char *name, const char *value, void *priv)
{
struct env_entry e, *ep;
struct env_clbk_tbl *clbkp;
e.key = name;
e.data = NULL;
e.callback = NULL;
hsearch_r(e, ENV_FIND, &ep, &env_htab, 0);
/* does the env variable actually exist? */
if (ep != NULL) {
/* the assocaition delares no callback, so remove the pointer */
if (value == NULL || strlen(value) == 0)
ep->callback = NULL;
else {
/* assign the requested callback */
clbkp = find_env_callback(value);
if (clbkp != NULL)
#if defined(CONFIG_NEEDS_MANUAL_RELOC)
ep->callback = clbkp->callback + gd->reloc_off;
#else
ep->callback = clbkp->callback;
#endif
}
}
return 0;
}
static int on_callbacks(const char *name, const char *value, enum env_op op,
int flags)
{
/* remove all callbacks */
hwalk_r(&env_htab, clear_callback);
/* configure any static callback bindings */
env_attr_walk(ENV_CALLBACK_LIST_STATIC, set_callback, NULL);
/* configure any dynamic callback bindings */
env_attr_walk(value, set_callback, NULL);
return 0;
}
U_BOOT_ENV_CALLBACK(callbacks, on_callbacks);
+320
View File
@@ -0,0 +1,320 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2000-2010
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
* Andreas Heppel <aheppel@sysgo.de>
*/
#include <common.h>
#include <command.h>
#include <env.h>
#include <env_internal.h>
#include <sort.h>
#include <linux/stddef.h>
#include <search.h>
#include <errno.h>
#include <malloc.h>
#include <u-boot/crc.h>
DECLARE_GLOBAL_DATA_PTR;
/************************************************************************
* Default settings to be used when no valid environment is found
*/
#include <env_default.h>
struct hsearch_data env_htab = {
.change_ok = env_flags_validate,
};
/*
* Read an environment variable as a boolean
* Return -1 if variable does not exist (default to true)
*/
int env_get_yesno(const char *var)
{
char *s = env_get(var);
if (s == NULL)
return -1;
return (*s == '1' || *s == 'y' || *s == 'Y' || *s == 't' || *s == 'T') ?
1 : 0;
}
/*
* Look up the variable from the default environment
*/
char *env_get_default(const char *name)
{
char *ret_val;
unsigned long really_valid = gd->env_valid;
unsigned long real_gd_flags = gd->flags;
/* Pretend that the image is bad. */
gd->flags &= ~GD_FLG_ENV_READY;
gd->env_valid = ENV_INVALID;
ret_val = env_get(name);
gd->env_valid = really_valid;
gd->flags = real_gd_flags;
return ret_val;
}
void env_set_default(const char *s, int flags)
{
if (sizeof(default_environment) > ENV_SIZE) {
puts("*** Error - default environment is too large\n\n");
return;
}
if (s) {
if ((flags & H_INTERACTIVE) == 0) {
printf("*** Warning - %s, "
"using default environment\n\n", s);
} else {
puts(s);
}
} else {
debug("Using default environment\n");
}
if (himport_r(&env_htab, (char *)default_environment,
sizeof(default_environment), '\0', flags, 0,
0, NULL) == 0)
pr_err("## Error: Environment import failed: errno = %d\n",
errno);
gd->flags |= GD_FLG_ENV_READY;
gd->flags |= GD_FLG_ENV_DEFAULT;
}
/* [re]set individual variables to their value in the default environment */
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;
return himport_r(&env_htab, (const char *)default_environment,
sizeof(default_environment), '\0',
flags, 0, nvars, vars);
}
/*
* 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)
{
env_t *ep = (env_t *)buf;
if (check) {
uint32_t crc;
memcpy(&crc, &ep->crc, sizeof(crc));
if (crc32(0, ep->data, ENV_SIZE) != crc) {
env_set_default("bad CRC", 0);
return -ENOMSG; /* needed for env_load() */
}
}
if (himport_r(&env_htab, (char *)ep->data, ENV_SIZE, '\0', 0, 0,
0, NULL)) {
gd->flags |= GD_FLG_ENV_READY;
return 0;
}
pr_err("Cannot import environment: errno = %d\n", errno);
env_set_default("import failed", 0);
return -EIO;
}
#ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT
static unsigned char env_flags;
int env_import_redund(const char *buf1, int buf1_read_fail,
const char *buf2, int buf2_read_fail)
{
int crc1_ok, crc2_ok;
env_t *ep, *tmp_env1, *tmp_env2;
tmp_env1 = (env_t *)buf1;
tmp_env2 = (env_t *)buf2;
if (buf1_read_fail && buf2_read_fail) {
puts("*** Error - No Valid Environment Area found\n");
} else if (buf1_read_fail || buf2_read_fail) {
puts("*** Warning - some problems detected ");
puts("reading environment; recovered successfully\n");
}
if (buf1_read_fail && buf2_read_fail) {
env_set_default("bad env area", 0);
return -EIO;
} else if (!buf1_read_fail && buf2_read_fail) {
gd->env_valid = ENV_VALID;
return env_import((char *)tmp_env1, 1);
} else if (buf1_read_fail && !buf2_read_fail) {
gd->env_valid = ENV_REDUND;
return env_import((char *)tmp_env2, 1);
}
crc1_ok = crc32(0, tmp_env1->data, ENV_SIZE) ==
tmp_env1->crc;
crc2_ok = crc32(0, tmp_env2->data, ENV_SIZE) ==
tmp_env2->crc;
if (!crc1_ok && !crc2_ok) {
env_set_default("bad CRC", 0);
return -ENOMSG; /* needed for env_load() */
} else if (crc1_ok && !crc2_ok) {
gd->env_valid = ENV_VALID;
} else if (!crc1_ok && crc2_ok) {
gd->env_valid = ENV_REDUND;
} else {
/* both ok - check serial */
if (tmp_env1->flags == 255 && tmp_env2->flags == 0)
gd->env_valid = ENV_REDUND;
else if (tmp_env2->flags == 255 && tmp_env1->flags == 0)
gd->env_valid = ENV_VALID;
else if (tmp_env1->flags > tmp_env2->flags)
gd->env_valid = ENV_VALID;
else if (tmp_env2->flags > tmp_env1->flags)
gd->env_valid = ENV_REDUND;
else /* flags are equal - almost impossible */
gd->env_valid = ENV_VALID;
}
if (gd->env_valid == ENV_VALID)
ep = tmp_env1;
else
ep = tmp_env2;
env_flags = ep->flags;
return env_import((char *)ep, 0);
}
#endif /* CONFIG_SYS_REDUNDAND_ENVIRONMENT */
/* Export the environment and generate CRC for it. */
int env_export(env_t *env_out)
{
char *res;
ssize_t len;
res = (char *)env_out->data;
len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
if (len < 0) {
pr_err("Cannot export environment: errno = %d\n", errno);
return 1;
}
env_out->crc = crc32(0, env_out->data, ENV_SIZE);
#ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT
env_out->flags = ++env_flags; /* increase the serial */
#endif
return 0;
}
void env_relocate(void)
{
#if defined(CONFIG_NEEDS_MANUAL_RELOC)
env_reloc();
env_fix_drivers();
env_htab.change_ok += gd->reloc_off;
#endif
if (gd->env_valid == ENV_INVALID) {
#if defined(CONFIG_ENV_IS_NOWHERE) || defined(CONFIG_SPL_BUILD)
/* Environment not changable */
env_set_default(NULL, 0);
#else
bootstage_error(BOOTSTAGE_ID_NET_CHECKSUM);
env_set_default("bad CRC", 0);
#endif
} else {
env_load();
}
}
#ifdef CONFIG_AUTO_COMPLETE
int env_complete(char *var, int maxv, char *cmdv[], int bufsz, char *buf,
bool dollar_comp)
{
struct env_entry *match;
int found, idx;
if (dollar_comp) {
/*
* When doing $ completion, the first character should
* obviously be a '$'.
*/
if (var[0] != '$')
return 0;
var++;
/*
* The second one, if present, should be a '{', as some
* configuration of the u-boot shell expand ${var} but not
* $var.
*/
if (var[0] == '{')
var++;
else if (var[0] != '\0')
return 0;
}
idx = 0;
found = 0;
cmdv[0] = NULL;
while ((idx = hmatch_r(var, idx, &match, &env_htab))) {
int vallen = strlen(match->key) + 1;
if (found >= maxv - 2 ||
bufsz < vallen + (dollar_comp ? 3 : 0))
break;
cmdv[found++] = buf;
/* Add the '${' prefix to each var when doing $ completion. */
if (dollar_comp) {
strcpy(buf, "${");
buf += 2;
bufsz -= 3;
}
memcpy(buf, match->key, vallen);
buf += vallen;
bufsz -= vallen;
if (dollar_comp) {
/*
* This one is a bit odd: vallen already contains the
* '\0' character but we need to add the '}' suffix,
* hence the buf - 1 here. strcpy() will add the '\0'
* character just after '}'. buf is then incremented
* to account for the extra '}' we just added.
*/
strcpy(buf - 1, "}");
buf++;
}
}
qsort(cmdv, found, sizeof(cmdv[0]), strcmp_compar);
if (idx)
cmdv[found++] = dollar_comp ? "${...}" : "...";
cmdv[found] = NULL;
return found;
}
#endif
+240
View File
@@ -0,0 +1,240 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2000-2010
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
* Andreas Heppel <aheppel@sysgo.de>
*/
#include <common.h>
#include <command.h>
#include <eeprom.h>
#include <env.h>
#include <env_internal.h>
#include <linux/stddef.h>
#include <u-boot/crc.h>
#if defined(CONFIG_I2C_ENV_EEPROM_BUS)
#include <i2c.h>
#endif
#include <search.h>
#include <errno.h>
#include <linux/compiler.h> /* for BUG_ON */
DECLARE_GLOBAL_DATA_PTR;
static int eeprom_bus_read(unsigned dev_addr, unsigned offset,
uchar *buffer, unsigned cnt)
{
int rcode;
#if defined(CONFIG_I2C_ENV_EEPROM_BUS)
int old_bus = i2c_get_bus_num();
if (old_bus != CONFIG_I2C_ENV_EEPROM_BUS)
i2c_set_bus_num(CONFIG_I2C_ENV_EEPROM_BUS);
#endif
rcode = eeprom_read(dev_addr, offset, buffer, cnt);
#if defined(CONFIG_I2C_ENV_EEPROM_BUS)
i2c_set_bus_num(old_bus);
#endif
return rcode;
}
static int eeprom_bus_write(unsigned dev_addr, unsigned offset,
uchar *buffer, unsigned cnt)
{
int rcode;
#if defined(CONFIG_I2C_ENV_EEPROM_BUS)
int old_bus = i2c_get_bus_num();
if (old_bus != CONFIG_I2C_ENV_EEPROM_BUS)
i2c_set_bus_num(CONFIG_I2C_ENV_EEPROM_BUS);
#endif
rcode = eeprom_write(dev_addr, offset, buffer, cnt);
#if defined(CONFIG_I2C_ENV_EEPROM_BUS)
i2c_set_bus_num(old_bus);
#endif
return rcode;
}
/** Call this function from overridden env_get_char_spec() if you need
* this functionality.
*/
int env_eeprom_get_char(int index)
{
uchar c;
unsigned int off = CONFIG_ENV_OFFSET;
#ifdef CONFIG_ENV_OFFSET_REDUND
if (gd->env_valid == ENV_REDUND)
off = CONFIG_ENV_OFFSET_REDUND;
#endif
eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
off + index + offsetof(env_t, data), &c, 1);
return c;
}
static int env_eeprom_load(void)
{
char buf_env[CONFIG_ENV_SIZE];
unsigned int off = CONFIG_ENV_OFFSET;
#ifdef CONFIG_ENV_OFFSET_REDUND
ulong len, crc[2], crc_tmp;
unsigned int off_env[2];
uchar rdbuf[64], flags[2];
int i, crc_ok[2] = {0, 0};
eeprom_init(-1); /* prepare for EEPROM read/write */
off_env[0] = CONFIG_ENV_OFFSET;
off_env[1] = CONFIG_ENV_OFFSET_REDUND;
for (i = 0; i < 2; i++) {
/* read CRC */
eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
off_env[i] + offsetof(env_t, crc),
(uchar *)&crc[i], sizeof(ulong));
/* read FLAGS */
eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
off_env[i] + offsetof(env_t, flags),
(uchar *)&flags[i], sizeof(uchar));
crc_tmp = 0;
len = ENV_SIZE;
off = off_env[i] + offsetof(env_t, data);
while (len > 0) {
int n = (len > sizeof(rdbuf)) ? sizeof(rdbuf) : len;
eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR, off,
rdbuf, n);
crc_tmp = crc32(crc_tmp, rdbuf, n);
len -= n;
off += n;
}
if (crc_tmp == crc[i])
crc_ok[i] = 1;
}
if (!crc_ok[0] && !crc_ok[1]) {
gd->env_addr = 0;
gd->env_valid = ENV_INVALID;
} else if (crc_ok[0] && !crc_ok[1]) {
gd->env_valid = ENV_VALID;
} else if (!crc_ok[0] && crc_ok[1]) {
gd->env_valid = ENV_REDUND;
} else {
/* both ok - check serial */
if (flags[0] == ENV_REDUND_ACTIVE &&
flags[1] == ENV_REDUND_OBSOLETE)
gd->env_valid = ENV_VALID;
else if (flags[0] == ENV_REDUND_OBSOLETE &&
flags[1] == ENV_REDUND_ACTIVE)
gd->env_valid = ENV_REDUND;
else if (flags[0] == 0xFF && flags[1] == 0)
gd->env_valid = ENV_REDUND;
else if (flags[1] == 0xFF && flags[0] == 0)
gd->env_valid = ENV_VALID;
else /* flags are equal - almost impossible */
gd->env_valid = ENV_VALID;
}
#else /* CONFIG_ENV_OFFSET_REDUND */
ulong crc, len, new;
uchar rdbuf[64];
eeprom_init(-1); /* prepare for EEPROM read/write */
/* read old CRC */
eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
CONFIG_ENV_OFFSET + offsetof(env_t, crc),
(uchar *)&crc, sizeof(ulong));
new = 0;
len = ENV_SIZE;
off = offsetof(env_t, data);
while (len > 0) {
int n = (len > sizeof(rdbuf)) ? sizeof(rdbuf) : len;
eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
CONFIG_ENV_OFFSET + off, rdbuf, n);
new = crc32(new, rdbuf, n);
len -= n;
off += n;
}
if (crc == new) {
gd->env_valid = ENV_VALID;
} else {
gd->env_valid = ENV_INVALID;
}
#endif /* CONFIG_ENV_OFFSET_REDUND */
off = CONFIG_ENV_OFFSET;
#ifdef CONFIG_ENV_OFFSET_REDUND
if (gd->env_valid == ENV_REDUND)
off = CONFIG_ENV_OFFSET_REDUND;
#endif
eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
off, (uchar *)buf_env, CONFIG_ENV_SIZE);
return env_import(buf_env, 1);
}
static int env_eeprom_save(void)
{
env_t env_new;
int rc;
unsigned int off = CONFIG_ENV_OFFSET;
#ifdef CONFIG_ENV_OFFSET_REDUND
unsigned int off_red = CONFIG_ENV_OFFSET_REDUND;
char flag_obsolete = ENV_REDUND_OBSOLETE;
#endif
rc = env_export(&env_new);
if (rc)
return rc;
#ifdef CONFIG_ENV_OFFSET_REDUND
if (gd->env_valid == ENV_VALID) {
off = CONFIG_ENV_OFFSET_REDUND;
off_red = CONFIG_ENV_OFFSET;
}
env_new.flags = ENV_REDUND_ACTIVE;
#endif
rc = eeprom_bus_write(CONFIG_SYS_DEF_EEPROM_ADDR,
off, (uchar *)&env_new, CONFIG_ENV_SIZE);
#ifdef CONFIG_ENV_OFFSET_REDUND
if (rc == 0) {
eeprom_bus_write(CONFIG_SYS_DEF_EEPROM_ADDR,
off_red + offsetof(env_t, flags),
(uchar *)&flag_obsolete, 1);
if (gd->env_valid == ENV_VALID)
gd->env_valid = ENV_REDUND;
else
gd->env_valid = ENV_VALID;
}
#endif
return rc;
}
U_BOOT_ENV_LOCATION(eeprom) = {
.location = ENVL_EEPROM,
ENV_NAME("EEPROM")
.load = env_eeprom_load,
.save = env_save_ptr(env_eeprom_save),
};
+96
View File
@@ -0,0 +1,96 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2001
* Erik Theisen, Wave 7 Optics, etheisen@mindspring.com.
*/
#include <linux/kconfig.h>
#ifndef __ASSEMBLY__
#define __ASSEMBLY__ /* Dirty trick to get only #defines */
#endif
#define __ASM_STUB_PROCESSOR_H__ /* don't include asm/processor. */
#include <config.h>
#undef __ASSEMBLY__
#include <env_internal.h>
#include <linux/stringify.h>
/* Handle HOSTS that have prepended crap on symbol names, not TARGETS. */
#if defined(__APPLE__)
/* Leading underscore on symbols */
# define SYM_CHAR "_"
#else /* No leading character on symbols */
# define SYM_CHAR
#endif
/*
* Generate embedded environment table
* inside U-Boot image, if needed.
*/
#if defined(ENV_IS_EMBEDDED) || defined(CONFIG_BUILD_ENVCRC)
/*
* Put the environment in the .text section when we are building
* U-Boot proper. The host based program "tools/envcrc" does not need
* a seperate section.
*/
#if defined(USE_HOSTCC) /* Native for 'tools/envcrc' */
# define __UBOOT_ENV_SECTION__(name) /*XXX DO_NOT_DEL_THIS_COMMENT*/
#else /* Environment is embedded in U-Boot's .text section */
/* XXX - This only works with GNU C */
# define __UBOOT_ENV_SECTION__(name) __attribute__ ((section(".text."#name)))
#endif
/*
* Macros to generate global absolutes.
*/
#if defined(__bfin__)
# define GEN_SET_VALUE(name, value) \
asm(".set " GEN_SYMNAME(name) ", " GEN_VALUE(value))
#else
# define GEN_SET_VALUE(name, value) \
asm(GEN_SYMNAME(name) " = " GEN_VALUE(value))
#endif
#define GEN_SYMNAME(str) SYM_CHAR #str
#define GEN_VALUE(str) #str
#define GEN_ABS(name, value) \
asm(".globl " GEN_SYMNAME(name)); \
GEN_SET_VALUE(name, value)
/*
* Check to see if we are building with a
* computed CRC. Otherwise define it as ~0.
*/
#if !defined(ENV_CRC)
# define ENV_CRC (~0)
#endif
#define DEFAULT_ENV_INSTANCE_EMBEDDED
#include <env_default.h>
#ifdef CONFIG_ENV_ADDR_REDUND
env_t redundand_environment __UBOOT_ENV_SECTION__(redundand_environment) = {
0, /* CRC Sum: invalid */
0, /* Flags: invalid */
{
"\0"
}
};
#endif /* CONFIG_ENV_ADDR_REDUND */
/*
* These will end up in the .text section
* if the environment strings are embedded
* in the image. When this is used for
* tools/envcrc, they are placed in the
* .data/.sdata section.
*
*/
unsigned long env_size __UBOOT_ENV_SECTION__(env_size) = sizeof(env_t);
/*
* Add in absolutes.
*/
GEN_ABS(env_offset, (CONFIG_ENV_ADDR - CONFIG_SYS_FLASH_BASE));
#endif /* ENV_IS_EMBEDDED */
+328
View File
@@ -0,0 +1,328 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2017 Google, Inc
* Written by Simon Glass <sjg@chromium.org>
*/
#include <common.h>
#include <env.h>
#include <env_internal.h>
#include <linux/lotus/timestamp.h>
#include <linux/lotus/step.h>
DECLARE_GLOBAL_DATA_PTR;
#if defined(CONFIG_NEEDS_MANUAL_RELOC)
void env_fix_drivers(void)
{
struct env_driver *drv;
const int n_ents = ll_entry_count(struct env_driver, env_driver);
struct env_driver *entry;
drv = ll_entry_start(struct env_driver, env_driver);
for (entry = drv; entry != drv + n_ents; entry++) {
if (entry->name)
entry->name += gd->reloc_off;
if (entry->load)
entry->load += gd->reloc_off;
if (entry->save)
entry->save += gd->reloc_off;
if (entry->erase)
entry->erase += gd->reloc_off;
if (entry->init)
entry->init += gd->reloc_off;
}
}
#endif
static struct env_driver *_env_driver_lookup(enum env_location loc)
{
struct env_driver *drv;
const int n_ents = ll_entry_count(struct env_driver, env_driver);
struct env_driver *entry;
drv = ll_entry_start(struct env_driver, env_driver);
for (entry = drv; entry != drv + n_ents; entry++) {
if (loc == entry->location)
return entry;
}
/* Not found */
return NULL;
}
static enum env_location env_locations[] = {
#ifdef CONFIG_ENV_IS_IN_EEPROM
ENVL_EEPROM,
#endif
#ifdef CONFIG_ENV_IS_IN_EXT4
ENVL_EXT4,
#endif
#ifdef CONFIG_ENV_IS_IN_FAT
ENVL_FAT,
#endif
#ifdef CONFIG_ENV_IS_IN_FLASH
ENVL_FLASH,
#endif
#ifdef CONFIG_ENV_IS_IN_MMC
ENVL_MMC,
#endif
#ifdef CONFIG_ENV_IS_IN_NAND
ENVL_NAND,
#endif
#ifdef CONFIG_ENV_IS_IN_NVRAM
ENVL_NVRAM,
#endif
#ifdef CONFIG_ENV_IS_IN_REMOTE
ENVL_REMOTE,
#endif
#ifdef CONFIG_ENV_IS_IN_SATA
ENVL_ESATA,
#endif
#ifdef CONFIG_ENV_IS_IN_SPI_FLASH
ENVL_SPI_FLASH,
#endif
#ifdef CONFIG_ENV_IS_IN_UBI
ENVL_UBI,
#endif
#ifdef CONFIG_ENV_IS_NOWHERE
ENVL_NOWHERE,
#endif
};
static bool env_has_inited(enum env_location location)
{
return gd->env_has_init & BIT(location);
}
static void env_set_inited(enum env_location location)
{
/*
* We're using a 32-bits bitmask stored in gd (env_has_init)
* using the above enum value as the bit index. We need to
* make sure that we're not overflowing it.
*/
BUILD_BUG_ON(ARRAY_SIZE(env_locations) > BITS_PER_LONG);
gd->env_has_init |= BIT(location);
}
/**
* env_get_location() - Returns the best env location for a board
* @op: operations performed on the environment
* @prio: priority between the multiple environments, 0 being the
* highest priority
*
* This will return the preferred environment for the given priority.
* This is overridable by boards if they need to.
*
* All implementations are free to use the operation, the priority and
* any other data relevant to their choice, but must take into account
* the fact that the lowest prority (0) is the most important location
* in the system. The following locations should be returned by order
* of descending priorities, from the highest to the lowest priority.
*
* Returns:
* an enum env_location value on success, a negative error code otherwise
*/
__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];
}
/**
* env_driver_lookup() - Finds the most suited environment location
* @op: operations performed on the environment
* @prio: priority between the multiple environments, 0 being the
* highest priority
*
* This will try to find the available environment with the highest
* priority in the system.
*
* Returns:
* NULL on error, a pointer to a struct env_driver otherwise
*/
static struct env_driver *env_driver_lookup(enum env_operation op, int prio)
{
enum env_location loc = env_get_location(op, prio);
struct env_driver *drv;
if (loc == ENVL_UNKNOWN)
return NULL;
drv = _env_driver_lookup(loc);
if (!drv) {
debug("%s: No environment driver for location %d\n", __func__,
loc);
return NULL;
}
return drv;
}
__weak int env_get_char_spec(int index)
{
return *(uchar *)(gd->env_addr + index);
}
int env_get_char(int index)
{
if (gd->env_valid == ENV_INVALID)
return default_environment[index];
else
return env_get_char_spec(index);
}
int env_load(void)
{
struct env_driver *drv;
int best_prio = -1;
int prio;
TIME_STAMP(0);
for (prio = 0; (drv = env_driver_lookup(ENVOP_LOAD, prio)); prio++) {
int ret;
if (!drv->load)
continue;
if (!env_has_inited(drv->location))
continue;
printf("Loading Environment from %s... ", drv->name);
/*
* In error case, the error message must be printed during
* drv->load() in some underlying API, and it must be exactly
* one message.
*/
ret = drv->load();
if (!ret) {
printf("OK\n");
TIME_STAMP(0);
return 0;
} else if (ret == -ENOMSG) {
/* Handle "bad CRC" case */
if (best_prio == -1)
best_prio = prio;
} else {
debug("Failed (%d)\n", ret);
}
}
/*
* In case of invalid environment, we set the 'default' env location
* to the best choice, i.e.:
* 1. Environment location with bad CRC, if such location was found
* 2. Otherwise use the location with highest priority
*
* This way, next calls to env_save() will restore the environment
* at the right place.
*/
if (best_prio >= 0)
debug("Selecting environment with bad CRC\n");
else
best_prio = 0;
env_get_location(ENVOP_LOAD, best_prio);
TIME_STAMP(0);
return -ENODEV;
}
int env_save(void)
{
struct env_driver *drv;
drv = env_driver_lookup(ENVOP_SAVE, gd->env_load_prio);
if (drv) {
int ret;
if (!drv->save)
return -ENODEV;
if (!env_has_inited(drv->location))
return -ENODEV;
printf("Saving Environment to %s... ", drv->name);
ret = drv->save();
if (ret)
printf("Failed (%d)\n", ret);
else
printf("OK\n");
if (!ret)
return 0;
}
return -ENODEV;
}
int env_erase(void)
{
struct env_driver *drv;
drv = env_driver_lookup(ENVOP_ERASE, gd->env_load_prio);
if (drv) {
int ret;
if (!drv->erase)
return -ENODEV;
if (!env_has_inited(drv->location))
return -ENODEV;
printf("Erasing Environment on %s... ", drv->name);
ret = drv->erase();
if (ret)
printf("Failed (%d)\n", ret);
else
printf("OK\n");
if (!ret)
return 0;
}
return -ENODEV;
}
int env_init(void)
{
struct env_driver *drv;
int ret = -ENOENT;
int prio;
step(55);
TIME_STAMP(0);
for (prio = 0; (drv = env_driver_lookup(ENVOP_INIT, prio)); prio++) {
if (!drv->init || !(ret = drv->init()))
env_set_inited(drv->location);
debug("%s: Environment %s init done (ret=%d)\n", __func__,
drv->name, ret);
}
if (!prio)
return -ENODEV;
if (ret == -ENOENT) {
gd->env_addr = (ulong)&default_environment[0];
gd->env_valid = ENV_VALID;
TIME_STAMP(0);
return 0;
}
step(56);
TIME_STAMP(0);
return ret;
}
+141
View File
@@ -0,0 +1,141 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (c) Copyright 2016 by VRT Technology
*
* Author:
* Stuart Longland <stuartl@vrt.com.au>
*
* Based on FAT environment driver
* (c) Copyright 2011 by Tigris Elektronik GmbH
*
* Author:
* Maximilian Schwerin <mvs@tigris.de>
*
* and EXT4 filesystem implementation
* (C) Copyright 2011 - 2012 Samsung Electronics
* EXT4 filesystem implementation in Uboot by
* Uma Shankar <uma.shankar@samsung.com>
* Manjunatha C Achar <a.manjunatha@samsung.com>
*/
#include <common.h>
#include <command.h>
#include <env.h>
#include <env_internal.h>
#include <linux/stddef.h>
#include <malloc.h>
#include <memalign.h>
#include <search.h>
#include <errno.h>
#include <ext4fs.h>
#include <mmc.h>
__weak const char *env_ext4_get_intf(void)
{
return (const char *)CONFIG_ENV_EXT4_INTERFACE;
}
__weak const char *env_ext4_get_dev_part(void)
{
return (const char *)CONFIG_ENV_EXT4_DEVICE_AND_PART;
}
#ifdef CONFIG_CMD_SAVEENV
static int env_ext4_save(void)
{
env_t env_new;
struct blk_desc *dev_desc = NULL;
disk_partition_t info;
int dev, part;
int err;
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)
return 1;
dev = dev_desc->devnum;
ext4fs_set_blk_dev(dev_desc, &info);
if (!ext4fs_mount(info.size)) {
printf("\n** Unable to use %s %s for saveenv **\n",
ifname, dev_and_part);
return 1;
}
err = ext4fs_write(CONFIG_ENV_EXT4_FILE, (void *)&env_new,
sizeof(env_t), FILETYPE_REG);
ext4fs_close();
if (err == -1) {
printf("\n** Unable to write \"%s\" from %s%d:%d **\n",
CONFIG_ENV_EXT4_FILE, ifname, dev, part);
return 1;
}
puts("done\n");
return 0;
}
#endif /* CONFIG_CMD_SAVEENV */
static int env_ext4_load(void)
{
ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_SIZE);
struct blk_desc *dev_desc = NULL;
disk_partition_t info;
int dev, part;
int err;
loff_t off;
const char *ifname = env_ext4_get_intf();
const char *dev_and_part = env_ext4_get_dev_part();
#ifdef CONFIG_MMC
if (!strcmp(ifname, "mmc"))
mmc_initialize(NULL);
#endif
part = blk_get_device_part_str(ifname, dev_and_part,
&dev_desc, &info, 1);
if (part < 0)
goto err_env_relocate;
dev = dev_desc->devnum;
ext4fs_set_blk_dev(dev_desc, &info);
if (!ext4fs_mount(info.size)) {
printf("\n** Unable to use %s %s for loading the env **\n",
ifname, dev_and_part);
goto err_env_relocate;
}
err = ext4_read_file(CONFIG_ENV_EXT4_FILE, buf, 0, CONFIG_ENV_SIZE,
&off);
ext4fs_close();
if (err == -1) {
printf("\n** Unable to read \"%s\" from %s%d:%d **\n",
CONFIG_ENV_EXT4_FILE, ifname, dev, part);
goto err_env_relocate;
}
return env_import(buf, 1);
err_env_relocate:
env_set_default(NULL, 0);
return -EIO;
}
U_BOOT_ENV_LOCATION(ext4) = {
.location = ENVL_EXT4,
ENV_NAME("EXT4")
.load = env_ext4_load,
.save = env_save_ptr(env_ext4_save),
};
+141
View File
@@ -0,0 +1,141 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (c) Copyright 2011 by Tigris Elektronik GmbH
*
* Author:
* Maximilian Schwerin <mvs@tigris.de>
*/
#include <common.h>
#include <command.h>
#include <env.h>
#include <env_internal.h>
#include <linux/stddef.h>
#include <malloc.h>
#include <memalign.h>
#include <search.h>
#include <errno.h>
#include <fat.h>
#include <mmc.h>
#ifdef CONFIG_SPL_BUILD
/* TODO(sjg@chromium.org): Figure out why this is needed */
# if !defined(CONFIG_TARGET_AM335X_EVM) || defined(CONFIG_SPL_OS_BOOT)
# define LOADENV
# endif
#else
# define LOADENV
# if defined(CONFIG_CMD_SAVEENV)
# define CMD_SAVEENV
# endif
#endif
#ifdef CMD_SAVEENV
static int env_fat_save(void)
{
env_t __aligned(ARCH_DMA_MINALIGN) env_new;
struct blk_desc *dev_desc = NULL;
disk_partition_t info;
int dev, part;
int err;
loff_t size;
err = env_export(&env_new);
if (err)
return err;
part = blk_get_device_part_str(CONFIG_ENV_FAT_INTERFACE,
CONFIG_ENV_FAT_DEVICE_AND_PART,
&dev_desc, &info, 1);
if (part < 0)
return 1;
dev = dev_desc->devnum;
if (fat_set_blk_dev(dev_desc, &info) != 0) {
/*
* This printf is embedded in the messages from env_save that
* will calling it. The missing \n is intentional.
*/
printf("Unable to use %s %d:%d... ",
CONFIG_ENV_FAT_INTERFACE, dev, part);
return 1;
}
err = file_fat_write(CONFIG_ENV_FAT_FILE, (void *)&env_new, 0, sizeof(env_t),
&size);
if (err == -1) {
/*
* This printf is embedded in the messages from env_save that
* will calling it. The missing \n is intentional.
*/
printf("Unable to write \"%s\" from %s%d:%d... ",
CONFIG_ENV_FAT_FILE, CONFIG_ENV_FAT_INTERFACE, dev, part);
return 1;
}
return 0;
}
#endif /* CMD_SAVEENV */
#ifdef LOADENV
static int env_fat_load(void)
{
ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_SIZE);
struct blk_desc *dev_desc = NULL;
disk_partition_t info;
int dev, part;
int err;
#ifdef CONFIG_MMC
if (!strcmp(CONFIG_ENV_FAT_INTERFACE, "mmc"))
mmc_initialize(NULL);
#endif
part = blk_get_device_part_str(CONFIG_ENV_FAT_INTERFACE,
CONFIG_ENV_FAT_DEVICE_AND_PART,
&dev_desc, &info, 1);
if (part < 0)
goto err_env_relocate;
dev = dev_desc->devnum;
if (fat_set_blk_dev(dev_desc, &info) != 0) {
/*
* This printf is embedded in the messages from env_save that
* will calling it. The missing \n is intentional.
*/
printf("Unable to use %s %d:%d... ",
CONFIG_ENV_FAT_INTERFACE, dev, part);
goto err_env_relocate;
}
err = file_fat_read(CONFIG_ENV_FAT_FILE, buf, CONFIG_ENV_SIZE);
if (err == -1) {
/*
* This printf is embedded in the messages from env_save that
* will calling it. The missing \n is intentional.
*/
printf("Unable to read \"%s\" from %s%d:%d... ",
CONFIG_ENV_FAT_FILE, CONFIG_ENV_FAT_INTERFACE, dev, part);
goto err_env_relocate;
}
return env_import(buf, 1);
err_env_relocate:
env_set_default(NULL, 0);
return -EIO;
}
#endif /* LOADENV */
U_BOOT_ENV_LOCATION(fat) = {
.location = ENVL_FAT,
ENV_NAME("FAT")
#ifdef LOADENV
.load = env_fat_load,
#endif
#ifdef CMD_SAVEENV
.save = env_save_ptr(env_fat_save),
#endif
};
+567
View File
@@ -0,0 +1,567 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2012
* Joe Hershberger, National Instruments, joe.hershberger@ni.com
*/
#include <env.h>
#include <linux/string.h>
#include <linux/ctype.h>
#ifdef USE_HOSTCC /* Eliminate "ANSI does not permit..." warnings */
#include <stdint.h>
#include <stdio.h>
#include "fw_env_private.h"
#include "fw_env.h"
#include <env_attr.h>
#include <env_flags.h>
#define env_get fw_getenv
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#else
#include <common.h>
#include <env_internal.h>
#endif
#ifdef CONFIG_CMD_NET
#define ENV_FLAGS_NET_VARTYPE_REPS "im"
#else
#define ENV_FLAGS_NET_VARTYPE_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 int env_flags_varaccess_mask[] = {
0,
ENV_FLAGS_VARACCESS_PREVENT_DELETE |
ENV_FLAGS_VARACCESS_PREVENT_CREATE |
ENV_FLAGS_VARACCESS_PREVENT_OVERWR,
ENV_FLAGS_VARACCESS_PREVENT_DELETE |
ENV_FLAGS_VARACCESS_PREVENT_OVERWR,
ENV_FLAGS_VARACCESS_PREVENT_DELETE |
ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR};
#ifdef CONFIG_CMD_ENV_FLAGS
static const char * const env_flags_vartype_names[] = {
"string",
"decimal",
"hexadecimal",
"boolean",
#ifdef CONFIG_CMD_NET
"IP address",
"MAC address",
#endif
};
static const char * const env_flags_varaccess_names[] = {
"any",
"read-only",
"write-once",
"change-default",
};
/*
* Print the whole list of available type flags.
*/
void env_flags_print_vartypes(void)
{
enum env_flags_vartype curtype = (enum env_flags_vartype)0;
while (curtype != env_flags_vartype_end) {
printf("\t%c -\t%s\n", env_flags_vartype_rep[curtype],
env_flags_vartype_names[curtype]);
curtype++;
}
}
/*
* Print the whole list of available access flags.
*/
void env_flags_print_varaccess(void)
{
enum env_flags_varaccess curaccess = (enum env_flags_varaccess)0;
while (curaccess != env_flags_varaccess_end) {
printf("\t%c -\t%s\n", env_flags_varaccess_rep[curaccess],
env_flags_varaccess_names[curaccess]);
curaccess++;
}
}
/*
* Return the name of the type.
*/
const char *env_flags_get_vartype_name(enum env_flags_vartype type)
{
return env_flags_vartype_names[type];
}
/*
* Return the name of the access.
*/
const char *env_flags_get_varaccess_name(enum env_flags_varaccess access)
{
return env_flags_varaccess_names[access];
}
#endif /* CONFIG_CMD_ENV_FLAGS */
/*
* Parse the flags string from a .flags attribute list into the vartype enum.
*/
enum env_flags_vartype env_flags_parse_vartype(const char *flags)
{
char *type;
if (strlen(flags) <= ENV_FLAGS_VARTYPE_LOC)
return env_flags_vartype_string;
type = strchr(env_flags_vartype_rep,
flags[ENV_FLAGS_VARTYPE_LOC]);
if (type != NULL)
return (enum env_flags_vartype)
(type - &env_flags_vartype_rep[0]);
printf("## Warning: Unknown environment variable type '%c'\n",
flags[ENV_FLAGS_VARTYPE_LOC]);
return env_flags_vartype_string;
}
/*
* Parse the flags string from a .flags attribute list into the varaccess enum.
*/
enum env_flags_varaccess env_flags_parse_varaccess(const char *flags)
{
char *access;
if (strlen(flags) <= ENV_FLAGS_VARACCESS_LOC)
return env_flags_varaccess_any;
access = strchr(env_flags_varaccess_rep,
flags[ENV_FLAGS_VARACCESS_LOC]);
if (access != NULL)
return (enum env_flags_varaccess)
(access - &env_flags_varaccess_rep[0]);
printf("## Warning: Unknown environment variable access method '%c'\n",
flags[ENV_FLAGS_VARACCESS_LOC]);
return env_flags_varaccess_any;
}
/*
* Parse the binary flags from a hash table entry into the varaccess enum.
*/
enum env_flags_varaccess env_flags_parse_varaccess_from_binflags(int binflags)
{
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;
printf("Warning: Non-standard access flags. (0x%x)\n",
binflags & ENV_FLAGS_VARACCESS_BIN_MASK);
return env_flags_varaccess_any;
}
static inline int is_hex_prefix(const char *value)
{
return value[0] == '0' && (value[1] == 'x' || value[1] == 'X');
}
static void skip_num(int hex, const char *value, const char **end,
int max_digits)
{
int i;
if (hex && is_hex_prefix(value))
value += 2;
for (i = max_digits; i != 0; i--) {
if (hex && !isxdigit(*value))
break;
if (!hex && !isdigit(*value))
break;
value++;
}
if (end != NULL)
*end = value;
}
#ifdef CONFIG_CMD_NET
int eth_validate_ethaddr_str(const char *addr)
{
const char *end;
const char *cur;
int i;
cur = addr;
for (i = 0; i < 6; i++) {
skip_num(1, cur, &end, 2);
if (cur == end)
return -1;
if (cur + 2 == end && is_hex_prefix(cur))
return -1;
if (i != 5 && *end != ':')
return -1;
if (i == 5 && *end != '\0')
return -1;
cur = end + 1;
}
return 0;
}
#endif
/*
* Based on the declared type enum, validate that the value string complies
* with that format
*/
static int _env_flags_validate_type(const char *value,
enum env_flags_vartype type)
{
const char *end;
#ifdef CONFIG_CMD_NET
const char *cur;
int i;
#endif
switch (type) {
case env_flags_vartype_string:
break;
case env_flags_vartype_decimal:
skip_num(0, value, &end, -1);
if (*end != '\0')
return -1;
break;
case env_flags_vartype_hex:
skip_num(1, value, &end, -1);
if (*end != '\0')
return -1;
if (value + 2 == end && is_hex_prefix(value))
return -1;
break;
case env_flags_vartype_bool:
if (value[0] != '1' && value[0] != 'y' && value[0] != 't' &&
value[0] != 'Y' && value[0] != 'T' &&
value[0] != '0' && value[0] != 'n' && value[0] != 'f' &&
value[0] != 'N' && value[0] != 'F')
return -1;
if (value[1] != '\0')
return -1;
break;
#ifdef CONFIG_CMD_NET
case env_flags_vartype_ipaddr:
cur = value;
for (i = 0; i < 4; i++) {
skip_num(0, cur, &end, 3);
if (cur == end)
return -1;
if (i != 3 && *end != '.')
return -1;
if (i == 3 && *end != '\0')
return -1;
cur = end + 1;
}
break;
case env_flags_vartype_macaddr:
if (eth_validate_ethaddr_str(value))
return -1;
break;
#endif
case env_flags_vartype_end:
return -1;
}
/* OK */
return 0;
}
/*
* Look for flags in a provided list and failing that the static list
*/
static inline int env_flags_lookup(const char *flags_list, const char *name,
char *flags)
{
int ret = 1;
if (!flags)
/* bad parameter */
return -1;
/* try the env first */
if (flags_list)
ret = env_attr_lookup(flags_list, name, flags);
if (ret != 0)
/* if not found in the env, look in the static list */
ret = env_attr_lookup(ENV_FLAGS_LIST_STATIC, name, flags);
return ret;
}
#ifdef USE_HOSTCC /* Functions only used from tools/env */
/*
* Look up any flags directly from the .flags variable and the static list
* and convert them to the vartype enum.
*/
enum env_flags_vartype env_flags_get_type(const char *name)
{
const char *flags_list = env_get(ENV_FLAGS_VAR);
char flags[ENV_FLAGS_ATTR_MAX_LEN + 1];
if (env_flags_lookup(flags_list, name, flags))
return env_flags_vartype_string;
if (strlen(flags) <= ENV_FLAGS_VARTYPE_LOC)
return env_flags_vartype_string;
return env_flags_parse_vartype(flags);
}
/*
* Look up the access of a variable directly from the .flags var.
*/
enum env_flags_varaccess env_flags_get_varaccess(const char *name)
{
const char *flags_list = env_get(ENV_FLAGS_VAR);
char flags[ENV_FLAGS_ATTR_MAX_LEN + 1];
if (env_flags_lookup(flags_list, name, flags))
return env_flags_varaccess_any;
if (strlen(flags) <= ENV_FLAGS_VARACCESS_LOC)
return env_flags_varaccess_any;
return env_flags_parse_varaccess(flags);
}
/*
* Validate that the proposed new value for "name" is valid according to the
* defined flags for that variable, if any.
*/
int env_flags_validate_type(const char *name, const char *value)
{
enum env_flags_vartype type;
if (value == NULL)
return 0;
type = env_flags_get_type(name);
if (_env_flags_validate_type(value, type) < 0) {
printf("## Error: flags type check failure for "
"\"%s\" <= \"%s\" (type: %c)\n",
name, value, env_flags_vartype_rep[type]);
return -1;
}
return 0;
}
/*
* Validate that the proposed access to variable "name" is valid according to
* the defined flags for that variable, if any.
*/
int env_flags_validate_varaccess(const char *name, int check_mask)
{
enum env_flags_varaccess access;
int access_mask;
access = env_flags_get_varaccess(name);
access_mask = env_flags_varaccess_mask[access];
return (check_mask & access_mask) != 0;
}
/*
* Validate the parameters to "env set" directly
*/
int env_flags_validate_env_set_params(char *name, char * const val[], int count)
{
if ((count >= 1) && val[0] != NULL) {
enum env_flags_vartype type = env_flags_get_type(name);
/*
* we don't currently check types that need more than
* one argument
*/
if (type != env_flags_vartype_string && count > 1) {
printf("## Error: too many parameters for setting \"%s\"\n",
name);
return -1;
}
return env_flags_validate_type(name, val[0]);
}
/* ok */
return 0;
}
#else /* !USE_HOSTCC - Functions only used from lib/hashtable.c */
/*
* Parse the flag charachters from the .flags attribute list into the binary
* form to be stored in the environment entry->flags field.
*/
static int env_parse_flags_to_bin(const char *flags)
{
int binflags;
binflags = env_flags_parse_vartype(flags) & ENV_FLAGS_VARTYPE_BIN_MASK;
binflags |= env_flags_varaccess_mask[env_flags_parse_varaccess(flags)];
return binflags;
}
static int first_call = 1;
static const char *flags_list;
/*
* Look for possible flags for a newly added variable
* This is called specifically when the variable did not exist in the hash
* previously, so the blanket update did not find this variable.
*/
void env_flags_init(struct env_entry *var_entry)
{
const char *var_name = var_entry->key;
char flags[ENV_FLAGS_ATTR_MAX_LEN + 1] = "";
int ret = 1;
if (first_call) {
flags_list = env_get(ENV_FLAGS_VAR);
first_call = 0;
}
/* look in the ".flags" and static for a reference to this variable */
ret = env_flags_lookup(flags_list, var_name, flags);
/* if any flags were found, set the binary form to the entry */
if (!ret && strlen(flags))
var_entry->flags = env_parse_flags_to_bin(flags);
}
/*
* Called on each existing env var prior to the blanket update since removing
* a flag in the flag list should remove its flags.
*/
static int clear_flags(struct env_entry *entry)
{
entry->flags = 0;
return 0;
}
/*
* Call for each element in the list that defines flags for a variable
*/
static int set_flags(const char *name, const char *value, void *priv)
{
struct env_entry e, *ep;
e.key = name;
e.data = NULL;
e.callback = NULL;
hsearch_r(e, ENV_FIND, &ep, &env_htab, 0);
/* does the env variable actually exist? */
if (ep != NULL) {
/* the flag list is empty, so clear the flags */
if (value == NULL || strlen(value) == 0)
ep->flags = 0;
else
/* assign the requested flags */
ep->flags = env_parse_flags_to_bin(value);
}
return 0;
}
static int on_flags(const char *name, const char *value, enum env_op op,
int flags)
{
/* remove all flags */
hwalk_r(&env_htab, clear_flags);
/* configure any static flags */
env_attr_walk(ENV_FLAGS_LIST_STATIC, set_flags, NULL);
/* configure any dynamic flags */
env_attr_walk(value, set_flags, NULL);
return 0;
}
U_BOOT_ENV_CALLBACK(flags, on_flags);
/*
* Perform consistency checking before creating, overwriting, or deleting an
* environment variable. Called as a callback function by hsearch_r() and
* hdelete_r(). Returns 0 in case of success, 1 in case of failure.
* When (flag & H_FORCE) is set, do not print out any error message and force
* overwriting of write-once variables.
*/
int env_flags_validate(const struct env_entry *item, const char *newval,
enum env_op op, int flag)
{
const char *name;
const char *oldval = NULL;
if (op != env_op_create)
oldval = item->data;
name = item->key;
/* Default value for NULL to protect string-manipulating functions */
newval = newval ? : "";
/* validate the value to match the variable type */
if (op != env_op_delete) {
enum env_flags_vartype type = (enum env_flags_vartype)
(ENV_FLAGS_VARTYPE_BIN_MASK & item->flags);
if (_env_flags_validate_type(newval, type) < 0) {
printf("## Error: flags type check failure for "
"\"%s\" <= \"%s\" (type: %c)\n",
name, newval, env_flags_vartype_rep[type]);
return -1;
}
}
/* check for access permission */
#ifndef CONFIG_ENV_ACCESS_IGNORE_FORCE
if (flag & H_FORCE)
return 0;
#endif
switch (op) {
case env_op_delete:
if (item->flags & ENV_FLAGS_VARACCESS_PREVENT_DELETE) {
printf("## Error: Can't delete \"%s\"\n", name);
return 1;
}
break;
case env_op_overwrite:
if (item->flags & ENV_FLAGS_VARACCESS_PREVENT_OVERWR) {
printf("## Error: Can't overwrite \"%s\"\n", name);
return 1;
} else if (item->flags &
ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR) {
const char *defval = env_get_default(name);
if (defval == NULL)
defval = "";
printf("oldval: %s defval: %s\n", oldval, defval);
if (strcmp(oldval, defval) != 0) {
printf("## Error: Can't overwrite \"%s\"\n",
name);
return 1;
}
}
break;
case env_op_create:
if (item->flags & ENV_FLAGS_VARACCESS_PREVENT_CREATE) {
printf("## Error: Can't create \"%s\"\n", name);
return 1;
}
break;
}
return 0;
}
#endif
+368
View File
@@ -0,0 +1,368 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2000-2010
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
* Andreas Heppel <aheppel@sysgo.de>
*/
/* #define DEBUG */
#include <common.h>
#include <command.h>
#include <env.h>
#include <env_internal.h>
#include <linux/stddef.h>
#include <malloc.h>
#include <search.h>
#include <errno.h>
#include <u-boot/crc.h>
DECLARE_GLOBAL_DATA_PTR;
#ifndef CONFIG_SPL_BUILD
# if defined(CONFIG_CMD_SAVEENV) && defined(CONFIG_CMD_FLASH)
# define CMD_SAVEENV
# elif defined(CONFIG_ENV_ADDR_REDUND)
# error CONFIG_ENV_ADDR_REDUND must have CONFIG_CMD_SAVEENV & CONFIG_CMD_FLASH
# endif
#endif
/* TODO(sjg@chromium.org): Figure out all these special cases */
#if (!defined(CONFIG_MICROBLAZE) && !defined(CONFIG_ARCH_ZYNQ) && \
!defined(CONFIG_TARGET_MCCMON6) && !defined(CONFIG_TARGET_X600) && \
!defined(CONFIG_TARGET_EDMINIV2)) || \
!defined(CONFIG_SPL_BUILD)
#define LOADENV
#endif
#if !defined(CONFIG_TARGET_X600) || !defined(CONFIG_SPL_BUILD)
#define INITENV
#endif
#if defined(CONFIG_ENV_ADDR_REDUND) && defined(CMD_SAVEENV) || \
!defined(CONFIG_ENV_ADDR_REDUND) && defined(INITENV)
#ifdef ENV_IS_EMBEDDED
static env_t *env_ptr = &embedded_environment;
#else /* ! ENV_IS_EMBEDDED */
static env_t *env_ptr = (env_t *)CONFIG_ENV_ADDR;
#endif /* ENV_IS_EMBEDDED */
#endif
static __maybe_unused env_t *flash_addr = (env_t *)CONFIG_ENV_ADDR;
/* CONFIG_ENV_ADDR is supposed to be on sector boundary */
static ulong __maybe_unused end_addr =
CONFIG_ENV_ADDR + CONFIG_ENV_SECT_SIZE - 1;
#ifdef CONFIG_ENV_ADDR_REDUND
static env_t __maybe_unused *flash_addr_new = (env_t *)CONFIG_ENV_ADDR_REDUND;
/* CONFIG_ENV_ADDR_REDUND is supposed to be on sector boundary */
static ulong __maybe_unused end_addr_new =
CONFIG_ENV_ADDR_REDUND + CONFIG_ENV_SECT_SIZE - 1;
#endif /* CONFIG_ENV_ADDR_REDUND */
#ifdef CONFIG_ENV_ADDR_REDUND
#ifdef INITENV
static int env_flash_init(void)
{
int crc1_ok = 0, crc2_ok = 0;
uchar flag1 = flash_addr->flags;
uchar flag2 = flash_addr_new->flags;
ulong addr_default = (ulong)&default_environment[0];
ulong addr1 = (ulong)&(flash_addr->data);
ulong addr2 = (ulong)&(flash_addr_new->data);
crc1_ok = crc32(0, flash_addr->data, ENV_SIZE) == flash_addr->crc;
crc2_ok =
crc32(0, flash_addr_new->data, ENV_SIZE) == flash_addr_new->crc;
if (crc1_ok && !crc2_ok) {
gd->env_addr = addr1;
gd->env_valid = ENV_VALID;
} else if (!crc1_ok && crc2_ok) {
gd->env_addr = addr2;
gd->env_valid = ENV_VALID;
} else if (!crc1_ok && !crc2_ok) {
gd->env_addr = addr_default;
gd->env_valid = ENV_INVALID;
} else if (flag1 == ENV_REDUND_ACTIVE &&
flag2 == ENV_REDUND_OBSOLETE) {
gd->env_addr = addr1;
gd->env_valid = ENV_VALID;
} else if (flag1 == ENV_REDUND_OBSOLETE &&
flag2 == ENV_REDUND_ACTIVE) {
gd->env_addr = addr2;
gd->env_valid = ENV_VALID;
} else if (flag1 == flag2) {
gd->env_addr = addr1;
gd->env_valid = ENV_REDUND;
} else if (flag1 == 0xFF) {
gd->env_addr = addr1;
gd->env_valid = ENV_REDUND;
} else if (flag2 == 0xFF) {
gd->env_addr = addr2;
gd->env_valid = ENV_REDUND;
}
return 0;
}
#endif
#ifdef CMD_SAVEENV
static int env_flash_save(void)
{
env_t env_new;
char *saved_data = NULL;
char flag = ENV_REDUND_OBSOLETE, new_flag = ENV_REDUND_ACTIVE;
int rc = 1;
#if CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE
ulong up_data = 0;
#endif
debug("Protect off %08lX ... %08lX\n", (ulong)flash_addr, end_addr);
if (flash_sect_protect(0, (ulong)flash_addr, end_addr))
goto done;
debug("Protect off %08lX ... %08lX\n",
(ulong)flash_addr_new, end_addr_new);
if (flash_sect_protect(0, (ulong)flash_addr_new, end_addr_new))
goto done;
rc = env_export(&env_new);
if (rc)
return rc;
env_new.flags = new_flag;
#if CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE
up_data = end_addr_new + 1 - ((long)flash_addr_new + CONFIG_ENV_SIZE);
debug("Data to save 0x%lX\n", up_data);
if (up_data) {
saved_data = malloc(up_data);
if (saved_data == NULL) {
printf("Unable to save the rest of sector (%ld)\n",
up_data);
goto done;
}
memcpy(saved_data,
(void *)((long)flash_addr_new + CONFIG_ENV_SIZE),
up_data);
debug("Data (start 0x%lX, len 0x%lX) saved at 0x%p\n",
(long)flash_addr_new + CONFIG_ENV_SIZE,
up_data, saved_data);
}
#endif
puts("Erasing Flash...");
debug(" %08lX ... %08lX ...", (ulong)flash_addr_new, end_addr_new);
if (flash_sect_erase((ulong)flash_addr_new, end_addr_new))
goto done;
puts("Writing to Flash... ");
debug(" %08lX ... %08lX ...",
(ulong)&(flash_addr_new->data),
sizeof(env_ptr->data) + (ulong)&(flash_addr_new->data));
rc = flash_write((char *)&env_new, (ulong)flash_addr_new,
sizeof(env_new));
if (rc)
goto perror;
rc = flash_write(&flag, (ulong)&(flash_addr->flags),
sizeof(flash_addr->flags));
if (rc)
goto perror;
#if CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE
if (up_data) { /* restore the rest of sector */
debug("Restoring the rest of data to 0x%lX len 0x%lX\n",
(long)flash_addr_new + CONFIG_ENV_SIZE, up_data);
if (flash_write(saved_data,
(long)flash_addr_new + CONFIG_ENV_SIZE,
up_data))
goto perror;
}
#endif
puts("done\n");
{
env_t *etmp = flash_addr;
ulong ltmp = end_addr;
flash_addr = flash_addr_new;
flash_addr_new = etmp;
end_addr = end_addr_new;
end_addr_new = ltmp;
}
rc = 0;
goto done;
perror:
flash_perror(rc);
done:
if (saved_data)
free(saved_data);
/* try to re-protect */
flash_sect_protect(1, (ulong)flash_addr, end_addr);
flash_sect_protect(1, (ulong)flash_addr_new, end_addr_new);
return rc;
}
#endif /* CMD_SAVEENV */
#else /* ! CONFIG_ENV_ADDR_REDUND */
#ifdef INITENV
static int env_flash_init(void)
{
if (crc32(0, env_ptr->data, ENV_SIZE) == env_ptr->crc) {
gd->env_addr = (ulong)&(env_ptr->data);
gd->env_valid = ENV_VALID;
return 0;
}
gd->env_addr = (ulong)&default_environment[0];
gd->env_valid = ENV_INVALID;
return 0;
}
#endif
#ifdef CMD_SAVEENV
static int env_flash_save(void)
{
env_t env_new;
int rc = 1;
char *saved_data = NULL;
#if CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE
ulong up_data = 0;
up_data = end_addr + 1 - ((long)flash_addr + CONFIG_ENV_SIZE);
debug("Data to save 0x%lx\n", up_data);
if (up_data) {
saved_data = malloc(up_data);
if (saved_data == NULL) {
printf("Unable to save the rest of sector (%ld)\n",
up_data);
goto done;
}
memcpy(saved_data,
(void *)((long)flash_addr + CONFIG_ENV_SIZE), up_data);
debug("Data (start 0x%lx, len 0x%lx) saved at 0x%lx\n",
(ulong)flash_addr + CONFIG_ENV_SIZE,
up_data,
(ulong)saved_data);
}
#endif /* CONFIG_ENV_SECT_SIZE */
debug("Protect off %08lX ... %08lX\n", (ulong)flash_addr, end_addr);
if (flash_sect_protect(0, (long)flash_addr, end_addr))
goto done;
rc = env_export(&env_new);
if (rc)
goto done;
puts("Erasing Flash...");
if (flash_sect_erase((long)flash_addr, end_addr))
goto done;
puts("Writing to Flash... ");
rc = flash_write((char *)&env_new, (long)flash_addr, CONFIG_ENV_SIZE);
if (rc != 0)
goto perror;
#if CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE
if (up_data) { /* restore the rest of sector */
debug("Restoring the rest of data to 0x%lx len 0x%lx\n",
(ulong)flash_addr + CONFIG_ENV_SIZE, up_data);
if (flash_write(saved_data,
(long)flash_addr + CONFIG_ENV_SIZE,
up_data))
goto perror;
}
#endif
puts("done\n");
rc = 0;
goto done;
perror:
flash_perror(rc);
done:
if (saved_data)
free(saved_data);
/* try to re-protect */
flash_sect_protect(1, (long)flash_addr, end_addr);
return rc;
}
#endif /* CMD_SAVEENV */
#endif /* CONFIG_ENV_ADDR_REDUND */
#ifdef LOADENV
static int env_flash_load(void)
{
#ifdef CONFIG_ENV_ADDR_REDUND
if (gd->env_addr != (ulong)&(flash_addr->data)) {
env_t *etmp = flash_addr;
ulong ltmp = end_addr;
flash_addr = flash_addr_new;
flash_addr_new = etmp;
end_addr = end_addr_new;
end_addr_new = ltmp;
}
if (flash_addr_new->flags != ENV_REDUND_OBSOLETE &&
crc32(0, flash_addr_new->data, ENV_SIZE) == flash_addr_new->crc) {
char flag = ENV_REDUND_OBSOLETE;
gd->env_valid = ENV_REDUND;
flash_sect_protect(0, (ulong)flash_addr_new, end_addr_new);
flash_write(&flag,
(ulong)&(flash_addr_new->flags),
sizeof(flash_addr_new->flags));
flash_sect_protect(1, (ulong)flash_addr_new, end_addr_new);
}
if (flash_addr->flags != ENV_REDUND_ACTIVE &&
(flash_addr->flags & ENV_REDUND_ACTIVE) == ENV_REDUND_ACTIVE) {
char flag = ENV_REDUND_ACTIVE;
gd->env_valid = ENV_REDUND;
flash_sect_protect(0, (ulong)flash_addr, end_addr);
flash_write(&flag,
(ulong)&(flash_addr->flags),
sizeof(flash_addr->flags));
flash_sect_protect(1, (ulong)flash_addr, end_addr);
}
if (gd->env_valid == ENV_REDUND)
puts("*** Warning - some problems detected "
"reading environment; recovered successfully\n\n");
#endif /* CONFIG_ENV_ADDR_REDUND */
return env_import((char *)flash_addr, 1);
}
#endif /* LOADENV */
U_BOOT_ENV_LOCATION(flash) = {
.location = ENVL_FLASH,
ENV_NAME("Flash")
#ifdef LOADENV
.load = env_flash_load,
#endif
#ifdef CMD_SAVEENV
.save = env_save_ptr(env_flash_save),
#endif
#ifdef INITENV
.init = env_flash_init,
#endif
};
+398
View File
@@ -0,0 +1,398 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2008-2011 Freescale Semiconductor, Inc.
*/
/* #define DEBUG */
#include <common.h>
#include <command.h>
#include <env.h>
#include <env_internal.h>
#include <fdtdec.h>
#include <linux/stddef.h>
#include <malloc.h>
#include <memalign.h>
#include <mmc.h>
#include <part.h>
#include <search.h>
#include <errno.h>
#define __STR(X) #X
#define STR(X) __STR(X)
DECLARE_GLOBAL_DATA_PTR;
#if CONFIG_IS_ENABLED(OF_CONTROL)
static inline int mmc_offset_try_partition(const char *str, s64 *val)
{
disk_partition_t info;
struct blk_desc *desc;
int len, i, ret;
ret = blk_get_device_by_str("mmc", STR(CONFIG_SYS_MMC_ENV_DEV), &desc);
if (ret < 0)
return (ret);
for (i = 1;;i++) {
ret = part_get_info(desc, i, &info);
if (ret < 0)
return ret;
if (!strncmp((const char *)info.name, str, sizeof(str)))
break;
}
/* round up to info.blksz */
len = (CONFIG_ENV_SIZE + info.blksz - 1) & ~(info.blksz - 1);
/* use the top of the partion for the environment */
*val = (info.start + info.size - 1) - len / info.blksz;
return 0;
}
static inline s64 mmc_offset(int copy)
{
const struct {
const char *offset_redund;
const char *partition;
const char *offset;
} dt_prop = {
.offset_redund = "u-boot,mmc-env-offset-redundant",
.partition = "u-boot,mmc-env-partition",
.offset = "u-boot,mmc-env-offset",
};
s64 val = 0, defvalue;
const char *propname;
const char *str;
int err;
/* look for the partition in mmc CONFIG_SYS_MMC_ENV_DEV */
str = fdtdec_get_config_string(gd->fdt_blob, dt_prop.partition);
if (str) {
/* try to place the environment at end of the partition */
err = mmc_offset_try_partition(str, &val);
if (!err)
return val;
}
defvalue = CONFIG_ENV_OFFSET;
propname = dt_prop.offset;
#if defined(CONFIG_ENV_OFFSET_REDUND)
if (copy) {
defvalue = CONFIG_ENV_OFFSET_REDUND;
propname = dt_prop.offset_redund;
}
#endif
return fdtdec_get_config_int(gd->fdt_blob, propname, defvalue);
}
#else
static inline s64 mmc_offset(int copy)
{
s64 offset = CONFIG_ENV_OFFSET;
#if defined(CONFIG_ENV_OFFSET_REDUND)
if (copy)
offset = CONFIG_ENV_OFFSET_REDUND;
#endif
return offset;
}
#endif
__weak int mmc_get_env_addr(struct mmc *mmc, int copy, u32 *env_addr)
{
s64 offset = mmc_offset(copy);
if (offset < 0)
offset += mmc->capacity;
*env_addr = offset;
return 0;
}
__weak int mmc_get_env_dev(void)
{
return CONFIG_SYS_MMC_ENV_DEV;
}
#ifdef CONFIG_SYS_MMC_ENV_PART
__weak uint mmc_get_env_part(struct mmc *mmc)
{
return CONFIG_SYS_MMC_ENV_PART;
}
static unsigned char env_mmc_orig_hwpart;
static int mmc_set_env_part(struct mmc *mmc)
{
uint part = mmc_get_env_part(mmc);
int dev = mmc_get_env_dev();
int ret = 0;
env_mmc_orig_hwpart = mmc_get_blk_desc(mmc)->hwpart;
ret = blk_select_hwpart_devnum(IF_TYPE_MMC, dev, part);
if (ret)
puts("MMC partition switch failed\n");
return ret;
}
#else
static inline int mmc_set_env_part(struct mmc *mmc) {return 0; };
#endif
static const char *init_mmc_for_env(struct mmc *mmc)
{
if (!mmc)
return "No MMC card found";
#if CONFIG_IS_ENABLED(BLK)
struct udevice *dev;
if (blk_get_from_parent(mmc->dev, &dev))
return "No block device";
#else
if (mmc_init(mmc))
return "MMC init failed";
#endif
if (mmc_set_env_part(mmc))
return "MMC partition switch failed";
return NULL;
}
static void fini_mmc_for_env(struct mmc *mmc)
{
#ifdef CONFIG_SYS_MMC_ENV_PART
int dev = mmc_get_env_dev();
blk_select_hwpart_devnum(IF_TYPE_MMC, dev, env_mmc_orig_hwpart);
#endif
}
#if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_SPL_BUILD)
static inline int write_env(struct mmc *mmc, unsigned long size,
unsigned long offset, const void *buffer)
{
uint blk_start, blk_cnt, n;
struct blk_desc *desc = mmc_get_blk_desc(mmc);
blk_start = ALIGN(offset, mmc->write_bl_len) / mmc->write_bl_len;
blk_cnt = ALIGN(size, mmc->write_bl_len) / mmc->write_bl_len;
n = blk_dwrite(desc, blk_start, blk_cnt, (u_char *)buffer);
return (n == blk_cnt) ? 0 : -1;
}
static int env_mmc_save(void)
{
ALLOC_CACHE_ALIGN_BUFFER(env_t, env_new, 1);
int dev = mmc_get_env_dev();
struct mmc *mmc = find_mmc_device(dev);
u32 offset;
int ret, copy = 0;
const char *errmsg;
errmsg = init_mmc_for_env(mmc);
if (errmsg) {
printf("%s\n", errmsg);
return 1;
}
ret = env_export(env_new);
if (ret)
goto fini;
#ifdef CONFIG_ENV_OFFSET_REDUND
if (gd->env_valid == ENV_VALID)
copy = 1;
#endif
if (mmc_get_env_addr(mmc, copy, &offset)) {
ret = 1;
goto fini;
}
printf("Writing to %sMMC(%d)... ", copy ? "redundant " : "", dev);
if (write_env(mmc, CONFIG_ENV_SIZE, offset, (u_char *)env_new)) {
puts("failed\n");
ret = 1;
goto fini;
}
ret = 0;
#ifdef CONFIG_ENV_OFFSET_REDUND
gd->env_valid = gd->env_valid == ENV_REDUND ? ENV_VALID : ENV_REDUND;
#endif
fini:
fini_mmc_for_env(mmc);
return ret;
}
#if defined(CONFIG_CMD_ERASEENV)
static inline int erase_env(struct mmc *mmc, unsigned long size,
unsigned long offset)
{
uint blk_start, blk_cnt, n;
struct blk_desc *desc = mmc_get_blk_desc(mmc);
blk_start = ALIGN(offset, mmc->write_bl_len) / mmc->write_bl_len;
blk_cnt = ALIGN(size, mmc->write_bl_len) / mmc->write_bl_len;
n = blk_derase(desc, blk_start, blk_cnt);
printf("%d blocks erased: %s\n", n, (n == blk_cnt) ? "OK" : "ERROR");
return (n == blk_cnt) ? 0 : 1;
}
static int env_mmc_erase(void)
{
int dev = mmc_get_env_dev();
struct mmc *mmc = find_mmc_device(dev);
int ret, copy = 0;
u32 offset;
const char *errmsg;
errmsg = init_mmc_for_env(mmc);
if (errmsg) {
printf("%s\n", errmsg);
return 1;
}
if (mmc_get_env_addr(mmc, copy, &offset))
return CMD_RET_FAILURE;
ret = erase_env(mmc, CONFIG_ENV_SIZE, offset);
#ifdef CONFIG_ENV_OFFSET_REDUND
copy = 1;
if (mmc_get_env_addr(mmc, copy, &offset))
return CMD_RET_FAILURE;
ret |= erase_env(mmc, CONFIG_ENV_SIZE, offset);
#endif
return ret;
}
#endif /* CONFIG_CMD_ERASEENV */
#endif /* CONFIG_CMD_SAVEENV && !CONFIG_SPL_BUILD */
static inline int read_env(struct mmc *mmc, unsigned long size,
unsigned long offset, const void *buffer)
{
uint blk_start, blk_cnt, n;
struct blk_desc *desc = mmc_get_blk_desc(mmc);
blk_start = ALIGN(offset, mmc->read_bl_len) / mmc->read_bl_len;
blk_cnt = ALIGN(size, mmc->read_bl_len) / mmc->read_bl_len;
n = blk_dread(desc, blk_start, blk_cnt, (uchar *)buffer);
return (n == blk_cnt) ? 0 : -1;
}
#ifdef CONFIG_ENV_OFFSET_REDUND
static int env_mmc_load(void)
{
#if !defined(ENV_IS_EMBEDDED)
struct mmc *mmc;
u32 offset1, offset2;
int read1_fail = 0, read2_fail = 0;
int ret;
int dev = mmc_get_env_dev();
const char *errmsg = NULL;
ALLOC_CACHE_ALIGN_BUFFER(env_t, tmp_env1, 1);
ALLOC_CACHE_ALIGN_BUFFER(env_t, tmp_env2, 1);
mmc_initialize(NULL);
mmc = find_mmc_device(dev);
errmsg = init_mmc_for_env(mmc);
if (errmsg) {
ret = -EIO;
goto err;
}
if (mmc_get_env_addr(mmc, 0, &offset1) ||
mmc_get_env_addr(mmc, 1, &offset2)) {
ret = -EIO;
goto fini;
}
read1_fail = read_env(mmc, CONFIG_ENV_SIZE, offset1, tmp_env1);
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);
fini:
fini_mmc_for_env(mmc);
err:
if (ret)
env_set_default(errmsg, 0);
#endif
return ret;
}
#else /* ! CONFIG_ENV_OFFSET_REDUND */
static int env_mmc_load(void)
{
#if !defined(ENV_IS_EMBEDDED)
ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_SIZE);
struct mmc *mmc;
u32 offset;
int ret;
int dev = mmc_get_env_dev();
const char *errmsg;
mmc = find_mmc_device(dev);
errmsg = init_mmc_for_env(mmc);
if (errmsg) {
ret = -EIO;
goto err;
}
if (mmc_get_env_addr(mmc, 0, &offset)) {
ret = -EIO;
goto fini;
}
if (read_env(mmc, CONFIG_ENV_SIZE, offset, buf)) {
errmsg = "!read failed";
ret = -EIO;
goto fini;
}
ret = env_import(buf, 1);
fini:
fini_mmc_for_env(mmc);
err:
if (ret)
env_set_default(errmsg, 0);
#endif
return ret;
}
#endif /* CONFIG_ENV_OFFSET_REDUND */
U_BOOT_ENV_LOCATION(mmc) = {
.location = ENVL_MMC,
ENV_NAME("MMC")
.load = env_mmc_load,
#ifndef CONFIG_SPL_BUILD
.save = env_save_ptr(env_mmc_save),
#if defined(CONFIG_CMD_ERASEENV)
.erase = env_mmc_erase,
#endif
#endif
};
+390
View File
@@ -0,0 +1,390 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2000-2010
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* (C) Copyright 2008
* Stuart Wood, Lab X Technologies <stuart.wood@labxtechnologies.com>
*
* (C) Copyright 2004
* Jian Zhang, Texas Instruments, jzhang@ti.com.
*
* (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
* Andreas Heppel <aheppel@sysgo.de>
*/
#include <common.h>
#include <command.h>
#include <env.h>
#include <env_internal.h>
#include <linux/stddef.h>
#include <malloc.h>
#include <memalign.h>
#include <nand.h>
#include <search.h>
#include <errno.h>
#include <u-boot/crc.h>
#if defined(CONFIG_CMD_SAVEENV) && defined(CONFIG_CMD_NAND) && \
!defined(CONFIG_SPL_BUILD)
#define CMD_SAVEENV
#elif defined(CONFIG_ENV_OFFSET_REDUND) && !defined(CONFIG_SPL_BUILD)
#error CONFIG_ENV_OFFSET_REDUND must have CONFIG_CMD_SAVEENV & CONFIG_CMD_NAND
#endif
#ifndef CONFIG_ENV_RANGE
#define CONFIG_ENV_RANGE CONFIG_ENV_SIZE
#endif
#if defined(ENV_IS_EMBEDDED)
static env_t *env_ptr = &environment;
#elif defined(CONFIG_NAND_ENV_DST)
static env_t *env_ptr = (env_t *)CONFIG_NAND_ENV_DST;
#endif /* ENV_IS_EMBEDDED */
DECLARE_GLOBAL_DATA_PTR;
/*
* This is called before nand_init() so we can't read NAND to
* validate env data.
*
* Mark it OK for now. env_relocate() in env_common.c will call our
* relocate function which does the real validation.
*
* When using a NAND boot image (like sequoia_nand), the environment
* can be embedded or attached to the U-Boot image in NAND flash.
* This way the SPL loads not only the U-Boot image from NAND but
* also the environment.
*/
static int env_nand_init(void)
{
#if defined(ENV_IS_EMBEDDED) || defined(CONFIG_NAND_ENV_DST)
int crc1_ok = 0, crc2_ok = 0;
env_t *tmp_env1;
#ifdef CONFIG_ENV_OFFSET_REDUND
env_t *tmp_env2;
tmp_env2 = (env_t *)((ulong)env_ptr + CONFIG_ENV_SIZE);
crc2_ok = crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc;
#endif
tmp_env1 = env_ptr;
crc1_ok = crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc;
if (!crc1_ok && !crc2_ok) {
gd->env_addr = 0;
gd->env_valid = ENV_INVALID;
return 0;
} else if (crc1_ok && !crc2_ok) {
gd->env_valid = ENV_VALID;
}
#ifdef CONFIG_ENV_OFFSET_REDUND
else if (!crc1_ok && crc2_ok) {
gd->env_valid = ENV_REDUND;
} else {
/* both ok - check serial */
if (tmp_env1->flags == 255 && tmp_env2->flags == 0)
gd->env_valid = ENV_REDUND;
else if (tmp_env2->flags == 255 && tmp_env1->flags == 0)
gd->env_valid = ENV_VALID;
else if (tmp_env1->flags > tmp_env2->flags)
gd->env_valid = ENV_VALID;
else if (tmp_env2->flags > tmp_env1->flags)
gd->env_valid = ENV_REDUND;
else /* flags are equal - almost impossible */
gd->env_valid = ENV_VALID;
}
if (gd->env_valid == ENV_REDUND)
env_ptr = tmp_env2;
else
#endif
if (gd->env_valid == ENV_VALID)
env_ptr = tmp_env1;
gd->env_addr = (ulong)env_ptr->data;
#else /* ENV_IS_EMBEDDED || CONFIG_NAND_ENV_DST */
gd->env_addr = (ulong)&default_environment[0];
gd->env_valid = ENV_VALID;
#endif /* ENV_IS_EMBEDDED || CONFIG_NAND_ENV_DST */
return 0;
}
#ifdef CMD_SAVEENV
/*
* The legacy NAND code saved the environment in the first NAND device i.e.,
* nand_dev_desc + 0. This is also the behaviour using the new NAND code.
*/
static int writeenv(size_t offset, u_char *buf)
{
size_t end = offset + CONFIG_ENV_RANGE;
size_t amount_saved = 0;
size_t blocksize, len;
struct mtd_info *mtd;
u_char *char_ptr;
mtd = get_nand_dev_by_index(0);
if (!mtd)
return 1;
blocksize = mtd->erasesize;
len = min(blocksize, (size_t)CONFIG_ENV_SIZE);
while (amount_saved < CONFIG_ENV_SIZE && offset < end) {
if (nand_block_isbad(mtd, offset)) {
offset += blocksize;
} else {
char_ptr = &buf[amount_saved];
if (nand_write(mtd, offset, &len, char_ptr))
return 1;
offset += blocksize;
amount_saved += len;
}
}
if (amount_saved != CONFIG_ENV_SIZE)
return 1;
return 0;
}
struct nand_env_location {
const char *name;
const nand_erase_options_t erase_opts;
};
static int erase_and_write_env(const struct nand_env_location *location,
u_char *env_new)
{
struct mtd_info *mtd;
int ret = 0;
mtd = get_nand_dev_by_index(0);
if (!mtd)
return 1;
printf("Erasing %s...\n", location->name);
if (nand_erase_opts(mtd, &location->erase_opts))
return 1;
printf("Writing to %s... ", location->name);
ret = writeenv(location->erase_opts.offset, env_new);
puts(ret ? "FAILED!\n" : "OK\n");
return ret;
}
static int env_nand_save(void)
{
int ret = 0;
ALLOC_CACHE_ALIGN_BUFFER(env_t, env_new, 1);
int env_idx = 0;
static const struct nand_env_location location[] = {
{
.name = "NAND",
.erase_opts = {
.length = CONFIG_ENV_RANGE,
.offset = CONFIG_ENV_OFFSET,
},
},
#ifdef CONFIG_ENV_OFFSET_REDUND
{
.name = "redundant NAND",
.erase_opts = {
.length = CONFIG_ENV_RANGE,
.offset = CONFIG_ENV_OFFSET_REDUND,
},
},
#endif
};
if (CONFIG_ENV_RANGE < CONFIG_ENV_SIZE)
return 1;
ret = env_export(env_new);
if (ret)
return ret;
#ifdef CONFIG_ENV_OFFSET_REDUND
env_idx = (gd->env_valid == ENV_VALID);
#endif
ret = erase_and_write_env(&location[env_idx], (u_char *)env_new);
#ifdef CONFIG_ENV_OFFSET_REDUND
if (!ret) {
/* preset other copy for next write */
gd->env_valid = gd->env_valid == ENV_REDUND ? ENV_VALID :
ENV_REDUND;
return ret;
}
env_idx = (env_idx + 1) & 1;
ret = erase_and_write_env(&location[env_idx], (u_char *)env_new);
if (!ret)
printf("Warning: primary env write failed,"
" redundancy is lost!\n");
#endif
return ret;
}
#endif /* CMD_SAVEENV */
#if defined(CONFIG_SPL_BUILD)
static int readenv(size_t offset, u_char *buf)
{
return nand_spl_load_image(offset, CONFIG_ENV_SIZE, buf);
}
#else
static int readenv(size_t offset, u_char *buf)
{
size_t end = offset + CONFIG_ENV_RANGE;
size_t amount_loaded = 0;
size_t blocksize, len;
struct mtd_info *mtd;
u_char *char_ptr;
mtd = get_nand_dev_by_index(0);
if (!mtd)
return 1;
blocksize = mtd->erasesize;
len = min(blocksize, (size_t)CONFIG_ENV_SIZE);
while (amount_loaded < CONFIG_ENV_SIZE && offset < end) {
if (nand_block_isbad(mtd, offset)) {
offset += blocksize;
} else {
char_ptr = &buf[amount_loaded];
if (nand_read_skip_bad(mtd, offset,
&len, NULL,
mtd->size, char_ptr))
return 1;
offset += blocksize;
amount_loaded += len;
}
}
if (amount_loaded != CONFIG_ENV_SIZE)
return 1;
return 0;
}
#endif /* #if defined(CONFIG_SPL_BUILD) */
#ifdef CONFIG_ENV_OFFSET_OOB
int get_nand_env_oob(struct mtd_info *mtd, unsigned long *result)
{
struct mtd_oob_ops ops;
uint32_t oob_buf[ENV_OFFSET_SIZE / sizeof(uint32_t)];
int ret;
ops.datbuf = NULL;
ops.mode = MTD_OOB_AUTO;
ops.ooboffs = 0;
ops.ooblen = ENV_OFFSET_SIZE;
ops.oobbuf = (void *)oob_buf;
ret = mtd->read_oob(mtd, ENV_OFFSET_SIZE, &ops);
if (ret) {
printf("error reading OOB block 0\n");
return ret;
}
if (oob_buf[0] == ENV_OOB_MARKER) {
*result = ovoid ob_buf[1] * mtd->erasesize;
} else if (oob_buf[0] == ENV_OOB_MARKER_OLD) {
*result = oob_buf[1];
} else {
printf("No dynamic environment marker in OOB block 0\n");
return -ENOENT;
}
return 0;
}
#endif
#ifdef CONFIG_ENV_OFFSET_REDUND
static int env_nand_load(void)
{
#if defined(ENV_IS_EMBEDDED)
return 0;
#else
int read1_fail, read2_fail;
env_t *tmp_env1, *tmp_env2;
int ret = 0;
tmp_env1 = (env_t *)malloc(CONFIG_ENV_SIZE);
tmp_env2 = (env_t *)malloc(CONFIG_ENV_SIZE);
if (tmp_env1 == NULL || tmp_env2 == NULL) {
puts("Can't allocate buffers for environment\n");
env_set_default("malloc() failed", 0);
ret = -EIO;
goto done;
}
read1_fail = readenv(CONFIG_ENV_OFFSET, (u_char *) tmp_env1);
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);
done:
free(tmp_env1);
free(tmp_env2);
return ret;
#endif /* ! ENV_IS_EMBEDDED */
}
#else /* ! CONFIG_ENV_OFFSET_REDUND */
/*
* The legacy NAND code saved the environment in the first NAND
* device i.e., nand_dev_desc + 0. This is also the behaviour using
* the new NAND code.
*/
static int env_nand_load(void)
{
#if !defined(ENV_IS_EMBEDDED)
int ret;
ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_SIZE);
#if defined(CONFIG_ENV_OFFSET_OOB)
struct mtd_info *mtd = get_nand_dev_by_index(0);
/*
* If unable to read environment offset from NAND OOB then fall through
* to the normal environment reading code below
*/
if (mtd && !get_nand_env_oob(mtd, &nand_env_oob_offset)) {
printf("Found Environment offset in OOB..\n");
} else {
env_set_default("no env offset in OOB", 0);
return;
}
#endif
ret = readenv(CONFIG_ENV_OFFSET, (u_char *)buf);
if (ret) {
env_set_default("readenv() failed", 0);
return -EIO;
}
return env_import(buf, 1);
#endif /* ! ENV_IS_EMBEDDED */
return 0;
}
#endif /* CONFIG_ENV_OFFSET_REDUND */
U_BOOT_ENV_LOCATION(nand) = {
.location = ENVL_NAND,
ENV_NAME("NAND")
.load = env_nand_load,
#if defined(CMD_SAVEENV)
.save = env_save_ptr(env_nand_save),
#endif
.init = env_nand_init,
};
+34
View File
@@ -0,0 +1,34 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2000-2010
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
* Andreas Heppel <aheppel@sysgo.de>
*/
#include <common.h>
#include <command.h>
#include <env.h>
#include <env_internal.h>
#include <linux/stddef.h>
DECLARE_GLOBAL_DATA_PTR;
/*
* Because we only ever have the default environment available we must mark
* it as invalid.
*/
static int env_nowhere_init(void)
{
gd->env_addr = (ulong)&default_environment[0];
gd->env_valid = ENV_INVALID;
return 0;
}
U_BOOT_ENV_LOCATION(nowhere) = {
.location = ENVL_NOWHERE,
.init = env_nowhere_init,
ENV_NAME("nowhere")
};
+123
View File
@@ -0,0 +1,123 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2000-2010
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
* Andreas Heppel <aheppel@sysgo.de>
*/
/*
* 09-18-2001 Andreas Heppel, Sysgo RTS GmbH <aheppel@sysgo.de>
*
* It might not be possible in all cases to use 'memcpy()' to copy
* the environment to NVRAM, as the NVRAM might not be mapped into
* the memory space. (I.e. this is the case for the BAB750). In those
* cases it might be possible to access the NVRAM using a different
* method. For example, the RTC on the BAB750 is accessible in IO
* space using its address and data registers. To enable usage of
* NVRAM in those cases I invented the functions 'nvram_read()' and
* 'nvram_write()', which will be activated upon the configuration
* #define CONFIG_SYS_NVRAM_ACCESS_ROUTINE. Note, that those functions are
* strongly dependent on the used HW, and must be redefined for each
* board that wants to use them.
*/
#include <common.h>
#include <command.h>
#include <env.h>
#include <env_internal.h>
#include <linux/stddef.h>
#include <search.h>
#include <errno.h>
#include <u-boot/crc.h>
DECLARE_GLOBAL_DATA_PTR;
#ifdef CONFIG_SYS_NVRAM_ACCESS_ROUTINE
extern void *nvram_read(void *dest, const long src, size_t count);
extern void nvram_write(long dest, const void *src, size_t count);
#else
env_t *env_ptr = (env_t *)CONFIG_ENV_ADDR;
#endif
#ifdef CONFIG_SYS_NVRAM_ACCESS_ROUTINE
/** Call this function from overridden env_get_char_spec() if you need
* this functionality.
*/
int env_nvram_get_char(int index)
{
uchar c;
nvram_read(&c, CONFIG_ENV_ADDR + index, 1);
return c;
}
#endif
static int env_nvram_load(void)
{
char buf[CONFIG_ENV_SIZE];
#if defined(CONFIG_SYS_NVRAM_ACCESS_ROUTINE)
nvram_read(buf, CONFIG_ENV_ADDR, CONFIG_ENV_SIZE);
#else
memcpy(buf, (void *)CONFIG_ENV_ADDR, CONFIG_ENV_SIZE);
#endif
return env_import(buf, 1);
}
static int env_nvram_save(void)
{
env_t env_new;
int rcode = 0;
rcode = env_export(&env_new);
if (rcode)
return rcode;
#ifdef CONFIG_SYS_NVRAM_ACCESS_ROUTINE
nvram_write(CONFIG_ENV_ADDR, &env_new, CONFIG_ENV_SIZE);
#else
if (memcpy((char *)CONFIG_ENV_ADDR, &env_new, CONFIG_ENV_SIZE) == NULL)
rcode = 1;
#endif
return rcode;
}
/*
* Initialize Environment use
*
* We are still running from ROM, so data use is limited
*/
static int env_nvram_init(void)
{
#if defined(CONFIG_SYS_NVRAM_ACCESS_ROUTINE)
ulong crc;
uchar data[ENV_SIZE];
nvram_read(&crc, CONFIG_ENV_ADDR, sizeof(ulong));
nvram_read(data, CONFIG_ENV_ADDR + sizeof(ulong), ENV_SIZE);
if (crc32(0, data, ENV_SIZE) == crc) {
gd->env_addr = (ulong)CONFIG_ENV_ADDR + sizeof(long);
#else
if (crc32(0, env_ptr->data, ENV_SIZE) == env_ptr->crc) {
gd->env_addr = (ulong)&env_ptr->data;
#endif
gd->env_valid = ENV_VALID;
} else {
gd->env_addr = (ulong)&default_environment[0];
gd->env_valid = ENV_INVALID;
}
return 0;
}
U_BOOT_ENV_LOCATION(nvram) = {
.location = ENVL_NVRAM,
ENV_NAME("NVRAM")
.load = env_nvram_load,
.save = env_save_ptr(env_nvram_save),
.init = env_nvram_init,
};
+113
View File
@@ -0,0 +1,113 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2010 DENX Software Engineering
* Wolfgang Denk <wd@denx.de>
*
* (C) Copyright 2005-2009 Samsung Electronics
* Kyungmin Park <kyungmin.park@samsung.com>
*/
#include <common.h>
#include <command.h>
#include <env_internal.h>
#include <linux/stddef.h>
#include <malloc.h>
#include <search.h>
#include <errno.h>
#include <onenand_uboot.h>
#include <linux/compat.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/onenand.h>
#define ONENAND_MAX_ENV_SIZE CONFIG_ENV_SIZE
#define ONENAND_ENV_SIZE(mtd) (ONENAND_MAX_ENV_SIZE - ENV_HEADER_SIZE)
DECLARE_GLOBAL_DATA_PTR;
static int env_onenand_load(void)
{
struct mtd_info *mtd = &onenand_mtd;
#ifdef CONFIG_ENV_ADDR_FLEX
struct onenand_chip *this = &onenand_chip;
#endif
int rc;
size_t retlen;
#ifdef ENV_IS_EMBEDDED
char *buf = (char *)&environment;
#else
loff_t env_addr = CONFIG_ENV_ADDR;
char onenand_env[ONENAND_MAX_ENV_SIZE];
char *buf = (char *)&onenand_env[0];
#endif /* ENV_IS_EMBEDDED */
#ifndef ENV_IS_EMBEDDED
# ifdef CONFIG_ENV_ADDR_FLEX
if (FLEXONENAND(this))
env_addr = CONFIG_ENV_ADDR_FLEX;
# endif
/* Check OneNAND exist */
if (mtd->writesize)
/* Ignore read fail */
mtd_read(mtd, env_addr, ONENAND_MAX_ENV_SIZE,
&retlen, (u_char *)buf);
else
mtd->writesize = MAX_ONENAND_PAGESIZE;
#endif /* !ENV_IS_EMBEDDED */
rc = env_import(buf, 1);
if (!rc)
gd->env_valid = ENV_VALID;
return rc;
}
static int env_onenand_save(void)
{
env_t env_new;
int ret;
struct mtd_info *mtd = &onenand_mtd;
#ifdef CONFIG_ENV_ADDR_FLEX
struct onenand_chip *this = &onenand_chip;
#endif
loff_t env_addr = CONFIG_ENV_ADDR;
size_t retlen;
struct erase_info instr = {
.callback = NULL,
};
ret = env_export(&env_new);
if (ret)
return ret;
instr.len = CONFIG_ENV_SIZE;
#ifdef CONFIG_ENV_ADDR_FLEX
if (FLEXONENAND(this)) {
env_addr = CONFIG_ENV_ADDR_FLEX;
instr.len = CONFIG_ENV_SIZE_FLEX;
instr.len <<= onenand_mtd.eraseregions[0].numblocks == 1 ?
1 : 0;
}
#endif
instr.addr = env_addr;
instr.mtd = mtd;
if (mtd_erase(mtd, &instr)) {
printf("OneNAND: erase failed at 0x%08llx\n", env_addr);
return 1;
}
if (mtd_write(mtd, env_addr, ONENAND_MAX_ENV_SIZE, &retlen,
(u_char *)&env_new)) {
printf("OneNAND: write failed at 0x%llx\n", instr.addr);
return 2;
}
return 0;
}
U_BOOT_ENV_LOCATION(onenand) = {
.location = ENVL_ONENAND,
ENV_NAME("OneNAND")
.load = env_onenand_load,
.save = env_save_ptr(env_onenand_save),
};
+60
View File
@@ -0,0 +1,60 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2011-2012 Freescale Semiconductor, Inc.
*/
/* #define DEBUG */
#include <common.h>
#include <command.h>
#include <env_internal.h>
#include <linux/stddef.h>
#include <u-boot/crc.h>
#ifdef ENV_IS_EMBEDDED
env_t *env_ptr = &environment;
#else /* ! ENV_IS_EMBEDDED */
env_t *env_ptr = (env_t *)CONFIG_ENV_ADDR;
#endif /* ENV_IS_EMBEDDED */
DECLARE_GLOBAL_DATA_PTR;
static int env_remote_init(void)
{
if (crc32(0, env_ptr->data, ENV_SIZE) == env_ptr->crc) {
gd->env_addr = (ulong)&(env_ptr->data);
gd->env_valid = ENV_VALID;
return 0;
}
return -ENOENT;
}
#ifdef CONFIG_CMD_SAVEENV
static int env_remote_save(void)
{
#ifdef CONFIG_SRIO_PCIE_BOOT_SLAVE
printf("Can not support the 'saveenv' when boot from SRIO or PCIE!\n");
return 1;
#else
return 0;
#endif
}
#endif /* CONFIG_CMD_SAVEENV */
static int env_remote_load(void)
{
#ifndef ENV_IS_EMBEDDED
return env_import((char *)env_ptr, 1);
#endif
return 0;
}
U_BOOT_ENV_LOCATION(remote) = {
.location = ENVL_REMOTE,
ENV_NAME("Remote")
.load = env_remote_load,
.save = env_save_ptr(env_remote_save),
.init = env_remote_init,
};
+122
View File
@@ -0,0 +1,122 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2010-2016 Freescale Semiconductor, Inc.
*/
/* #define DEBUG */
#include <common.h>
#include <command.h>
#include <env.h>
#include <env_internal.h>
#include <linux/stddef.h>
#include <errno.h>
#include <memalign.h>
#include <sata.h>
#include <search.h>
#if defined(CONFIG_ENV_OFFSET_REDUND)
#error ENV REDUND not supported
#endif
#if !defined(CONFIG_ENV_OFFSET) || !defined(CONFIG_ENV_SIZE)
#error CONFIG_ENV_OFFSET or CONFIG_ENV_SIZE not defined
#endif
__weak int sata_get_env_dev(void)
{
return CONFIG_SYS_SATA_ENV_DEV;
}
#ifdef CONFIG_CMD_SAVEENV
static inline int write_env(struct blk_desc *sata, unsigned long size,
unsigned long offset, void *buffer)
{
uint blk_start, blk_cnt, n;
blk_start = ALIGN(offset, sata->blksz) / sata->blksz;
blk_cnt = ALIGN(size, sata->blksz) / sata->blksz;
n = blk_dwrite(sata, blk_start, blk_cnt, buffer);
return (n == blk_cnt) ? 0 : -1;
}
static int env_sata_save(void)
{
ALLOC_CACHE_ALIGN_BUFFER(env_t, env_new, 1);
struct blk_desc *sata = NULL;
int env_sata, ret;
if (sata_initialize())
return 1;
env_sata = sata_get_env_dev();
sata = sata_get_dev(env_sata);
if (sata == NULL) {
printf("Unknown SATA(%d) device for environment!\n",
env_sata);
return 1;
}
ret = env_export(env_new);
if (ret)
return 1;
printf("Writing to SATA(%d)...", env_sata);
if (write_env(sata, CONFIG_ENV_SIZE, CONFIG_ENV_OFFSET, (u_char *)env_new)) {
puts("failed\n");
return 1;
}
puts("done\n");
return 0;
}
#endif /* CONFIG_CMD_SAVEENV */
static inline int read_env(struct blk_desc *sata, unsigned long size,
unsigned long offset, void *buffer)
{
uint blk_start, blk_cnt, n;
blk_start = ALIGN(offset, sata->blksz) / sata->blksz;
blk_cnt = ALIGN(size, sata->blksz) / sata->blksz;
n = blk_dread(sata, blk_start, blk_cnt, buffer);
return (n == blk_cnt) ? 0 : -1;
}
static void env_sata_load(void)
{
ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_SIZE);
struct blk_desc *sata = NULL;
int env_sata;
if (sata_initialize())
return -EIO;
env_sata = sata_get_env_dev();
sata = sata_get_dev(env_sata);
if (sata == NULL) {
printf("Unknown SATA(%d) device for environment!\n", env_sata);
return -EIO;
}
if (read_env(sata, CONFIG_ENV_SIZE, CONFIG_ENV_OFFSET, buf)) {
env_set_default(NULL, 0);
return -EIO;
}
return env_import(buf, 1);
}
U_BOOT_ENV_LOCATION(sata) = {
.location = ENVL_ESATA,
ENV_NAME("SATA")
.load = env_sata_load,
.save = env_save_ptr(env_sata_save),
};
+324
View File
@@ -0,0 +1,324 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2000-2010
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
* Andreas Heppel <aheppel@sysgo.de>
*
* (C) Copyright 2008 Atmel Corporation
*/
#include <common.h>
#include <dm.h>
#include <env.h>
#include <env_internal.h>
#include <malloc.h>
#include <spi.h>
#include <spi_flash.h>
#include <search.h>
#include <errno.h>
#include <dm/device-internal.h>
#include <u-boot/crc.h>
#ifndef CONFIG_SPL_BUILD
#ifdef CONFIG_CMD_SAVEENV /* fix "env_sf_save not used" warning */
#define CMD_SAVEENV
#endif
#define INITENV
#endif
#ifdef CONFIG_ENV_OFFSET_REDUND
#ifdef CMD_SAVEENV
static ulong env_offset = CONFIG_ENV_OFFSET;
static ulong env_new_offset = CONFIG_ENV_OFFSET_REDUND;
#endif
#endif /* CONFIG_ENV_OFFSET_REDUND */
DECLARE_GLOBAL_DATA_PTR;
static struct spi_flash *env_flash;
static int setup_flash_device(void)
{
#ifdef CONFIG_DM_SPI_FLASH
struct udevice *new;
int ret;
/* speed and mode will be read from DT */
ret = spi_flash_probe_bus_cs(CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS,
CONFIG_ENV_SPI_MAX_HZ, CONFIG_ENV_SPI_MODE,
&new);
if (ret) {
env_set_default("spi_flash_probe_bus_cs() failed", 0);
return ret;
}
env_flash = dev_get_uclass_priv(new);
#else
if (!env_flash) {
env_flash = spi_flash_probe(CONFIG_ENV_SPI_BUS,
CONFIG_ENV_SPI_CS,
CONFIG_ENV_SPI_MAX_HZ, CONFIG_ENV_SPI_MODE);
if (!env_flash) {
env_set_default("spi_flash_probe() failed", 0);
return -EIO;
}
}
#endif
return 0;
}
#if defined(CONFIG_ENV_OFFSET_REDUND)
#ifdef CMD_SAVEENV
static int env_sf_save(void)
{
env_t env_new;
char *saved_buffer = NULL, flag = ENV_REDUND_OBSOLETE;
u32 saved_size, saved_offset, sector;
int ret;
ret = setup_flash_device();
if (ret)
return ret;
ret = env_export(&env_new);
if (ret)
return -EIO;
env_new.flags = ENV_REDUND_ACTIVE;
if (gd->env_valid == ENV_VALID) {
env_new_offset = CONFIG_ENV_OFFSET_REDUND;
env_offset = CONFIG_ENV_OFFSET;
} else {
env_new_offset = CONFIG_ENV_OFFSET;
env_offset = CONFIG_ENV_OFFSET_REDUND;
}
/* Is the sector larger than the env (i.e. embedded) */
if (CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE) {
saved_size = CONFIG_ENV_SECT_SIZE - CONFIG_ENV_SIZE;
saved_offset = env_new_offset + CONFIG_ENV_SIZE;
saved_buffer = memalign(ARCH_DMA_MINALIGN, saved_size);
if (!saved_buffer) {
ret = -ENOMEM;
goto done;
}
ret = spi_flash_read(env_flash, saved_offset,
saved_size, saved_buffer);
if (ret)
goto done;
}
sector = DIV_ROUND_UP(CONFIG_ENV_SIZE, CONFIG_ENV_SECT_SIZE);
puts("Erasing SPI flash...");
ret = spi_flash_erase(env_flash, env_new_offset,
sector * CONFIG_ENV_SECT_SIZE);
if (ret)
goto done;
puts("Writing to SPI flash...");
ret = spi_flash_write(env_flash, env_new_offset,
CONFIG_ENV_SIZE, &env_new);
if (ret)
goto done;
if (CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE) {
ret = spi_flash_write(env_flash, saved_offset,
saved_size, saved_buffer);
if (ret)
goto done;
}
ret = spi_flash_write(env_flash, env_offset + offsetof(env_t, flags),
sizeof(env_new.flags), &flag);
if (ret)
goto done;
puts("done\n");
gd->env_valid = gd->env_valid == ENV_REDUND ? ENV_VALID : ENV_REDUND;
printf("Valid environment: %d\n", (int)gd->env_valid);
done:
if (saved_buffer)
free(saved_buffer);
return ret;
}
#endif /* CMD_SAVEENV */
static int env_sf_load(void)
{
int ret;
int read1_fail, read2_fail;
env_t *tmp_env1, *tmp_env2;
tmp_env1 = (env_t *)memalign(ARCH_DMA_MINALIGN,
CONFIG_ENV_SIZE);
tmp_env2 = (env_t *)memalign(ARCH_DMA_MINALIGN,
CONFIG_ENV_SIZE);
if (!tmp_env1 || !tmp_env2) {
env_set_default("malloc() failed", 0);
ret = -EIO;
goto out;
}
ret = setup_flash_device();
if (ret)
goto out;
read1_fail = spi_flash_read(env_flash, CONFIG_ENV_OFFSET,
CONFIG_ENV_SIZE, tmp_env1);
read2_fail = spi_flash_read(env_flash, CONFIG_ENV_OFFSET_REDUND,
CONFIG_ENV_SIZE, tmp_env2);
ret = env_import_redund((char *)tmp_env1, read1_fail, (char *)tmp_env2,
read2_fail);
spi_flash_free(env_flash);
env_flash = NULL;
out:
free(tmp_env1);
free(tmp_env2);
return ret;
}
#else
#ifdef CMD_SAVEENV
static int env_sf_save(void)
{
u32 saved_size, saved_offset, sector;
char *saved_buffer = NULL;
int ret = 1;
env_t env_new;
ret = setup_flash_device();
if (ret)
return ret;
/* Is the sector larger than the env (i.e. embedded) */
if (CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE) {
saved_size = CONFIG_ENV_SECT_SIZE - CONFIG_ENV_SIZE;
saved_offset = CONFIG_ENV_OFFSET + CONFIG_ENV_SIZE;
saved_buffer = malloc(saved_size);
if (!saved_buffer)
goto done;
ret = spi_flash_read(env_flash, saved_offset,
saved_size, saved_buffer);
if (ret)
goto done;
}
ret = env_export(&env_new);
if (ret)
goto done;
sector = DIV_ROUND_UP(CONFIG_ENV_SIZE, CONFIG_ENV_SECT_SIZE);
puts("Erasing SPI flash...");
ret = spi_flash_erase(env_flash, CONFIG_ENV_OFFSET,
sector * CONFIG_ENV_SECT_SIZE);
if (ret)
goto done;
puts("Writing to SPI flash...");
ret = spi_flash_write(env_flash, CONFIG_ENV_OFFSET,
CONFIG_ENV_SIZE, &env_new);
if (ret)
goto done;
if (CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE) {
ret = spi_flash_write(env_flash, saved_offset,
saved_size, saved_buffer);
if (ret)
goto done;
}
ret = 0;
puts("done\n");
done:
if (saved_buffer)
free(saved_buffer);
return ret;
}
#endif /* CMD_SAVEENV */
static int env_sf_load(void)
{
int ret;
char *buf = NULL;
buf = (char *)memalign(ARCH_DMA_MINALIGN, CONFIG_ENV_SIZE);
if (!buf) {
env_set_default("malloc() failed", 0);
return -EIO;
}
ret = setup_flash_device();
if (ret)
goto out;
ret = spi_flash_read(env_flash,
CONFIG_ENV_OFFSET, CONFIG_ENV_SIZE, buf);
if (ret) {
env_set_default("spi_flash_read() failed", 0);
goto err_read;
}
ret = env_import(buf, 1);
if (!ret)
gd->env_valid = ENV_VALID;
err_read:
spi_flash_free(env_flash);
env_flash = NULL;
out:
free(buf);
return ret;
}
#endif
#if CONFIG_ENV_ADDR != 0x0
__weak void *env_sf_get_env_addr(void)
{
return (void *)CONFIG_ENV_ADDR;
}
#endif
#if defined(INITENV) && (CONFIG_ENV_ADDR != 0x0)
static int env_sf_init(void)
{
env_t *env_ptr = (env_t *)env_sf_get_env_addr();
if (crc32(0, env_ptr->data, ENV_SIZE) == env_ptr->crc) {
gd->env_addr = (ulong)&(env_ptr->data);
gd->env_valid = 1;
} else {
gd->env_addr = (ulong)&default_environment[0];
gd->env_valid = 1;
}
return 0;
}
#endif
U_BOOT_ENV_LOCATION(sf) = {
.location = ENVL_SPI_FLASH,
ENV_NAME("SPI Flash")
.load = env_sf_load,
#ifdef CMD_SAVEENV
.save = env_save_ptr(env_sf_save),
#endif
#if defined(INITENV) && (CONFIG_ENV_ADDR != 0x0)
.init = env_sf_init,
#endif
};
+184
View File
@@ -0,0 +1,184 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (c) Copyright 2012 by National Instruments,
* Joe Hershberger <joe.hershberger@ni.com>
*/
#include <common.h>
#include <command.h>
#include <env.h>
#include <env_internal.h>
#include <errno.h>
#include <malloc.h>
#include <memalign.h>
#include <search.h>
#include <ubi_uboot.h>
#undef crc32
#define _QUOTE(x) #x
#define QUOTE(x) _QUOTE(x)
#if (CONFIG_ENV_UBI_VID_OFFSET == 0)
#define UBI_VID_OFFSET NULL
#else
#define UBI_VID_OFFSET QUOTE(CONFIG_ENV_UBI_VID_OFFSET)
#endif
DECLARE_GLOBAL_DATA_PTR;
#ifdef CONFIG_CMD_SAVEENV
#ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT
static int env_ubi_save(void)
{
ALLOC_CACHE_ALIGN_BUFFER(env_t, env_new, 1);
int ret;
ret = env_export(env_new);
if (ret)
return ret;
if (ubi_part(CONFIG_ENV_UBI_PART, UBI_VID_OFFSET)) {
printf("\n** Cannot find mtd partition \"%s\"\n",
CONFIG_ENV_UBI_PART);
return 1;
}
if (gd->env_valid == ENV_VALID) {
puts("Writing to redundant UBI... ");
if (ubi_volume_write(CONFIG_ENV_UBI_VOLUME_REDUND,
(void *)env_new, CONFIG_ENV_SIZE)) {
printf("\n** Unable to write env to %s:%s **\n",
CONFIG_ENV_UBI_PART,
CONFIG_ENV_UBI_VOLUME_REDUND);
return 1;
}
} else {
puts("Writing to UBI... ");
if (ubi_volume_write(CONFIG_ENV_UBI_VOLUME,
(void *)env_new, CONFIG_ENV_SIZE)) {
printf("\n** Unable to write env to %s:%s **\n",
CONFIG_ENV_UBI_PART,
CONFIG_ENV_UBI_VOLUME);
return 1;
}
}
puts("done\n");
gd->env_valid = gd->env_valid == ENV_REDUND ? ENV_VALID : ENV_REDUND;
return 0;
}
#else /* ! CONFIG_SYS_REDUNDAND_ENVIRONMENT */
static int env_ubi_save(void)
{
ALLOC_CACHE_ALIGN_BUFFER(env_t, env_new, 1);
int ret;
ret = env_export(env_new);
if (ret)
return ret;
if (ubi_part(CONFIG_ENV_UBI_PART, UBI_VID_OFFSET)) {
printf("\n** Cannot find mtd partition \"%s\"\n",
CONFIG_ENV_UBI_PART);
return 1;
}
if (ubi_volume_write(CONFIG_ENV_UBI_VOLUME, (void *)env_new,
CONFIG_ENV_SIZE)) {
printf("\n** Unable to write env to %s:%s **\n",
CONFIG_ENV_UBI_PART, CONFIG_ENV_UBI_VOLUME);
return 1;
}
puts("done\n");
return 0;
}
#endif /* CONFIG_SYS_REDUNDAND_ENVIRONMENT */
#endif /* CONFIG_CMD_SAVEENV */
#ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT
static int env_ubi_load(void)
{
ALLOC_CACHE_ALIGN_BUFFER(char, env1_buf, CONFIG_ENV_SIZE);
ALLOC_CACHE_ALIGN_BUFFER(char, env2_buf, CONFIG_ENV_SIZE);
int read1_fail, read2_fail;
env_t *tmp_env1, *tmp_env2;
/*
* In case we have restarted u-boot there is a chance that buffer
* contains old environment (from the previous boot).
* If UBI volume is zero size, ubi_volume_read() doesn't modify the
* buffer.
* We need to clear buffer manually here, so the invalid CRC will
* cause setting default environment as expected.
*/
memset(env1_buf, 0x0, CONFIG_ENV_SIZE);
memset(env2_buf, 0x0, CONFIG_ENV_SIZE);
tmp_env1 = (env_t *)env1_buf;
tmp_env2 = (env_t *)env2_buf;
if (ubi_part(CONFIG_ENV_UBI_PART, UBI_VID_OFFSET)) {
printf("\n** Cannot find mtd partition \"%s\"\n",
CONFIG_ENV_UBI_PART);
env_set_default(NULL, 0);
return -EIO;
}
read1_fail = ubi_volume_read(CONFIG_ENV_UBI_VOLUME, (void *)tmp_env1,
CONFIG_ENV_SIZE);
if (read1_fail)
printf("\n** Unable to read env from %s:%s **\n",
CONFIG_ENV_UBI_PART, CONFIG_ENV_UBI_VOLUME);
read2_fail = ubi_volume_read(CONFIG_ENV_UBI_VOLUME_REDUND,
(void *)tmp_env2, CONFIG_ENV_SIZE);
if (read2_fail)
printf("\n** Unable to read redundant env from %s:%s **\n",
CONFIG_ENV_UBI_PART, CONFIG_ENV_UBI_VOLUME_REDUND);
return env_import_redund((char *)tmp_env1, read1_fail, (char *)tmp_env2,
read2_fail);
}
#else /* ! CONFIG_SYS_REDUNDAND_ENVIRONMENT */
static int env_ubi_load(void)
{
ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_SIZE);
/*
* In case we have restarted u-boot there is a chance that buffer
* contains old environment (from the previous boot).
* If UBI volume is zero size, ubi_volume_read() doesn't modify the
* buffer.
* We need to clear buffer manually here, so the invalid CRC will
* cause setting default environment as expected.
*/
memset(buf, 0x0, CONFIG_ENV_SIZE);
if (ubi_part(CONFIG_ENV_UBI_PART, UBI_VID_OFFSET)) {
printf("\n** Cannot find mtd partition \"%s\"\n",
CONFIG_ENV_UBI_PART);
env_set_default(NULL, 0);
return -EIO;
}
if (ubi_volume_read(CONFIG_ENV_UBI_VOLUME, buf, CONFIG_ENV_SIZE)) {
printf("\n** Unable to read env from %s:%s **\n",
CONFIG_ENV_UBI_PART, CONFIG_ENV_UBI_VOLUME);
env_set_default(NULL, 0);
return -EIO;
}
return env_import(buf, 1);
}
#endif /* CONFIG_SYS_REDUNDAND_ENVIRONMENT */
U_BOOT_ENV_LOCATION(ubi) = {
.location = ENVL_UBI,
ENV_NAME("UBI")
.load = env_ubi_load,
.save = env_save_ptr(env_ubi_save),
};