GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)
This commit is contained in:
+699
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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),
|
||||
};
|
||||
Reference in New Issue
Block a user