diff options
author | 2023-10-10 14:33:42 +0000 | |
---|---|---|
committer | 2023-10-10 14:33:42 +0000 | |
commit | af1a266670d040d2f4083ff309d732d648afba2a (patch) | |
tree | 2fc46203448ddcc6f81546d379abfaeb323575e9 /roms/u-boot/env | |
parent | e02cda008591317b1625707ff8e115a4841aa889 (diff) |
Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
Diffstat (limited to 'roms/u-boot/env')
-rw-r--r-- | roms/u-boot/env/Kconfig | 839 | ||||
-rw-r--r-- | roms/u-boot/env/Makefile | 33 | ||||
-rw-r--r-- | roms/u-boot/env/attr.c | 309 | ||||
-rw-r--r-- | roms/u-boot/env/callback.c | 139 | ||||
-rw-r--r-- | roms/u-boot/env/common.c | 366 | ||||
-rw-r--r-- | roms/u-boot/env/eeprom.c | 241 | ||||
-rw-r--r-- | roms/u-boot/env/embedded.c | 96 | ||||
-rw-r--r-- | roms/u-boot/env/env.c | 396 | ||||
-rw-r--r-- | roms/u-boot/env/ext4.c | 192 | ||||
-rw-r--r-- | roms/u-boot/env/fat.c | 178 | ||||
-rw-r--r-- | roms/u-boot/env/flags.c | 609 | ||||
-rw-r--r-- | roms/u-boot/env/flash.c | 371 | ||||
-rw-r--r-- | roms/u-boot/env/mmc.c | 397 | ||||
-rw-r--r-- | roms/u-boot/env/nand.c | 391 | ||||
-rw-r--r-- | roms/u-boot/env/nowhere.c | 52 | ||||
-rw-r--r-- | roms/u-boot/env/nvram.c | 124 | ||||
-rw-r--r-- | roms/u-boot/env/onenand.c | 114 | ||||
-rw-r--r-- | roms/u-boot/env/remote.c | 61 | ||||
-rw-r--r-- | roms/u-boot/env/sata.c | 122 | ||||
-rw-r--r-- | roms/u-boot/env/sf.c | 457 | ||||
-rw-r--r-- | roms/u-boot/env/ubi.c | 185 |
21 files changed, 5672 insertions, 0 deletions
diff --git a/roms/u-boot/env/Kconfig b/roms/u-boot/env/Kconfig new file mode 100644 index 000000000..1411f9e81 --- /dev/null +++ b/roms/u-boot/env/Kconfig @@ -0,0 +1,839 @@ +menu "Environment" + +config ENV_SUPPORT + def_bool y + +config SAVEENV + def_bool y if CMD_SAVEENV + +config ENV_OVERWRITE + bool "Enable overwriting environment" + help + Use this to permit overriding of certain environmental variables + like Ethernet and Serial + +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 FS_EXT4 + 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 + 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 ENV_SECT_SIZE_AUTO + bool "Use automatically detected sector size" + depends on ENV_IS_IN_SPI_FLASH + help + Some boards exist in multiple variants, with different + flashes having different sector sizes. In such cases, you + can select this option to make U-Boot use the actual sector + size when figuring out how much to erase, which can thus be + more efficient on the flashes with smaller erase size. Since + the environment must always be aligned on a sector boundary, + CONFIG_ENV_OFFSET must be aligned to the largest of the + different sector sizes, and CONFIG_ENV_SECT_SIZE should be + set to that value. + +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_SPI_EARLY + bool "Access Environment in SPI flashes before relocation" + depends on ENV_IS_IN_SPI_FLASH + help + Enable this if you want to use Environment in SPI flash + before relocation. Call env_init() and than you can use + env_get_f() for accessing Environment variables. + +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" + 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. + Also this config changes the binary environment structure handling + which is used by env import/export commands which are independent of + storing variables to redundant location on a non volatile device. + +config ENV_FAT_INTERFACE + string "Name of the block device for the environment" + depends on ENV_IS_IN_FAT + default "mmc" + 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_ZYNQ || ARCH_ZYNQMP || ARCH_VERSAL + 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. + + If ENV_FAT_INTERFACE is set to "mmc" then device 'D' can be omitted, + leaving the string starting with a colon, and the boot device will + be used. + +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_FAT_FILE_REDUND + string "Name of the FAT file to use for the environment" + depends on ENV_IS_IN_FAT && SYS_REDUNDAND_ENVIRONMENT + default "uboot-redund.env" + help + It's a string of the FAT file name. This file use to store the + redundant 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. + + If ENV_EXT4_INTERFACE is set to "mmc" then device 'D' can be omitted, + leaving the string starting with a colon, and the boot device will + be used. + +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 && ENV_IS_IN_MMC + default 0x140000 if ARCH_ROCKCHIP && ENV_IS_IN_SPI_FLASH + 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 + default 0x1080000 if MICROBLAZE && ENV_IS_IN_SPI_FLASH + 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 + default 0 + 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 && ENV_IS_IN_MMC + default 0x2000 if ARCH_ROCKCHIP && ENV_IS_IN_SPI_FLASH + default 0x8000 if 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 0x2000 if ARCH_ROCKCHIP + default 0x40000 if ARCH_ZYNQMP || ARCH_VERSAL + default 0x20000 if ARCH_ZYNQ || ARCH_OMAP2PLUS || ARCH_AT91 + default 0x20000 if MICROBLAZE && ENV_IS_IN_SPI_FLASH + 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->env_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 SYS_MMC_ENV_DEV + int "mmc device number" + depends on ENV_IS_IN_MMC || ENV_IS_IN_FAT || SYS_LS_PPA_FW_IN_MMC || \ + CMD_MVEBU_BUBT || FMAN_ENET || QE + default 0 + help + MMC device number on the platform where the environment is stored. + +config SYS_MMC_ENV_PART + int "mmc partition number" + depends on ENV_IS_IN_MMC || ENV_IS_IN_FAT + default 0 + help + MMC hardware partition device number on the platform where the + environment is stored. Note that this is not related to any software + defined partition table but instead if we are in the user area, which is + partition 0 or the first boot partition, which is 1 or some other defined + partition. + +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. + +config DELAY_ENVIRONMENT + bool "Delay environment loading" + depends on !OF_CONTROL + help + Enable this to inhibit loading the environment during board + initialization. This can address the security risk of untrusted data + being used during boot. Normally the environment is loaded when the + board is initialised so that it is available to U-Boot. This inhibits + that so that the environment is not available until explicitly loaded + later by U-Boot code. With CONFIG_OF_CONTROL this is instead + controlled by the value of /config/load-environment. + +config ENV_IMPORT_FDT + bool "Amend environment by FDT properties" + depends on OF_CONTROL + help + If selected, after the environment has been loaded from its + persistent location, the "env_fdt_path" variable is looked + up and used as a path to a node in the control DTB. The + property/value pairs in that node is then used to update the + run-time environment. This can be useful to use the same + U-Boot binary with different board variants. + +config ENV_FDT_PATH + string "Default value for env_fdt_path variable" + depends on ENV_IMPORT_FDT + default "/config/environment" + help + The initial value of the env_fdt_path variable. + +config ENV_APPEND + bool "Always append the environment with new data" + default n + help + If defined, the environment hash table is only ever appended with new + data, but the existing hash table can never be dropped and reloaded + with newly imported data. This may be used in combination with static + flags to e.g. to protect variables which must not be modified. + +config ENV_WRITEABLE_LIST + bool "Permit write access only to listed variables" + default n + help + If defined, only environment variables which explicitly set the 'w' + writeable flag can be written and modified at runtime. No variables + can be otherwise created, written or imported into the environment. + +config ENV_ACCESS_IGNORE_FORCE + bool "Block forced environment operations" + default n + help + If defined, don't allow the -f switch to env set override variable + access flags. + +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 + +config VERSION_VARIABLE + bool "Add a 'ver' environment variable with the U-Boot version" + help + If this variable is defined, an environment variable + named "ver" is created by U-Boot showing the U-Boot + version as printed by the "version" command. + Any change to this variable will be reverted at the + next reset. + +endmenu diff --git a/roms/u-boot/env/Makefile b/roms/u-boot/env/Makefile new file mode 100644 index 000000000..c4ad65432 --- /dev/null +++ b/roms/u-boot/env/Makefile @@ -0,0 +1,33 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# (C) Copyright 2004-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. + +obj-$(CONFIG_$(SPL_TPL_)ENV_SUPPORT) += common.o +obj-$(CONFIG_$(SPL_TPL_)ENV_SUPPORT) += env.o +obj-$(CONFIG_$(SPL_TPL_)ENV_SUPPORT) += attr.o +obj-$(CONFIG_$(SPL_TPL_)ENV_SUPPORT) += flags.o + +ifndef CONFIG_SPL_BUILD +obj-y += callback.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 +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) diff --git a/roms/u-boot/env/attr.c b/roms/u-boot/env/attr.c new file mode 100644 index 000000000..a958c7148 --- /dev/null +++ b/roms/u-boot/env/attr.c @@ -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 diff --git a/roms/u-boot/env/callback.c b/roms/u-boot/env/callback.c new file mode 100644 index 000000000..638a02b28 --- /dev/null +++ b/roms/u-boot/env/callback.c @@ -0,0 +1,139 @@ +// 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> +#include <asm/global_data.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; + } + + var_entry->callback = NULL; + + /* 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); diff --git a/roms/u-boot/env/common.c b/roms/u-boot/env/common.c new file mode 100644 index 000000000..81e9e0b2a --- /dev/null +++ b/roms/u-boot/env/common.c @@ -0,0 +1,366 @@ +// 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 <bootstage.h> +#include <command.h> +#include <env.h> +#include <env_internal.h> +#include <log.h> +#include <sort.h> +#include <asm/global_data.h> +#include <linux/stddef.h> +#include <search.h> +#include <errno.h> +#include <malloc.h> +#include <u-boot/crc.h> +#include <dm/ofnode.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"); + } + + flags |= H_DEFAULT; + 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 | H_DEFAULT; + 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, int flags) +{ + 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', flags, 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_check_redund(const char *buf1, int buf1_read_fail, + const char *buf2, int buf2_read_fail) +{ + int crc1_ok = 0, crc2_ok = 0; + env_t *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"); + return -EIO; + } else if (buf1_read_fail || buf2_read_fail) { + puts("*** Warning - some problems detected "); + puts("reading environment; recovered successfully\n"); + } + + if (!buf1_read_fail) + crc1_ok = crc32(0, tmp_env1->data, ENV_SIZE) == + tmp_env1->crc; + if (!buf2_read_fail) + crc2_ok = crc32(0, tmp_env2->data, ENV_SIZE) == + tmp_env2->crc; + + if (!crc1_ok && !crc2_ok) { + 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; + } + + return 0; +} + +int env_import_redund(const char *buf1, int buf1_read_fail, + const char *buf2, int buf2_read_fail, + int flags) +{ + env_t *ep; + int ret; + + ret = env_check_redund(buf1, buf1_read_fail, buf2, buf2_read_fail); + + if (ret == -EIO) { + env_set_default("bad env area", 0); + return -EIO; + } else if (ret == -ENOMSG) { + env_set_default("bad CRC", 0); + return -ENOMSG; + } + + if (gd->env_valid == ENV_VALID) + ep = (env_t *)buf1; + else + ep = (env_t *)buf2; + + env_flags = ep->flags; + + return env_import((char *)ep, 0, flags); +} +#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 + +#ifdef CONFIG_ENV_IMPORT_FDT +void env_import_fdt(void) +{ + const char *path; + struct ofprop prop; + ofnode node; + int res; + + path = env_get("env_fdt_path"); + if (!path || !path[0]) + return; + + node = ofnode_path(path); + if (!ofnode_valid(node)) { + printf("Warning: device tree node '%s' not found\n", path); + return; + } + + for (res = ofnode_get_first_property(node, &prop); + !res; + res = ofnode_get_next_property(&prop)) { + const char *name, *val; + + val = ofnode_get_property_by_prop(&prop, &name, NULL); + env_set(name, val); + } +} +#endif diff --git a/roms/u-boot/env/eeprom.c b/roms/u-boot/env/eeprom.c new file mode 100644 index 000000000..ba168014e --- /dev/null +++ b/roms/u-boot/env/eeprom.c @@ -0,0 +1,241 @@ +// 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 <asm/global_data.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, H_EXTERNAL); +} + +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), +}; diff --git a/roms/u-boot/env/embedded.c b/roms/u-boot/env/embedded.c new file mode 100644 index 000000000..208553e6a --- /dev/null +++ b/roms/u-boot/env/embedded.c @@ -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 */ diff --git a/roms/u-boot/env/env.c b/roms/u-boot/env/env.c new file mode 100644 index 000000000..e53400800 --- /dev/null +++ b/roms/u-boot/env/env.c @@ -0,0 +1,396 @@ +// 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 <log.h> +#include <asm/global_data.h> +#include <linux/bitops.h> +#include <linux/bug.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(ENVL_COUNT > 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; + + 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; + + for (prio = 0; (drv = env_driver_lookup(ENVOP_LOAD, prio)); prio++) { + int ret; + + 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"); + gd->env_load_prio = prio; + +#if !CONFIG_IS_ENABLED(ENV_APPEND) + return 0; +#endif + } else if (ret == -ENOMSG) { + /* Handle "bad CRC" case */ + if (best_prio == -1) + 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; + + gd->env_load_prio = best_prio; + + return -ENODEV; +} + +int env_reload(void) +{ + struct env_driver *drv; + + drv = env_driver_lookup(ENVOP_LOAD, gd->env_load_prio); + if (drv) { + int ret; + + printf("Loading Environment from %s... ", drv->name); + + if (!env_has_inited(drv->location)) { + printf("not initialized\n"); + return -ENODEV; + } + + ret = drv->load(); + if (ret) + printf("Failed (%d)\n", ret); + else + printf("OK\n"); + + if (!ret) + return 0; + } + + return -ENODEV; +} + +int env_save(void) +{ + struct env_driver *drv; + + drv = env_driver_lookup(ENVOP_SAVE, gd->env_load_prio); + if (drv) { + int ret; + + printf("Saving Environment to %s... ", drv->name); + if (!drv->save) { + printf("not possible\n"); + return -ENODEV; + } + + if (!env_has_inited(drv->location)) { + printf("not initialized\n"); + return -ENODEV; + } + + 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; + + for (prio = 0; (drv = env_driver_lookup(ENVOP_INIT, prio)); prio++) { + if (!drv->init || !(ret = drv->init())) + env_set_inited(drv->location); + if (ret == -ENOENT) + env_set_inited(drv->location); + + debug("%s: Environment %s init done (ret=%d)\n", __func__, + drv->name, ret); + + if (gd->env_valid == ENV_INVALID) + ret = -ENOENT; + } + + if (!prio) + return -ENODEV; + + if (ret == -ENOENT) { + gd->env_addr = (ulong)&default_environment[0]; + gd->env_valid = ENV_VALID; + + return 0; + } + + return ret; +} + +int env_select(const char *name) +{ + struct env_driver *drv; + const int n_ents = ll_entry_count(struct env_driver, env_driver); + struct env_driver *entry; + int prio; + bool found = false; + + printf("Select Environment on %s: ", name); + + /* search ENV driver by name */ + drv = ll_entry_start(struct env_driver, env_driver); + for (entry = drv; entry != drv + n_ents; entry++) { + if (!strcmp(entry->name, name)) { + found = true; + break; + } + } + + if (!found) { + printf("driver not found\n"); + return -ENODEV; + } + + /* search priority by driver */ + for (prio = 0; (drv = env_driver_lookup(ENVOP_INIT, prio)); prio++) { + if (entry->location == env_get_location(ENVOP_LOAD, prio)) { + /* when priority change, reset the ENV flags */ + if (gd->env_load_prio != prio) { + gd->env_load_prio = prio; + gd->env_valid = ENV_INVALID; + gd->flags &= ~GD_FLG_ENV_DEFAULT; + } + printf("OK\n"); + return 0; + } + } + printf("priority not found\n"); + + return -ENODEV; +} diff --git a/roms/u-boot/env/ext4.c b/roms/u-boot/env/ext4.c new file mode 100644 index 000000000..9f65afb8a --- /dev/null +++ b/roms/u-boot/env/ext4.c @@ -0,0 +1,192 @@ +// 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 <part.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> +#include <asm/global_data.h> + +DECLARE_GLOBAL_DATA_PTR; + +__weak const char *env_ext4_get_intf(void) +{ + return (const char *)CONFIG_ENV_EXT4_INTERFACE; +} + +__weak const char *env_ext4_get_dev_part(void) +{ +#ifdef CONFIG_MMC + static char *part_str; + + if (!part_str) { + part_str = CONFIG_ENV_EXT4_DEVICE_AND_PART; + if (!strcmp(CONFIG_ENV_EXT4_INTERFACE, "mmc") && part_str[0] == ':') { + part_str = "0" CONFIG_ENV_EXT4_DEVICE_AND_PART; + part_str[0] += mmc_get_env_dev(); + } + } + + return part_str; +#else + return (const char *)CONFIG_ENV_EXT4_DEVICE_AND_PART; +#endif +} + +static int env_ext4_save_buffer(env_t *env_new) +{ + struct blk_desc *dev_desc = NULL; + struct disk_partition info; + int dev, part; + int err; + const char *ifname = env_ext4_get_intf(); + const char *dev_and_part = env_ext4_get_dev_part(); + + 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; + } + + return 0; +} + +static int env_ext4_save(void) +{ + env_t env_new; + int err; + + err = env_export(&env_new); + if (err) + return err; + + err = env_ext4_save_buffer(&env_new); + if (err) + return err; + + gd->env_valid = ENV_VALID; + puts("done\n"); + + return 0; +} + +static int env_ext4_erase(void) +{ + env_t env_new; + int err; + + memset(&env_new, 0, sizeof(env_t)); + + err = env_ext4_save_buffer(&env_new); + if (err) + return err; + + gd->env_valid = ENV_INVALID; + puts("done\n"); + + return 0; +} + +static int env_ext4_load(void) +{ + ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_SIZE); + struct blk_desc *dev_desc = NULL; + struct disk_partition 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; + } + + err = env_import(buf, 1, H_EXTERNAL); + if (!err) + gd->env_valid = ENV_VALID; + + return err; + +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), + .erase = ENV_ERASE_PTR(env_ext4_erase), +}; diff --git a/roms/u-boot/env/fat.c b/roms/u-boot/env/fat.c new file mode 100644 index 000000000..9d37d26f9 --- /dev/null +++ b/roms/u-boot/env/fat.c @@ -0,0 +1,178 @@ +// 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 <part.h> +#include <malloc.h> +#include <memalign.h> +#include <search.h> +#include <errno.h> +#include <fat.h> +#include <mmc.h> +#include <asm/cache.h> +#include <asm/global_data.h> +#include <linux/stddef.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 +#endif + +DECLARE_GLOBAL_DATA_PTR; + +static char *env_fat_device_and_part(void) +{ +#ifdef CONFIG_MMC + static char *part_str; + + if (!part_str) { + part_str = CONFIG_ENV_FAT_DEVICE_AND_PART; + if (!strcmp(CONFIG_ENV_FAT_INTERFACE, "mmc") && part_str[0] == ':') { + part_str = "0" CONFIG_ENV_FAT_DEVICE_AND_PART; + part_str[0] += mmc_get_env_dev(); + } + } + + return part_str; +#else + return CONFIG_ENV_FAT_DEVICE_AND_PART; +#endif +} + +static int env_fat_save(void) +{ + env_t __aligned(ARCH_DMA_MINALIGN) env_new; + struct blk_desc *dev_desc = NULL; + struct disk_partition info; + const char *file = CONFIG_ENV_FAT_FILE; + 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, + 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; + } + +#ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT + if (gd->env_valid == ENV_VALID) + file = CONFIG_ENV_FAT_FILE_REDUND; +#endif + + err = file_fat_write(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... ", + file, CONFIG_ENV_FAT_INTERFACE, dev, part); + return 1; + } + +#ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT + gd->env_valid = (gd->env_valid == ENV_REDUND) ? ENV_VALID : ENV_REDUND; +#endif + + return 0; +} + +#ifdef LOADENV +static int env_fat_load(void) +{ + ALLOC_CACHE_ALIGN_BUFFER(char, buf1, CONFIG_ENV_SIZE); +#ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT + ALLOC_CACHE_ALIGN_BUFFER(char, buf2, CONFIG_ENV_SIZE); + int err2; +#endif + struct blk_desc *dev_desc = NULL; + struct disk_partition info; + int dev, part; + int err1; + +#ifdef CONFIG_MMC + if (!strcmp(CONFIG_ENV_FAT_INTERFACE, "mmc")) + mmc_initialize(NULL); +#endif + + part = blk_get_device_part_str(CONFIG_ENV_FAT_INTERFACE, + 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; + } + + err1 = file_fat_read(CONFIG_ENV_FAT_FILE, buf1, CONFIG_ENV_SIZE); +#ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT + err2 = file_fat_read(CONFIG_ENV_FAT_FILE_REDUND, buf2, CONFIG_ENV_SIZE); + + err1 = (err1 >= 0) ? 0 : -1; + err2 = (err2 >= 0) ? 0 : -1; + return env_import_redund(buf1, err1, buf2, err2, H_EXTERNAL); +#else + if (err1 < 0) { + /* + * 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(buf1, 1, H_EXTERNAL); +#endif + +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 + .save = ENV_SAVE_PTR(env_fat_save), +}; diff --git a/roms/u-boot/env/flags.c b/roms/u-boot/env/flags.c new file mode 100644 index 000000000..e3e833c43 --- /dev/null +++ b/roms/u-boot/env/flags.c @@ -0,0 +1,609 @@ +// 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 + +#ifdef CONFIG_ENV_WRITEABLE_LIST +#define ENV_FLAGS_WRITEABLE_VARACCESS_REPS "w" +#else +#define ENV_FLAGS_WRITEABLE_VARACCESS_REPS "" +#endif + +static const char env_flags_vartype_rep[] = "sdxb" ENV_FLAGS_NET_VARTYPE_REPS; +static const char env_flags_varaccess_rep[] = + "aroc" ENV_FLAGS_WRITEABLE_VARACCESS_REPS; +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_ENV_WRITEABLE_LIST + ENV_FLAGS_VARACCESS_WRITEABLE, +#endif + }; + +#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", +#ifdef CONFIG_ENV_WRITEABLE_LIST + "writeable", +#endif +}; + +/* + * 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) +{ + enum env_flags_varaccess va_default = env_flags_varaccess_any; + enum env_flags_varaccess va; + char *access; + + if (strlen(flags) <= ENV_FLAGS_VARACCESS_LOC) + return va_default; + + access = strchr(env_flags_varaccess_rep, + flags[ENV_FLAGS_VARACCESS_LOC]); + + if (access != NULL) { + va = (enum env_flags_varaccess) + (access - &env_flags_varaccess_rep[0]); + return va; + } + + printf("## Warning: Unknown environment variable access method '%c'\n", + flags[ENV_FLAGS_VARACCESS_LOC]); + return va_default; +} + +/* + * 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) +{ + enum env_flags_varaccess va_default = env_flags_varaccess_any; + enum env_flags_varaccess va; + int i; + + for (i = 0; i < ARRAY_SIZE(env_flags_varaccess_mask); i++) + if (env_flags_varaccess_mask[i] == + (binflags & ENV_FLAGS_VARACCESS_BIN_MASK)) { + va = (enum env_flags_varaccess)i; + return va; + } + + printf("Warning: Non-standard access flags. (0x%x)\n", + binflags & ENV_FLAGS_VARACCESS_BIN_MASK); + + return va_default; +} + +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); + enum env_flags_varaccess va_default = env_flags_varaccess_any; + char flags[ENV_FLAGS_ATTR_MAX_LEN + 1]; + + if (env_flags_lookup(flags_list, name, flags)) + return va_default; + + if (strlen(flags) <= ENV_FLAGS_VARACCESS_LOC) + return va_default; + + 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) { +#ifdef CONFIG_ENV_WRITEABLE_LIST + flags_list = ENV_FLAGS_LIST_STATIC; +#else + flags_list = env_get(ENV_FLAGS_VAR); +#endif + first_call = 0; + } + /* look in the ".flags" and static for a reference to this variable */ + 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; + 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 */ +#ifdef CONFIG_ENV_WRITEABLE_LIST + if (flag & H_DEFAULT) + return 0; /* Default env is always OK */ + + /* + * External writeable variables can be overwritten by external env, + * anything else can not be overwritten by external env. + */ + if ((flag & H_EXTERNAL) && + !(item->flags & ENV_FLAGS_VARACCESS_WRITEABLE)) + return 1; +#endif + + if (flag & H_FORCE) { +#ifdef CONFIG_ENV_ACCESS_IGNORE_FORCE + printf("## Error: Can't force access to \"%s\"\n", name); +#else + 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 diff --git a/roms/u-boot/env/flash.c b/roms/u-boot/env/flash.c new file mode 100644 index 000000000..ebee9069e --- /dev/null +++ b/roms/u-boot/env/flash.c @@ -0,0 +1,371 @@ +// 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 <flash.h> +#include <log.h> +#include <asm/global_data.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, H_EXTERNAL); +} +#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 +}; diff --git a/roms/u-boot/env/mmc.c b/roms/u-boot/env/mmc.c new file mode 100644 index 000000000..09e94f0bd --- /dev/null +++ b/roms/u-boot/env/mmc.c @@ -0,0 +1,397 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2008-2011 Freescale Semiconductor, Inc. + */ + +/* #define DEBUG */ + +#include <common.h> +#include <asm/global_data.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, int copy, s64 *val) +{ + struct disk_partition info; + struct blk_desc *desc; + int len, i, ret; + char dev_str[4]; + + snprintf(dev_str, sizeof(dev_str), "%d", mmc_get_env_dev()); + ret = blk_get_device_by_str("mmc", dev_str, &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(info.name))) + break; + } + + /* round up to info.blksz */ + len = DIV_ROUND_UP(CONFIG_ENV_SIZE, info.blksz); + + /* use the top of the partion for the environment */ + *val = (info.start + info.size - (1 + copy) * 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, copy, &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; +} + +#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; +} + +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_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, H_EXTERNAL); + +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; + env_t *ep = 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, &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, H_EXTERNAL); + if (!ret) { + ep = (env_t *)buf; + gd->env_addr = (ulong)&ep->data; + } + +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), + .erase = ENV_ERASE_PTR(env_mmc_erase) +#endif +}; diff --git a/roms/u-boot/env/nand.c b/roms/u-boot/env/nand.c new file mode 100644 index 000000000..be82e97d6 --- /dev/null +++ b/roms/u-boot/env/nand.c @@ -0,0 +1,391 @@ +// 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 <asm/global_data.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, H_EXTERNAL); + +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, H_EXTERNAL); +#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, +}; diff --git a/roms/u-boot/env/nowhere.c b/roms/u-boot/env/nowhere.c new file mode 100644 index 000000000..41557f5ce --- /dev/null +++ b/roms/u-boot/env/nowhere.c @@ -0,0 +1,52 @@ +// 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 <asm/global_data.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; +} + +static int env_nowhere_load(void) +{ + /* + * for SPL, set env_valid = ENV_INVALID is enough as env_get_char() + * return the default env if env_get is used + * and SPL don't used env_import to reduce its size + * For U-Boot proper, import the default environment to allow reload. + */ + if (!IS_ENABLED(CONFIG_SPL_BUILD)) + env_set_default(NULL, 0); + + gd->env_valid = ENV_INVALID; + + return 0; +} + +U_BOOT_ENV_LOCATION(nowhere) = { + .location = ENVL_NOWHERE, + .init = env_nowhere_init, + .load = env_nowhere_load, + ENV_NAME("nowhere") +}; diff --git a/roms/u-boot/env/nvram.c b/roms/u-boot/env/nvram.c new file mode 100644 index 000000000..f4126858b --- /dev/null +++ b/roms/u-boot/env/nvram.c @@ -0,0 +1,124 @@ +// 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 <asm/global_data.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 +static 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, H_EXTERNAL); +} + +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, +}; diff --git a/roms/u-boot/env/onenand.c b/roms/u-boot/env/onenand.c new file mode 100644 index 000000000..c8da3ff81 --- /dev/null +++ b/roms/u-boot/env/onenand.c @@ -0,0 +1,114 @@ +// 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 <asm/global_data.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, H_EXTERNAL); + 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), +}; diff --git a/roms/u-boot/env/remote.c b/roms/u-boot/env/remote.c new file mode 100644 index 000000000..166bebf52 --- /dev/null +++ b/roms/u-boot/env/remote.c @@ -0,0 +1,61 @@ +// 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 <asm/global_data.h> +#include <linux/stddef.h> +#include <u-boot/crc.h> + +#ifdef ENV_IS_EMBEDDED +static env_t *env_ptr = &environment; +#else /* ! ENV_IS_EMBEDDED */ +static 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, H_EXTERNAL); +#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, +}; diff --git a/roms/u-boot/env/sata.c b/roms/u-boot/env/sata.c new file mode 100644 index 000000000..9442cfcaf --- /dev/null +++ b/roms/u-boot/env/sata.c @@ -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, H_EXTERNAL); +} + +U_BOOT_ENV_LOCATION(sata) = { + .location = ENVL_ESATA, + ENV_NAME("SATA") + .load = env_sata_load, + .save = env_save_ptr(env_sata_save), +}; diff --git a/roms/u-boot/env/sf.c b/roms/u-boot/env/sf.c new file mode 100644 index 000000000..e4b7ca9e0 --- /dev/null +++ b/roms/u-boot/env/sf.c @@ -0,0 +1,457 @@ +// 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 <flash.h> +#include <malloc.h> +#include <spi.h> +#include <spi_flash.h> +#include <search.h> +#include <errno.h> +#include <uuid.h> +#include <asm/cache.h> +#include <asm/global_data.h> +#include <dm/device-internal.h> +#include <u-boot/crc.h> + +#ifndef CONFIG_SPL_BUILD +#define INITENV +#endif + +#define OFFSET_INVALID (~(u32)0) + +#ifdef CONFIG_ENV_OFFSET_REDUND +#define ENV_OFFSET_REDUND CONFIG_ENV_OFFSET_REDUND + +static ulong env_offset = CONFIG_ENV_OFFSET; +static ulong env_new_offset = CONFIG_ENV_OFFSET_REDUND; + +#else + +#define ENV_OFFSET_REDUND OFFSET_INVALID + +#endif /* CONFIG_ENV_OFFSET_REDUND */ + +DECLARE_GLOBAL_DATA_PTR; + +static int setup_flash_device(struct spi_flash **env_flash) +{ +#if CONFIG_IS_ENABLED(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 + *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) +static int env_sf_save(void) +{ + env_t env_new; + char *saved_buffer = NULL, flag = ENV_REDUND_OBSOLETE; + u32 saved_size = 0, saved_offset = 0, sector; + u32 sect_size = CONFIG_ENV_SECT_SIZE; + int ret; + struct spi_flash *env_flash; + + ret = setup_flash_device(&env_flash); + if (ret) + return ret; + + if (IS_ENABLED(CONFIG_ENV_SECT_SIZE_AUTO)) + sect_size = env_flash->mtd.erasesize; + + 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 (sect_size > CONFIG_ENV_SIZE) { + saved_size = 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, sect_size); + + puts("Erasing SPI flash..."); + ret = spi_flash_erase(env_flash, env_new_offset, + sector * 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 (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: + spi_flash_free(env_flash); + + if (saved_buffer) + free(saved_buffer); + + return ret; +} + +static int env_sf_load(void) +{ + int ret; + int read1_fail, read2_fail; + env_t *tmp_env1, *tmp_env2; + struct spi_flash *env_flash; + + 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(&env_flash); + 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, H_EXTERNAL); + + spi_flash_free(env_flash); +out: + free(tmp_env1); + free(tmp_env2); + + return ret; +} +#else +static int env_sf_save(void) +{ + u32 saved_size = 0, saved_offset = 0, sector; + u32 sect_size = CONFIG_ENV_SECT_SIZE; + char *saved_buffer = NULL; + int ret = 1; + env_t env_new; + struct spi_flash *env_flash; + + ret = setup_flash_device(&env_flash); + if (ret) + return ret; + + if (IS_ENABLED(CONFIG_ENV_SECT_SIZE_AUTO)) + sect_size = env_flash->mtd.erasesize; + + /* Is the sector larger than the env (i.e. embedded) */ + if (sect_size > CONFIG_ENV_SIZE) { + saved_size = 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, sect_size); + + puts("Erasing SPI flash..."); + ret = spi_flash_erase(env_flash, CONFIG_ENV_OFFSET, + sector * 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 (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: + spi_flash_free(env_flash); + + if (saved_buffer) + free(saved_buffer); + + return ret; +} + +static int env_sf_load(void) +{ + int ret; + char *buf = NULL; + struct spi_flash *env_flash; + + buf = (char *)memalign(ARCH_DMA_MINALIGN, CONFIG_ENV_SIZE); + if (!buf) { + env_set_default("malloc() failed", 0); + return -EIO; + } + + ret = setup_flash_device(&env_flash); + 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, H_EXTERNAL); + if (!ret) + gd->env_valid = ENV_VALID; + +err_read: + spi_flash_free(env_flash); +out: + free(buf); + + return ret; +} +#endif + +static int env_sf_erase(void) +{ + int ret; + env_t env; + struct spi_flash *env_flash; + + ret = setup_flash_device(&env_flash); + if (ret) + return ret; + + memset(&env, 0, sizeof(env_t)); + ret = spi_flash_write(env_flash, CONFIG_ENV_OFFSET, CONFIG_ENV_SIZE, &env); + if (ret) + goto done; + + if (ENV_OFFSET_REDUND != OFFSET_INVALID) + ret = spi_flash_write(env_flash, ENV_OFFSET_REDUND, CONFIG_ENV_SIZE, &env); + +done: + spi_flash_free(env_flash); + + return ret; +} + +#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) +/* + * check if Environment on CONFIG_ENV_ADDR is valid. + */ +static int env_sf_init_addr(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 + +#if defined(CONFIG_ENV_SPI_EARLY) +/* + * early load environment from SPI flash (before relocation) + * and check if it is valid. + */ +static int env_sf_init_early(void) +{ + int ret; + int read1_fail; + int read2_fail; + int crc1_ok; + env_t *tmp_env2 = NULL; + env_t *tmp_env1; + struct spi_flash *env_flash; + + /* + * if malloc is not ready yet, we cannot use + * this part yet. + */ + if (!gd->malloc_limit) + return -ENOENT; + + tmp_env1 = (env_t *)memalign(ARCH_DMA_MINALIGN, + CONFIG_ENV_SIZE); + if (IS_ENABLED(CONFIG_SYS_REDUNDAND_ENVIRONMENT)) + tmp_env2 = (env_t *)memalign(ARCH_DMA_MINALIGN, + CONFIG_ENV_SIZE); + + if (!tmp_env1 || !tmp_env2) + goto out; + + ret = setup_flash_device(&env_flash); + if (ret) + goto out; + + read1_fail = spi_flash_read(env_flash, CONFIG_ENV_OFFSET, + CONFIG_ENV_SIZE, tmp_env1); + + if (IS_ENABLED(CONFIG_SYS_REDUNDAND_ENVIRONMENT)) { + read2_fail = spi_flash_read(env_flash, + CONFIG_ENV_OFFSET_REDUND, + CONFIG_ENV_SIZE, tmp_env2); + ret = env_check_redund((char *)tmp_env1, read1_fail, + (char *)tmp_env2, read2_fail); + + if (ret < 0) + goto err_read; + + if (gd->env_valid == ENV_VALID) + gd->env_addr = (unsigned long)&tmp_env1->data; + else + gd->env_addr = (unsigned long)&tmp_env2->data; + } else { + if (read1_fail) + goto err_read; + + crc1_ok = crc32(0, tmp_env1->data, ENV_SIZE) == + tmp_env1->crc; + if (!crc1_ok) + goto err_read; + + /* if valid -> this is our env */ + gd->env_valid = ENV_VALID; + gd->env_addr = (unsigned long)&tmp_env1->data; + } + + spi_flash_free(env_flash); + + return 0; +err_read: + spi_flash_free(env_flash); + + free(tmp_env1); + if (IS_ENABLED(CONFIG_SYS_REDUNDAND_ENVIRONMENT)) + free(tmp_env2); +out: + /* env is not valid. always return 0 */ + gd->env_valid = ENV_INVALID; + return 0; +} +#endif + +static int env_sf_init(void) +{ +#if defined(INITENV) && (CONFIG_ENV_ADDR != 0x0) + return env_sf_init_addr(); +#elif defined(CONFIG_ENV_SPI_EARLY) + return env_sf_init_early(); +#endif + /* + * return here -ENOENT, so env_init() + * can set the init bit and later if no + * other Environment storage is defined + * can set the default environment + */ + return -ENOENT; +} + +U_BOOT_ENV_LOCATION(sf) = { + .location = ENVL_SPI_FLASH, + ENV_NAME("SPIFlash") + .load = env_sf_load, + .save = ENV_SAVE_PTR(env_sf_save), + .erase = ENV_ERASE_PTR(env_sf_erase), + .init = env_sf_init, +}; diff --git a/roms/u-boot/env/ubi.c b/roms/u-boot/env/ubi.c new file mode 100644 index 000000000..eb21c4f38 --- /dev/null +++ b/roms/u-boot/env/ubi.c @@ -0,0 +1,185 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (c) Copyright 2012 by National Instruments, + * Joe Hershberger <joe.hershberger@ni.com> + */ + +#include <common.h> +#include <asm/global_data.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, H_EXTERNAL); +} +#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, H_EXTERNAL); +} +#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), +}; |