summaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
Diffstat (limited to 'common')
-rw-r--r--common/.gitignore2
-rw-r--r--common/Kconfig427
-rw-r--r--common/Makefile20
-rw-r--r--common/bbu.c224
-rw-r--r--common/binfmt.c6
-rw-r--r--common/block.c84
-rw-r--r--common/blspec.c219
-rw-r--r--common/boards/Kconfig16
-rw-r--r--common/boards/Makefile5
-rw-r--r--common/boards/phytec/Makefile5
-rw-r--r--common/boards/phytec/phytec-som-detection.c209
-rw-r--r--common/boards/phytec/phytec-som-imx8m-detection.c151
-rw-r--r--common/boards/qemu-virt/Makefile13
-rw-r--r--common/boards/qemu-virt/board.c90
-rw-r--r--common/boards/qemu-virt/fitimage-pubkey.dts7
-rw-r--r--common/boards/qemu-virt/qemu-virt-flash.dtso99
-rw-r--r--common/boards/qemu-virt/qemu-virt-flash.h22
-rw-r--r--common/boards/tq/Makefile1
-rw-r--r--common/boards/tq/tq_eeprom.c139
-rw-r--r--common/boot.c36
-rw-r--r--common/bootchooser.c25
-rw-r--r--common/booti.c41
-rw-r--r--common/bootm.c249
-rw-r--r--common/bootsource.c146
-rw-r--r--common/bthread.c2
-rw-r--r--common/calloc.c2
-rw-r--r--common/complete.c126
-rw-r--r--common/console.c47
-rw-r--r--common/console_common.c61
-rw-r--r--common/console_simple.c4
-rw-r--r--common/ddr1_dimm_params.c323
-rw-r--r--common/ddr2_dimm_params.c326
-rw-r--r--common/ddr3_dimm_params.c328
-rw-r--r--common/ddr4_dimm_params.c355
-rw-r--r--common/ddr_spd.c615
-rw-r--r--common/deep-probe.c4
-rw-r--r--common/dlmalloc.c36
-rw-r--r--common/dummy_malloc.c2
-rw-r--r--common/efi-devicepath.c1195
-rw-r--r--common/efi-guid.c93
-rw-r--r--common/efi/Makefile4
-rw-r--r--common/efi/efi-image.c289
-rw-r--r--common/efi/efi-iomem.c175
-rw-r--r--common/efi/efi.c481
-rw-r--r--common/efi/env-efi/network/eth0-discover5
-rw-r--r--common/elf.c104
-rw-r--r--common/env.c53
-rw-r--r--common/envfs-core.c17
-rw-r--r--common/environment.c90
-rw-r--r--common/fastboot.c107
-rw-r--r--common/file-list.c71
-rw-r--r--common/filetype.c83
-rw-r--r--common/firmware.c41
-rw-r--r--common/globalvar.c40
-rw-r--r--common/hush.c12
-rw-r--r--common/image-fit.c205
-rw-r--r--common/imd-barebox.c12
-rw-r--r--common/imd.c12
-rw-r--r--common/imx-bbu-nand-fcb.c464
-rw-r--r--common/kallsyms.c10
-rw-r--r--common/machine_id.c99
-rw-r--r--common/meminfo.c8
-rw-r--r--common/memory.c49
-rw-r--r--common/memory_display.c6
-rw-r--r--common/memtest.c44
-rw-r--r--common/menutree.c12
-rw-r--r--common/misc.c92
-rw-r--r--common/module.lds.S2
-rw-r--r--common/oftree.c144
-rw-r--r--common/optee.c52
-rw-r--r--common/parser.c2
-rw-r--r--common/partitions.c235
-rw-r--r--common/partitions/Kconfig3
-rw-r--r--common/partitions/Makefile2
-rw-r--r--common/partitions/dos.c346
-rw-r--r--common/partitions/efi.c344
-rw-r--r--common/partitions/efi.h119
-rw-r--r--common/partitions/parser.h39
-rw-r--r--common/password.c4
-rw-r--r--common/pe.c379
-rw-r--r--common/ratp/Kconfig3
-rw-r--r--common/ratp/Makefile2
-rw-r--r--common/ratp/getenv.c3
-rw-r--r--common/ratp/i2c.c4
-rw-r--r--common/ratp/md.c4
-rw-r--r--common/ratp/mw.c1
-rw-r--r--common/ratp/ratp.c2
-rw-r--r--common/reset_source.c28
-rw-r--r--common/resource.c13
-rw-r--r--common/restart.c39
-rw-r--r--common/serdev.c5
-rw-r--r--common/startup.c80
-rw-r--r--common/state/Makefile2
-rw-r--r--common/state/backend_bucket_circular.c4
-rw-r--r--common/state/backend_bucket_direct.c28
-rw-r--r--common/state/backend_format_dtb.c4
-rw-r--r--common/state/backend_format_raw.c13
-rw-r--r--common/state/backend_storage.c28
-rw-r--r--common/state/state.c97
-rw-r--r--common/state/state.h32
-rw-r--r--common/state/state_variables.c13
-rw-r--r--common/tlsf.c64
-rw-r--r--common/tlsfbits.h2
-rw-r--r--common/ubiformat.c6
-rw-r--r--common/uimage.c50
-rw-r--r--common/usbgadget.c51
-rw-r--r--common/version.c8
107 files changed, 6892 insertions, 3705 deletions
diff --git a/common/.gitignore b/common/.gitignore
index 8e0d6c160e..e3e3d504dc 100644
--- a/common/.gitignore
+++ b/common/.gitignore
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
module.lds
barebox_default_env*
diff --git a/common/Kconfig b/common/Kconfig
index f4120b2083..0000dac874 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -1,3 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+source "common/boards/Kconfig"
+
config GREGORIAN_CALENDER
bool
@@ -23,7 +27,7 @@ config HAS_DMA
Drivers that depend on a DMA implementation can depend on this
config, so that you don't get a compilation error.
-config HAS_ARCH_SJLJ
+config ARCH_HAS_SJLJ
bool
help
Architecture has support implemented for setjmp()/longjmp()/initjmp()
@@ -37,15 +41,6 @@ config BLOCK
config BLOCK_WRITE
bool
-config USE_COMPRESSED_DTB
- bool
- depends on ARM || RISCV
- select UNCOMPRESS
- select LZO_DECOMPRESS
-
-config ELF
- bool "ELF Support" if COMPILE_TEST
-
config FILETYPE
bool
@@ -78,20 +73,12 @@ config MENUTREE
select GLOB
select GLOB_SORT
-config EFI_GUID
- bool
- help
- With this option a table of EFI guids is compiled in.
-
-config EFI_DEVICEPATH
- bool
-
config ARCH_DMA_ADDR_T_64BIT
bool
config BAREBOX_UPDATE_IMX_NAND_FCB
bool
- depends on ARCH_IMX6 || ARCH_IMX28
+ depends on ARCH_IMX7 || ARCH_IMX6 || ARCH_IMX28
depends on BAREBOX_UPDATE
depends on MTD_WRITE
depends on NAND_MXS
@@ -157,6 +144,9 @@ config MEMINFO
bool "display memory info"
default y
+config MEMTEST
+ bool
+
config ENVIRONMENT_VARIABLES
bool "environment variables support"
@@ -198,14 +188,8 @@ config MMU
to enable the data cache which depends on the MMU. See Documentation/mmu.txt
for further information.
-config MMU_EARLY
- bool "Enable MMU early"
- depends on ARM
- depends on MMU
- default y
- help
- This enables the MMU during early startup. This speeds up things during startup
- of barebox, but may lead to harder to debug code. If unsure say yes here.
+config MMUINFO
+ bool
config HAVE_CONFIGURABLE_TEXT_BASE
bool
@@ -214,9 +198,13 @@ config TEXT_BASE
depends on HAVE_CONFIGURABLE_TEXT_BASE
prompt "TEXT_BASE"
hex
+ range 0 0xffffffff
default ARCH_TEXT_BASE
help
- The Address barebox gets linked at.
+ The 32-bit address barebox gets linked at. This is forced
+ to zero for relocatable barebox and fixed up at runtime,
+ so barebox is executable on arbitrary addresses (given
+ sufficient alignment).
config BAREBOX_MAX_IMAGE_SIZE
prompt "Maximum size of barebox"
@@ -289,6 +277,11 @@ config MALLOC_SIZE
hex
default 0x400000
prompt "malloc area size"
+
+config MALLOC_ALIGNMENT
+ hex
+ default 8
+
endmenu
config BROKEN
@@ -360,16 +353,40 @@ config RELOCATABLE
allowing it to relocate to the end of the available RAM. This
way you have the whole memory in a single piece.
-config PANIC_HANG
- bool "hang the system in case of a fatal error"
- help
- This option enables stop of the system in case of a
- fatal error, so that you have to reset it manually.
- This is probably NOT a good idea for an embedded
- system where you want the system to reboot
- automatically as fast as possible, but it may be
- useful during development since you can try to debug
- the conditions that lead to the situation.
+choice
+ prompt "Configure action on fatal error"
+ default PANIC_RESET
+
+ config PANIC_POWEROFF
+ bool "power off the system"
+ help
+ This option shuts down the system in case of a
+ fatal error, so that you have to power it on manually.
+ This is probably NOT a good idea for an embedded
+ system where you want the system to reboot
+ automatically as fast as possible, but it may be
+ useful in emulation, because the system returns
+ to parent shell immediately.
+
+ config PANIC_HANG
+ bool "hang the system"
+ help
+ This option enables stop of the system in case of a
+ fatal error, so that you have to reset it manually.
+ This is probably NOT a good idea for an embedded
+ system where you want the system to reboot
+ automatically as fast as possible, but it may be
+ useful during development since you can try to debug
+ the conditions that lead to the situation.
+
+ config PANIC_RESET
+ bool "reset the system"
+ help
+ This option enables reset of the system in case of a
+ fatal error, so you don't have to reset it manually.
+ This is the recommended configuration in production.
+
+endchoice
config PROMPT
string
@@ -531,15 +548,6 @@ endchoice
endif
-config DYNAMIC_CRC_TABLE
- bool
- depends on CRC32
- prompt "Generate the crc32 table dynamically"
- default y
- help
- Saying yes to this option saves around 800 bytes of binary size.
- If unsure say yes.
-
config ERRNO_MESSAGES
bool
prompt "print error values as text"
@@ -549,12 +557,11 @@ config TIMESTAMP
bool
default y
select GREGORIAN_CALENDER
- prompt "print timestamp information from images"
+ prompt "print timestamp information from uImages"
help
When CONFIG_TIMESTAMP is selected, the timestamp
- (date and time) of an image is printed by image
- commands like bootm or iminfo. This option is
- automatically enabled when you select CFG_CMD_DATE .
+ (date and time) of an uImage is printed by image
+ commands like bootm or uimage.
menuconfig BOOTM
select UIMAGE
@@ -616,6 +623,12 @@ config BOOTM_AIMAGE
help
Support using Android Images.
+config PE
+ bool "PE/COFF Support" if COMPILE_TEST
+
+config ELF
+ bool "ELF Support" if COMPILE_TEST
+
config BOOTM_ELF
bool
depends on BOOTM
@@ -649,6 +662,22 @@ config BOOTM_FITIMAGE_SIGNATURE
Additionally the barebox device tree needs a /signature node with the
public key with which the image has been signed.
+config BOOTM_FITIMAGE_PUBKEY_ENV
+ bool "Specify path to public key in environment"
+ depends on BOOTM_FITIMAGE_SIGNATURE
+ help
+ If this option is enabled the path to the device tree snippet
+ containing the public key for verifying FIT images signature is taken
+ from make's build-time environment, which can allow for better
+ integration with some build systems.
+
+ The environment variable has the same name as the corresponding
+ Kconfig variable:
+
+ CONFIG_BOOTM_FITIMAGE_PUBKEY
+
+if BOOTM_FITIMAGE_SIGNATURE && !BOOTM_FITIMAGE_PUBKEY_ENV
+
config BOOTM_FITIMAGE_PUBKEY
string "Path to dtsi containing pubkey"
default "../fit/pubkey.dtsi"
@@ -658,6 +687,12 @@ config BOOTM_FITIMAGE_PUBKEY
snippet can then be included in a device tree with
"#include CONFIG_BOOTM_FITIMAGE_PUBKEY".
+ This snippet is usually generated by decompiling a device tree produced
+ by mkimage. An alternative is CONFIG_CRYPTO_RSA_KEY, which takes a PEM
+ file or a PKCS#11 URI.
+
+endif
+
config BOOTM_FORCE_SIGNED_IMAGES
bool
prompt "Force booting of signed images"
@@ -676,8 +711,8 @@ config BLSPEC
bool
prompt "Support bootloader spec"
help
- Enable this to let barebox support the Freedesktop bootloader spec,
- see: http://www.freedesktop.org/wiki/Specifications/BootLoaderSpec/
+ Enable this to let barebox support the UAPI bootloader spec,
+ see: https://uapi-group.org/specifications/specs/boot_loader_specification/
The bootloader spec is a standard interface between the bootloader
and the kernel. It allows the bootloader to discover boot options
on a device and it allows the Operating System to install / update
@@ -707,7 +742,7 @@ config MMCBLKDEV_ROOTARG
kernel doesn't contain commit [1]. The first linux kernel release
containing that commit is v5.10-rc1.
- The appending only happen if barebox 'linux.bootargs.bootm.appendroot'
+ The appending only happens if barebox' 'linux.bootargs.bootm.appendroot'
variable is set or the used blspec entry contains 'linux-appendroot'.
Note: It is crucial that the kernel device tree and the barebox device
@@ -734,6 +769,12 @@ config IMD
select CRC32
bool "barebox metadata support"
+config IMD_ENDIANNESS
+ bool "add endianness record to metadata"
+ depends on IMD
+ depends on SYS_SUPPORTS_LITTLE_ENDIAN && SYS_SUPPORTS_BIG_ENDIAN
+ default y
+
choice
prompt "console support"
default CONSOLE_FULL
@@ -799,6 +840,16 @@ config CONSOLE_ALLOW_COLOR
compile time default for colored console output. After boot it
can be controlled using global.allow_color.
+config CONSOLE_FLUSH_LINE_BREAK
+ bool "Flush consoles on new line" if COMPILE_TEST
+ help
+ Many serial drivers configure and use hardware FIFOs as not to
+ delay the boot. When debuging some king of bugs, such as clock
+ issues that hang the SoC, this can falsify debugging output,
+ because the UART doesn't output a submitted message fully, before
+ the SoC hangs. This option will flush serial FIFOs when processing
+ the new line feed characters.
+
config CONSOLE_DISABLE_INPUT
prompt "Disable input on all consoles by default (non-interactive)"
def_bool CONSOLE_NONE
@@ -827,6 +878,9 @@ config PARTITION
bool
prompt "Enable Partitions"
+config PARTITION_MANIPULATION
+ bool
+
source "common/partitions/Kconfig"
config ENV_HANDLING
@@ -858,29 +912,30 @@ choice
default DEFAULT_COMPRESSION_LZ4 if LZ4_DECOMPRESS
default DEFAULT_COMPRESSION_BZIP2 if BZLIB
help
- Select the default compression for in-barebox binary files. Files
- compiled into barebox like for example the default environment will
- be compressed with this compression type.
+ For barebox builds without a prebootloader, select here the default
+ compression for in-barebox binary files. barebox itself can't be
+ compressed without a prebootloader, but for example the default
+ environment will be compressed with this compression type.
config DEFAULT_COMPRESSION_GZIP
bool "gzip"
- depends on ZLIB
+ depends on !PBL_IMAGE && ZLIB
config DEFAULT_COMPRESSION_BZIP2
bool "bzip2"
- depends on BZLIB
+ depends on !PBL_IMAGE && BZLIB
config DEFAULT_COMPRESSION_LZO
bool "lzo"
- depends on LZO_DECOMPRESS
+ depends on !PBL_IMAGE && LZO_DECOMPRESS
config DEFAULT_COMPRESSION_LZ4
bool "lz4"
- depends on LZ4_DECOMPRESS
+ depends on !PBL_IMAGE && LZ4_DECOMPRESS
config DEFAULT_COMPRESSION_XZ
bool "xz"
- depends on XZ_DECOMPRESS
+ depends on !PBL_IMAGE && XZ_DECOMPRESS
config DEFAULT_COMPRESSION_NONE
bool "no compression"
@@ -990,7 +1045,7 @@ config POLLER
config BTHREAD
bool "barebox co-operative (green) thread infrastructure"
select HAS_SCHED
- depends on HAS_ARCH_SJLJ
+ depends on ARCH_HAS_SJLJ
help
barebox threads are lightweight cooperative (green) threads that are
scheduled within delay loops and the console idle to asynchronously
@@ -1002,6 +1057,13 @@ config STATE
select ENVIRONMENT_VARIABLES
select OFTREE
select PARAMETER
+ imply STATE_DRV
+ imply CMD_STATE
+ help
+ barebox state is a generic framework for atomic power fail-safe
+ variable storage and retrieval. It can be used to safely maintain
+ data over reboots and to exchange information with Linux, e.g.
+ for redundant boot with bootchooser.
config STATE_CRYPTO
bool "HMAC based authentication support"
@@ -1048,7 +1110,7 @@ config RESET_SOURCE
config MACHINE_ID
bool "compute unique machine-id"
depends on FLEXIBLE_BOOTARGS
- depends on SHA1
+ depends on HAVE_DIGEST_SHA1
help
Compute a persistent machine-specific id and store it to $global.machine_id.
The id is a hash of device-specific information added via
@@ -1100,20 +1162,38 @@ config EXTERNAL_DTS_FRAGMENTS
menu "OP-TEE loading"
+config HAVE_OPTEE
+ bool
+ help
+ This symbol is selected by configuration where barebox either
+ starts OP-TEE or runs while OP-TEE is running. Actual
+ bidirectional communication with OP-TEE is enabled via
+ CONFIG_OPTEE.
+
config OPTEE_SIZE
hex
default 0x02000000
prompt "OP-TEE Memory Size"
- depends on BOOTM_OPTEE || PBL_OPTEE
+ depends on HAVE_OPTEE
help
Size to reserve in main memory for OP-TEE.
Can be smaller than the actual size used by OP-TEE, this is used to prevent
barebox from allocating memory in this area.
+config OPTEE_SHM_SIZE
+ hex
+ default 0x400000
+ prompt "OP-TEE Shared Memory Size"
+ depends on HAVE_OPTEE
+ help
+ Size to reserve in main memory for OP-TEE shared memory communication.
+ Can be used for fixing up the OP-TEE OF node.
+
config BOOTM_OPTEE
bool
prompt "support booting OP-TEE"
- depends on BOOTM && ARM
+ depends on BOOTM && ARM && 32BIT
+ select HAVE_OPTEE
help
OP-TEE is a trusted execution environment (TEE). With this option
enabled barebox supports starting optee_os as part of the bootm command.
@@ -1125,6 +1205,7 @@ config PBL_OPTEE
bool "Enable OP-TEE early start"
depends on ARM
depends on !THUMB2_BAREBOX
+ select HAVE_OPTEE
help
Allows starting OP-TEE during lowlevel initialization of the PBL.
Requires explicit support in the board's lowlevel file.
@@ -1213,6 +1294,30 @@ config DEBUG_LL
platform *will not work*, so this option should not be enabled
for builds that are intended to be portable.
+config ARCH_WANT_FRAME_POINTERS
+ bool
+
+config FRAME_POINTER
+ bool "Compile barebox with frame pointers" if COMPILE_TEST
+ default y if ARCH_WANT_FRAME_POINTERS
+ help
+ Selected by platforms that expect frame pointer usage, e.g.
+ when stack unwinding is enabled. The resulting barebox image
+ will be slightly larger and slower, but it can give precise
+ debugging information when print stack traces.
+
+config DEBUG_IMX_UART
+ bool
+
+config DEBUG_ROCKCHIP_UART
+ bool
+
+config DEBUG_OMAP_UART
+ bool
+
+config DEBUG_BCM283X_UART
+ bool
+
choice
prompt "Kernel low-level debugging port"
depends on DEBUG_LL
@@ -1220,6 +1325,7 @@ choice
config DEBUG_IMX1_UART
bool "i.MX1 Debug UART"
depends on ARCH_IMX1
+ select DEBUG_IMX_UART
help
Say Y here if you want kernel low-level debugging support
on i.MX1.
@@ -1227,6 +1333,7 @@ config DEBUG_IMX1_UART
config DEBUG_IMX21_UART
bool "i.MX21 Debug UART"
depends on ARCH_IMX21
+ select DEBUG_IMX_UART
help
Say Y here if you want kernel low-level debugging support
on i.MX21.
@@ -1234,6 +1341,7 @@ config DEBUG_IMX21_UART
config DEBUG_IMX25_UART
bool "i.MX25 Debug UART"
depends on ARCH_IMX25
+ select DEBUG_IMX_UART
help
Say Y here if you want kernel low-level debugging support
on i.MX25.
@@ -1241,6 +1349,7 @@ config DEBUG_IMX25_UART
config DEBUG_IMX27_UART
bool "i.MX27 Debug UART"
depends on ARCH_IMX27
+ select DEBUG_IMX_UART
help
Say Y here if you want kernel low-level debugging support
on i.MX27.
@@ -1248,6 +1357,7 @@ config DEBUG_IMX27_UART
config DEBUG_IMX31_UART
bool "i.MX31 Debug UART"
depends on ARCH_IMX31
+ select DEBUG_IMX_UART
help
Say Y here if you want kernel low-level debugging support
on i.MX31.
@@ -1255,6 +1365,7 @@ config DEBUG_IMX31_UART
config DEBUG_IMX35_UART
bool "i.MX35 Debug UART"
depends on ARCH_IMX35
+ select DEBUG_IMX_UART
help
Say Y here if you want kernel low-level debugging support
on i.MX35.
@@ -1262,6 +1373,7 @@ config DEBUG_IMX35_UART
config DEBUG_IMX50_UART
bool "i.MX50 Debug UART"
depends on ARCH_IMX50
+ select DEBUG_IMX_UART
help
Say Y here if you want kernel low-level debugging support
on i.MX50.
@@ -1269,6 +1381,7 @@ config DEBUG_IMX50_UART
config DEBUG_IMX51_UART
bool "i.MX51 Debug UART"
depends on ARCH_IMX51
+ select DEBUG_IMX_UART
help
Say Y here if you want kernel low-level debugging support
on i.MX51.
@@ -1276,6 +1389,7 @@ config DEBUG_IMX51_UART
config DEBUG_IMX53_UART
bool "i.MX53 Debug UART"
depends on ARCH_IMX53
+ select DEBUG_IMX_UART
help
Say Y here if you want kernel low-level debugging support
on i.MX53.
@@ -1283,6 +1397,7 @@ config DEBUG_IMX53_UART
config DEBUG_IMX6Q_UART
bool "i.MX6Q Debug UART"
depends on ARCH_IMX6
+ select DEBUG_IMX_UART
help
Say Y here if you want kernel low-level debugging support
on i.MX6Q.
@@ -1290,6 +1405,7 @@ config DEBUG_IMX6Q_UART
config DEBUG_IMX7D_UART
bool "i.MX7D Debug UART"
depends on ARCH_IMX7
+ select DEBUG_IMX_UART
help
Say Y here if you want barebox low-level debugging support
on i.MX7D.
@@ -1297,13 +1413,27 @@ config DEBUG_IMX7D_UART
config DEBUG_IMX8M_UART
bool "i.MX8M Debug UART"
depends on ARCH_IMX8M
+ select DEBUG_IMX_UART
help
Say Y here if you want barebox low-level debugging support
on i.MX8M*.
+config DEBUG_IMX9_UART
+ bool "i.MX9 Debug UART"
+ depends on ARCH_IMX93
+ select DEBUG_IMX_UART
+
+config DEBUG_VEXPRESS_UART
+ bool "Vexpress Debug UART"
+ depends on ARCH_VEXPRESS
+ help
+ Say Y here if you want barebox low-level debugging support
+ on Vexpress.
+
config DEBUG_VF610_UART
bool "VF610 Debug UART"
depends on ARCH_VF610
+ select DEBUG_IMX_UART
help
Say Y here if you want kernel low-level debugging support
on VF610.
@@ -1311,6 +1441,7 @@ config DEBUG_VF610_UART
config DEBUG_OMAP3_UART
bool "OMAP3 Debug UART"
depends on ARCH_OMAP3
+ select DEBUG_OMAP_UART
help
Say Y here if you want kernel low-level debugging support
on OMAP3.
@@ -1318,6 +1449,7 @@ config DEBUG_OMAP3_UART
config DEBUG_OMAP4_UART
bool "OMAP4 Debug UART"
depends on ARCH_OMAP4
+ select DEBUG_OMAP_UART
help
Say Y here if you want kernel low-level debugging support
on OMAP4.
@@ -1325,6 +1457,7 @@ config DEBUG_OMAP4_UART
config DEBUG_AM33XX_UART
bool "AM33XX Debug UART"
depends on ARCH_AM33XX
+ select DEBUG_OMAP_UART
help
Say Y here if you want kernel low-level debugging support
on AM33XX.
@@ -1332,6 +1465,7 @@ config DEBUG_AM33XX_UART
config DEBUG_ROCKCHIP_RK3188_UART
bool "RK3188 Debug UART"
depends on ARCH_RK3188
+ select DEBUG_ROCKCHIP_UART
help
Say Y here if you want kernel low-level debugging support
on RK3188.
@@ -1339,6 +1473,7 @@ config DEBUG_ROCKCHIP_RK3188_UART
config DEBUG_ROCKCHIP_RK3288_UART
bool "RK3288 Debug UART"
depends on ARCH_RK3288
+ select DEBUG_ROCKCHIP_UART
help
Say Y here if you want kernel low-level debugging support
on RK3288.
@@ -1346,10 +1481,27 @@ config DEBUG_ROCKCHIP_RK3288_UART
config DEBUG_ROCKCHIP_RK3568_UART
bool "RK3568 Debug UART"
depends on ARCH_RK3568
+ select DEBUG_ROCKCHIP_UART
help
Say Y here if you want kernel low-level debugging support
on RK3568.
+config DEBUG_ROCKCHIP_RK3588_UART
+ bool "RK3588 Debug UART"
+ depends on ARCH_RK3588
+ select DEBUG_ROCKCHIP_UART
+ help
+ Say Y here if you want kernel low-level debugging support
+ on RK3588.
+
+config DEBUG_ROCKCHIP_RK3399_UART
+ bool "RK3399 Debug UART"
+ depends on ARCH_RK3399
+ select DEBUG_ROCKCHIP_UART
+ help
+ Say Y here if you want kernel low-level debugging support
+ on RK3399.
+
config DEBUG_SOCFPGA_UART0
bool "Use SOCFPGA UART0 for low-level debug"
depends on ARCH_SOCFPGA
@@ -1364,9 +1516,17 @@ config DEBUG_SOCFPGA_UART1
Say Y here if you want kernel low-level debugging support
on SOCFPGA(Arria 10) based platforms.
+config DEBUG_STM32MP_UART
+ bool "Use STM32MP UART4 for low-level debug"
+ depends on ARCH_STM32
+ help
+ Say Y here if you want kernel low-level debugging support
+ on STM32MP.
+
config DEBUG_RPI1_UART
bool "RaspberryPi 1 PL011 UART"
depends on ARCH_BCM283X
+ select DEBUG_BCM283X_UART
help
Say Y here if you want low-level debugging support on
RaspberryPi 1 boards.
@@ -1381,6 +1541,7 @@ config DEBUG_AT91_UART
config DEBUG_RPI2_3_UART
bool "RaspberryPi 2/3 PL011 UART"
depends on ARCH_BCM283X
+ select DEBUG_BCM283X_UART
help
Say Y here if you want low-level debugging support on
RaspberryPi 2 and 3 boards.
@@ -1388,10 +1549,26 @@ config DEBUG_RPI2_3_UART
config DEBUG_RPI3_MINI_UART
bool "RaspberryPi 3 mini UART"
depends on ARCH_BCM283X
+ select DEBUG_BCM283X_UART
help
Say Y here if you want low-level debugging support on
RaspberryPi 3 board mini UART.
+config DEBUG_RPI4_MINI_UART
+ bool "RaspberryPi 4 mini UART"
+ depends on ARCH_BCM283X
+ select DEBUG_BCM283X_UART
+ help
+ Say Y here if you want low-level debugging support on
+ RaspberryPi 4 board mini UART.
+
+config DEBUG_ZYNQMP_UART
+ bool "Zynqmp Debug UART"
+ depends on ARCH_ZYNQMP
+ help
+ Say Y here if you want kernel low-level debugging support
+ on Zynqmp.
+
config DEBUG_ERIZO
bool "Erizo ns16550 port"
depends on SOC_ERIZO
@@ -1402,6 +1579,20 @@ config DEBUG_STARFIVE
depends on SOC_STARFIVE
select DEBUG_LL_NS16550
+config DEBUG_RISCV_VIRT
+ bool "RISC-V Virt ns16550 port"
+ depends on SOC_VIRT
+ select DEBUG_LL_NS16550
+
+config DEBUG_RISCVEMU_HTIF
+ bool "riscvemu HTIF port"
+ depends on SOC_VIRT
+ help
+ When run without graphics support, tinyemu will expose access
+ to the Virt I/O console as HTIF blocking console device as well.
+ This is useful for low level debugging before Virt I/O DMA is
+ initialized.
+
config DEBUG_SIFIVE
bool "SiFive serial0 port"
depends on SOC_SIFIVE
@@ -1410,6 +1601,19 @@ config DEBUG_LITEX
bool "LiteX serial port"
depends on SOC_LITEX
+config DEBUG_SUN20I
+ bool "Allwinner Sun20i ns16550 serial0 port"
+ depends on SOC_ALLWINNER_SUN20I
+ select DEBUG_LL_NS16550
+
+config DEBUG_AM62X_UART
+ bool "Texas Instruments AM62X debug UART"
+ depends on ARCH_K3
+
+config DEBUG_QEMU_ARM64_VIRT
+ bool "QEMU ARM64 Virt PL011 console"
+ depends on ARCH_ARM64_VIRT
+
endchoice
config DEBUG_LL_NS16550
@@ -1429,6 +1633,7 @@ config DEBUG_IMX_UART_PORT
DEBUG_IMX6Q_UART || \
DEBUG_IMX7D_UART || \
DEBUG_IMX8M_UART || \
+ DEBUG_IMX9_UART || \
DEBUG_VF610_UART
default 1
depends on ARCH_IMX
@@ -1436,10 +1641,20 @@ config DEBUG_IMX_UART_PORT
Choose UART port on which kernel low-level debug messages
should be output.
+config DEBUG_K3_UART_PORT
+ int "K3 Debug UART Port Selection" if DEBUG_AM62X_UART
+ default 0
+ depends on ARCH_K3
+ help
+ Choose UART port on which kernel low-level debug messages
+ should be output. Possible values are:
+ AM62x: 0 - 6
+
config DEBUG_OMAP_UART_PORT
int "OMAP Debug UART Port Selection" if DEBUG_OMAP3_UART || \
DEBUG_OMAP4_UART || \
- DEBUG_AM33XX_UART
+ DEBUG_AM33XX_UART || \
+ DEBUG_AM62X_UART
default 1
depends on ARCH_OMAP
help
@@ -1452,7 +1667,9 @@ config DEBUG_OMAP_UART_PORT
config DEBUG_ROCKCHIP_UART_PORT
int "RK3xxx UART debug port" if DEBUG_ROCKCHIP_RK3188_UART || \
DEBUG_ROCKCHIP_RK3288_UART || \
- DEBUG_ROCKCHIP_RK3568_UART
+ DEBUG_ROCKCHIP_RK3568_UART || \
+ DEBUG_ROCKCHIP_RK3588_UART || \
+ DEBUG_ROCKCHIP_RK3399_UART
default 2
depends on ARCH_ROCKCHIP
help
@@ -1498,13 +1715,52 @@ config DEBUG_AT91_UART_BASE
config DEBUG_INITCALLS
bool "Trace initcalls"
+ select CONSOLE_FLUSH_LINE_BREAK
help
If enabled this will print initcall traces.
+config DEBUG_PBL
+ bool "Print PBL debugging information"
+ depends on PBL_CONSOLE
+ help
+ If enabled this will enable all debug prints in the prebootloader.
+ For this to work, a console needs to be configured in the
+ board-specific entry point and configured for either DEBUG_LL
+ or PBL_CONSOLE.
+
config DEBUG_PROBES
- bool "Trace driver probes"
+ bool "Trace driver probes/removes"
+ select CONSOLE_FLUSH_LINE_BREAK
help
- If enabled this will print driver probe traces.
+ If enabled this will log driver probe and remove traces. If DEBUG_LL is enabled,
+ probes will be printed even before registering consoles. If it's disabled, they
+ will be collected in the log and written out once a console is active.
+
+ Removes are written to the log and will be printed as long as consoles exist.
+ Most consoles do not implement a remove callback to remain operable until
+ the very end. Consoles using DMA, however, must be removed.
+
+config DMA_API_DEBUG
+ bool "Enable debugging of DMA-API usage"
+ depends on HAS_DMA
+ help
+ Enable this option to debug the use of the DMA API by device drivers.
+ With this option you will be able to detect common bugs in device
+ drivers like double-freeing of DMA mappings or freeing mappings that
+ were never allocated.
+
+ This option causes a performance degradation. Use only if you want to
+ debug device drivers and dma interactions.
+
+ If unsure, say N.
+
+config DEBUG_LIST
+ bool "Debug linked list manipulation"
+ help
+ Enable this to turn on extended checks in the linked-list
+ walking routines.
+
+ If unsure, say N.
config PBL_BREAK
bool "Execute software break on pbl start"
@@ -1513,6 +1769,13 @@ config PBL_BREAK
If enabled, barebox will be compiled with BKPT instruction
on early pbl init. This option should be used only with JTAG debugger!
+config PRINTF_FULL
+ bool "Support all extended printf format specifiers"
+ help
+ Adds support for lesser used format specifiers like UUIDs and
+ hex strings. Code requiring them should select it directly,
+ so this is mainly for debugging. If unsure, say no.
+
source "lib/Kconfig.ubsan"
source "lib/kasan/Kconfig"
@@ -1536,18 +1799,34 @@ config COMPILE_TEST
say Y here. If you are a user, say N here to avoid being prompted for
inclusion of unrelated drivers.
+config WERROR
+ bool "Compile barebox with warnings as errors"
+ default COMPILE_TEST
+ help
+ A barebox build should not cause any compiler warnings, and this
+ enables the '-Werror' flags to enforce that rule by default.
+
+ However, if you have a new (or very old) compiler with odd and
+ unusual warnings, or you have some architecture with problems,
+ you may need to disable this config option in order to
+ successfully build barebox.
+
+ If in doubt, say Y.
+
endmenu
config HAS_DEBUG_LL
bool
-config HAS_ASM_DEBUG_LL
- bool
- select HAS_DEBUG_LL
-
config DDR_SPD
bool
select CRC_ITU_T
config HAVE_ARCH_ASAN
bool
+
+config ARCH_USE_SYM_ANNOTATIONS
+ bool
+ help
+ This is selected by architectures that exclusively use the new SYM_
+ macros in their assembly code and not the deprecated ENTRY/PROC.
diff --git a/common/Makefile b/common/Makefile
index 4b45f678c7..96498790b3 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -1,15 +1,19 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+obj-y += boards/
obj-y += memory.o
obj-y += memory_display.o
pbl-$(CONFIG_PBL_CONSOLE) += memory_display.o
obj-y += clock.o
obj-y += console_common.o
-obj-y += deep-probe.o
+obj-$(CONFIG_OFDEVICE) += deep-probe.o
obj-y += startup.o
obj-y += misc.o
obj-pbl-y += memsize.o
obj-y += resource.o
-obj-y += bootsource.o
+obj-pbl-y += bootsource.o
obj-$(CONFIG_ELF) += elf.o
+obj-$(CONFIG_PE) += pe.o
obj-y += restart.o
obj-y += poweroff.o
obj-y += slice.o
@@ -24,12 +28,16 @@ obj-$(CONFIG_BLOCK) += block.o
obj-$(CONFIG_BLSPEC) += blspec.o
obj-$(CONFIG_BOOTM) += bootm.o booti.o
obj-$(CONFIG_CMD_LOADS) += s_record.o
-obj-$(CONFIG_CMD_MEMTEST) += memtest.o
+obj-$(CONFIG_MEMTEST) += memtest.o
obj-$(CONFIG_COMMAND_SUPPORT) += command.o
obj-$(CONFIG_CONSOLE_FULL) += console.o
obj-$(CONFIG_CONSOLE_SIMPLE) += console_simple.o
obj-y += console_countdown.o
obj-pbl-$(CONFIG_DDR_SPD) += ddr_spd.o
+obj-pbl-$(CONFIG_DDR_SPD) += ddr1_dimm_params.o
+obj-pbl-$(CONFIG_DDR_SPD) += ddr2_dimm_params.o
+obj-pbl-$(CONFIG_DDR_SPD) += ddr3_dimm_params.o
+obj-pbl-$(CONFIG_DDR_SPD) += ddr4_dimm_params.o
obj-$(CONFIG_ENV_HANDLING) += environment.o envfs-core.o
obj-$(CONFIG_DEFAULT_ENVIRONMENT) += envfs-core.o
obj-$(CONFIG_ENVIRONMENT_VARIABLES) += env.o
@@ -63,9 +71,6 @@ obj-$(CONFIG_BOOTCHOOSER) += bootchooser.o
obj-$(CONFIG_UIMAGE) += image.o uimage.o
obj-$(CONFIG_FITIMAGE) += image-fit.o
obj-$(CONFIG_MENUTREE) += menutree.o
-obj-$(CONFIG_EFI_BOOTUP) += efi/
-obj-$(CONFIG_EFI_GUID) += efi-guid.o
-obj-$(CONFIG_EFI_DEVICEPATH) += efi-devicepath.o
lwl-$(CONFIG_IMD) += imd-barebox.o
obj-$(CONFIG_IMD) += imd.o
obj-y += file-list.o
@@ -75,8 +80,7 @@ obj-$(CONFIG_BAREBOX_UPDATE_IMX_NAND_FCB) += imx-bbu-nand-fcb.o
obj-$(CONFIG_BOOT) += boot.o
obj-$(CONFIG_SERIAL_DEV_BUS) += serdev.o
obj-$(CONFIG_USBGADGET_START) += usbgadget.o
-pbl-$(CONFIG_PBL_OPTEE) += optee.o
-obj-$(CONFIG_BOOTM_OPTEE) += optee.o
+obj-pbl-$(CONFIG_HAVE_OPTEE) += optee.o
obj-$(CONFIG_FASTBOOT_BASE) += fastboot.o
ifdef CONFIG_PASSWORD
diff --git a/common/bbu.c b/common/bbu.c
index cd7bdc40b7..ba2566acdf 100644
--- a/common/bbu.c
+++ b/common/bbu.c
@@ -19,47 +19,47 @@
#include <malloc.h>
#include <linux/stat.h>
#include <image-metadata.h>
+#include <environment.h>
#include <file-list.h>
static LIST_HEAD(bbu_image_handlers);
-static void append_bbu_entry(struct bbu_handler *handler, struct file_list *files)
+static void append_bbu_entry(const char *_name,
+ const char *devicefile,
+ struct file_list *files)
{
char *name;
- name = basprintf("bbu-%s", handler->name);
+ name = basprintf("bbu-%s", _name);
- if (file_list_add_entry(files, name, handler->devicefile, 0))
+ if (file_list_add_entry(files, name, devicefile, 0))
pr_warn("duplicate partition name %s\n", name);
free(name);
}
-static bool bbu_handler_is_available(struct bbu_handler *handler)
-{
- struct stat s;
- int ret;
-
- device_detect_by_name(devpath_to_name(handler->devicefile));
-
- ret = stat(handler->devicefile, &s);
- if (ret)
- return false;
-
- return true;
-}
-
void bbu_append_handlers_to_file_list(struct file_list *files)
{
struct bbu_handler *handler;
list_for_each_entry(handler, &bbu_image_handlers, list) {
- if (bbu_handler_is_available(handler)) {
- append_bbu_entry(handler, files);
+ const char *cdevname;
+ struct stat s;
+ char *devpath;
+
+ cdevname = devpath_to_name(handler->devicefile);
+ device_detect_by_name(cdevname);
+
+ devpath = basprintf("/dev/%s", cdevname);
+
+ if (stat(devpath, &s) == 0) {
+ append_bbu_entry(handler->name, devpath, files);
} else {
pr_info("Skipping unavailable handler bbu-%s\n",
handler->name);
}
+
+ free(devpath);
}
}
@@ -95,17 +95,23 @@ out:
int bbu_confirm(struct bbu_data *data)
{
int key;
+ const char *prompt;
if (data->flags & BBU_FLAG_YES)
- return 0;
+ prompt = ".";
+ else
+ prompt = " (y/n)?";
if (data->imagefile)
- printf("update barebox from %s using handler %s to %s (y/n)?\n",
- data->imagefile, data->handler_name,
- data->devicefile);
+ printf("update barebox on %s from %s using handler %s%s\n",
+ data->devicefile, data->imagefile,
+ data->handler_name, prompt);
else
- printf("Refresh barebox on %s using handler %s (y/n)?\n",
- data->devicefile, data->handler_name);
+ printf("Refresh barebox on %s using handler %s%s\n",
+ data->devicefile, data->handler_name, prompt);
+
+ if (data->flags & BBU_FLAG_YES)
+ return 0;
key = read_key();
@@ -154,36 +160,47 @@ struct bbu_handler *bbu_find_handler_by_device(const char *devicepath)
return NULL;
}
-static int bbu_check_of_compat(struct bbu_data *data)
+static int bbu_check_of_compat(struct bbu_data *data, unsigned short of_compat_nr)
{
+ const struct imd_header *imd = data->imd_data;
+ const struct imd_header *of_compat;
struct device_node *root_node;
const char *machine, *str;
int ret;
- const struct imd_header *of_compat;
if (!IS_ENABLED(CONFIG_OFDEVICE) || !IS_ENABLED(CONFIG_IMD))
return 0;
- of_compat = imd_find_type(data->imd_data, IMD_TYPE_OF_COMPATIBLE);
- if (!of_compat)
- return 0;
-
root_node = of_get_root_node();
if (!root_node)
return 0;
- str = imd_string_data(of_compat, 0);
-
- if (of_machine_is_compatible(str)) {
- pr_info("Devicetree compatible \"%s\" matches current machine\n", str);
+ if (!of_compat_nr)
return 0;
- }
ret = of_property_read_string(root_node, "compatible", &machine);
if (ret)
return 0;
- if (!bbu_force(data, "machine is incompatible with \"%s\", have \"%s\"\n", str, machine))
+ for (; of_compat_nr; of_compat_nr--) {
+ of_compat = imd_find_type(imd, IMD_TYPE_OF_COMPATIBLE);
+ if (!of_compat)
+ return 0;
+
+ str = imd_string_data(of_compat, 0);
+
+ if (of_machine_is_compatible(str)) {
+ pr_info("Devicetree compatible \"%s\" matches current machine\n", str);
+ return 0;
+ }
+
+ pr_debug("machine is incompatible with \"%s\", have \"%s\"\n",
+ str, machine);
+
+ imd = of_compat;
+ }
+
+ if (!bbu_force(data, "incompatible machine \"%s\"\n", machine))
return -EINVAL;
return 0;
@@ -191,6 +208,7 @@ static int bbu_check_of_compat(struct bbu_data *data)
static int bbu_check_metadata(struct bbu_data *data)
{
+ unsigned short imd_of_compat_nr = 0;
const struct imd_header *imd;
int ret;
char *str;
@@ -211,6 +229,9 @@ static int bbu_check_metadata(struct bbu_data *data)
imd_for_each(data->imd_data, imd) {
uint32_t type = imd_read_type(imd);
+ if (imd_read_type(imd) == IMD_TYPE_OF_COMPATIBLE)
+ imd_of_compat_nr++;
+
if (!imd_is_string(type))
continue;
@@ -220,7 +241,7 @@ static int bbu_check_metadata(struct bbu_data *data)
free(str);
}
- ret = bbu_check_of_compat(data);
+ ret = bbu_check_of_compat(data, imd_of_compat_nr);
if (ret)
return ret;
@@ -304,23 +325,107 @@ struct bbu_std {
enum filetype filetype;
};
-static int bbu_std_file_handler(struct bbu_handler *handler,
- struct bbu_data *data)
+int bbu_mmcboot_handler(struct bbu_handler *handler, struct bbu_data *data,
+ int (*chained_handler)(struct bbu_handler *, struct bbu_data *))
+{
+ struct bbu_data _data = *data;
+ int ret;
+ char *devicefile = NULL, *bootpartvar = NULL, *bootackvar = NULL;
+ const char *bootpart;
+ const char *devname = devpath_to_name(data->devicefile);
+
+ ret = device_detect_by_name(devname);
+ if (ret) {
+ pr_err("Couldn't detect device '%s'\n", devname);
+ return ret;
+ }
+
+ ret = asprintf(&bootpartvar, "%s.boot", devname);
+ if (ret < 0)
+ return ret;
+
+ bootpart = getenv(bootpartvar);
+ if (!bootpart) {
+ ret = -ENOENT;
+ goto out;
+ }
+
+ if (!strcmp(bootpart, "boot0")) {
+ bootpart = "boot1";
+ } else {
+ bootpart = "boot0";
+ }
+
+ ret = asprintf(&devicefile, "/dev/%s.%s", devname, bootpart);
+ if (ret < 0)
+ goto out;
+
+ _data.devicefile = devicefile;
+
+ ret = chained_handler(handler, &_data);
+ if (ret < 0)
+ goto out;
+
+ if (handler->flags & BBU_HANDLER_FLAG_MMC_BOOT_ACK) {
+ ret = asprintf(&bootackvar, "%s.boot_ack", devname);
+ if (ret < 0)
+ goto out;
+
+ ret = setenv(bootackvar, "1");
+ if (ret)
+ goto out;
+ }
+
+ /* on success switch boot source */
+ ret = setenv(bootpartvar, bootpart);
+
+out:
+ free(bootackvar);
+ free(devicefile);
+ free(bootpartvar);
+
+ return ret;
+}
+
+static int bbu_internal_mmcboot_update(struct bbu_handler *handler,
+ struct bbu_data *data)
+{
+ int ret;
+
+ ret = bbu_mmcboot_handler(handler, data, bbu_std_file_handler);
+ if (ret == -ENOENT)
+ pr_err("Couldn't read the value of .boot parameter\n");
+
+ return ret;
+}
+
+int bbu_mmcboot_register_handler(const char *name,
+ const char *devicefile,
+ unsigned long flags)
+{
+ struct bbu_handler *handler;
+ int ret;
+
+ handler = xzalloc(sizeof(*handler));
+ handler->devicefile = devicefile;
+ handler->name = name;
+ handler->handler = bbu_internal_mmcboot_update;
+ handler->flags = flags;
+
+ ret = bbu_register_handler(handler);
+ if (ret)
+ free(handler);
+
+ return ret;
+}
+
+int bbu_std_file_handler(struct bbu_handler *handler,
+ struct bbu_data *data)
{
- struct bbu_std *std = container_of(handler, struct bbu_std, handler);
int fd, ret;
- enum filetype filetype;
struct stat s;
unsigned oflags = O_WRONLY;
- filetype = file_detect_type(data->image, data->len);
- if (filetype != std->filetype) {
- if (!bbu_force(data, "incorrect image type. Expected: %s, got %s",
- file_type_to_string(std->filetype),
- file_type_to_string(filetype)))
- return -EINVAL;
- }
-
device_detect_by_name(devpath_to_name(data->devicefile));
ret = stat(data->devicefile, &s);
@@ -369,6 +474,23 @@ err_close:
return ret;
}
+static int bbu_std_file_handler_checked(struct bbu_handler *handler,
+ struct bbu_data *data)
+{
+ struct bbu_std *std = container_of(handler, struct bbu_std, handler);
+ enum filetype filetype;
+
+ filetype = file_detect_type(data->image, data->len);
+ if (filetype != std->filetype) {
+ if (!bbu_force(data, "incorrect image type. Expected: %s, got %s",
+ file_type_to_string(std->filetype),
+ file_type_to_string(filetype)))
+ return -EINVAL;
+ }
+
+ return bbu_std_file_handler(handler, data);
+}
+
/**
* bbu_register_std_file_update() - register a barebox update handler for a
* standard file-to-device-copy operation
@@ -399,7 +521,7 @@ int bbu_register_std_file_update(const char *name, unsigned long flags,
handler->flags = flags;
handler->devicefile = devicefile;
handler->name = name;
- handler->handler = bbu_std_file_handler;
+ handler->handler = bbu_std_file_handler_checked;
ret = bbu_register_handler(handler);
if (ret)
diff --git a/common/binfmt.c b/common/binfmt.c
index 1846477206..6a1e9fc83e 100644
--- a/common/binfmt.c
+++ b/common/binfmt.c
@@ -15,9 +15,13 @@ static LIST_HEAD(binfmt_hooks);
static int binfmt_run(char *file, int argc, char **argv)
{
struct binfmt_hook *b;
- enum filetype type = file_name_detect_type(file);
+ enum filetype type;
int ret;
+ ret = file_name_detect_type(file, &type);
+ if (ret)
+ return ret;
+
list_for_each_entry(b, &binfmt_hooks, list) {
if (b->type != type)
continue;
diff --git a/common/block.c b/common/block.c
index 1d386edcfd..c7ca4fb403 100644
--- a/common/block.c
+++ b/common/block.c
@@ -6,12 +6,12 @@
*/
#include <common.h>
#include <block.h>
+#include <disks.h>
#include <malloc.h>
#include <linux/err.h>
#include <linux/list.h>
#include <dma.h>
-
-#define BLOCKSIZE(blk) (1 << blk->blockbits)
+#include <file-list.h>
LIST_HEAD(block_device_list);
@@ -282,6 +282,17 @@ static ssize_t block_op_write(struct cdev *cdev, const void *buf, size_t count,
blkcnt_t blocks;
int ret;
+ /*
+ * When the offset that is written to is within the first two
+ * LBAs then the partition table has changed, reparse the partition
+ * table at close time in this case. A GPT covers more space than
+ * only the first two LBAs, but a CRC of the remaining pieces is
+ * written to LBA1, so LBA1 must change as well when the partioning
+ * is changed.
+ */
+ if (offset < 2 * SECTOR_SIZE)
+ blk->need_reparse = true;
+
if (offset & mask) {
size_t now = BLOCKSIZE(blk) - (offset & mask);
void *iobuf = block_get(blk, block);
@@ -339,7 +350,19 @@ static int block_op_flush(struct cdev *cdev)
return writebuffer_flush(blk);
}
-static int block_op_close(struct cdev *cdev) __alias(block_op_flush);
+static int block_op_close(struct cdev *cdev)
+{
+ struct block_device *blk = cdev->priv;
+
+ block_op_flush(cdev);
+
+ if (blk->need_reparse) {
+ reparse_partition_table(blk);
+ blk->need_reparse = false;
+ }
+
+ return 0;
+}
static int block_op_discard_range(struct cdev *cdev, loff_t count, loff_t offset)
{
@@ -361,6 +384,14 @@ static struct cdev_operations block_ops = {
.discard_range = block_op_discard_range,
};
+struct block_device *cdev_get_block_device(const struct cdev *cdev)
+{
+ if (!cdev || cdev->ops != &block_ops)
+ return NULL;
+
+ return cdev->priv;
+}
+
int blockdevice_register(struct block_device *blk)
{
loff_t size = (loff_t)blk->num_blocks * BLOCKSIZE(blk);
@@ -380,6 +411,11 @@ int blockdevice_register(struct block_device *blk)
dev_dbg(blk->dev, "rdbufsize: %d blockbits: %d blkmask: 0x%08x\n",
blk->rdbufsize, blk->blockbits, blk->blkmask);
+ if (!blk->rdbufsize) {
+ pr_warn("block size of %u not supported\n", BLOCKSIZE(blk));
+ return -ENOSYS;
+ }
+
for (i = 0; i < 8; i++) {
struct chunk *chunk = xzalloc(sizeof(*chunk));
chunk->data = dma_alloc(BUFSIZE);
@@ -395,6 +431,9 @@ int blockdevice_register(struct block_device *blk)
cdev_create_default_automount(&blk->cdev);
+ /* Lack of partition table is unusual, but not a failure */
+ (void)parse_partition_table(blk);
+
return 0;
}
@@ -441,3 +480,42 @@ int block_write(struct block_device *blk, void *buf, sector_t block, blkcnt_t nu
return ret < 0 ? ret : 0;
}
+
+unsigned file_list_add_blockdevs(struct file_list *files)
+{
+ struct block_device *blk;
+ unsigned count = 0;
+ int err;
+
+ list_for_each_entry(blk, &block_device_list, list) {
+ err = file_list_add_cdev_entry(files, &blk->cdev, 0);
+ if (!err)
+ count++;
+ }
+
+ return count;
+}
+
+const char *blk_type_str(enum blk_type type)
+{
+ switch (type) {
+ case BLK_TYPE_UNSPEC:
+ return "unspecified";
+ case BLK_TYPE_SD:
+ return "SD";
+ case BLK_TYPE_MMC:
+ return "MMC";
+ case BLK_TYPE_VIRTUAL:
+ return "virtual";
+ case BLK_TYPE_IDE:
+ return "IDE";
+ case BLK_TYPE_AHCI:
+ return "AHCI";
+ case BLK_TYPE_USB:
+ return "USB";
+ case BLK_TYPE_NVME:
+ return "NVMe";
+ default:
+ return "unknown";
+ }
+}
diff --git a/common/blspec.c b/common/blspec.c
index 158fd1e9a2..23a24c63db 100644
--- a/common/blspec.c
+++ b/common/blspec.c
@@ -15,6 +15,7 @@
#include <libbb.h>
#include <init.h>
#include <bootm.h>
+#include <glob.h>
#include <net.h>
#include <fs.h>
#include <of.h>
@@ -87,7 +88,7 @@ static int blspec_boot(struct bootentry *be, int verbose, int dryrun)
bootm_data_init_defaults(&data);
- data.verbose = verbose || data.verbose;
+ data.verbose = max(verbose, data.verbose);
devicetree = blspec_entry_var_get(entry, "devicetree");
initrd = blspec_entry_var_get(entry, "initrd");
@@ -315,7 +316,7 @@ static int blspec_have_entry(struct bootentries *bootentries, const char *path)
*/
static const char *nfs_find_mountpath(const char *nfshostpath)
{
- struct fs_device_d *fsdev;
+ struct fs_device *fsdev;
for_each_fs_device(fsdev) {
if (fsdev->backingstore && !strcmp(fsdev->backingstore, nfshostpath))
@@ -340,10 +341,10 @@ static char *parse_nfs_url(const char *url)
int ret;
if (!IS_ENABLED(CONFIG_FS_NFS))
- return ERR_PTR(-ENOSYS);
+ return NULL;
if (strncmp(url, "nfs://", 6))
- return ERR_PTR(-EINVAL);
+ return NULL;
url += 6;
@@ -412,7 +413,7 @@ out:
if (ret)
free(mountpath);
- return ret ? ERR_PTR(ret) : mountpath;
+ return ret ? NULL : mountpath;
}
/*
@@ -425,10 +426,10 @@ static bool entry_is_of_compatible(struct blspec_entry *entry)
{
const char *devicetree;
const char *abspath;
- size_t size;
- void *fdt = NULL;
int ret;
- struct device_node *root = NULL, *barebox_root;
+ struct device_node *barebox_root;
+ size_t size;
+ void *fdt;
const char *compat;
char *filename;
@@ -458,33 +459,22 @@ static bool entry_is_of_compatible(struct blspec_entry *entry)
fdt = read_file(filename, &size);
if (!fdt) {
- pr_err("Cannot read: %s\n", filename);
- ret = false;
- goto out;
- }
-
- root = of_unflatten_dtb(fdt, size);
- if (IS_ERR(root)) {
ret = false;
- root = NULL;
goto out;
}
- if (of_device_is_compatible(root, compat)) {
+ if (fdt_machine_is_compatible(fdt, size, compat)) {
ret = true;
goto out;
}
- pr_info("ignoring entry with incompatible devicetree \"%s\"\n",
- (char *)of_get_property(root, "compatible", NULL));
+ pr_info("ignoring entry with incompatible devicetree: %s\n", devicetree);
ret = false;
out:
- if (root)
- of_delete_node(root);
- free(filename);
free(fdt);
+ free(filename);
return ret;
}
@@ -513,6 +503,55 @@ static bool entry_is_match_machine_id(struct blspec_entry *entry)
return ret;
}
+int blspec_scan_file(struct bootentries *bootentries, const char *root,
+ const char *configname)
+{
+ char *devname = NULL, *hwdevname = NULL;
+ struct blspec_entry *entry;
+
+ if (blspec_have_entry(bootentries, configname))
+ return -EEXIST;
+
+ entry = blspec_entry_open(bootentries, configname);
+ if (IS_ERR(entry))
+ return PTR_ERR(entry);
+
+ root = root ?: get_mounted_path(configname);
+ entry->rootpath = xstrdup(root);
+ entry->configpath = xstrdup(configname);
+ entry->cdev = get_cdev_by_mountpath(root);
+
+ if (!entry_is_of_compatible(entry)) {
+ blspec_entry_free(&entry->entry);
+ return -ENODEV;
+ }
+
+ if (!entry_is_match_machine_id(entry)) {
+ blspec_entry_free(&entry->entry);
+ return -ENODEV;
+ }
+
+ if (entry->cdev && entry->cdev->dev) {
+ devname = xstrdup(dev_name(entry->cdev->dev));
+ if (entry->cdev->dev->parent)
+ hwdevname = xstrdup(dev_name(entry->cdev->dev->parent));
+ }
+
+ entry->entry.title = xasprintf("%s (%s)", blspec_entry_var_get(entry, "title"),
+ configname);
+ entry->entry.description = basprintf("blspec entry, device: %s hwdevice: %s",
+ devname ? devname : "none",
+ hwdevname ? hwdevname : "none");
+ free(devname);
+ free(hwdevname);
+
+ entry->entry.me.type = MENU_ENTRY_NORMAL;
+ entry->entry.release = blspec_entry_free;
+
+ bootentries_add_entry(bootentries, &entry->entry);
+ return 1;
+}
+
/*
* blspec_scan_directory - scan over a directory
*
@@ -522,115 +561,40 @@ static bool entry_is_match_machine_id(struct blspec_entry *entry)
*/
int blspec_scan_directory(struct bootentries *bootentries, const char *root)
{
- struct blspec_entry *entry;
- DIR *dir;
- struct dirent *d;
+ glob_t globb;
char *abspath;
int ret, found = 0;
const char *dirname = "loader/entries";
- char *nfspath = NULL;
-
- nfspath = parse_nfs_url(root);
- if (!IS_ERR(nfspath))
- root = nfspath;
+ int i;
pr_debug("%s: %s %s\n", __func__, root, dirname);
- abspath = basprintf("%s/%s", root, dirname);
+ abspath = basprintf("%s/%s/*.conf", root, dirname);
- dir = opendir(abspath);
- if (!dir) {
+ ret = glob(abspath, 0, NULL, &globb);
+ if (ret) {
pr_debug("%s: %s: %s\n", __func__, abspath, strerror(errno));
ret = -errno;
goto err_out;
}
- while ((d = readdir(dir))) {
- char *configname;
+ for (i = 0; i < globb.gl_pathc; i++) {
+ const char *configname = globb.gl_pathv[i];
struct stat s;
- char *dot;
- char *devname = NULL, *hwdevname = NULL;
-
- if (*d->d_name == '.')
- continue;
-
- configname = basprintf("%s/%s", abspath, d->d_name);
-
- dot = strrchr(configname, '.');
- if (!dot) {
- free(configname);
- continue;
- }
-
- if (strcmp(dot, ".conf")) {
- free(configname);
- continue;
- }
ret = stat(configname, &s);
- if (ret) {
- free(configname);
- continue;
- }
-
- if (!S_ISREG(s.st_mode)) {
- free(configname);
+ if (ret || !S_ISREG(s.st_mode))
continue;
- }
-
- if (blspec_have_entry(bootentries, configname)) {
- free(configname);
- continue;
- }
- entry = blspec_entry_open(bootentries, configname);
- if (IS_ERR(entry)) {
- free(configname);
- continue;
- }
-
- entry->rootpath = xstrdup(root);
- entry->configpath = configname;
- entry->cdev = get_cdev_by_mountpath(root);
-
- if (!entry_is_of_compatible(entry)) {
- blspec_entry_free(&entry->entry);
- continue;
- }
-
- if (!entry_is_match_machine_id(entry)) {
- blspec_entry_free(&entry->entry);
- continue;
- }
-
- found++;
-
- if (entry->cdev && entry->cdev->dev) {
- devname = xstrdup(dev_name(entry->cdev->dev));
- if (entry->cdev->dev->parent)
- hwdevname = xstrdup(dev_name(entry->cdev->dev->parent));
- }
-
- entry->entry.title = xasprintf("%s (%s)", blspec_entry_var_get(entry, "title"),
- configname);
- entry->entry.description = basprintf("blspec entry, device: %s hwdevice: %s",
- devname ? devname : "none",
- hwdevname ? hwdevname : "none");
- free(devname);
- free(hwdevname);
-
- entry->entry.me.type = MENU_ENTRY_NORMAL;
- entry->entry.release = blspec_entry_free;
-
- bootentries_add_entry(bootentries, &entry->entry);
+ ret = blspec_scan_file(bootentries, root, configname);
+ if (ret > 0)
+ found += ret;
}
ret = found;
- closedir(dir);
+ globfree(&globb);
err_out:
- if (!IS_ERR(nfspath))
- free(nfspath);
free(abspath);
return ret;
@@ -647,7 +611,7 @@ err_out:
*/
static int blspec_scan_ubi(struct bootentries *bootentries, struct cdev *cdev)
{
- struct device_d *child;
+ struct device *child;
int ret, found = 0;
pr_debug("%s: %s\n", __func__, cdev->name);
@@ -702,9 +666,7 @@ static int blspec_scan_cdev(struct bootentries *bootentries, struct cdev *cdev)
found += ret;
}
- rootpath = cdev_get_mount_path(cdev);
- if (!rootpath)
- rootpath = cdev_mount_default(cdev, NULL);
+ rootpath = cdev_mount(cdev);
if (!IS_ERR(rootpath)) {
ret = blspec_scan_directory(bootentries, rootpath);
if (ret > 0)
@@ -723,7 +685,7 @@ static int blspec_scan_cdev(struct bootentries *bootentries, struct cdev *cdev)
*/
int blspec_scan_devices(struct bootentries *bootentries)
{
- struct device_d *dev;
+ struct device *dev;
struct block_device *bdev;
int ret, found = 0;
@@ -751,9 +713,9 @@ int blspec_scan_devices(struct bootentries *bootentries)
* Returns the number of entries found or a negative error code if some unexpected
* error occurred.
*/
-int blspec_scan_device(struct bootentries *bootentries, struct device_d *dev)
+int blspec_scan_device(struct bootentries *bootentries, struct device *dev)
{
- struct device_d *child;
+ struct device *child;
struct cdev *cdev;
int ret, found = 0;
@@ -767,7 +729,7 @@ int blspec_scan_device(struct bootentries *bootentries, struct device_d *dev)
* partition with the MBR type id of 0xEA already exists it
* should be used as $BOOT
*/
- if (cdev->dos_partition_type == 0xea) {
+ if (cdev_is_mbr_partitioned(cdev->master) && cdev->dos_partition_type == 0xea) {
ret = blspec_scan_cdev(bootentries, cdev);
if (ret == 0)
ret = -ENOENT;
@@ -815,11 +777,14 @@ int blspec_scan_device(struct bootentries *bootentries, struct device_d *dev)
*/
int blspec_scan_devicename(struct bootentries *bootentries, const char *devname)
{
- struct device_d *dev;
+ struct device *dev;
struct cdev *cdev;
pr_debug("%s: %s\n", __func__, devname);
+ /* Support both boot /dev/disk0.rootfs and boot disk0.rootfs */
+ devname += str_has_prefix(devname, "/dev/");
+
device_detect_by_name(devname);
cdev = cdev_by_name(devname);
@@ -839,6 +804,7 @@ int blspec_scan_devicename(struct bootentries *bootentries, const char *devname)
static int blspec_bootentry_provider(struct bootentries *bootentries,
const char *name)
{
+ struct stat s;
int ret, found = 0;
ret = blspec_scan_devicename(bootentries, name);
@@ -846,9 +812,24 @@ static int blspec_bootentry_provider(struct bootentries *bootentries,
found += ret;
if (*name == '/' || !strncmp(name, "nfs://", 6)) {
- ret = blspec_scan_directory(bootentries, name);
+ char *nfspath = parse_nfs_url(name);
+
+ if (nfspath)
+ name = nfspath;
+
+ ret = stat(name, &s);
+ if (ret)
+ goto out;
+
+ if (S_ISDIR(s.st_mode))
+ ret = blspec_scan_directory(bootentries, name);
+ else if (S_ISREG(s.st_mode) && strends(name, ".conf"))
+ ret = blspec_scan_file(bootentries, NULL, name);
if (ret > 0)
found += ret;
+
+out:
+ free(nfspath);
}
return found;
diff --git a/common/boards/Kconfig b/common/boards/Kconfig
new file mode 100644
index 0000000000..f6d4a56f88
--- /dev/null
+++ b/common/boards/Kconfig
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config BOARD_QEMU_VIRT
+ bool
+ select OF_OVERLAY
+
+config BOARD_PHYTEC_SOM_DETECTION
+ bool
+
+config BOARD_PHYTEC_SOM_IMX8M_DETECTION
+ bool
+ select BOARD_PHYTEC_SOM_DETECTION
+
+config BOARD_TQ
+ select CRC_ITU_T
+ bool
diff --git a/common/boards/Makefile b/common/boards/Makefile
new file mode 100644
index 0000000000..147c36643d
--- /dev/null
+++ b/common/boards/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+obj-$(CONFIG_BOARD_QEMU_VIRT) += qemu-virt/
+obj-$(CONFIG_BOARD_PHYTEC_SOM_DETECTION) += phytec/
+obj-$(CONFIG_BOARD_TQ) += tq/
diff --git a/common/boards/phytec/Makefile b/common/boards/phytec/Makefile
new file mode 100644
index 0000000000..fef6134a16
--- /dev/null
+++ b/common/boards/phytec/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+lwl- += dummy.o
+lwl-$(CONFIG_BOARD_PHYTEC_SOM_DETECTION) += phytec-som-detection.o
+lwl-$(CONFIG_BOARD_PHYTEC_SOM_IMX8M_DETECTION) += phytec-som-imx8m-detection.o
diff --git a/common/boards/phytec/phytec-som-detection.c b/common/boards/phytec/phytec-som-detection.c
new file mode 100644
index 0000000000..e338639d03
--- /dev/null
+++ b/common/boards/phytec/phytec-som-detection.c
@@ -0,0 +1,209 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020 PHYTEC Messtechnik GmbH
+ * Author: Teresa Remmet <t.remmet@phytec.de>
+ */
+
+#include <boards/phytec/phytec-som-imx8m-detection.h>
+#include <common.h>
+#include <pbl/eeprom.h>
+
+struct phytec_eeprom_data eeprom_data;
+
+#define POLY (0x1070U << 3)
+
+static u8 _crc8(u16 data)
+{
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ if (data & 0x8000)
+ data = data ^ POLY;
+ data = data << 1;
+ }
+
+ return data >> 8;
+}
+
+static unsigned int crc8(unsigned int crc, const u8 *vptr, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ crc = _crc8((crc ^ vptr[i]) << 8);
+
+ return crc;
+}
+
+const char *phytec_get_opt(const struct phytec_eeprom_data *data)
+{
+ const char *opt;
+
+ if (!data)
+ data = &eeprom_data;
+
+ switch (data->api_rev) {
+ case PHYTEC_API_REV0:
+ case PHYTEC_API_REV1:
+ opt = data->data.data_api0.opt;
+ break;
+ case PHYTEC_API_REV2:
+ opt = data->data.data_api2.opt;
+ break;
+ default:
+ opt = NULL;
+ break;
+ };
+
+ return opt;
+}
+
+static int phytec_eeprom_data_init(struct pbl_i2c *i2c,
+ struct phytec_eeprom_data *data,
+ int addr, u8 phytec_som_type)
+{
+ unsigned int crc;
+ const char *opt;
+ int *ptr;
+ int ret = -1, i;
+ u8 som;
+
+ if (!data)
+ data = &eeprom_data;
+
+ eeprom_read(i2c, addr, I2C_ADDR_16_BIT, data, sizeof(struct phytec_eeprom_data));
+
+ if (data->api_rev == 0xff) {
+ pr_err("%s: EEPROM is not flashed. Prototype?\n", __func__);
+ return -EINVAL;
+ }
+
+ for (i = 0, ptr = (int *)data;
+ i < sizeof(struct phytec_eeprom_data);
+ i += sizeof(ptr), ptr++)
+ if (*ptr != 0x0)
+ break;
+
+ if (i == sizeof(struct phytec_eeprom_data)) {
+ pr_err("%s: EEPROM data is all zero. Erased?\n", __func__);
+ return -EINVAL;
+ }
+
+ if (data->api_rev > PHYTEC_API_REV2) {
+ pr_err("%s: EEPROM API revision %u not supported\n",
+ __func__, data->api_rev);
+ return -EINVAL;
+ }
+
+ /* We are done here for early revisions */
+ if (data->api_rev <= PHYTEC_API_REV1)
+ return 0;
+
+ crc = crc8(0, (const unsigned char *)data,
+ sizeof(struct phytec_eeprom_data));
+ pr_debug("%s: crc: %x\n", __func__, crc);
+
+ if (crc) {
+ pr_err("%s: CRC mismatch. EEPROM data is not usable\n", __func__);
+ return -EINVAL;
+ }
+
+ som = data->data.data_api2.som_no;
+ pr_debug("%s: som id: %u\n", __func__, som);
+ opt = phytec_get_opt(data);
+ if (!opt)
+ return -EINVAL;
+
+ if (IS_ENABLED(CONFIG_BOARD_PHYTEC_SOM_IMX8M_DETECTION))
+ ret = phytec_imx8m_detect(som, opt, phytec_som_type);
+
+ if (ret) {
+ pr_err("%s: SoM ID does not match. Wrong EEPROM data?\n", __func__);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+void phytec_print_som_info(const struct phytec_eeprom_data *data)
+{
+ const struct phytec_api2_data *api2;
+ char pcb_sub_rev;
+ unsigned int ksp_no, sub_som_type1 = -1, sub_som_type2 = -1;
+
+ if (!data)
+ data = &eeprom_data;
+
+ if (data->api_rev < PHYTEC_API_REV2)
+ return;
+
+ api2 = &data->data.data_api2;
+
+ /* Calculate PCB subrevision */
+ pcb_sub_rev = api2->pcb_sub_opt_rev & 0x0f;
+ pcb_sub_rev = pcb_sub_rev ? ((pcb_sub_rev - 1) + 'a') : ' ';
+
+ /* print standard product string */
+ if (api2->som_type <= 1) {
+ pr_info("SoM: %s-%03u-%s.%s PCB rev: %u%c\n",
+ phytec_som_type_str[api2->som_type], api2->som_no,
+ api2->opt, api2->bom_rev, api2->pcb_rev, pcb_sub_rev);
+ return;
+ }
+ /* print KSP/KSM string */
+ if (api2->som_type <= 3) {
+ ksp_no = (api2->ksp_no << 8) | api2->som_no;
+ pr_info("SoM: %s-%u ",
+ phytec_som_type_str[api2->som_type], ksp_no);
+ /* print standard product based KSP/KSM strings */
+ } else {
+ switch (api2->som_type) {
+ case 4:
+ sub_som_type1 = 0;
+ sub_som_type2 = 3;
+ break;
+ case 5:
+ sub_som_type1 = 0;
+ sub_som_type2 = 2;
+ break;
+ case 6:
+ sub_som_type1 = 1;
+ sub_som_type2 = 3;
+ break;
+ case 7:
+ sub_som_type1 = 1;
+ sub_som_type2 = 2;
+ break;
+ default:
+ break;
+ };
+
+ pr_info("SoM: %s-%03u-%s-%03u ",
+ phytec_som_type_str[sub_som_type1],
+ api2->som_no, phytec_som_type_str[sub_som_type2],
+ api2->ksp_no);
+ }
+
+ printf("Option: %s BOM rev: %s PCB rev: %u%c\n", api2->opt,
+ api2->bom_rev, api2->pcb_rev, pcb_sub_rev);
+}
+
+int phytec_eeprom_data_setup(struct pbl_i2c *i2c, struct phytec_eeprom_data *data,
+ int addr, int addr_fallback, u8 cpu_type)
+{
+ int ret;
+
+ ret = phytec_eeprom_data_init(i2c, data, addr, cpu_type);
+ if (ret) {
+ pr_err("%s: init failed. Trying fall back address 0x%x\n",
+ __func__, addr_fallback);
+ ret = phytec_eeprom_data_init(i2c, data, addr_fallback, cpu_type);
+ }
+
+ if (ret)
+ pr_err("%s: EEPROM data init failed\n", __func__);
+ else
+ pr_debug("%s: init successful\n", __func__);
+
+ return ret;
+}
diff --git a/common/boards/phytec/phytec-som-imx8m-detection.c b/common/boards/phytec/phytec-som-imx8m-detection.c
new file mode 100644
index 0000000000..495896f5b2
--- /dev/null
+++ b/common/boards/phytec/phytec-som-imx8m-detection.c
@@ -0,0 +1,151 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020 PHYTEC Messtechnik GmbH
+ * Author: Teresa Remmet <t.remmet@phytec.de>
+ */
+
+#include <boards/phytec/phytec-som-imx8m-detection.h>
+#include <common.h>
+#include <mach/imx/generic.h>
+
+extern struct phytec_eeprom_data eeprom_data;
+
+/* Check if the SoM is actually one of the following products:
+ * - i.MX8MM
+ * - i.MX8MN
+ * - i.MX8MP
+ * - i.MX8MQ
+ *
+ * Returns 0 in case it's a known SoM. Otherwise, returns -errno.
+ */
+int phytec_imx8m_detect(u8 som, const char *opt, u8 cpu_type)
+{
+ if (som == PHYTEC_IMX8MP_SOM && cpu_type == IMX_CPU_IMX8MP)
+ return 0;
+
+ if (som == PHYTEC_IMX8MM_SOM) {
+ if (((opt[0] - '0') != 0) &&
+ ((opt[1] - '0') == 0) && cpu_type == IMX_CPU_IMX8MM)
+ return 0;
+ else if (((opt[0] - '0') == 0) &&
+ ((opt[1] - '0') != 0) && cpu_type == IMX_CPU_IMX8MN)
+ return 0;
+ return -EINVAL;
+ }
+
+ if (som == PHYTEC_IMX8MQ_SOM && cpu_type == IMX_CPU_IMX8MQ)
+ return 0;
+
+ return -EINVAL;
+}
+
+/*
+ * So far all PHYTEC i.MX8M boards have RAM size definition at the
+ * same location.
+ */
+enum phytec_imx8m_ddr_size phytec_get_imx8m_ddr_size(const struct phytec_eeprom_data *data)
+{
+ const char *opt;
+ u8 ddr_id;
+
+ if (!data)
+ data = &eeprom_data;
+
+ opt = phytec_get_opt(data);
+ if (opt)
+ ddr_id = opt[2] - '0';
+ else
+ ddr_id = PHYTEC_IMX8M_DDR_AUTODETECT;
+
+ pr_debug("%s: ddr id: %u\n", __func__, ddr_id);
+
+ return ddr_id;
+}
+
+/*
+ * Filter SPI-NOR flash information. All i.MX8M boards have this at
+ * the same location.
+ * returns: 0x0 if no SPI is populated. Otherwise a board depended
+ * code for the size. PHYTEC_EEPROM_INVAL when the data is invalid.
+ */
+u8 phytec_get_imx8m_spi(const struct phytec_eeprom_data *data)
+{
+ const char *opt;
+ u8 spi;
+
+ if (!data)
+ data = &eeprom_data;
+
+ if (data->api_rev < PHYTEC_API_REV2)
+ return PHYTEC_EEPROM_INVAL;
+
+ opt = phytec_get_opt(data);
+ if (opt)
+ spi = opt[4] - '0';
+ else
+ spi = PHYTEC_EEPROM_INVAL;
+
+ pr_debug("%s: spi: %u\n", __func__, spi);
+
+ return spi;
+}
+
+/*
+ * Filter ethernet phy information. All i.MX8M boards have this at
+ * the same location.
+ * returns: 0x0 if no ethernet phy is poulated. 0x1 if it is populated.
+ * PHYTEC_EEPROM_INVAL when the data is invalid.
+ */
+u8 phytec_get_imx8m_eth(const struct phytec_eeprom_data *data)
+{
+ const char *opt;
+ u8 eth;
+
+ if (!data)
+ data = &eeprom_data;
+
+ if (data->api_rev < PHYTEC_API_REV2)
+ return PHYTEC_EEPROM_INVAL;
+
+ opt = phytec_get_opt(data);
+ if (opt) {
+ eth = opt[5] - '0';
+ eth &= 0x1;
+ } else {
+ eth = PHYTEC_EEPROM_INVAL;
+ }
+
+ pr_debug("%s: eth: %u\n", __func__, eth);
+
+ return eth;
+}
+
+/*
+ * Filter RTC information.
+ * returns: 0 if no RTC is poulated. 1 if it is populated.
+ * PHYTEC_EEPROM_INVAL when the data is invalid.
+ */
+u8 phytec_get_imx8mp_rtc(const struct phytec_eeprom_data *data)
+{
+ const char *opt;
+ u8 rtc;
+
+ if (!data)
+ data = &eeprom_data;
+
+ if (data->api_rev < PHYTEC_API_REV2)
+ return PHYTEC_EEPROM_INVAL;
+
+ opt = phytec_get_opt(data);
+ if (opt) {
+ rtc = opt[5] - '0';
+ rtc &= 0x4;
+ rtc = !(rtc >> 2);
+ } else {
+ rtc = PHYTEC_EEPROM_INVAL;
+ }
+
+ pr_debug("%s: rtc: %u\n", __func__, rtc);
+
+ return rtc;
+}
diff --git a/common/boards/qemu-virt/Makefile b/common/boards/qemu-virt/Makefile
new file mode 100644
index 0000000000..30bf4f1955
--- /dev/null
+++ b/common/boards/qemu-virt/Makefile
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+obj-y += board.o
+obj-y += qemu-virt-flash.dtbo.o fitimage-pubkey.dtb.o
+ifeq ($(CONFIG_RISCV),y)
+DTC_CPP_FLAGS_qemu-virt-flash.dtbo := -DCONFIG_RISCV
+endif
+ifeq ($(CONFIG_ARM),y)
+DTC_CPP_FLAGS_qemu-virt-flash.dtbo := -DCONFIG_ARM
+endif
+
+clean-files := *.dtb *.dtb.S .*.dtc .*.pre .*.dts *.dtb.z
+clean-files += *.dtbo *.dtbo.S .*.dtso
diff --git a/common/boards/qemu-virt/board.c b/common/boards/qemu-virt/board.c
new file mode 100644
index 0000000000..4f2f7374c5
--- /dev/null
+++ b/common/boards/qemu-virt/board.c
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2020 Pengutronix e.K.
+ *
+ */
+#include <common.h>
+#include <init.h>
+#include <of.h>
+#include <deep-probe.h>
+#include "qemu-virt-flash.h"
+
+#ifdef CONFIG_64BIT
+#define MACHINE "virt64"
+#else
+#define MACHINE "virt"
+#endif
+
+#ifdef CONFIG_ARM
+#include <asm/system_info.h>
+
+static inline void arm_virt_init(void)
+{
+ const char *hostname = MACHINE;
+
+ if (cpu_is_cortex_a7())
+ hostname = "virt-a7";
+ else if (cpu_is_cortex_a15())
+ hostname = "virt-a15";
+
+ barebox_set_model("ARM QEMU " MACHINE);
+ barebox_set_hostname(hostname);
+}
+
+#else
+static inline void arm_virt_init(void) {}
+#endif
+
+extern char __dtbo_qemu_virt_flash_start[];
+extern char __dtb_fitimage_pubkey_start[];
+
+static const struct of_device_id virt_of_match[] = {
+ { .compatible = "linux,dummy-virt", .data = arm_virt_init },
+ { .compatible = "riscv-virtio" },
+ { /* Sentinel */},
+};
+BAREBOX_DEEP_PROBE_ENABLE(virt_of_match);
+
+/*
+ * We don't have a dedicated qemu-virt device tree and instead rely
+ * on what Qemu passes us. To be able to get fundamental changes
+ * in very early, we forego having a board driver here and do this
+ * directly in the initcall.
+ */
+static int virt_board_driver_init(void)
+{
+ struct device_node *root = of_get_root_node();
+ struct device_node *flash, *overlay, *pubkey;
+ const struct of_device_id *id;
+ void (*init)(void);
+
+ id = of_match_node(virt_of_match, root);
+ if (!id)
+ return 0;
+
+ if (id->data) {
+ init = id->data;
+ init();
+ }
+
+ /*
+ * Catch both old Qemu versions that place /flash in /soc and
+ * configurations, where the first flash bank is secure-world only
+ */
+ flash = of_find_node_by_path(PARTS_TARGET_PATH_STR);
+ if (flash && of_device_is_available(flash)) {
+ overlay = of_unflatten_dtb(__dtbo_qemu_virt_flash_start, INT_MAX);
+ of_overlay_apply_tree(root, overlay);
+ }
+
+ pubkey = of_unflatten_dtb(__dtb_fitimage_pubkey_start, INT_MAX);
+ of_merge_nodes(root, pubkey);
+
+ /* fragment may have added aliases to the DT */
+ of_alias_scan();
+
+ /* of_probe() will happen later at of_populate_initcall */
+
+ return 0;
+}
+postcore_initcall(virt_board_driver_init);
diff --git a/common/boards/qemu-virt/fitimage-pubkey.dts b/common/boards/qemu-virt/fitimage-pubkey.dts
new file mode 100644
index 0000000000..497799fa4b
--- /dev/null
+++ b/common/boards/qemu-virt/fitimage-pubkey.dts
@@ -0,0 +1,7 @@
+/dts-v1/;
+
+#ifdef CONFIG_BOOTM_FITIMAGE_PUBKEY
+#include CONFIG_BOOTM_FITIMAGE_PUBKEY
+#endif
+
+/{ };
diff --git a/common/boards/qemu-virt/qemu-virt-flash.dtso b/common/boards/qemu-virt/qemu-virt-flash.dtso
new file mode 100644
index 0000000000..087568a26d
--- /dev/null
+++ b/common/boards/qemu-virt/qemu-virt-flash.dtso
@@ -0,0 +1,99 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/dts-v1/;
+/plugin/;
+
+#include "qemu-virt-flash.h"
+
+&{PARTS_TARGET_PATH} {
+#ifdef CONFIG_ARM
+ virtual-reg = <0x1000>;
+#endif
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "initramfs";
+ reg = <0x0 0x3c00000>;
+ };
+
+ environment_flash: partition@3c00000 {
+ label = "barebox-environment";
+ reg = <0x3c00000 0x200000>;
+ };
+
+ backend_state_flash: partition@3e00000 {
+ label = "barebox-state";
+ reg = <0x3e00000 0x200000>;
+ };
+ };
+};
+
+&{/chosen} {
+ environment {
+ compatible = "barebox,environment";
+ device-path = ENV_DEVICE_PATH_STR;
+ };
+};
+
+&{/} {
+ aliases {
+ state = "/state";
+ };
+
+ state {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "barebox,state";
+ magic = <0x290cf8c6>;
+ backend-type = "raw";
+ backend = < &backend_state_flash >;
+ backend-stridesize = <0x200>;
+
+ bootstate {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ system0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ remaining_attempts@0 {
+ reg = <0x0 0x4>;
+ type = "uint32";
+ default = <3>;
+ };
+
+ priority@4 {
+ reg = <0x4 0x4>;
+ type = "uint32";
+ default = <20>;
+ };
+ };
+
+ system1 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ remaining_attempts@8 {
+ reg = <0x8 0x4>;
+ type = "uint32";
+ default = <3>;
+ };
+
+ priority@c {
+ reg = <0xc 0x4>;
+ type = "uint32";
+ default = <21>;
+ };
+ };
+
+ last_chosen@10 {
+ reg = <0x10 0x4>;
+ type = "uint32";
+ };
+ };
+ };
+};
diff --git a/common/boards/qemu-virt/qemu-virt-flash.h b/common/boards/qemu-virt/qemu-virt-flash.h
new file mode 100644
index 0000000000..85f67ff030
--- /dev/null
+++ b/common/boards/qemu-virt/qemu-virt-flash.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef __QEMU_VIRT_FLASH_H__
+#define __QEMU_VIRT_FLASH_H__
+
+#include <linux/stringify.h>
+
+#ifdef CONFIG_RISCV
+#define PARTS_TARGET_PATH /flash@20000000
+#define ENV_DEVICE_PATH /flash@20000000/partitions/partition@3c00000
+#elif defined CONFIG_ARM
+#define PARTS_TARGET_PATH /flash@0
+#define ENV_DEVICE_PATH /flash@0/partitions/partition@3c00000
+#else
+#define PARTS_TARGET_PATH
+#define ENV_DEVICE_PATH
+#endif
+
+#define PARTS_TARGET_PATH_STR __stringify(PARTS_TARGET_PATH)
+#define ENV_DEVICE_PATH_STR __stringify(ENV_DEVICE_PATH)
+
+#endif
diff --git a/common/boards/tq/Makefile b/common/boards/tq/Makefile
new file mode 100644
index 0000000000..9950cbdb00
--- /dev/null
+++ b/common/boards/tq/Makefile
@@ -0,0 +1 @@
+obj-pbl-y += tq_eeprom.o
diff --git a/common/boards/tq/tq_eeprom.c b/common/boards/tq/tq_eeprom.c
new file mode 100644
index 0000000000..fe776d6bab
--- /dev/null
+++ b/common/boards/tq/tq_eeprom.c
@@ -0,0 +1,139 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2014-2023 TQ-Systems GmbH <u-boot@ew.tq-group.com>,
+ * D-82229 Seefeld, Germany.
+ * Author: Markus Niebel
+ */
+
+#include <common.h>
+#include <net.h>
+#include <linux/ctype.h>
+#include <crc.h>
+#include <pbl/i2c.h>
+#include <pbl/eeprom.h>
+#include <boards/tq/tq_eeprom.h>
+
+/*
+ * static EEPROM layout
+ */
+#define TQ_EE_HRCW_BYTES 0x20
+#define TQ_EE_RSV1_BYTES 10
+#define TQ_EE_RSV2_BYTES 8
+
+struct __packed tq_eeprom_data {
+ union {
+ struct tq_vard vard;
+ _Static_assert(sizeof(struct tq_vard) == TQ_EE_HRCW_BYTES, \
+ "struct tq_vard has incorrect size");
+ u8 hrcw_primary[TQ_EE_HRCW_BYTES];
+ } tq_hw_data;
+ u8 mac[TQ_EE_MAC_BYTES]; /* 0x20 ... 0x25 */
+ u8 rsv1[TQ_EE_RSV1_BYTES];
+ u8 serial[TQ_EE_SERIAL_BYTES]; /* 0x30 ... 0x37 */
+ u8 rsv2[TQ_EE_RSV2_BYTES];
+ u8 id[TQ_EE_BDID_BYTES]; /* 0x40 ... 0x7f */
+};
+
+static bool tq_vard_valid(const struct tq_vard *vard)
+{
+ const unsigned char *start = (const unsigned char *)(vard) +
+ sizeof(vard->crc);
+ u16 crc;
+
+ crc = crc_itu_t(0, start, sizeof(*vard) - sizeof(vard->crc));
+
+ return vard->crc == crc;
+}
+
+phys_size_t tq_vard_memsize(u8 val, unsigned int multiply, unsigned int tmask)
+{
+ phys_size_t result = 0;
+
+ if (val != VARD_MEMSIZE_DEFAULT) {
+ result = 1 << (size_t)(val & VARD_MEMSIZE_MASK_EXP);
+ if (val & tmask)
+ result *= 3;
+ result *= multiply;
+ }
+
+ return result;
+}
+
+void tq_vard_show(const struct tq_vard *vard)
+{
+ /* display data anyway to support developer */
+ printf("HW\tREV.%02uxx\n", (unsigned int)vard->hwrev);
+ printf("RAM\ttype %u, %lu MiB, %s\n",
+ (unsigned int)(vard->memtype & VARD_MEMTYPE_MASK_TYPE),
+ (unsigned long)(tq_vard_ramsize(vard) / (SZ_1M)),
+ (tq_vard_has_ramecc(vard) ? "ECC" : "no ECC"));
+ printf("RTC\t%c\nSPINOR\t%c\ne-MMC\t%c\nSE\t%c\nEEPROM\t%c\n",
+ (tq_vard_has_rtc(vard) ? 'y' : 'n'),
+ (tq_vard_has_spinor(vard) ? 'y' : 'n'),
+ (tq_vard_has_emmc(vard) ? 'y' : 'n'),
+ (tq_vard_has_secelem(vard) ? 'y' : 'n'),
+ (tq_vard_has_eeprom(vard) ? 'y' : 'n'));
+
+ if (tq_vard_has_eeprom(vard))
+ printf("EEPROM\ttype %u, %lu KiB, page %zu\n",
+ (unsigned int)(vard->eepromtype & VARD_EETYPE_MASK_MFR) >> 4,
+ (unsigned long)(tq_vard_eepromsize(vard) / (SZ_1K)),
+ tq_vard_eeprom_pgsize(vard));
+
+ printf("FORMFACTOR: ");
+
+ switch (tq_vard_get_formfactor(vard)) {
+ case VARD_FORMFACTOR_TYPE_LGA:
+ printf("LGA\n");
+ break;
+ case VARD_FORMFACTOR_TYPE_CONNECTOR:
+ printf("CONNECTOR\n");
+ break;
+ case VARD_FORMFACTOR_TYPE_SMARC2:
+ printf("SMARC-2\n");
+ break;
+ case VARD_FORMFACTOR_TYPE_NONE:
+ /*
+ * applies to boards with no variants or older boards
+ * where this field is not written
+ */
+ printf("UNSPECIFIED\n");
+ break;
+ default:
+ /*
+ * generic fall trough
+ * unhandled form factor or invalid data
+ */
+ printf("UNKNOWN\n");
+ break;
+ }
+}
+
+static void tq_read_string(const char *src, char *dst, int len)
+{
+ int i;
+
+ for (i = 0; i < len && isprint(src[i]) && isascii(src[i]); ++i)
+ dst[i] = src[i];
+ dst[i] = '\0';
+}
+
+struct tq_eeprom *pbl_tq_read_eeprom(struct pbl_i2c *i2c, u8 addr, u32 eeprom_addr)
+{
+ struct tq_eeprom_data raw;
+ static struct tq_eeprom eeprom;
+ int ret;
+
+ ret = eeprom_read(i2c, addr, eeprom_addr, &raw, sizeof(raw));
+ if (ret)
+ return NULL;
+
+ if (tq_vard_valid(&raw.tq_hw_data.vard))
+ eeprom.vard = raw.tq_hw_data.vard;
+
+ memcpy(eeprom.mac, raw.mac, TQ_EE_MAC_BYTES);
+ tq_read_string(raw.serial, eeprom.serial, TQ_EE_SERIAL_BYTES);
+ tq_read_string(raw.id, eeprom.id, TQ_EE_BDID_BYTES);
+
+ return &eeprom;
+}
diff --git a/common/boot.c b/common/boot.c
index 8220b8d3fb..cbfe6649b3 100644
--- a/common/boot.c
+++ b/common/boot.c
@@ -75,7 +75,7 @@ static int bootscript_boot(struct bootentry *entry, int verbose, int dryrun)
struct bootm_data data = {};
- if (dryrun) {
+ if (dryrun == 1) {
printf("Would run %s\n", bs->scriptpath);
return 0;
}
@@ -94,8 +94,8 @@ static int bootscript_boot(struct bootentry *entry, int verbose, int dryrun)
if (verbose)
data.verbose = verbose;
- if (dryrun)
- data.dryrun = dryrun;
+ if (dryrun >= 2)
+ data.dryrun = dryrun - 1;
return bootm_boot(&data);
}
@@ -115,11 +115,18 @@ struct watchdog *boot_get_enabled_watchdog(void)
}
static char *global_boot_default;
+
+void boot_set_default(const char *boot_default)
+{
+ free(global_boot_default);
+ global_boot_default = xstrdup(boot_default);
+}
+
static char *global_user;
static int init_boot(void)
{
- global_boot_default = xstrdup("net");
+ global_boot_default = global_boot_default ? : xstrdup("net");
globalvar_add_simple_string("boot.default", &global_boot_default);
globalvar_add_simple_int("boot.watchdog_timeout",
&boot_watchdog_timeout, "%u");
@@ -151,8 +158,8 @@ int boot_entry(struct bootentry *be, int verbose, int dryrun)
}
ret = be->boot(be, verbose, dryrun);
- if (ret)
- pr_err("Booting entry '%s' failed\n", be->title);
+ if (ret && ret != -ENOMEDIUM)
+ pr_err("Booting entry '%s' failed: %pe\n", be->title, ERR_PTR(ret));
return ret;
}
@@ -183,8 +190,12 @@ static int bootscript_create_entry(struct bootentries *bootentries, const char *
{
struct bootentry_script *bs;
enum filetype type;
+ int ret;
+
+ ret = file_name_detect_type(name, &type);
+ if (ret)
+ return ret;
- type = file_name_detect_type(name);
if (type != filetype_sh)
return -EINVAL;
@@ -272,6 +283,7 @@ int bootentry_register_provider(int (*fn)(struct bootentries *bootentries, const
* name can be:
* - a name of a boot script under /env/boot
* - a full path of a boot script
+ * - a full path of a bootloader spec entry
* - a device name
* - a cdev name
* - a full path of a directory containing bootloader spec entries
@@ -313,10 +325,12 @@ int bootentry_create_from_name(struct bootentries *bootentries,
/*
* bootsources_menu - show a menu from an array of names
*/
-void bootsources_menu(struct bootentries *bootentries, int timeout)
+void bootsources_menu(struct bootentries *bootentries,
+ unsigned default_entry, int timeout)
{
struct bootentry *entry;
struct menu_entry *back_entry;
+ int i = 1;
if (!IS_ENABLED(CONFIG_MENU)) {
pr_warn("no menu support available\n");
@@ -328,6 +342,9 @@ void bootsources_menu(struct bootentries *bootentries, int timeout)
entry->me.display = xstrdup(entry->title);
entry->me.action = bootsource_action;
menu_add_entry(bootentries->menu, &entry->me);
+
+ if (i++ == default_entry)
+ bootentries->menu->selected = &entry->me;
}
back_entry = xzalloc(sizeof(*back_entry));
@@ -336,6 +353,9 @@ void bootsources_menu(struct bootentries *bootentries, int timeout)
back_entry->non_re_ent = 1;
menu_add_entry(bootentries->menu, back_entry);
+ if (i == default_entry)
+ bootentries->menu->selected = back_entry;
+
if (timeout >= 0)
bootentries->menu->auto_select = timeout;
diff --git a/common/bootchooser.c b/common/bootchooser.c
index 2f22e03c47..022e225165 100644
--- a/common/bootchooser.c
+++ b/common/bootchooser.c
@@ -13,7 +13,7 @@
#include <libfile.h>
#include <common.h>
#include <malloc.h>
-#include <printk.h>
+#include <linux/printk.h>
#include <xfuncs.h>
#include <envfs.h>
#include <errno.h>
@@ -77,6 +77,7 @@ struct bootchooser_target {
enum reset_attempts {
RESET_ATTEMPTS_POWER_ON,
RESET_ATTEMPTS_ALL_ZERO,
+ RESET_ATTEMPTS_SRC_RST,
};
static unsigned long reset_attempts;
@@ -128,7 +129,7 @@ static void pr_target(struct bootchooser_target *target)
printf(" disabled due to %s\n", reason);
}
-static int pr_setenv(struct bootchooser *bc, const char *fmt, ...)
+static int bc_setenv(struct bootchooser *bc, const char *fmt, ...)
{
va_list ap;
int ret = 0;
@@ -162,7 +163,7 @@ err:
return ret;
}
-static const char *pr_getenv(const char *fmt, ...)
+static const char *bc_getenv(const char *fmt, ...)
{
va_list ap;
char *str;
@@ -258,7 +259,7 @@ static struct bootchooser_target *bootchooser_target_new(struct bootchooser *bc,
target->remaining_attempts = 0;
}
- val = pr_getenv("%s.boot", target->prefix);
+ val = bc_getenv("%s.boot", target->prefix);
if (!val)
val = target->name;
target->boot = xstrdup(val);
@@ -439,6 +440,13 @@ struct bootchooser *bootchooser_get(void)
attempts_resetted = 1;
}
+ if (test_bit(RESET_ATTEMPTS_SRC_RST, &reset_attempts) &&
+ reset_source_get() == RESET_RST && !attempts_resetted) {
+ pr_info("RST Reset, resetting remaining attempts\n");
+ bootchooser_reset_attempts(bc);
+ attempts_resetted = 1;
+ }
+
if (test_bit(RESET_ATTEMPTS_ALL_ZERO, &reset_attempts)) {
int attempts = 0;
@@ -497,17 +505,17 @@ int bootchooser_save(struct bootchooser *bc)
int ret;
if (bc->last_chosen)
- pr_setenv(bc, "%s.last_chosen=%d", bc->state_prefix,
+ bc_setenv(bc, "%s.last_chosen=%d", bc->state_prefix,
bc->last_chosen->id);
list_for_each_entry(target, &bc->targets, list) {
- ret = pr_setenv(bc, "%s.remaining_attempts=%d",
+ ret = bc_setenv(bc, "%s.remaining_attempts=%d",
target->state_prefix,
target->remaining_attempts);
if (ret)
return ret;
- ret = pr_setenv(bc, "%s.priority=%d",
+ ret = bc_setenv(bc, "%s.priority=%d",
target->state_prefix, target->priority);
if (ret)
return ret;
@@ -915,6 +923,7 @@ static int bootchooser_add_entry(struct bootentries *entries, const char *name)
static const char * const reset_attempts_names[] = {
[RESET_ATTEMPTS_POWER_ON] = "power-on",
[RESET_ATTEMPTS_ALL_ZERO] = "all-zero",
+ [RESET_ATTEMPTS_SRC_RST] = "reset",
};
static const char * const reset_priorities_names[] = {
@@ -951,6 +960,8 @@ BAREBOX_MAGICVAR(global.bootchooser.targets,
"bootchooser: Space separated list of target names");
BAREBOX_MAGICVAR(global.bootchooser.default_attempts,
"bootchooser: Default number of attempts for a target");
+BAREBOX_MAGICVAR(global.bootchooser.reset_attempts,
+ "bootchooser: Choose condition to reset number of attempts for all enabled targets ('power-on', 'all-zero', 'reset')");
BAREBOX_MAGICVAR(global.bootchooser.default_priority,
"bootchooser: Default priority for a target");
BAREBOX_MAGICVAR(global.bootchooser.state_prefix,
diff --git a/common/booti.c b/common/booti.c
index a2d63d8c31..e745ff6963 100644
--- a/common/booti.c
+++ b/common/booti.c
@@ -1,17 +1,39 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: 2018 Sascha Hauer <s.hauer@pengutronix.de>
+#define pr_fmt(fmt) "booti: " fmt
+
#include <common.h>
#include <memory.h>
#include <bootm.h>
#include <linux/sizes.h>
+static unsigned long get_kernel_address(unsigned long os_address,
+ unsigned long text_offset)
+{
+ resource_size_t start, end;
+ int ret;
+
+ if (os_address == UIMAGE_SOME_ADDRESS ||
+ os_address == UIMAGE_INVALID_ADDRESS) {
+ ret = memory_bank_first_find_space(&start, &end);
+ if (ret)
+ return UIMAGE_INVALID_ADDRESS;
+
+ return ALIGN(start, SZ_2M) + text_offset;
+ }
+
+ if (os_address >= text_offset && IS_ALIGNED(os_address - text_offset, SZ_2M))
+ return os_address;
+
+ return ALIGN(os_address, SZ_2M) + text_offset;
+}
+
void *booti_load_image(struct image_data *data, phys_addr_t *oftree)
{
const void *kernel_header =
data->os_fit ? data->fit_kernel : data->os_header;
- resource_size_t start, end;
- unsigned long text_offset, image_size, devicetree, kernel;
+ unsigned long text_offset, image_size, kernel;
unsigned long image_end;
int ret;
void *fdt;
@@ -19,11 +41,14 @@ void *booti_load_image(struct image_data *data, phys_addr_t *oftree)
text_offset = le64_to_cpup(kernel_header + 8);
image_size = le64_to_cpup(kernel_header + 16);
- ret = memory_bank_first_find_space(&start, &end);
- if (ret)
- return ERR_PTR(ret);
+ kernel = get_kernel_address(data->os_address, text_offset);
- kernel = ALIGN(start, SZ_2M) + text_offset;
+ print_hex_dump_bytes("header ", DUMP_PREFIX_OFFSET,
+ kernel_header, 80);
+ pr_debug("Kernel to be loaded to %lx+%lx\n", kernel, image_size);
+
+ if (kernel == UIMAGE_INVALID_ADDRESS)
+ return ERR_PTR(-ENOENT);
ret = bootm_load_os(data, kernel);
if (ret)
@@ -32,6 +57,8 @@ void *booti_load_image(struct image_data *data, phys_addr_t *oftree)
image_end = PAGE_ALIGN(kernel + image_size);
if (oftree) {
+ unsigned long devicetree;
+
if (bootm_has_initrd(data)) {
ret = bootm_load_initrd(data, image_end);
if (ret)
@@ -59,7 +86,7 @@ void *booti_load_image(struct image_data *data, phys_addr_t *oftree)
printf("Loaded kernel to 0x%08lx", kernel);
if (oftree)
- printf(", devicetree at 0x%08lx", devicetree);
+ printf(", devicetree at %pa", oftree);
printf("\n");
return (void *)kernel;
diff --git a/common/bootm.c b/common/bootm.c
index 89e3e93f2c..4cc88eed76 100644
--- a/common/bootm.c
+++ b/common/bootm.c
@@ -13,6 +13,7 @@
#include <linux/stat.h>
#include <magicvar.h>
#include <uncompress.h>
+#include <zero_page.h>
static LIST_HEAD(handler_list);
@@ -41,6 +42,7 @@ static struct image_handler *bootm_find_handler(enum filetype filetype,
}
static int bootm_appendroot;
+static int bootm_earlycon;
static int bootm_provide_machine_id;
static int bootm_verbosity;
@@ -69,6 +71,11 @@ enum bootm_verify bootm_get_verify_mode(void)
return bootm_verify_mode;
}
+void bootm_set_verify_mode(enum bootm_verify mode)
+{
+ bootm_verify_mode = mode;
+}
+
static const char * const bootm_verify_names[] = {
#ifndef CONFIG_BOOTM_FORCE_SIGNED_IMAGES
[BOOTM_VERIFY_NONE] = "none",
@@ -113,12 +120,12 @@ int bootm_load_os(struct image_data *data, unsigned long load_address)
load_address, kernel_size);
if (!data->os_res) {
pr_err("unable to request SDRAM region for kernel at"
- "0x%08llx-0x%08llx\n",
+ " 0x%08llx-0x%08llx\n",
(unsigned long long)load_address,
(unsigned long long)load_address + kernel_size - 1);
return -ENOMEM;
}
- memcpy((void *)load_address, kernel, kernel_size);
+ zero_page_memcpy((void *)load_address, kernel, kernel_size);
return 0;
}
@@ -243,12 +250,10 @@ int bootm_load_initrd(struct image_data *data, unsigned long load_address)
goto done1;
}
- type = file_name_detect_type(data->initrd_file);
-
- if ((int)type < 0) {
- pr_err("could not open %s: %s\n", data->initrd_file,
- strerror(-type));
- return (int)type;
+ ret = file_name_detect_type(data->initrd_file, &type);
+ if (ret) {
+ pr_err("could not open initrd \"%s\": %s\n", data->initrd_file, strerror(-ret));
+ return ret;
}
if (type == filetype_uimage) {
@@ -365,12 +370,11 @@ void *bootm_get_devicetree(struct image_data *data)
} else if (data->oftree_file) {
size_t size;
- type = file_name_detect_type(data->oftree_file);
-
- if ((int)type < 0) {
- pr_err("could not open %s: %s\n", data->oftree_file,
- strerror(-type));
- return ERR_PTR((int)type);
+ ret = file_name_detect_type(data->oftree_file, &type);
+ if (ret) {
+ pr_err("could not open device tree \"%s\": %s\n", data->oftree_file,
+ strerror(-ret));
+ return ERR_PTR(ret);
}
switch (type) {
@@ -400,10 +404,13 @@ void *bootm_get_devicetree(struct image_data *data)
}
} else {
- data->of_root_node = of_get_root_node();
- if (!data->of_root_node)
+ struct device_node *root = of_get_root_node();
+
+ if (!root)
return NULL;
+ data->of_root_node = of_dup(root);
+
if (bootm_verbose(data) > 1 && data->of_root_node)
printf("using internal devicetree\n");
}
@@ -414,7 +421,9 @@ void *bootm_get_devicetree(struct image_data *data)
of_add_reserve_entry(data->initrd_res->start, data->initrd_res->end);
}
- oftree = of_get_fixed_tree(data->of_root_node);
+ of_fix_tree(data->of_root_node);
+
+ oftree = of_flatten_dtb(data->of_root_node);
if (!oftree)
return ERR_PTR(-EINVAL);
@@ -459,8 +468,10 @@ int bootm_load_devicetree(struct image_data *data, void *fdt,
memcpy((void *)data->oftree_res->start, fdt, fdt_size);
of_print_cmdline(data->of_root_node);
- if (bootm_verbose(data) > 1)
- of_print_nodes(data->of_root_node, 0);
+ if (bootm_verbose(data) > 1) {
+ of_print_nodes(data->of_root_node, 0, ~0);
+ fdt_print_reserve_map(fdt);
+ }
return 0;
}
@@ -518,18 +529,84 @@ static int bootm_open_os_uimage(struct image_data *data)
return 0;
}
+static int bootm_open_fit(struct image_data *data)
+{
+ struct fit_handle *fit;
+ struct fdt_header *header;
+ static const char *kernel_img = "kernel";
+ size_t flen, hlen;
+ int ret;
+
+ if (!IS_ENABLED(CONFIG_FITIMAGE))
+ return 0;
+
+ header = (struct fdt_header *)data->os_header;
+ flen = bootm_get_os_size(data);
+ hlen = fdt32_to_cpu(header->totalsize);
+
+ fit = fit_open(data->os_file, data->verbose, data->verify,
+ min(flen, hlen));
+ if (IS_ERR(fit)) {
+ pr_err("Loading FIT image %s failed with: %pe\n", data->os_file, fit);
+ return PTR_ERR(fit);
+ }
+
+ data->os_fit = fit;
+
+ data->fit_config = fit_open_configuration(data->os_fit,
+ data->os_part);
+ if (IS_ERR(data->fit_config)) {
+ pr_err("Cannot open FIT image configuration '%s'\n",
+ data->os_part ? data->os_part : "default");
+ return PTR_ERR(data->fit_config);
+ }
+
+ ret = fit_open_image(data->os_fit, data->fit_config, kernel_img,
+ &data->fit_kernel, &data->fit_kernel_size);
+ if (ret)
+ return ret;
+ if (data->os_address == UIMAGE_SOME_ADDRESS) {
+ ret = fit_get_image_address(data->os_fit,
+ data->fit_config,
+ kernel_img,
+ "load", &data->os_address);
+ if (!ret)
+ pr_info("Load address from FIT '%s': 0x%lx\n",
+ kernel_img, data->os_address);
+ /* Note: Error case uses default value. */
+ }
+ if (data->os_entry == UIMAGE_SOME_ADDRESS) {
+ unsigned long entry;
+ ret = fit_get_image_address(data->os_fit,
+ data->fit_config,
+ kernel_img,
+ "entry", &entry);
+ if (!ret) {
+ data->os_entry = entry - data->os_address;
+ pr_info("Entry address from FIT '%s': 0x%lx\n",
+ kernel_img, entry);
+ }
+ /* Note: Error case uses default value. */
+ }
+
+ return 0;
+}
+
static int bootm_open_elf(struct image_data *data)
{
+ struct elf_image *elf;
+
if (!IS_ENABLED(CONFIG_ELF))
return -ENOSYS;
- data->elf = elf_open(data->os_file);
- if (IS_ERR(data->elf))
- return PTR_ERR(data->elf);
+ elf = elf_open(data->os_file);
+ if (IS_ERR(elf))
+ return PTR_ERR(elf);
- pr_info("Entry Point: %08llx\n", data->elf->entry);
+ pr_info("Entry Point: %08llx\n", elf->entry);
- data->os_address = data->elf->entry;
+ data->os_address = elf->entry;
+ data->elf = elf;
return 0;
}
@@ -632,74 +709,25 @@ int bootm_boot(struct bootm_data *bootm_data)
}
}
- if (IS_ENABLED(CONFIG_FITIMAGE) && os_type == filetype_oftree) {
- struct fit_handle *fit;
- static const char *kernel_img = "kernel";
-
- fit = fit_open(data->os_file, data->verbose, data->verify);
- if (IS_ERR(fit)) {
- pr_err("Loading FIT image %s failed with: %pe\n", data->os_file, fit);
- ret = PTR_ERR(fit);
- goto err_out;
- }
-
- data->os_fit = fit;
-
- data->fit_config = fit_open_configuration(data->os_fit,
- data->os_part);
- if (IS_ERR(data->fit_config)) {
- pr_err("Cannot open FIT image configuration '%s'\n",
- data->os_part ? data->os_part : "default");
- ret = PTR_ERR(data->fit_config);
- goto err_out;
- }
-
- ret = fit_open_image(data->os_fit, data->fit_config, kernel_img,
- &data->fit_kernel, &data->fit_kernel_size);
- if (ret)
- goto err_out;
- if (data->os_address == UIMAGE_SOME_ADDRESS) {
- ret = fit_get_image_address(data->os_fit,
- data->fit_config,
- kernel_img,
- "load", &data->os_address);
- if (!ret)
- pr_info("Load address from FIT '%s': 0x%lx\n",
- kernel_img, data->os_address);
- /* Note: Error case uses default value. */
- }
- if (data->os_entry == UIMAGE_SOME_ADDRESS) {
- unsigned long entry;
- ret = fit_get_image_address(data->os_fit,
- data->fit_config,
- kernel_img,
- "entry", &entry);
- if (!ret) {
- data->os_entry = entry - data->os_address;
- pr_info("Entry address from FIT '%s': 0x%lx\n",
- kernel_img, entry);
- }
- /* Note: Error case uses default value. */
- }
- }
-
- if (os_type == filetype_uimage) {
+ switch (os_type) {
+ case filetype_oftree:
+ ret = bootm_open_fit(data);
+ break;
+ case filetype_uimage:
ret = bootm_open_os_uimage(data);
- if (ret) {
- pr_err("Loading OS image failed with: %s\n",
- strerror(-ret));
- goto err_out;
- }
+ break;
+ case filetype_elf:
+ ret = bootm_open_elf(data);
+ break;
+ default:
+ ret = 0;
+ break;
}
- if (os_type == filetype_elf) {
- ret = bootm_open_elf(data);
- if (ret) {
- pr_err("Loading ELF image failed with: %s\n",
- strerror(-ret));
- data->elf = NULL;
- goto err_out;
- }
+ if (ret) {
+ pr_err("Loading %s image failed with: %pe\n",
+ file_type_to_short_string(os_type), ERR_PTR(ret));
+ goto err_out;
}
if (bootm_data->appendroot) {
@@ -709,9 +737,8 @@ int bootm_boot(struct bootm_data *bootm_data)
const char *root_dev_name = devpath_to_name(bootm_data->root_dev);
const struct cdev *root_cdev = cdev_by_name(root_dev_name);
- if (root_cdev && root_cdev->partuuid[0] != 0) {
- rootarg = basprintf("root=PARTUUID=%s", root_cdev->partuuid);
- } else {
+ rootarg = cdev_get_linux_rootarg(root_cdev);
+ if (!rootarg) {
rootarg = ERR_PTR(-EINVAL);
if (!root_cdev)
@@ -724,7 +751,10 @@ int bootm_boot(struct bootm_data *bootm_data)
} else {
rootarg = path_get_linux_rootarg(data->os_file);
}
- if (!IS_ERR(rootarg)) {
+
+ if (IS_ERR(rootarg)) {
+ pr_err("Failed to append kernel cmdline parameter 'root='\n");
+ } else {
pr_info("Adding \"%s\" to Kernel commandline\n", rootarg);
globalvar_add_simple("linux.bootargs.bootm.appendroot",
rootarg);
@@ -732,6 +762,26 @@ int bootm_boot(struct bootm_data *bootm_data)
}
}
+ if (bootm_earlycon) {
+ struct console_device *console;
+ const char *earlycon = NULL;
+
+ for_each_console(console) {
+ if (!(console->f_active & (CONSOLE_STDOUT | CONSOLE_STDERR)))
+ continue;
+
+ earlycon = dev_get_param(&console->class_dev, "linux.bootargs.earlycon");
+ if (earlycon)
+ break;
+ }
+
+ if (!earlycon)
+ earlycon = "earlycon";
+
+ pr_info("Adding \"%s\" to Kernel commandline\n", earlycon);
+ globalvar_add_simple("linux.bootargs.bootm.earlycon", earlycon);
+ }
+
if (bootm_data->provide_machine_id) {
const char *machine_id = getenv_nonempty("global.machine_id");
char *machine_id_bootarg;
@@ -795,9 +845,10 @@ err_out:
elf_close(data->elf);
if (IS_ENABLED(CONFIG_FITIMAGE) && data->os_fit)
fit_close(data->os_fit);
- if (data->of_root_node && data->of_root_node != of_get_root_node())
+ if (data->of_root_node)
of_delete_node(data->of_root_node);
+ globalvar_remove("linux.bootargs.bootm.earlycon");
globalvar_remove("linux.bootargs.bootm.appendroot");
free(data->os_header);
free(data->os_file);
@@ -889,6 +940,12 @@ static struct image_handler xz_bootm_handler = {
.filetype = filetype_xz_compressed,
};
+static struct image_handler zstd_bootm_handler = {
+ .name = "ZSTD compressed file",
+ .bootm = do_bootm_compressed,
+ .filetype = filetype_zstd_compressed,
+};
+
static int bootm_init(void)
{
globalvar_add_simple("bootm.image", NULL);
@@ -897,6 +954,7 @@ static int bootm_init(void)
globalvar_add_simple("bootm.root_dev", NULL);
globalvar_add_simple("bootm.tee", NULL);
globalvar_add_simple_bool("bootm.appendroot", &bootm_appendroot);
+ globalvar_add_simple_bool("bootm.earlycon", &bootm_earlycon);
globalvar_add_simple_bool("bootm.provide_machine_id", &bootm_provide_machine_id);
if (IS_ENABLED(CONFIG_BOOTM_INITRD)) {
globalvar_add_simple("bootm.initrd", NULL);
@@ -922,6 +980,8 @@ static int bootm_init(void)
register_image_handler(&lz4_bootm_handler);
if (IS_ENABLED(CONFIG_XZ_DECOMPRESS))
register_image_handler(&xz_bootm_handler);
+ if (IS_ENABLED(CONFIG_ZSTD_DECOMPRESS))
+ register_image_handler(&zstd_bootm_handler);
return 0;
}
@@ -936,6 +996,7 @@ BAREBOX_MAGICVAR(global.bootm.oftree, "bootm default oftree");
BAREBOX_MAGICVAR(global.bootm.tee, "bootm default tee image");
BAREBOX_MAGICVAR(global.bootm.verify, "bootm default verify level");
BAREBOX_MAGICVAR(global.bootm.verbose, "bootm default verbosity level (0=quiet)");
+BAREBOX_MAGICVAR(global.bootm.earlycon, "Add earlycon option to Kernel for early log output");
BAREBOX_MAGICVAR(global.bootm.appendroot, "Add root= option to Kernel to mount rootfs from the device the Kernel comes from (default, device can be overridden via global.bootm.root_dev)");
BAREBOX_MAGICVAR(global.bootm.root_dev, "bootm default root device (overrides default device in global.bootm.appendroot)");
BAREBOX_MAGICVAR(global.bootm.provide_machine_id, "If true, append systemd.machine_id=$global.machine_id to Kernel command line");
diff --git a/common/bootsource.c b/common/bootsource.c
index 1f8d053a81..6808c9c51d 100644
--- a/common/bootsource.c
+++ b/common/bootsource.c
@@ -10,7 +10,7 @@
#include <magicvar.h>
#include <init.h>
-static const char *bootsource_str[] = {
+static const char *bootsource_str[BOOTSOURCE_MAX] = {
[BOOTSOURCE_UNKNOWN] = "unknown",
[BOOTSOURCE_NAND] = "nand",
[BOOTSOURCE_NOR] = "nor",
@@ -33,6 +33,42 @@ static enum bootsource bootsource = BOOTSOURCE_UNKNOWN;
static int bootsource_instance = BOOTSOURCE_INSTANCE_UNKNOWN;
const char *bootsource_alias_name = NULL;
+const char *bootsource_to_string(enum bootsource src)
+{
+ if (src >= ARRAY_SIZE(bootsource_str))
+ return NULL;
+
+ return bootsource_str[src];
+}
+
+const char *bootsource_get_alias_stem(enum bootsource src)
+{
+ switch (src) {
+ /*
+ * For I2C and SPI EEPROMs we set the stem to be 'i2c'
+ * and 'spi' correspondingly. The resulting alias will
+ * be pointing at the controller said EEPROM is
+ * attached to.
+ *
+ * NOTE: This code assumes single bootable EEPROM per
+ * controller
+ */
+ case BOOTSOURCE_I2C_EEPROM:
+ return bootsource_str[BOOTSOURCE_I2C];
+ case BOOTSOURCE_SPI_EEPROM:
+ case BOOTSOURCE_SPI_NOR:
+ return bootsource_str[BOOTSOURCE_SPI];
+ case BOOTSOURCE_SERIAL: /* FALLTHROUGH */
+ case BOOTSOURCE_I2C: /* FALLTHROUGH */
+ case BOOTSOURCE_MMC: /* FALLTHROUGH */
+ case BOOTSOURCE_SPI: /* FALLTHROUGH */
+ case BOOTSOURCE_CAN:
+ return bootsource_str[src];
+ default:
+ return NULL;
+ }
+}
+
/**
* bootsource_get_alias_name() - Get the name of the bootsource alias
*
@@ -58,33 +94,9 @@ char *bootsource_get_alias_name(void)
if (bootsource_alias_name)
return strdup(bootsource_alias_name);
- switch (bootsource) {
- /*
- * For I2C and SPI EEPROMs we set the stem to be 'i2c'
- * and 'spi' correspondingly. The resulting alias will
- * be pointing at the controller said EEPROM is
- * attached to.
- *
- * NOTE: This code assumes single bootable EEPROM per
- * controller
- */
- case BOOTSOURCE_I2C_EEPROM:
- stem = bootsource_str[BOOTSOURCE_I2C];
- break;
- case BOOTSOURCE_SPI_EEPROM:
- case BOOTSOURCE_SPI_NOR:
- stem = bootsource_str[BOOTSOURCE_SPI];
- break;
- case BOOTSOURCE_SERIAL: /* FALLTHROUGH */
- case BOOTSOURCE_I2C: /* FALLTHROUGH */
- case BOOTSOURCE_MMC: /* FALLTHROUGH */
- case BOOTSOURCE_SPI: /* FALLTHROUGH */
- case BOOTSOURCE_CAN:
- stem = bootsource_str[bootsource];
- break;
- default:
+ stem = bootsource_get_alias_stem(bootsource);
+ if (!stem)
return NULL;
- }
/*
* We expect SoC specific bootsource detection code to properly
@@ -96,33 +108,92 @@ char *bootsource_get_alias_name(void)
return basprintf("%s%d", stem, bootsource_instance);
}
+struct device_node *bootsource_of_node_get(struct device_node *root)
+{
+ struct device_node *np;
+ char *alias_name;
+
+ alias_name = bootsource_get_alias_name();
+ if (!alias_name)
+ return NULL;
+
+ np = of_find_node_by_alias(root, alias_name);
+
+ free(alias_name);
+
+ return np;
+}
+
void bootsource_set_alias_name(const char *name)
{
bootsource_alias_name = name;
}
-void bootsource_set(enum bootsource src)
+void bootsource_set_raw(enum bootsource src, int instance)
{
- if (src >= ARRAY_SIZE(bootsource_str))
+ if (src >= BOOTSOURCE_MAX)
src = BOOTSOURCE_UNKNOWN;
bootsource = src;
- setenv("bootsource", bootsource_str[src]);
+ setenv("bootsource", bootsource_to_string(src));
+
+ bootsource_set_raw_instance(instance);
}
-void bootsource_set_instance(int instance)
+void bootsource_set_raw_instance(int instance)
{
- char buf[32];
-
bootsource_instance = instance;
if (instance < 0)
- sprintf(buf, "unknown");
+ setenv("bootsource_instance","unknown");
else
- snprintf(buf, sizeof(buf), "%d", instance);
+ pr_setenv("bootsource_instance", "%d", instance);
+}
+
+int bootsource_of_alias_xlate(enum bootsource src, int instance)
+{
+ char chosen[sizeof("barebox,bootsource-harddisk4294967295")];
+ const char *bootsource_stem;
+ struct device_node *np;
+ int alias_id;
+
+ if (!IS_ENABLED(CONFIG_OFDEVICE))
+ return BOOTSOURCE_INSTANCE_UNKNOWN;
+
+ if (src == BOOTSOURCE_UNKNOWN ||
+ instance == BOOTSOURCE_INSTANCE_UNKNOWN)
+ return BOOTSOURCE_INSTANCE_UNKNOWN;
+
+ bootsource_stem = bootsource_get_alias_stem(src);
+ if (!bootsource_stem)
+ return BOOTSOURCE_INSTANCE_UNKNOWN;
+
+ scnprintf(chosen, sizeof(chosen), "barebox,bootsource-%s%u",
+ bootsource_stem, instance);
+
+ np = of_find_node_by_chosen(chosen, NULL);
+ if (!np)
+ return BOOTSOURCE_INSTANCE_UNKNOWN;
+
+ alias_id = of_alias_get_id(np, bootsource_stem);
+ if (alias_id < 0)
+ return BOOTSOURCE_INSTANCE_UNKNOWN;
+
+ return alias_id;
+}
+
+int bootsource_set(enum bootsource src, int instance)
+{
+ int alias_id;
+
+ alias_id = bootsource_of_alias_xlate(src, instance);
+ if (alias_id == BOOTSOURCE_INSTANCE_UNKNOWN)
+ alias_id = instance;
+
+ bootsource_set_raw(src, alias_id);
- setenv("bootsource_instance", buf);
+ return alias_id;
}
enum bootsource bootsource_get(void)
@@ -141,8 +212,7 @@ BAREBOX_MAGICVAR(bootsource_instance, "The instance of the source barebox has be
static int bootsource_init(void)
{
- bootsource_set(bootsource);
- bootsource_set_instance(bootsource_instance);
+ bootsource_set_raw(bootsource, bootsource_instance);
export("bootsource");
export("bootsource_instance");
diff --git a/common/bthread.c b/common/bthread.c
index 46e6987149..d40c0b0f9e 100644
--- a/common/bthread.c
+++ b/common/bthread.c
@@ -70,6 +70,8 @@ bool bthread_is_main(struct bthread *bthread)
static void bthread_free(struct bthread *bthread)
{
+ if (!bthread)
+ return;
free(bthread->stack);
free(bthread->name);
free(bthread);
diff --git a/common/calloc.c b/common/calloc.c
index 2b933ec272..65e843350d 100644
--- a/common/calloc.c
+++ b/common/calloc.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
#include <common.h>
#include <malloc.h>
diff --git a/common/complete.c b/common/complete.c
index e504b75606..3911535621 100644
--- a/common/complete.c
+++ b/common/complete.c
@@ -14,17 +14,39 @@
#include <command.h>
#include <environment.h>
-static int file_complete(struct string_list *sl, char *instr, int exec)
+static bool is_valid_escape(const char *str)
+{
+ return str[0] == '\\' && (str[1] == ' ' || str[1] == '\\');
+}
+
+static bool strstarts_escaped(const char *whole, const char *prefix_escaped)
+{
+ if (!prefix_escaped)
+ return true;
+
+ while (*prefix_escaped) {
+ if (is_valid_escape(prefix_escaped))
+ prefix_escaped++;
+
+ if (*whole++ != *prefix_escaped++)
+ return false;
+ }
+
+ return true;
+}
+
+static int file_complete(struct string_list *sl, char *instr,
+ const char *dirn, int exec)
{
char *path = strdup(instr);
struct stat s;
DIR *dir;
struct dirent *d;
char tmp[PATH_MAX];
- char *base, *dirn;
+ char *base;
base = basename(instr);
- dirn = dirname(path);
+ dirn = dirn ?: dirname(path);
dir = opendir(dirn);
if (!dir)
@@ -34,7 +56,7 @@ static int file_complete(struct string_list *sl, char *instr, int exec)
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
continue;
- if (strncmp(base, d->d_name, strlen(base)))
+ if (!strstarts_escaped(d->d_name, base))
continue;
strcpy(tmp, instr);
@@ -93,7 +115,7 @@ static int path_command_complete(struct string_list *sl, char *instr)
!strcmp(d->d_name, ".."))
continue;
- if (!strncmp(instr, d->d_name, strlen(instr))) {
+ if (strstarts_escaped(d->d_name, instr)) {
strcpy(tmp, d->d_name);
if (!stat(tmp, &s) &&
S_ISDIR(s.st_mode))
@@ -134,16 +156,10 @@ EXPORT_SYMBOL(command_complete);
int device_complete(struct string_list *sl, char *instr)
{
- struct device_d *dev;
- int len;
-
- if (!instr)
- instr = "";
-
- len = strlen(instr);
+ struct device *dev;
for_each_device(dev) {
- if (strncmp(instr, dev_name(dev), len))
+ if (!strstarts_escaped(dev_name(dev), instr))
continue;
string_list_add_asprintf(sl, "%s ", dev_name(dev));
@@ -153,26 +169,38 @@ int device_complete(struct string_list *sl, char *instr)
}
EXPORT_SYMBOL(device_complete);
-static int device_param_complete(struct device_d *dev, struct string_list *sl,
- char *instr, int eval)
+static int device_param_complete(struct device *dev, const char *devname,
+ struct string_list *sl, char *instr, int eval)
{
struct param_d *param;
- int len;
-
- len = strlen(instr);
list_for_each_entry(param, &dev->parameters, list) {
- if (strncmp(instr, param->name, len))
+ if (!strstarts_escaped(param->name, instr))
continue;
string_list_add_asprintf(sl, "%s%s.%s%c",
- eval ? "$" : "", dev_name(dev), param->name,
+ eval ? "$" : "", devname, param->name,
eval ? ' ' : '=');
}
return 0;
}
+int driver_complete(struct string_list *sl, char *instr)
+{
+ struct driver_d *drv;
+
+ for_each_driver(drv) {
+ if (!strstarts_escaped(drv->name, instr))
+ continue;
+
+ string_list_add_asprintf(sl, "%s ", drv->name);
+ }
+
+ return COMPLETE_CONTINUE;
+}
+EXPORT_SYMBOL(driver_complete);
+
int empty_complete(struct string_list *sl, char *instr)
{
return COMPLETE_END;
@@ -229,7 +257,7 @@ int devicetree_nodepath_complete(struct string_list *sl, char *instr)
for_each_child_of_node(node, child) {
if (strncmp(base, child->name, strlen(base)))
continue;
- string_list_add_asprintf(sl, "%s/", child->full_name);
+ string_list_add_asprintf(sl, "%pOF/", child);
}
out:
free(path);
@@ -250,15 +278,23 @@ EXPORT_SYMBOL(devicetree_complete);
int devicetree_file_complete(struct string_list *sl, char *instr)
{
devicetree_complete(sl, instr);
- file_complete(sl, instr, 0);
+ file_complete(sl, instr, NULL, 0);
return 0;
}
EXPORT_SYMBOL(devicetree_file_complete);
+int tutorial_complete(struct string_list *sl, char *instr)
+{
+ file_complete(sl, instr, "/env/data/tutorial", 0);
+
+ return 0;
+}
+EXPORT_SYMBOL(tutorial_complete);
+
static int env_param_complete(struct string_list *sl, char *instr, int eval)
{
- struct device_d *dev;
+ struct device *dev;
struct variable_d *var;
struct env_context *c;
int len;
@@ -299,14 +335,12 @@ static int env_param_complete(struct string_list *sl, char *instr, int eval)
char *devname;
devname = xstrndup(instr, dot - instr);
-
-
dev = get_device_by_name(devname);
- free(devname);
if (dev)
- device_param_complete(dev, sl, dot + 1, eval);
+ device_param_complete(dev, devname, sl, dot + 1, eval);
+ free(devname);
pos = dot + 1;
}
@@ -314,7 +348,7 @@ static int env_param_complete(struct string_list *sl, char *instr, int eval)
for_each_device(dev) {
if (!strncmp(instr, dev_name(dev), len))
- device_param_complete(dev, sl, "", eval);
+ device_param_complete(dev, dev_name(dev), sl, "", eval);
}
return 0;
@@ -333,21 +367,43 @@ void complete_reset(void)
tab_pressed = 0;
}
+static char *skip_to_last_unescaped_space(char *instr)
+{
+ char *t;
+
+ t = strrchr(instr, ' ');
+ if (t && (instr == t || t[-1] != '\\'))
+ return t + 1;
+
+ return instr;
+}
+
+static size_t strlen_escaped(char *instr)
+{
+ size_t count = 0;
+
+ for (; *instr; instr++) {
+ if (is_valid_escape(instr))
+ instr++;
+
+ count++;
+ }
+
+ return count;
+}
+
static char* cmd_complete_lookup(struct string_list *sl, char *instr)
{
struct command *cmdtp;
int len;
int ret = COMPLETE_END;
char *res = NULL;
- char *t;
for_each_command(cmdtp) {
len = strlen(cmdtp->name);
if (!strncmp(instr, cmdtp->name, len) && instr[len] == ' ') {
instr += len + 1;
- t = strrchr(instr, ' ');
- if (t)
- instr = t + 1;
+ instr = skip_to_last_unescaped_space(instr);
if (cmdtp->complete) {
ret = cmdtp->complete(sl, instr);
@@ -392,11 +448,11 @@ int complete(char *instr, char **outstr)
if (!instr) {
instr = t;
if (t && (t[0] == '/' || !strncmp(t, "./", 2))) {
- file_complete(&sl, t, 1);
+ file_complete(&sl, t, NULL, 1);
instr = t;
} else if ((t = strrchr(t, ' '))) {
t++;
- file_complete(&sl, t, 0);
+ file_complete(&sl, t, NULL, 0);
instr = t;
} else {
command_complete(&sl, instr);
@@ -407,7 +463,7 @@ int complete(char *instr, char **outstr)
env_param_complete(&sl, instr + 1, 1);
}
- pos = strlen(instr);
+ pos = strlen_escaped(instr);
*outstr = "";
if (list_empty(&sl.list))
diff --git a/common/console.c b/common/console.c
index 8727b187cf..5a0fd66ab3 100644
--- a/common/console.c
+++ b/common/console.c
@@ -220,6 +220,21 @@ static void console_init_early(void)
initialized = CONSOLE_INITIALIZED_BUFFER;
}
+static void console_add_earlycon_param(struct console_device *cdev, unsigned baudrate)
+{
+ char *str;
+
+ if (!cdev->linux_earlycon_name)
+ return;
+
+ str = basprintf("earlycon=%s,0x%lx", cdev->linux_earlycon_name,
+ (ulong)cdev->phys_base);
+
+ dev_add_param_fixed(&cdev->class_dev, "linux.bootargs.earlycon", str);
+
+ free(str);
+}
+
static void console_set_stdoutpath(struct console_device *cdev, unsigned baudrate)
{
int id;
@@ -228,7 +243,7 @@ static void console_set_stdoutpath(struct console_device *cdev, unsigned baudrat
if (!cdev->linux_console_name)
return;
- id = of_alias_get_id(cdev->dev->device_node, "serial");
+ id = of_alias_get_id(cdev->dev->of_node, "serial");
if (id < 0)
return;
@@ -239,14 +254,34 @@ static void console_set_stdoutpath(struct console_device *cdev, unsigned baudrat
free(str);
}
+struct console_device *of_console_by_stdout_path(void)
+{
+ struct console_device *console;
+ struct device_node *stdout_np;
+
+ stdout_np = of_get_stdoutpath(NULL);
+ if (!stdout_np)
+ return NULL;
+
+ for_each_console(console) {
+ if (dev_of_node(console->dev) == stdout_np)
+ return console;
+ }
+
+ return NULL;
+}
+
static int __console_puts(struct console_device *cdev, const char *s,
size_t nbytes)
{
size_t i;
for (i = 0; i < nbytes; i++) {
- if (*s == '\n')
+ if (*s == '\n') {
cdev->putc(cdev, '\r');
+ if (IS_ENABLED(CONFIG_CONSOLE_FLUSH_LINE_BREAK) && cdev->flush)
+ cdev->flush(cdev);
+ }
cdev->putc(cdev, *s);
s++;
@@ -294,7 +329,7 @@ static ssize_t fops_write(struct cdev* dev, const void* buf, size_t count,
int console_register(struct console_device *newcdev)
{
struct device_node *serdev_node = console_is_serdev_node(newcdev);
- struct device_d *dev = &newcdev->class_dev;
+ struct device *dev = &newcdev->class_dev;
int activate = 0, ret;
unsigned baudrate = CONFIG_BAUDRATE;
@@ -332,6 +367,8 @@ int console_register(struct console_device *newcdev)
console_set_stdoutpath(newcdev, baudrate);
}
+ console_add_earlycon_param(newcdev, baudrate);
+
if (newcdev->setbrg) {
ret = newcdev->setbrg(newcdev, baudrate);
if (ret)
@@ -389,7 +426,7 @@ EXPORT_SYMBOL(console_register);
int console_unregister(struct console_device *cdev)
{
- struct device_d *dev = &cdev->class_dev;
+ struct device *dev = &cdev->class_dev;
int status;
/*
@@ -591,7 +628,7 @@ int ctrlc(void)
if (ctrlc_abort)
return 1;
-#ifdef ARCH_HAS_CTRLC
+#ifdef CONFIG_ARCH_HAS_CTRLC
ret = arch_ctrlc();
#else
if (tstc() && getchar() == 3)
diff --git a/common/console_common.c b/common/console_common.c
index 91a81e50fa..0113a64138 100644
--- a/common/console_common.c
+++ b/common/console_common.c
@@ -10,36 +10,39 @@
#include <errno.h>
#include <console.h>
#include <init.h>
+#include <string.h>
#include <environment.h>
#include <globalvar.h>
#include <magicvar.h>
+#include <memory.h>
#include <of.h>
#include <password.h>
#include <clock.h>
#include <malloc.h>
#include <linux/pstore.h>
#include <linux/math64.h>
+#include <linux/sizes.h>
+#include <linux/overflow.h>
#ifndef CONFIG_CONSOLE_NONE
static const char *colored_log_level[] = {
- [MSG_EMERG] = "\033[31mEMERG:\033[0m ", /* red */
- [MSG_ALERT] = "\033[31mALERT:\033[0m ", /* red */
- [MSG_CRIT] = "\033[31mCRITICAL:\033[0m ", /* red */
- [MSG_ERR] = "\033[31mERROR:\033[0m ", /* red */
- [MSG_WARNING] = "\033[33mWARNING:\033[0m ", /* yellow */
- [MSG_NOTICE] = "\033[34mNOTICE:\033[0m ", /* blue */
+ [MSG_EMERG] = "\033[1;31mEMERG:\033[0m ", /* red */
+ [MSG_ALERT] = "\033[1;31mALERT:\033[0m ", /* red */
+ [MSG_CRIT] = "\033[1;31mCRITICAL:\033[0m ", /* red */
+ [MSG_ERR] = "\033[1;31mERROR:\033[0m ", /* red */
+ [MSG_WARNING] = "\033[1;33mWARNING:\033[0m ", /* yellow */
+ [MSG_NOTICE] = "\033[1;34mNOTICE:\033[0m ", /* blue */
};
int barebox_loglevel = CONFIG_DEFAULT_LOGLEVEL;
LIST_HEAD(barebox_logbuf);
static int barebox_logbuf_num_messages;
-static int barebox_log_max_messages = 1000;
+static int barebox_log_max_messages;
static void log_del(struct log_entry *log)
{
- free(log->msg);
list_del(&log->list);
free(log);
barebox_logbuf_num_messages--;
@@ -68,7 +71,7 @@ void log_clean(unsigned int limit)
}
}
-static void print_colored_log_level(const int level)
+static void print_colored_log_level(unsigned int ch, const int level)
{
if (!console_allow_color())
return;
@@ -77,7 +80,7 @@ static void print_colored_log_level(const int level)
if (!colored_log_level[level])
return;
- puts(colored_log_level[level]);
+ console_puts(ch, colored_log_level[level]);
}
static void pr_puts(int level, const char *str)
@@ -89,15 +92,14 @@ static void pr_puts(int level, const char *str)
log_clean(barebox_log_max_messages - 1);
if (barebox_log_max_messages >= 0) {
- log = malloc(sizeof(*log));
+ int msglen;
+
+ msglen = strlen(str);
+ log = malloc(struct_size(log, msg, msglen + 1));
if (!log)
goto nolog;
- log->msg = strdup(str);
- if (!log->msg) {
- free(log);
- goto nolog;
- }
+ memcpy(log->msg, str, msglen + 1);
log->timestamp = get_time_ns();
log->level = level;
@@ -112,8 +114,8 @@ nolog:
if (level > barebox_loglevel)
return;
- print_colored_log_level(level);
- puts(str);
+ print_colored_log_level(CONSOLE_STDERR, level);
+ console_puts(CONSOLE_STDERR, str);
}
int pr_print(int level, const char *fmt, ...)
@@ -134,7 +136,7 @@ int pr_print(int level, const char *fmt, ...)
return i;
}
-int dev_printf(int level, const struct device_d *dev, const char *format, ...)
+int dev_printf(int level, const struct device *dev, const char *format, ...)
{
va_list args;
int ret = 0;
@@ -144,7 +146,7 @@ int dev_printf(int level, const struct device_d *dev, const char *format, ...)
if (!IS_ENABLED(CONFIG_LOGBUF) && level > barebox_loglevel)
return 0;
- if (dev->driver && dev->driver->name)
+ if (dev && dev->driver && dev->driver->name)
ret += snprintf(printbuffer, size, "%s ", dev->driver->name);
ret += snprintf(printbuffer + ret, size - ret, "%s: ", dev_name(dev));
@@ -173,15 +175,18 @@ bool console_allow_color(void)
static int console_common_init(void)
{
- if (IS_ENABLED(CONFIG_LOGBUF))
+ if (IS_ENABLED(CONFIG_LOGBUF)) {
+ barebox_log_max_messages
+ = clamp(mem_malloc_size() / SZ_32K, 1000UL, 100000UL);
globalvar_add_simple_int("log_max_messages",
&barebox_log_max_messages, "%d");
+ }
globalvar_add_simple_bool("allow_color", &__console_allow_color);
return globalvar_add_simple_int("loglevel", &barebox_loglevel, "%d");
}
-device_initcall(console_common_init);
+core_initcall(console_common_init);
int log_writefile(const char *filepath)
{
@@ -203,7 +208,7 @@ int log_writefile(const char *filepath)
return ret < 0 ? ret : nbytes;
}
-void log_print(unsigned flags, unsigned levels)
+int log_print(unsigned flags, unsigned levels)
{
struct log_entry *log;
unsigned long last = 0;
@@ -214,10 +219,12 @@ void log_print(unsigned flags, unsigned levels)
if (levels && !(levels & (1 << log->level)))
continue;
+ if (ctrlc())
+ return -EINTR;
if (!(flags & (BAREBOX_LOG_PRINT_RAW | BAREBOX_LOG_PRINT_TIME
| BAREBOX_LOG_DIFF_TIME)))
- print_colored_log_level(log->level);
+ print_colored_log_level(CONSOLE_STDOUT, log->level);
if (flags & BAREBOX_LOG_PRINT_RAW)
printf("<%i>", log->level);
@@ -242,6 +249,8 @@ void log_print(unsigned flags, unsigned levels)
printf("%s", log->msg);
}
+
+ return 0;
}
int printf(const char *fmt, ...)
@@ -284,7 +293,7 @@ int vprintf(const char *fmt, va_list args)
}
EXPORT_SYMBOL(vprintf);
-struct console_device *console_get_by_dev(struct device_d *dev)
+struct console_device *console_get_by_dev(struct device *dev)
{
struct console_device *cdev;
@@ -336,7 +345,7 @@ EXPORT_SYMBOL(console_get_first_active);
struct console_device *of_console_get_by_alias(const char *alias)
{
struct device_node *node;
- struct device_d *dev;
+ struct device *dev;
node = of_find_node_by_alias(NULL, alias);
if (!node)
diff --git a/common/console_simple.c b/common/console_simple.c
index 8c404ad264..702087bd23 100644
--- a/common/console_simple.c
+++ b/common/console_simple.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
#include <config.h>
#include <common.h>
#include <fs.h>
@@ -68,7 +70,7 @@ EXPORT_SYMBOL(console_flush);
int ctrlc (void)
{
int ret = 0;
-#ifdef ARCH_HAS_CTRLC
+#ifdef CONFIG_ARCH_HAS_CTRLC
ret = arch_ctrlc();
#else
if (tstc() && getchar() == 3)
diff --git a/common/ddr1_dimm_params.c b/common/ddr1_dimm_params.c
new file mode 100644
index 0000000000..4a7db30e2e
--- /dev/null
+++ b/common/ddr1_dimm_params.c
@@ -0,0 +1,323 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright 2008 Freescale Semiconductor, Inc.
+ */
+#include <common.h>
+#include <linux/log2.h>
+#include <ddr_dimms.h>
+
+/*
+ * Calculate the Density of each Physical Rank.
+ * Returned size is in bytes.
+ *
+ * Study these table from Byte 31 of JEDEC SPD Spec.
+ *
+ * DDR I DDR II
+ * Bit Size Size
+ * --- ----- ------
+ * 7 high 512MB 512MB
+ * 6 256MB 256MB
+ * 5 128MB 128MB
+ * 4 64MB 16GB
+ * 3 32MB 8GB
+ * 2 16MB 4GB
+ * 1 2GB 2GB
+ * 0 low 1GB 1GB
+ *
+ * Reorder Table to be linear by stripping the bottom
+ * 2 or 5 bits off and shifting them up to the top.
+ */
+
+static unsigned long long
+compute_ranksize(unsigned int mem_type, unsigned char row_dens)
+{
+ unsigned long long bsize;
+
+ /* Bottom 2 bits up to the top. */
+ bsize = ((row_dens >> 2) | ((row_dens & 3) << 6));
+ bsize <<= 24ULL;
+ debug("DDR: DDR I rank density = 0x%16llx\n", bsize);
+
+ return bsize;
+}
+
+/*
+ * Convert a two-nibble BCD value into a cycle time.
+ * While the spec calls for nano-seconds, picos are returned.
+ *
+ * This implements the tables for bytes 9, 23 and 25 for both
+ * DDR I and II. No allowance for distinguishing the invalid
+ * fields absent for DDR I yet present in DDR II is made.
+ * (That is, cycle times of .25, .33, .66 and .75 ns are
+ * allowed for both DDR II and I.)
+ */
+static unsigned int
+convert_bcd_tenths_to_cycle_time_ps(unsigned int spd_val)
+{
+ /* Table look up the lower nibble, allow DDR I & II. */
+ unsigned int tenths_ps[16] = {
+ 0,
+ 100,
+ 200,
+ 300,
+ 400,
+ 500,
+ 600,
+ 700,
+ 800,
+ 900,
+ 250, /* This and the next 3 entries valid ... */
+ 330, /* ... only for tCK calculations. */
+ 660,
+ 750,
+ 0, /* undefined */
+ 0 /* undefined */
+ };
+
+ unsigned int whole_ns = (spd_val & 0xF0) >> 4;
+ unsigned int tenth_ns = spd_val & 0x0F;
+ unsigned int ps = whole_ns * 1000 + tenths_ps[tenth_ns];
+
+ return ps;
+}
+
+static unsigned int
+convert_bcd_hundredths_to_cycle_time_ps(unsigned int spd_val)
+{
+ unsigned int tenth_ns = (spd_val & 0xF0) >> 4;
+ unsigned int hundredth_ns = spd_val & 0x0F;
+ unsigned int ps = tenth_ns * 100 + hundredth_ns * 10;
+
+ return ps;
+}
+
+static unsigned int byte40_table_ps[8] = {
+ 0,
+ 250,
+ 330,
+ 500,
+ 660,
+ 750,
+ 0, /* supposed to be RFC, but not sure what that means */
+ 0 /* Undefined */
+};
+
+static unsigned int
+compute_trfc_ps_from_spd(unsigned char trctrfc_ext, unsigned char trfc)
+{
+ return ((trctrfc_ext & 0x1) * 256 + trfc) * 1000
+ + byte40_table_ps[(trctrfc_ext >> 1) & 0x7];
+}
+
+static unsigned int
+compute_trc_ps_from_spd(unsigned char trctrfc_ext, unsigned char trc)
+{
+ return trc * 1000 + byte40_table_ps[(trctrfc_ext >> 4) & 0x7];
+}
+
+/*
+ * tCKmax from DDR I SPD Byte 43
+ *
+ * Bits 7:2 == whole ns
+ * Bits 1:0 == quarter ns
+ * 00 == 0.00 ns
+ * 01 == 0.25 ns
+ * 10 == 0.50 ns
+ * 11 == 0.75 ns
+ *
+ * Returns picoseconds.
+ */
+static unsigned int
+compute_tckmax_from_spd_ps(unsigned int byte43)
+{
+ return (byte43 >> 2) * 1000 + (byte43 & 0x3) * 250;
+}
+
+/*
+ * Determine Refresh Rate. Ignore self refresh bit on DDR I.
+ * Table from SPD Spec, Byte 12, converted to picoseconds and
+ * filled in with "default" normal values.
+ */
+static unsigned int
+determine_refresh_rate_ps(const unsigned int spd_refresh)
+{
+ unsigned int refresh_time_ps[8] = {
+ 15625000, /* 0 Normal 1.00x */
+ 3900000, /* 1 Reduced .25x */
+ 7800000, /* 2 Extended .50x */
+ 31300000, /* 3 Extended 2.00x */
+ 62500000, /* 4 Extended 4.00x */
+ 125000000, /* 5 Extended 8.00x */
+ 15625000, /* 6 Normal 1.00x filler */
+ 15625000, /* 7 Normal 1.00x filler */
+ };
+
+ return refresh_time_ps[spd_refresh & 0x7];
+}
+
+/*
+ * The purpose of this function is to compute a suitable
+ * CAS latency given the DRAM clock period. The SPD only
+ * defines at most 3 CAS latencies. Typically the slower in
+ * frequency the DIMM runs at, the shorter its CAS latency can be.
+ * If the DIMM is operating at a sufficiently low frequency,
+ * it may be able to run at a CAS latency shorter than the
+ * shortest SPD-defined CAS latency.
+ *
+ * If a CAS latency is not found, 0 is returned.
+ *
+ * Do this by finding in the standard speed bin table the longest
+ * tCKmin that doesn't exceed the value of mclk_ps (tCK).
+ *
+ * An assumption made is that the SDRAM device allows the
+ * CL to be programmed for a value that is lower than those
+ * advertised by the SPD. This is not always the case,
+ * as those modes not defined in the SPD are optional.
+ *
+ * CAS latency de-rating based upon values JEDEC Standard No. 79-E
+ * Table 11.
+ *
+ * ordinal 2, ddr1_speed_bins[1] contains tCK for CL=2
+ */
+ /* CL2.0 CL2.5 CL3.0 */
+unsigned short ddr1_speed_bins[] = {0, 7500, 6000, 5000 };
+
+static unsigned int
+compute_derated_DDR1_CAS_latency(unsigned int mclk_ps)
+{
+ const unsigned int num_speed_bins = ARRAY_SIZE(ddr1_speed_bins);
+ unsigned int lowest_tCKmin_found = 0;
+ unsigned int lowest_tCKmin_CL = 0;
+ unsigned int i;
+
+ debug("mclk_ps = %u\n", mclk_ps);
+
+ for (i = 0; i < num_speed_bins; i++) {
+ unsigned int x = ddr1_speed_bins[i];
+ debug("i=%u, x = %u, lowest_tCKmin_found = %u\n",
+ i, x, lowest_tCKmin_found);
+ if (x && lowest_tCKmin_found <= x && x <= mclk_ps) {
+ lowest_tCKmin_found = x;
+ lowest_tCKmin_CL = i + 1;
+ }
+ }
+
+ debug("lowest_tCKmin_CL = %u\n", lowest_tCKmin_CL);
+
+ return lowest_tCKmin_CL;
+}
+
+/*
+ * ddr1_compute_dimm_parameters for DDR1 SPD
+ *
+ * Compute DIMM parameters based upon the SPD information in spd.
+ * Writes the results to the struct dimm_params structure pointed by pdimm.
+ *
+ * FIXME: use #define for the retvals
+ */
+unsigned int ddr1_compute_dimm_parameters(unsigned int mclk_ps,
+ const struct ddr1_spd_eeprom *spd,
+ struct dimm_params *pdimm)
+{
+ int ret;
+
+ if (spd->mem_type != SPD_MEMTYPE_DDR) {
+ printf("DIMM: SPD data is not DDR1\n");
+ return 3;
+ }
+
+ ret = ddr1_spd_check(spd);
+ if (ret) {
+ printf("DIMM: failed checksum\n");
+ return 2;
+ }
+
+ /*
+ * The part name in ASCII in the SPD EEPROM is not null terminated.
+ * Guarantee null termination here by presetting all bytes to 0
+ * and copying the part name in ASCII from the SPD onto it
+ */
+ memset(pdimm->mpart, 0, sizeof(pdimm->mpart));
+ memcpy(pdimm->mpart, spd->mpart, sizeof(pdimm->mpart) - 1);
+
+ /* DIMM organization parameters */
+ pdimm->n_ranks = spd->nrows;
+ pdimm->rank_density = compute_ranksize(spd->mem_type, spd->bank_dens);
+ pdimm->capacity = pdimm->n_ranks * pdimm->rank_density;
+ pdimm->data_width = spd->dataw_lsb;
+ pdimm->primary_sdram_width = spd->primw;
+ pdimm->ec_sdram_width = spd->ecw;
+
+ /*
+ * FIXME: Need to determine registered_dimm status.
+ * 1 == register buffered
+ * 0 == unbuffered
+ */
+ pdimm->registered_dimm = 0; /* unbuffered */
+
+ /* SDRAM device parameters */
+ pdimm->n_row_addr = spd->nrow_addr;
+ pdimm->n_col_addr = spd->ncol_addr;
+ pdimm->n_banks_per_sdram_device = spd->nbanks;
+ pdimm->edc_config = spd->config;
+ pdimm->burst_lengths_bitmask = spd->burstl;
+
+ /*
+ * Calculate the Maximum Data Rate based on the Minimum Cycle time.
+ * The SPD clk_cycle field (tCKmin) is measured in tenths of
+ * nanoseconds and represented as BCD.
+ */
+ pdimm->tckmin_x_ps
+ = convert_bcd_tenths_to_cycle_time_ps(spd->clk_cycle);
+ pdimm->tckmin_x_minus_1_ps
+ = convert_bcd_tenths_to_cycle_time_ps(spd->clk_cycle2);
+ pdimm->tckmin_x_minus_2_ps
+ = convert_bcd_tenths_to_cycle_time_ps(spd->clk_cycle3);
+
+ pdimm->tckmax_ps = compute_tckmax_from_spd_ps(spd->tckmax);
+
+ /*
+ * Compute CAS latencies defined by SPD
+ * The SPD caslat_x should have at least 1 and at most 3 bits set.
+ *
+ * If cas_lat after masking is 0, the __ilog2 function returns
+ * 255 into the variable. This behavior is abused once.
+ */
+ pdimm->caslat_x = ilog2(spd->cas_lat);
+ pdimm->caslat_x_minus_1 = ilog2(spd->cas_lat
+ & ~(1 << pdimm->caslat_x));
+ pdimm->caslat_x_minus_2 = ilog2(spd->cas_lat
+ & ~(1 << pdimm->caslat_x)
+ & ~(1 << pdimm->caslat_x_minus_1));
+
+ /* Compute CAS latencies below that defined by SPD */
+ pdimm->caslat_lowest_derated = compute_derated_DDR1_CAS_latency(
+ mclk_ps);
+
+ /* Compute timing parameters */
+ pdimm->trcd_ps = spd->trcd * 250;
+ pdimm->trp_ps = spd->trp * 250;
+ pdimm->tras_ps = spd->tras * 1000;
+
+ pdimm->twr_ps = mclk_ps * 3;
+ pdimm->twtr_ps = mclk_ps * 1;
+ pdimm->trfc_ps = compute_trfc_ps_from_spd(0, spd->trfc);
+
+ pdimm->trrd_ps = spd->trrd * 250;
+ pdimm->trc_ps = compute_trc_ps_from_spd(0, spd->trc);
+
+ pdimm->refresh_rate_ps = determine_refresh_rate_ps(spd->refresh);
+
+ pdimm->tis_ps = convert_bcd_hundredths_to_cycle_time_ps(spd->ca_setup);
+ pdimm->tih_ps = convert_bcd_hundredths_to_cycle_time_ps(spd->ca_hold);
+ pdimm->tds_ps
+ = convert_bcd_hundredths_to_cycle_time_ps(spd->data_setup);
+ pdimm->tdh_ps
+ = convert_bcd_hundredths_to_cycle_time_ps(spd->data_hold);
+
+ pdimm->trtp_ps = mclk_ps * 2; /* By the book. */
+ pdimm->tdqsq_max_ps = spd->tdqsq * 10;
+ pdimm->tqhs_ps = spd->tqhs * 10;
+
+ return 0;
+}
diff --git a/common/ddr2_dimm_params.c b/common/ddr2_dimm_params.c
new file mode 100644
index 0000000000..b9c0922385
--- /dev/null
+++ b/common/ddr2_dimm_params.c
@@ -0,0 +1,326 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright 2008 Freescale Semiconductor, Inc.
+ */
+
+#include <common.h>
+#include <linux/log2.h>
+#include <ddr_dimms.h>
+
+/*
+ * Calculate the Density of each Physical Rank.
+ * Returned size is in bytes.
+ *
+ * Study these table from Byte 31 of JEDEC SPD Spec.
+ *
+ * DDR I DDR II
+ * Bit Size Size
+ * --- ----- ------
+ * 7 high 512MB 512MB
+ * 6 256MB 256MB
+ * 5 128MB 128MB
+ * 4 64MB 16GB
+ * 3 32MB 8GB
+ * 2 16MB 4GB
+ * 1 2GB 2GB
+ * 0 low 1GB 1GB
+ *
+ * Reorder Table to be linear by stripping the bottom
+ * 2 or 5 bits off and shifting them up to the top.
+ *
+ */
+static unsigned long long
+compute_ranksize(unsigned int mem_type, unsigned char row_dens)
+{
+ unsigned long long bsize;
+
+ /* Bottom 5 bits up to the top. */
+ bsize = ((row_dens >> 5) | ((row_dens & 31) << 3));
+ bsize <<= 27ULL;
+ debug("DDR: DDR II rank density = 0x%16llx\n", bsize);
+
+ return bsize;
+}
+
+/*
+ * Convert a two-nibble BCD value into a cycle time.
+ * While the spec calls for nano-seconds, picos are returned.
+ *
+ * This implements the tables for bytes 9, 23 and 25 for both
+ * DDR I and II. No allowance for distinguishing the invalid
+ * fields absent for DDR I yet present in DDR II is made.
+ * (That is, cycle times of .25, .33, .66 and .75 ns are
+ * allowed for both DDR II and I.)
+ */
+static unsigned int
+convert_bcd_tenths_to_cycle_time_ps(unsigned int spd_val)
+{
+ /* Table look up the lower nibble, allow DDR I & II. */
+ unsigned int tenths_ps[16] = {
+ 0,
+ 100,
+ 200,
+ 300,
+ 400,
+ 500,
+ 600,
+ 700,
+ 800,
+ 900,
+ 250, /* This and the next 3 entries valid ... */
+ 330, /* ... only for tCK calculations. */
+ 660,
+ 750,
+ 0, /* undefined */
+ 0 /* undefined */
+ };
+
+ unsigned int whole_ns = (spd_val & 0xF0) >> 4;
+ unsigned int tenth_ns = spd_val & 0x0F;
+ unsigned int ps = whole_ns * 1000 + tenths_ps[tenth_ns];
+
+ return ps;
+}
+
+static unsigned int
+convert_bcd_hundredths_to_cycle_time_ps(unsigned int spd_val)
+{
+ unsigned int tenth_ns = (spd_val & 0xF0) >> 4;
+ unsigned int hundredth_ns = spd_val & 0x0F;
+ unsigned int ps = tenth_ns * 100 + hundredth_ns * 10;
+
+ return ps;
+}
+
+static unsigned int byte40_table_ps[8] = {
+ 0,
+ 250,
+ 330,
+ 500,
+ 660,
+ 750,
+ 0, /* supposed to be RFC, but not sure what that means */
+ 0 /* Undefined */
+};
+
+static unsigned int
+compute_trfc_ps_from_spd(unsigned char trctrfc_ext, unsigned char trfc)
+{
+ return (((trctrfc_ext & 0x1) * 256) + trfc) * 1000
+ + byte40_table_ps[(trctrfc_ext >> 1) & 0x7];
+}
+
+static unsigned int
+compute_trc_ps_from_spd(unsigned char trctrfc_ext, unsigned char trc)
+{
+ return trc * 1000 + byte40_table_ps[(trctrfc_ext >> 4) & 0x7];
+}
+
+/*
+ * Determine Refresh Rate. Ignore self refresh bit on DDR I.
+ * Table from SPD Spec, Byte 12, converted to picoseconds and
+ * filled in with "default" normal values.
+ */
+static unsigned int
+determine_refresh_rate_ps(const unsigned int spd_refresh)
+{
+ unsigned int refresh_time_ps[8] = {
+ 15625000, /* 0 Normal 1.00x */
+ 3900000, /* 1 Reduced .25x */
+ 7800000, /* 2 Extended .50x */
+ 31300000, /* 3 Extended 2.00x */
+ 62500000, /* 4 Extended 4.00x */
+ 125000000, /* 5 Extended 8.00x */
+ 15625000, /* 6 Normal 1.00x filler */
+ 15625000, /* 7 Normal 1.00x filler */
+ };
+
+ return refresh_time_ps[spd_refresh & 0x7];
+}
+
+/*
+ * The purpose of this function is to compute a suitable
+ * CAS latency given the DRAM clock period. The SPD only
+ * defines at most 3 CAS latencies. Typically the slower in
+ * frequency the DIMM runs at, the shorter its CAS latency can.
+ * be. If the DIMM is operating at a sufficiently low frequency,
+ * it may be able to run at a CAS latency shorter than the
+ * shortest SPD-defined CAS latency.
+ *
+ * If a CAS latency is not found, 0 is returned.
+ *
+ * Do this by finding in the standard speed bin table the longest
+ * tCKmin that doesn't exceed the value of mclk_ps (tCK).
+ *
+ * An assumption made is that the SDRAM device allows the
+ * CL to be programmed for a value that is lower than those
+ * advertised by the SPD. This is not always the case,
+ * as those modes not defined in the SPD are optional.
+ *
+ * CAS latency de-rating based upon values JEDEC Standard No. 79-2C
+ * Table 40, "DDR2 SDRAM stanadard speed bins and tCK, tRCD, tRP, tRAS,
+ * and tRC for corresponding bin"
+ *
+ * ordinal 2, ddr2_speed_bins[1] contains tCK for CL=3
+ * Not certain if any good value exists for CL=2
+ */
+ /* CL2 CL3 CL4 CL5 CL6 CL7*/
+static unsigned short ddr2_speed_bins[] = { 0, 5000, 3750, 3000, 2500, 1875 };
+
+static unsigned int
+compute_derated_DDR2_CAS_latency(unsigned int mclk_ps)
+{
+ const unsigned int num_speed_bins = ARRAY_SIZE(ddr2_speed_bins);
+ unsigned int lowest_tCKmin_found = 0;
+ unsigned int lowest_tCKmin_CL = 0;
+ unsigned int i;
+
+ debug("mclk_ps = %u\n", mclk_ps);
+
+ for (i = 0; i < num_speed_bins; i++) {
+ unsigned int x = ddr2_speed_bins[i];
+ debug("i=%u, x = %u, lowest_tCKmin_found = %u\n",
+ i, x, lowest_tCKmin_found);
+ if (x && x <= mclk_ps && x >= lowest_tCKmin_found ) {
+ lowest_tCKmin_found = x;
+ lowest_tCKmin_CL = i + 2;
+ }
+ }
+
+ debug("lowest_tCKmin_CL = %u\n", lowest_tCKmin_CL);
+
+ return lowest_tCKmin_CL;
+}
+
+/*
+ * ddr2_compute_dimm_parameters for DDR2 SPD
+ *
+ * Compute DIMM parameters based upon the SPD information in spd.
+ * Writes the results to the struct dimm_params structure pointed by pdimm.
+ *
+ * FIXME: use #define for the retvals
+ */
+unsigned int ddr2_compute_dimm_parameters(unsigned int mclk_ps,
+ const struct ddr2_spd_eeprom *spd,
+ struct dimm_params *pdimm)
+{
+ int ret;
+
+ if (spd->mem_type != SPD_MEMTYPE_DDR2 &&
+ spd->mem_type != SPD_MEMTYPE_DDR2_FBDIMM &&
+ spd->mem_type != SPD_MEMTYPE_DDR2_FBDIMM_PROBE) {
+ printf("DIMM: SPD data is not DDR2\n");
+ return 3;
+ }
+
+ ret = ddr2_spd_check(spd);
+ if (ret) {
+ printf("DIMM: failed checksum\n");
+ return 2;
+ }
+
+ /*
+ * The part name in ASCII in the SPD EEPROM is not null terminated.
+ * Guarantee null termination here by presetting all bytes to 0
+ * and copying the part name in ASCII from the SPD onto it
+ */
+ memset(pdimm->mpart, 0, sizeof(pdimm->mpart));
+ memcpy(pdimm->mpart, spd->mpart, sizeof(pdimm->mpart) - 1);
+
+ /* DIMM organization parameters */
+ pdimm->n_ranks = (spd->mod_ranks & 0x7) + 1;
+ pdimm->rank_density = compute_ranksize(spd->mem_type, spd->rank_dens);
+ pdimm->capacity = pdimm->n_ranks * pdimm->rank_density;
+ pdimm->data_width = spd->dataw;
+ pdimm->primary_sdram_width = spd->primw;
+ pdimm->ec_sdram_width = spd->ecw;
+
+ /* These are all the types defined by the JEDEC DDR2 SPD 1.3 spec */
+ switch (spd->dimm_type) {
+ case DDR2_SPD_DIMMTYPE_RDIMM:
+ case DDR2_SPD_DIMMTYPE_72B_SO_RDIMM:
+ case DDR2_SPD_DIMMTYPE_MINI_RDIMM:
+ /* Registered/buffered DIMMs */
+ pdimm->registered_dimm = 1;
+ break;
+
+ case DDR2_SPD_DIMMTYPE_UDIMM:
+ case DDR2_SPD_DIMMTYPE_SO_DIMM:
+ case DDR2_SPD_DIMMTYPE_MICRO_DIMM:
+ case DDR2_SPD_DIMMTYPE_MINI_UDIMM:
+ /* Unbuffered DIMMs */
+ pdimm->registered_dimm = 0;
+ break;
+
+ case DDR2_SPD_DIMMTYPE_72B_SO_CDIMM:
+ default:
+ printf("unknown dimm_type 0x%02X\n", spd->dimm_type);
+ return 1;
+ }
+
+ /* SDRAM device parameters */
+ pdimm->n_row_addr = spd->nrow_addr;
+ pdimm->n_col_addr = spd->ncol_addr;
+ pdimm->n_banks_per_sdram_device = spd->nbanks;
+ pdimm->edc_config = spd->config;
+ pdimm->burst_lengths_bitmask = spd->burstl;
+
+ /*
+ * Calculate the Maximum Data Rate based on the Minimum Cycle time.
+ * The SPD clk_cycle field (tCKmin) is measured in tenths of
+ * nanoseconds and represented as BCD.
+ */
+ pdimm->tckmin_x_ps
+ = convert_bcd_tenths_to_cycle_time_ps(spd->clk_cycle);
+ pdimm->tckmin_x_minus_1_ps
+ = convert_bcd_tenths_to_cycle_time_ps(spd->clk_cycle2);
+ pdimm->tckmin_x_minus_2_ps
+ = convert_bcd_tenths_to_cycle_time_ps(spd->clk_cycle3);
+
+ pdimm->tckmax_ps = convert_bcd_tenths_to_cycle_time_ps(spd->tckmax);
+
+ /*
+ * Compute CAS latencies defined by SPD
+ * The SPD caslat_x should have at least 1 and at most 3 bits set.
+ *
+ * If cas_lat after masking is 0, the __ilog2 function returns
+ * 255 into the variable. This behavior is abused once.
+ */
+ pdimm->caslat_x = ilog2(spd->cas_lat);
+ pdimm->caslat_x_minus_1 = ilog2(spd->cas_lat
+ & ~(1 << pdimm->caslat_x));
+ pdimm->caslat_x_minus_2 = ilog2(spd->cas_lat
+ & ~(1 << pdimm->caslat_x)
+ & ~(1 << pdimm->caslat_x_minus_1));
+
+ /* Compute CAS latencies below that defined by SPD */
+ pdimm->caslat_lowest_derated = compute_derated_DDR2_CAS_latency(
+ mclk_ps);
+
+ /* Compute timing parameters */
+ pdimm->trcd_ps = spd->trcd * 250;
+ pdimm->trp_ps = spd->trp * 250;
+ pdimm->tras_ps = spd->tras * 1000;
+
+ pdimm->twr_ps = spd->twr * 250;
+ pdimm->twtr_ps = spd->twtr * 250;
+ pdimm->trfc_ps = compute_trfc_ps_from_spd(spd->trctrfc_ext, spd->trfc);
+
+ pdimm->trrd_ps = spd->trrd * 250;
+ pdimm->trc_ps = compute_trc_ps_from_spd(spd->trctrfc_ext, spd->trc);
+
+ pdimm->refresh_rate_ps = determine_refresh_rate_ps(spd->refresh);
+
+ pdimm->tis_ps = convert_bcd_hundredths_to_cycle_time_ps(spd->ca_setup);
+ pdimm->tih_ps = convert_bcd_hundredths_to_cycle_time_ps(spd->ca_hold);
+ pdimm->tds_ps
+ = convert_bcd_hundredths_to_cycle_time_ps(spd->data_setup);
+ pdimm->tdh_ps
+ = convert_bcd_hundredths_to_cycle_time_ps(spd->data_hold);
+
+ pdimm->trtp_ps = spd->trtp * 250;
+ pdimm->tdqsq_max_ps = spd->tdqsq * 10;
+ pdimm->tqhs_ps = spd->tqhs * 10;
+
+ return 0;
+}
diff --git a/common/ddr3_dimm_params.c b/common/ddr3_dimm_params.c
new file mode 100644
index 0000000000..1b7512a275
--- /dev/null
+++ b/common/ddr3_dimm_params.c
@@ -0,0 +1,328 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright 2008-2012 Freescale Semiconductor, Inc.
+ * Dave Liu <daveliu@freescale.com>
+ *
+ * calculate the organization and timing parameter
+ * from ddr3 spd, please refer to the spec
+ * JEDEC standard No.21-C 4_01_02_11R18.pdf
+ */
+
+#include <common.h>
+#include <ddr_dimms.h>
+
+/*
+ * Calculate the Density of each Physical Rank.
+ * Returned size is in bytes.
+ *
+ * each rank size =
+ * sdram capacity(bit) / 8 * primary bus width / sdram width
+ *
+ * where: sdram capacity = spd byte4[3:0]
+ * primary bus width = spd byte8[2:0]
+ * sdram width = spd byte7[2:0]
+ *
+ * SPD byte4 - sdram density and banks
+ * bit[3:0] size(bit) size(byte)
+ * 0000 256Mb 32MB
+ * 0001 512Mb 64MB
+ * 0010 1Gb 128MB
+ * 0011 2Gb 256MB
+ * 0100 4Gb 512MB
+ * 0101 8Gb 1GB
+ * 0110 16Gb 2GB
+ *
+ * SPD byte8 - module memory bus width
+ * bit[2:0] primary bus width
+ * 000 8bits
+ * 001 16bits
+ * 010 32bits
+ * 011 64bits
+ *
+ * SPD byte7 - module organiztion
+ * bit[2:0] sdram device width
+ * 000 4bits
+ * 001 8bits
+ * 010 16bits
+ * 011 32bits
+ *
+ */
+static unsigned long long
+compute_ranksize(const struct ddr3_spd_eeprom *spd)
+{
+ unsigned long long bsize;
+
+ int nbit_sdram_cap_bsize = 0;
+ int nbit_primary_bus_width = 0;
+ int nbit_sdram_width = 0;
+
+ if ((spd->density_banks & 0xf) < 7)
+ nbit_sdram_cap_bsize = (spd->density_banks & 0xf) + 28;
+ if ((spd->bus_width & 0x7) < 4)
+ nbit_primary_bus_width = (spd->bus_width & 0x7) + 3;
+ if ((spd->organization & 0x7) < 4)
+ nbit_sdram_width = (spd->organization & 0x7) + 2;
+
+ bsize = 1ULL << (nbit_sdram_cap_bsize - 3
+ + nbit_primary_bus_width - nbit_sdram_width);
+
+ debug("DDR: DDR III rank density = 0x%16llx\n", bsize);
+
+ return bsize;
+}
+
+/*
+ * ddr3_compute_dimm_parameters for DDR3 SPD
+ *
+ * Compute DIMM parameters based upon the SPD information in spd.
+ * Writes the results to the struct dimm_params structure pointed by pdimm.
+ *
+ */
+unsigned int ddr3_compute_dimm_parameters(const struct ddr3_spd_eeprom *spd,
+ struct dimm_params *pdimm)
+{
+ int ret;
+ unsigned int mtb_ps;
+ int ftb_10th_ps;
+ int i;
+
+ if (spd->mem_type != SPD_MEMTYPE_DDR3) {
+ printf("DIMM: SPD data is not DDR3\n");
+ return 3;
+ }
+
+ ret = ddr3_spd_check(spd);
+ if (ret) {
+ printf("DIMM: failed checksum\n");
+ return 2;
+ }
+
+ /*
+ * The part name in ASCII in the SPD EEPROM is not null terminated.
+ * Guarantee null termination here by presetting all bytes to 0
+ * and copying the part name in ASCII from the SPD onto it
+ */
+ memset(pdimm->mpart, 0, sizeof(pdimm->mpart));
+ if ((spd->info_size_crc & 0xF) > 1)
+ memcpy(pdimm->mpart, spd->mpart, sizeof(pdimm->mpart) - 1);
+
+ /* DIMM organization parameters */
+ pdimm->n_ranks = ((spd->organization >> 3) & 0x7) + 1;
+ pdimm->rank_density = compute_ranksize(spd);
+ pdimm->capacity = pdimm->n_ranks * pdimm->rank_density;
+ pdimm->primary_sdram_width = 1 << (3 + (spd->bus_width & 0x7));
+ if ((spd->bus_width >> 3) & 0x3)
+ pdimm->ec_sdram_width = 8;
+ else
+ pdimm->ec_sdram_width = 0;
+ pdimm->data_width = pdimm->primary_sdram_width
+ + pdimm->ec_sdram_width;
+ pdimm->device_width = 1 << ((spd->organization & 0x7) + 2);
+
+ /* These are the types defined by the JEDEC DDR3 SPD spec */
+ pdimm->mirrored_dimm = 0;
+ pdimm->registered_dimm = 0;
+ switch (spd->module_type & DDR3_SPD_MODULETYPE_MASK) {
+ case DDR3_SPD_MODULETYPE_RDIMM:
+ case DDR3_SPD_MODULETYPE_MINI_RDIMM:
+ case DDR3_SPD_MODULETYPE_72B_SO_RDIMM:
+ /* Registered/buffered DIMMs */
+ pdimm->registered_dimm = 1;
+ for (i = 0; i < 16; i += 2) {
+ u8 rcw = spd->mod_section.registered.rcw[i/2];
+ pdimm->rcw[i] = (rcw >> 0) & 0x0F;
+ pdimm->rcw[i+1] = (rcw >> 4) & 0x0F;
+ }
+ break;
+
+ case DDR3_SPD_MODULETYPE_UDIMM:
+ case DDR3_SPD_MODULETYPE_SO_DIMM:
+ case DDR3_SPD_MODULETYPE_MICRO_DIMM:
+ case DDR3_SPD_MODULETYPE_MINI_UDIMM:
+ case DDR3_SPD_MODULETYPE_MINI_CDIMM:
+ case DDR3_SPD_MODULETYPE_72B_SO_UDIMM:
+ case DDR3_SPD_MODULETYPE_72B_SO_CDIMM:
+ case DDR3_SPD_MODULETYPE_LRDIMM:
+ case DDR3_SPD_MODULETYPE_16B_SO_DIMM:
+ case DDR3_SPD_MODULETYPE_32B_SO_DIMM:
+ /* Unbuffered DIMMs */
+ if (spd->mod_section.unbuffered.addr_mapping & 0x1)
+ pdimm->mirrored_dimm = 1;
+ break;
+
+ default:
+ printf("unknown module_type 0x%02X\n", spd->module_type);
+ return 1;
+ }
+
+ /* SDRAM device parameters */
+ pdimm->n_row_addr = ((spd->addressing >> 3) & 0x7) + 12;
+ pdimm->n_col_addr = (spd->addressing & 0x7) + 9;
+ pdimm->n_banks_per_sdram_device = 8 << ((spd->density_banks >> 4) & 0x7);
+
+ /*
+ * The SPD spec has not the ECC bit,
+ * We consider the DIMM as ECC capability
+ * when the extension bus exist
+ */
+ if (pdimm->ec_sdram_width)
+ pdimm->edc_config = 0x02;
+ else
+ pdimm->edc_config = 0x00;
+
+ /*
+ * The SPD spec has not the burst length byte
+ * but DDR3 spec has nature BL8 and BC4,
+ * BL8 -bit3, BC4 -bit2
+ */
+ pdimm->burst_lengths_bitmask = 0x0c;
+
+ /* MTB - medium timebase
+ * The unit in the SPD spec is ns,
+ * We convert it to ps.
+ * eg: MTB = 0.125ns (125ps)
+ */
+ mtb_ps = (spd->mtb_dividend * 1000) /spd->mtb_divisor;
+ pdimm->mtb_ps = mtb_ps;
+
+ /*
+ * FTB - fine timebase
+ * use 1/10th of ps as our unit to avoid floating point
+ * eg, 10 for 1ps, 25 for 2.5ps, 50 for 5ps
+ */
+ ftb_10th_ps =
+ ((spd->ftb_div & 0xf0) >> 4) * 10 / (spd->ftb_div & 0x0f);
+ pdimm->ftb_10th_ps = ftb_10th_ps;
+ /*
+ * sdram minimum cycle time
+ * we assume the MTB is 0.125ns
+ * eg:
+ * tck_min=15 MTB (1.875ns) ->DDR3-1066
+ * =12 MTB (1.5ns) ->DDR3-1333
+ * =10 MTB (1.25ns) ->DDR3-1600
+ */
+ pdimm->tckmin_x_ps = spd->tck_min * mtb_ps +
+ (spd->fine_tck_min * ftb_10th_ps) / 10;
+
+ /*
+ * CAS latency supported
+ * bit4 - CL4
+ * bit5 - CL5
+ * bit18 - CL18
+ */
+ pdimm->caslat_x = ((spd->caslat_msb << 8) | spd->caslat_lsb) << 4;
+
+ /*
+ * min CAS latency time
+ * eg: taa_min =
+ * DDR3-800D 100 MTB (12.5ns)
+ * DDR3-1066F 105 MTB (13.125ns)
+ * DDR3-1333H 108 MTB (13.5ns)
+ * DDR3-1600H 90 MTB (11.25ns)
+ */
+ pdimm->taa_ps = spd->taa_min * mtb_ps +
+ (spd->fine_taa_min * ftb_10th_ps) / 10;
+
+ /*
+ * min write recovery time
+ * eg:
+ * twr_min = 120 MTB (15ns) -> all speed grades.
+ */
+ pdimm->twr_ps = spd->twr_min * mtb_ps;
+
+ /*
+ * min RAS to CAS delay time
+ * eg: trcd_min =
+ * DDR3-800 100 MTB (12.5ns)
+ * DDR3-1066F 105 MTB (13.125ns)
+ * DDR3-1333H 108 MTB (13.5ns)
+ * DDR3-1600H 90 MTB (11.25)
+ */
+ pdimm->trcd_ps = spd->trcd_min * mtb_ps +
+ (spd->fine_trcd_min * ftb_10th_ps) / 10;
+
+ /*
+ * min row active to row active delay time
+ * eg: trrd_min =
+ * DDR3-800(1KB page) 80 MTB (10ns)
+ * DDR3-1333(1KB page) 48 MTB (6ns)
+ */
+ pdimm->trrd_ps = spd->trrd_min * mtb_ps;
+
+ /*
+ * min row precharge delay time
+ * eg: trp_min =
+ * DDR3-800D 100 MTB (12.5ns)
+ * DDR3-1066F 105 MTB (13.125ns)
+ * DDR3-1333H 108 MTB (13.5ns)
+ * DDR3-1600H 90 MTB (11.25ns)
+ */
+ pdimm->trp_ps = spd->trp_min * mtb_ps +
+ (spd->fine_trp_min * ftb_10th_ps) / 10;
+
+ /* min active to precharge delay time
+ * eg: tRAS_min =
+ * DDR3-800D 300 MTB (37.5ns)
+ * DDR3-1066F 300 MTB (37.5ns)
+ * DDR3-1333H 288 MTB (36ns)
+ * DDR3-1600H 280 MTB (35ns)
+ */
+ pdimm->tras_ps = (((spd->tras_trc_ext & 0xf) << 8) | spd->tras_min_lsb)
+ * mtb_ps;
+ /*
+ * min active to actice/refresh delay time
+ * eg: tRC_min =
+ * DDR3-800D 400 MTB (50ns)
+ * DDR3-1066F 405 MTB (50.625ns)
+ * DDR3-1333H 396 MTB (49.5ns)
+ * DDR3-1600H 370 MTB (46.25ns)
+ */
+ pdimm->trc_ps = (((spd->tras_trc_ext & 0xf0) << 4) | spd->trc_min_lsb)
+ * mtb_ps + (spd->fine_trc_min * ftb_10th_ps) / 10;
+ /*
+ * min refresh recovery delay time
+ * eg: tRFC_min =
+ * 512Mb 720 MTB (90ns)
+ * 1Gb 880 MTB (110ns)
+ * 2Gb 1280 MTB (160ns)
+ */
+ pdimm->trfc_ps = ((spd->trfc_min_msb << 8) | spd->trfc_min_lsb)
+ * mtb_ps;
+ /*
+ * min internal write to read command delay time
+ * eg: twtr_min = 40 MTB (7.5ns) - all speed bins.
+ * tWRT is at least 4 mclk independent of operating freq.
+ */
+ pdimm->twtr_ps = spd->twtr_min * mtb_ps;
+
+ /*
+ * min internal read to precharge command delay time
+ * eg: trtp_min = 40 MTB (7.5ns) - all speed bins.
+ * tRTP is at least 4 mclk independent of operating freq.
+ */
+ pdimm->trtp_ps = spd->trtp_min * mtb_ps;
+
+ /*
+ * Average periodic refresh interval
+ * tREFI = 7.8 us at normal temperature range
+ * = 3.9 us at ext temperature range
+ */
+ pdimm->refresh_rate_ps = 7800000;
+ if ((spd->therm_ref_opt & 0x1) && !(spd->therm_ref_opt & 0x2)) {
+ pdimm->refresh_rate_ps = 3900000;
+ pdimm->extended_op_srt = 1;
+ }
+
+ /*
+ * min four active window delay time
+ * eg: tfaw_min =
+ * DDR3-800(1KB page) 320 MTB (40ns)
+ * DDR3-1066(1KB page) 300 MTB (37.5ns)
+ * DDR3-1333(1KB page) 240 MTB (30ns)
+ * DDR3-1600(1KB page) 240 MTB (30ns)
+ */
+ pdimm->tfaw_ps = (((spd->tfaw_msb & 0xf) << 8) | spd->tfaw_min)
+ * mtb_ps;
+
+ return 0;
+}
diff --git a/common/ddr4_dimm_params.c b/common/ddr4_dimm_params.c
new file mode 100644
index 0000000000..045cbd457c
--- /dev/null
+++ b/common/ddr4_dimm_params.c
@@ -0,0 +1,355 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2014-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2018 NXP Semiconductor
+ *
+ * calculate the organization and timing parameter
+ * from ddr3 spd, please refer to the spec
+ * JEDEC standard No.21-C 4_01_02_12R23A.pdf
+ *
+ *
+ */
+
+#include <common.h>
+#include <ddr_dimms.h>
+
+/*
+ * Calculate the Density of each Physical Rank.
+ * Returned size is in bytes.
+ *
+ * Total DIMM size =
+ * sdram capacity(bit) / 8 * primary bus width / sdram width
+ * * Logical Ranks per DIMM
+ *
+ * where: sdram capacity = spd byte4[3:0]
+ * primary bus width = spd byte13[2:0]
+ * sdram width = spd byte12[2:0]
+ * Logical Ranks per DIMM = spd byte12[5:3] for SDP, DDP, QDP
+ * spd byte12{5:3] * spd byte6[6:4] for 3DS
+ *
+ * To simplify each rank size = total DIMM size / Number of Package Ranks
+ * where Number of Package Ranks = spd byte12[5:3]
+ *
+ * SPD byte4 - sdram density and banks
+ * bit[3:0] size(bit) size(byte)
+ * 0000 256Mb 32MB
+ * 0001 512Mb 64MB
+ * 0010 1Gb 128MB
+ * 0011 2Gb 256MB
+ * 0100 4Gb 512MB
+ * 0101 8Gb 1GB
+ * 0110 16Gb 2GB
+ * 0111 32Gb 4GB
+ *
+ * SPD byte13 - module memory bus width
+ * bit[2:0] primary bus width
+ * 000 8bits
+ * 001 16bits
+ * 010 32bits
+ * 011 64bits
+ *
+ * SPD byte12 - module organization
+ * bit[2:0] sdram device width
+ * 000 4bits
+ * 001 8bits
+ * 010 16bits
+ * 011 32bits
+ *
+ * SPD byte12 - module organization
+ * bit[5:3] number of package ranks per DIMM
+ * 000 1
+ * 001 2
+ * 010 3
+ * 011 4
+ *
+ * SPD byte6 - SDRAM package type
+ * bit[6:4] Die count
+ * 000 1
+ * 001 2
+ * 010 3
+ * 011 4
+ * 100 5
+ * 101 6
+ * 110 7
+ * 111 8
+ *
+ * SPD byte6 - SRAM package type
+ * bit[1:0] Signal loading
+ * 00 Not specified
+ * 01 Multi load stack
+ * 10 Sigle load stack (3DS)
+ * 11 Reserved
+ */
+static unsigned long long
+compute_ranksize(const struct ddr4_spd_eeprom *spd)
+{
+ unsigned long long bsize;
+
+ int nbit_sdram_cap_bsize = 0;
+ int nbit_primary_bus_width = 0;
+ int nbit_sdram_width = 0;
+ int die_count = 0;
+ bool package_3ds;
+
+ if ((spd->density_banks & 0xf) <= 7)
+ nbit_sdram_cap_bsize = (spd->density_banks & 0xf) + 28;
+ if ((spd->bus_width & 0x7) < 4)
+ nbit_primary_bus_width = (spd->bus_width & 0x7) + 3;
+ if ((spd->organization & 0x7) < 4)
+ nbit_sdram_width = (spd->organization & 0x7) + 2;
+ package_3ds = (spd->package_type & 0x3) == 0x2;
+ if ((spd->package_type & 0x80) && !package_3ds) { /* other than 3DS */
+ printf("Warning: not supported SDRAM package type\n");
+ return 0;
+ }
+ if (package_3ds)
+ die_count = (spd->package_type >> 4) & 0x7;
+
+ bsize = 1ULL << (nbit_sdram_cap_bsize - 3 +
+ nbit_primary_bus_width - nbit_sdram_width +
+ die_count);
+
+ debug("DDR: DDR rank density = 0x%16llx\n", bsize);
+
+ return bsize;
+}
+
+#define spd_to_ps(mtb, ftb) \
+ (mtb * pdimm->mtb_ps + (ftb * pdimm->ftb_10th_ps) / 10)
+/*
+ * ddr4_compute_dimm_parameters for DDR4 SPD
+ *
+ * Compute DIMM parameters based upon the SPD information in spd.
+ * Writes the results to the struct dimm_params structure pointed by pdimm.
+ *
+ */
+unsigned int ddr4_compute_dimm_parameters(const struct ddr4_spd_eeprom *spd,
+ struct dimm_params *pdimm)
+{
+ int ret;
+ int i;
+ const u8 udimm_rc_e_dq[18] = {
+ 0x0c, 0x2c, 0x15, 0x35, 0x15, 0x35, 0x0b, 0x2c, 0x15,
+ 0x35, 0x0b, 0x35, 0x0b, 0x2c, 0x0b, 0x35, 0x15, 0x36
+ };
+ int spd_error = 0;
+ u8 *ptr;
+ u8 val;
+
+ if (spd->mem_type != SPD_MEMTYPE_DDR4) {
+ printf("DIMM: SPD data is not DDR4\n");
+ return 3;
+ }
+
+ ret = ddr4_spd_check(spd);
+ if (ret) {
+ printf("DIMM: failed checksum\n");
+ return 2;
+ }
+
+ /*
+ * The part name in ASCII in the SPD EEPROM is not null terminated.
+ * Guarantee null termination here by presetting all bytes to 0
+ * and copying the part name in ASCII from the SPD onto it
+ */
+ memset(pdimm->mpart, 0, sizeof(pdimm->mpart));
+ if ((spd->info_size_crc & 0xF) > 2)
+ memcpy(pdimm->mpart, spd->mpart, sizeof(pdimm->mpart) - 1);
+
+ /* DIMM organization parameters */
+ pdimm->n_ranks = ((spd->organization >> 3) & 0x7) + 1;
+ pdimm->rank_density = compute_ranksize(spd);
+ pdimm->capacity = pdimm->n_ranks * pdimm->rank_density;
+ pdimm->die_density = spd->density_banks & 0xf;
+ pdimm->primary_sdram_width = 1 << (3 + (spd->bus_width & 0x7));
+ if ((spd->bus_width >> 3) & 0x3)
+ pdimm->ec_sdram_width = 8;
+ else
+ pdimm->ec_sdram_width = 0;
+ pdimm->data_width = pdimm->primary_sdram_width
+ + pdimm->ec_sdram_width;
+ pdimm->device_width = 1 << ((spd->organization & 0x7) + 2);
+ pdimm->package_3ds = (spd->package_type & 0x3) == 0x2 ?
+ (spd->package_type >> 4) & 0x7 : 0;
+
+ /* These are the types defined by the JEDEC SPD spec */
+ pdimm->mirrored_dimm = 0;
+ pdimm->registered_dimm = 0;
+ switch (spd->module_type & DDR4_SPD_MODULETYPE_MASK) {
+ case DDR4_SPD_MODULETYPE_RDIMM:
+ /* Registered/buffered DIMMs */
+ pdimm->registered_dimm = 1;
+ if (spd->mod_section.registered.reg_map & 0x1)
+ pdimm->mirrored_dimm = 1;
+ val = spd->mod_section.registered.ca_stren;
+ pdimm->rcw[3] = val >> 4;
+ pdimm->rcw[4] = ((val & 0x3) << 2) | ((val & 0xc) >> 2);
+ val = spd->mod_section.registered.clk_stren;
+ pdimm->rcw[5] = ((val & 0x3) << 2) | ((val & 0xc) >> 2);
+ /* Not all in SPD. For convience only. Boards may overwrite. */
+ pdimm->rcw[6] = 0xf;
+ /*
+ * A17 only used for 16Gb and above devices.
+ * C[2:0] only used for 3DS.
+ */
+ pdimm->rcw[8] = pdimm->die_density >= 0x6 ? 0x0 : 0x8 |
+ (pdimm->package_3ds > 0x3 ? 0x0 :
+ (pdimm->package_3ds > 0x1 ? 0x1 :
+ (pdimm->package_3ds > 0 ? 0x2 : 0x3)));
+ if (pdimm->package_3ds || pdimm->n_ranks != 4)
+ pdimm->rcw[13] = 0xc;
+ else
+ pdimm->rcw[13] = 0xd; /* Fix encoded by board */
+
+ break;
+
+ case DDR4_SPD_MODULETYPE_UDIMM:
+ case DDR4_SPD_MODULETYPE_SO_DIMM:
+ /* Unbuffered DIMMs */
+ if (spd->mod_section.unbuffered.addr_mapping & 0x1)
+ pdimm->mirrored_dimm = 1;
+ if ((spd->mod_section.unbuffered.mod_height & 0xe0) == 0 &&
+ (spd->mod_section.unbuffered.ref_raw_card == 0x04)) {
+ /* Fix SPD error found on DIMMs with raw card E0 */
+ for (i = 0; i < 18; i++) {
+ if (spd->mapping[i] == udimm_rc_e_dq[i])
+ continue;
+ spd_error = 1;
+ debug("SPD byte %d: 0x%x, should be 0x%x\n",
+ 60 + i, spd->mapping[i],
+ udimm_rc_e_dq[i]);
+ ptr = (u8 *)&spd->mapping[i];
+ *ptr = udimm_rc_e_dq[i];
+ }
+ if (spd_error)
+ printf("SPD DQ mapping error fixed\n");
+ }
+ break;
+
+ default:
+ printf("unknown module_type 0x%02X\n", spd->module_type);
+ return 1;
+ }
+
+ /* SDRAM device parameters */
+ pdimm->n_row_addr = ((spd->addressing >> 3) & 0x7) + 12;
+ pdimm->n_col_addr = (spd->addressing & 0x7) + 9;
+ pdimm->bank_addr_bits = (spd->density_banks >> 4) & 0x3;
+ pdimm->bank_group_bits = (spd->density_banks >> 6) & 0x3;
+
+ /*
+ * The SPD spec has not the ECC bit,
+ * We consider the DIMM as ECC capability
+ * when the extension bus exist
+ */
+ if (pdimm->ec_sdram_width)
+ pdimm->edc_config = 0x02;
+ else
+ pdimm->edc_config = 0x00;
+
+ /*
+ * The SPD spec has not the burst length byte
+ * but DDR4 spec has nature BL8 and BC4,
+ * BL8 -bit3, BC4 -bit2
+ */
+ pdimm->burst_lengths_bitmask = 0x0c;
+
+ /* MTB - medium timebase
+ * The MTB in the SPD spec is 125ps,
+ *
+ * FTB - fine timebase
+ * use 1/10th of ps as our unit to avoid floating point
+ * eg, 10 for 1ps, 25 for 2.5ps, 50 for 5ps
+ */
+ if ((spd->timebases & 0xf) == 0x0) {
+ pdimm->mtb_ps = 125;
+ pdimm->ftb_10th_ps = 10;
+
+ } else {
+ printf("Unknown Timebases\n");
+ }
+
+ /* sdram minimum cycle time */
+ pdimm->tckmin_x_ps = spd_to_ps(spd->tck_min, spd->fine_tck_min);
+
+ /* sdram max cycle time */
+ pdimm->tckmax_ps = spd_to_ps(spd->tck_max, spd->fine_tck_max);
+
+ /*
+ * CAS latency supported
+ * bit0 - CL7
+ * bit4 - CL11
+ * bit8 - CL15
+ * bit12- CL19
+ * bit16- CL23
+ */
+ pdimm->caslat_x = (spd->caslat_b1 << 7) |
+ (spd->caslat_b2 << 15) |
+ (spd->caslat_b3 << 23);
+
+ BUG_ON(spd->caslat_b4 != 0);
+
+ /*
+ * min CAS latency time
+ */
+ pdimm->taa_ps = spd_to_ps(spd->taa_min, spd->fine_taa_min);
+
+ /*
+ * min RAS to CAS delay time
+ */
+ pdimm->trcd_ps = spd_to_ps(spd->trcd_min, spd->fine_trcd_min);
+
+ /*
+ * Min Row Precharge Delay Time
+ */
+ pdimm->trp_ps = spd_to_ps(spd->trp_min, spd->fine_trp_min);
+
+ /* min active to precharge delay time */
+ pdimm->tras_ps = (((spd->tras_trc_ext & 0xf) << 8) +
+ spd->tras_min_lsb) * pdimm->mtb_ps;
+
+ /* min active to actice/refresh delay time */
+ pdimm->trc_ps = spd_to_ps((((spd->tras_trc_ext & 0xf0) << 4) +
+ spd->trc_min_lsb), spd->fine_trc_min);
+ /* Min Refresh Recovery Delay Time */
+ pdimm->trfc1_ps = ((spd->trfc1_min_msb << 8) | (spd->trfc1_min_lsb)) *
+ pdimm->mtb_ps;
+ pdimm->trfc2_ps = ((spd->trfc2_min_msb << 8) | (spd->trfc2_min_lsb)) *
+ pdimm->mtb_ps;
+ pdimm->trfc4_ps = ((spd->trfc4_min_msb << 8) | (spd->trfc4_min_lsb)) *
+ pdimm->mtb_ps;
+ /* min four active window delay time */
+ pdimm->tfaw_ps = (((spd->tfaw_msb & 0xf) << 8) | spd->tfaw_min) *
+ pdimm->mtb_ps;
+
+ /* min row active to row active delay time, different bank group */
+ pdimm->trrds_ps = spd_to_ps(spd->trrds_min, spd->fine_trrds_min);
+ /* min row active to row active delay time, same bank group */
+ pdimm->trrdl_ps = spd_to_ps(spd->trrdl_min, spd->fine_trrdl_min);
+ /* min CAS to CAS Delay Time (tCCD_Lmin), same bank group */
+ pdimm->tccdl_ps = spd_to_ps(spd->tccdl_min, spd->fine_tccdl_min);
+
+ if (pdimm->package_3ds) {
+ if (pdimm->die_density <= 0x4) {
+ pdimm->trfc_slr_ps = 260000;
+ } else if (pdimm->die_density <= 0x5) {
+ pdimm->trfc_slr_ps = 350000;
+ } else {
+ printf("WARN: Unsupported logical rank density 0x%x\n",
+ pdimm->die_density);
+ }
+ }
+
+ /*
+ * Average periodic refresh interval
+ * tREFI = 7.8 us at normal temperature range
+ */
+ pdimm->refresh_rate_ps = 7800000;
+
+ for (i = 0; i < 18; i++)
+ pdimm->dq_mapping[i] = spd->mapping[i];
+
+ pdimm->dq_mapping_ors = ((spd->mapping[0] >> 6) & 0x3) == 0 ? 1 : 0;
+
+ return 0;
+}
diff --git a/common/ddr_spd.c b/common/ddr_spd.c
index 7089923afb..b7693f3fd2 100644
--- a/common/ddr_spd.c
+++ b/common/ddr_spd.c
@@ -6,6 +6,7 @@
#include <common.h>
#include <crc.h>
#include <ddr_spd.h>
+#include <pbl/i2c.h>
/* used for ddr1 and ddr2 spd */
static int spd_check(const u8 *buf, u8 spd_rev, u8 spd_cksum)
@@ -64,8 +65,8 @@ int ddr3_spd_check(const struct ddr3_spd_eeprom *spd)
char *p = (char *)spd;
int csum16;
int len;
- char crc_lsb; /* byte 126 */
- char crc_msb; /* byte 127 */
+ unsigned char crc_lsb; /* byte 126 */
+ unsigned char crc_msb; /* byte 127 */
/*
* SPD byte0[7] - CRC coverage
@@ -76,8 +77,8 @@ int ddr3_spd_check(const struct ddr3_spd_eeprom *spd)
len = !(spd->info_size_crc & 0x80) ? 126 : 117;
csum16 = crc_itu_t(0, p, len);
- crc_lsb = (char) (csum16 & 0xff);
- crc_msb = (char) (csum16 >> 8);
+ crc_lsb = csum16 & 0xff;
+ crc_msb = csum16 >> 8;
if (spd->crc[0] == crc_lsb && spd->crc[1] == crc_msb) {
return 0;
@@ -95,14 +96,14 @@ int ddr4_spd_check(const struct ddr4_spd_eeprom *spd)
char *p = (char *)spd;
int csum16;
int len;
- char crc_lsb; /* byte 126 */
- char crc_msb; /* byte 127 */
+ unsigned char crc_lsb; /* byte 126 */
+ unsigned char crc_msb; /* byte 127 */
len = 126;
csum16 = crc_itu_t(0, p, len);
- crc_lsb = (char) (csum16 & 0xff);
- crc_msb = (char) (csum16 >> 8);
+ crc_lsb = csum16 & 0xff;
+ crc_msb = csum16 >> 8;
if (spd->crc[0] != crc_lsb || spd->crc[1] != crc_msb) {
printf("SPD checksum unexpected.\n"
@@ -116,8 +117,8 @@ int ddr4_spd_check(const struct ddr4_spd_eeprom *spd)
len = 126;
csum16 = crc_itu_t(0, p, len);
- crc_lsb = (char) (csum16 & 0xff);
- crc_msb = (char) (csum16 >> 8);
+ crc_lsb = csum16 & 0xff;
+ crc_msb = csum16 >> 8;
if (spd->mod_section.uc[126] != crc_lsb ||
spd->mod_section.uc[127] != crc_msb) {
@@ -230,11 +231,31 @@ static int ddr2_sdram_ctime(uint8_t byte)
return ctime;
}
+static void spd_print_manufacturing_date(uint8_t year, uint8_t week)
+{
+ /*
+ * According to JEDEC Standard the year/week bytes must be in BCD
+ * format. However, that is not always true for actual DIMMs out
+ * there, so fall back to binary format if it makes more sense.
+ */
+
+ printf("%-48s ", "Manufacturing Date");
+ if ((year & 0xf0) <= 0x90 && (year & 0xf) <= 0x9
+ && (week & 0xf0) <= 0x90 && (week & 0xf) <= 0x9) {
+ printf("20%02X-W%02X", year, week);
+ } else if (year <= 99 && week >= 1 && week <= 53) {
+ printf("20%02d-W%02d", year, week);
+ } else {
+ printf("0x%02X%02X", year, week);
+ }
+ printf("\n");
+}
+
/*
* Based on
* https://github.com/groeck/i2c-tools/blob/master/eeprom/decode-dimms
*/
-void ddr_spd_print(uint8_t *record)
+static void ddr2_spd_print(uint8_t *record)
{
int highestCAS = 0;
int i, i_i, k, x, y;
@@ -245,11 +266,6 @@ void ddr_spd_print(uint8_t *record)
char *ref, *sum;
struct ddr2_spd_eeprom *s = (struct ddr2_spd_eeprom *)record;
- if (s->mem_type != SPD_MEMTYPE_DDR2) {
- printf("Can't dump information for non-DDR2 memory\n");
- return;
- }
-
ctime = ddr2_sdram_ctime(s->clk_cycle);
ddrclk = 2 * (100000 / ctime);
tbits = (s->res_7 << 8) + (s->dataw);
@@ -419,20 +435,543 @@ void ddr_spd_print(uint8_t *record)
printf("%d", record[i]);
}
printf("\n");
- printf("%-48s 20%d-W%d\n", "Manufacturing Date", record[93],
- record[94]);
+ spd_print_manufacturing_date(record[93], record[94]);
printf("%-48s 0x", "Assembly Serial Number");
for (i = 95; i < 99; i++)
printf("%02X", record[i]);
printf("\n");
}
+static const char * const ddr3_spd_moduletypes[] = {
+ "Undefined",
+ "RDIMM",
+ "UDIMM",
+ "SO-DIMM",
+ "Micro-DIMM",
+ "Mini-RDIMM",
+ "Mini-UDIMM",
+ "Mini-CDIMM",
+ "72b-SO-UDIMM",
+ "72b-SO-RDIMM",
+ "72b-SO-CDIMM",
+ "LRDIMM",
+ "16b-SO-DIMM",
+ "32b-SO-DIMM"
+};
+
+static const char * const ddr3_spd_moduletypes_width[] = {
+ "Unknown",
+ "133.35 mm",
+ "133.35 mm",
+ "67.6 mm",
+ "TBD",
+ "82.0 mm",
+ "82.0 mm",
+ "67.6 mm",
+ "67.6 mm",
+ "67.6 mm",
+ "67.6 mm",
+ "133.35 mm",
+ "67.6 mm",
+ "67.6 mm"
+};
+
+#define DDR3_UNBUFFERED 1
+#define DDR3_REGISTERED 2
+#define DDR3_CLOCKED 3
+#define DDR3_LOAD_REDUCED 4
+
+static const uint8_t ddr3_spd_moduletypes_family[] = {
+ 0,
+ DDR3_REGISTERED,
+ DDR3_UNBUFFERED,
+ DDR3_UNBUFFERED,
+ DDR3_UNBUFFERED,
+ DDR3_REGISTERED,
+ DDR3_UNBUFFERED,
+ DDR3_CLOCKED,
+ DDR3_UNBUFFERED,
+ DDR3_REGISTERED,
+ DDR3_CLOCKED,
+ DDR3_LOAD_REDUCED,
+ DDR3_UNBUFFERED,
+ DDR3_UNBUFFERED
+};
+
+static const int ddr3_std_speeds[] = {
+ 1000 * 7.5 / 8,
+ 1000 * 7.5 / 7,
+ 1000 * 1.25,
+ 1000 * 1.5,
+ 1000 * 1.875,
+ 1000 * 2.5
+};
+
+static const char * const ddr3_maximum_activated_counts[] = {
+ "Untested",
+ "700 K",
+ "600 K",
+ "500 K",
+ "400 K",
+ "300 K",
+ "200 K",
+ "Reserved",
+ "Unlimited",
+};
+
+static int ddr3_timing_from_mtb_ftb(uint16_t txx, int8_t fine_txx,
+ uint8_t mtb_dividend, uint8_t mtb_divisor,
+ uint8_t ftb_div)
+{
+ /*
+ * Given mtb in ns and ftb in ps, return the result in ps,
+ * carefully rounding to the nearest picosecond.
+ */
+ int result = txx * 10000 * mtb_dividend / mtb_divisor
+ + fine_txx * (ftb_div >> 4) / (ftb_div & 0xf);
+ return DIV_ROUND_CLOSEST(result, 10);
+}
+
+static int ddr3_adjust_ctime(int ctime, uint8_t ftb_div)
+{
+ uint8_t ftb_divisor = ftb_div >> 4;
+ uint8_t ftb_dividend = ftb_div & 0xf;
+ int i;
+
+ /*
+ * Starting with DDR3-1866, vendors may start approximating the
+ * minimum cycle time. Try to guess what they really meant so
+ * that the reported speed matches the standard.
+ */
+ for (i = 7; i < 15; i++) {
+ int test = ctime * ftb_divisor - (int)(1000 * 7.5) * ftb_divisor / i;
+
+ if (test > -(int)ftb_dividend && test < ftb_dividend)
+ return (int)(1000 * 7.5) / i;
+ }
+
+ return ctime;
+}
+
+static void ddr3_print_reference_card(uint8_t ref_raw_card, uint8_t mod_height)
+{
+ const char alphabet[] = "ABCDEFGHJKLMNPRTUVWY";
+ uint8_t ref = ref_raw_card & 0x1f;
+ uint8_t revision = mod_height >> 5;
+ char ref_card[3] = { 0 };
+
+ if (ref == 0x1f) {
+ printf("%-48s %s\n", "Module Reference Card", "ZZ");
+ return;
+ }
+
+ if (ref_raw_card & 0x80)
+ ref += 0x1f;
+ if (!revision)
+ revision = ((ref_raw_card >> 5) & 0x3);
+
+ if (ref < ARRAY_SIZE(alphabet) - 1) {
+ /* One letter reference card */
+ ref_card[0] = alphabet[ref];
+ } else {
+ /* Two letter reference card */
+ uint8_t ref1 = ref / (ARRAY_SIZE(alphabet) - 1);
+
+ ref -= (ARRAY_SIZE(alphabet) - 1) * ref1;
+ ref_card[0] = alphabet[ref1];
+ ref_card[1] = alphabet[ref];
+ }
+
+ printf("%-48s %s revision %u\n", "Module Reference Card", ref_card, revision);
+}
+
+static void ddr3_print_revision_number(const char *name, uint8_t rev)
+{
+ uint8_t h = rev >> 4;
+ uint8_t l = rev & 0xf;
+
+ /* Decode as suggested by JEDEC Standard 21-C */
+ if (!h)
+ printf("%-48s %d\n", name, l);
+ if (h < 0xa)
+ printf("%-48s %d.%d\n", name, h, l);
+ else
+ printf("%-48s %c%d\n", name, 'A' + h - 0xa, l);
+}
+
+static void ddr3_spd_print(uint8_t *record)
+{
+ struct ddr3_spd_eeprom *s = (struct ddr3_spd_eeprom *)record;
+ const char *sum;
+ uint8_t spd_len;
+ int size, bytes_written;
+ int ctime, ddrclk;
+ uint8_t tbits;
+ int pcclk;
+ uint8_t cap, k;
+ int taa, trcd, trp, tras;
+ uint16_t cas_sup;
+ int twr, trrd, trc, trfc, twtr, trtp, tfaw;
+ uint8_t die_count, loading;
+ uint8_t mac;
+ uint8_t family;
+ int i;
+
+ sum = ddr3_spd_check(s) ? "ERR" : "OK";
+
+ printf("\n---=== SPD EEPROM Information ===---\n");
+
+ printf("EEPROM CRC of bytes 0-%3d %22s %s (0x%02X%02X)\n",
+ (s->info_size_crc & 0x80) ? 116 : 125, "", sum, s->crc[1], s->crc[0]);
+
+ spd_len = (s->info_size_crc >> 4) & 0x7;
+ size = 64 << (s->info_size_crc & 0xf);
+ if (spd_len == 0) {
+ bytes_written = 128;
+ } else if (spd_len == 1) {
+ bytes_written = 176;
+ } else if (spd_len == 2) {
+ bytes_written = 256;
+ } else {
+ size = 64;
+ bytes_written = 64;
+ }
+ printf("%-48s %d\n", "# of bytes written to SDRAM EEPROM", bytes_written);
+ printf("%-48s %d\n", "Total number of bytes in EEPROM", size);
+ printf("%-48s %s\n", "Fundamental Memory type", type_list[s->mem_type]);
+
+ if (s->spd_rev != 0xff)
+ printf("%-48s %x.%x\n", "SPD Revision", s->spd_rev >> 4,
+ s->spd_rev & 0xf);
+
+ printf("%-48s ", "Module Type");
+ if (s->module_type <= ARRAY_SIZE(ddr3_spd_moduletypes))
+ printf("%s\n", ddr3_spd_moduletypes[s->module_type]);
+ else
+ printf("Reserved (0x%02x)\n", s->module_type);
+
+ if ((s->ftb_div & 0x0f) == 0 || s->mtb_divisor == 0) {
+ printf("Invalid time base divisor, can't decode\n");
+ return;
+ }
+
+ printf("\n---=== Memory Characteristics ===---\n");
+
+ ctime = ddr3_timing_from_mtb_ftb(s->tck_min, s->fine_tck_min,
+ s->mtb_dividend, s->mtb_divisor, s->ftb_div);
+ ctime = ddr3_adjust_ctime(ctime, s->ftb_div);
+
+ ddrclk = 2 * 1000 * 1000 / ctime;
+ tbits = 1 << ((s->bus_width & 0x7) + 3);
+ pcclk = ddrclk * tbits / 8;
+ pcclk = pcclk - (pcclk % 100); /* Round down to comply with JEDEC */
+ printf("%-48s %d MT/s (PC3-%d)\n", "Maximum module speed", ddrclk, pcclk);
+
+ cap = (s->density_banks & 0xf) + 28 + (s->bus_width & 0x7) + 3
+ - ((s->organization & 0x7) + 2) - (20 + 3);
+ k = (s->organization >> 3) + 1;
+ printf("%-48s %d MB\n", "Size", (1 << cap) * k);
+
+ printf("%-48s %d x %d x %d x %d\n", "Banks x Rows x Columns x Bits",
+ 1 << (((s->density_banks >> 4) & 0x7) + 3),
+ (((s->addressing >> 3) & 0x1f) + 12),
+ ((s->addressing & 7) + 9),
+ (1 << ((s->bus_width & 0x7) + 3)));
+
+ printf("%-48s %d\n", "Ranks", k);
+
+ printf("%-48s %d bits\n", "SDRAM Device Width",
+ (1 << ((s->organization & 0x7) + 2)));
+
+ printf("%-48s %d bits\n", "Primary Bus Width",
+ (8 << (s->bus_width & 0x7)));
+ if (s->bus_width & 0x18)
+ printf("%-48s %d bits\n", "Bus Width Extension", s->bus_width & 0x18);
+
+ taa = ddr3_timing_from_mtb_ftb(s->taa_min, s->fine_taa_min,
+ s->mtb_dividend, s->mtb_divisor, s->ftb_div);
+ trcd = ddr3_timing_from_mtb_ftb(s->trcd_min, s->fine_trcd_min,
+ s->mtb_dividend, s->mtb_divisor, s->ftb_div);
+ trp = ddr3_timing_from_mtb_ftb(s->trp_min, s->fine_trp_min,
+ s->mtb_dividend, s->mtb_divisor, s->ftb_div);
+ tras = (((s->tras_trc_ext & 0xf) << 8) + s->tras_min_lsb)
+ * 1000 * s->mtb_dividend / s->mtb_divisor;
+
+ printf("%-48s %d-%d-%d-%d\n", "tCL-tRCD-tRP-tRAS",
+ DIV_ROUND_UP(taa, ctime), DIV_ROUND_UP(trcd, ctime),
+ DIV_ROUND_UP(trp, ctime), DIV_ROUND_UP(tras, ctime));
+
+ printf("%-48s", "Supported CAS Latencies (tCL)");
+ cas_sup = (s->caslat_msb << 8) + s->caslat_lsb;
+ for (i = 14; i >= 0; i--) {
+ if (cas_sup & (1 << i))
+ printf(" %dT", i + 4);
+ }
+ printf("\n");
+
+ printf("\n---=== Timings at Standard Speeds ===---\n");
+
+ for (i = 0; i < ARRAY_SIZE(ddr3_std_speeds); i++) {
+ int ctime_at_speed = ddr3_std_speeds[i];
+ int best_cas = 0;
+ int j;
+
+ /* Find min CAS latency at this speed */
+ for (j = 14; j >= 0; j--) {
+ if (!(cas_sup & (1 << j)))
+ continue;
+ if (DIV_ROUND_UP(taa, ctime_at_speed) <= j + 4) {
+ best_cas = j + 4;
+ }
+ }
+
+ if (!best_cas || ctime_at_speed < ctime)
+ continue;
+
+ printf("tCL-tRCD-tRP-tRAS as DDR3-%-4d %17s %d-%d-%d-%d\n",
+ 2000 * 1000 / ctime_at_speed, "", best_cas,
+ DIV_ROUND_UP(trcd, ctime_at_speed),
+ DIV_ROUND_UP(trp, ctime_at_speed),
+ DIV_ROUND_UP(tras, ctime_at_speed));
+ }
+
+ printf("\n---=== Timing Parameters ===---\n");
+
+ printf("%-48s %d.%03d ns\n", "Minimum Cycle Time (tCK)",
+ ctime / 1000, ctime % 1000);
+ printf("%-48s %d.%03d ns\n", "Minimum CAS Latency Time (tAA)",
+ taa / 1000, taa % 1000);
+ twr = s->twr_min * 1000 * s->mtb_dividend / s->mtb_divisor;
+ printf("%-48s %d.%03d ns\n", "Minimum Write Recovery time (tWR)",
+ twr / 1000, twr % 1000);
+ printf("%-48s %d.%03d ns\n", "Minimum RAS# to CAS# Delay (tRCD)",
+ trcd / 1000, trcd % 1000);
+ trrd = s->trrd_min * 1000 * s->mtb_dividend / s->mtb_divisor;
+ printf("%-48s %d.%03d ns\n", "Minimum Row Active to Row Active Delay (tRRD)",
+ trrd / 1000, trrd % 1000);
+ printf("%-48s %d.%03d ns\n", "Minimum Row Precharge Delay (tRP)",
+ trp / 1000, trp % 1000);
+ printf("%-48s %d.%03d ns\n", "Minimum Active to Precharge Delay (tRAS)",
+ tras / 1000, tras % 1000);
+ trc = ddr3_timing_from_mtb_ftb(((s->tras_trc_ext & 0xf0) << 4) + s->trc_min_lsb,
+ s->fine_trc_min, s->mtb_dividend, s->mtb_divisor,
+ s->ftb_div);
+ printf("%-48s %d.%03d ns\n", "Minimum Active to Auto-Refresh Delay (tRC)",
+ trc / 1000, trc % 1000);
+ trfc = ((s->trfc_min_msb << 8) + s->trfc_min_lsb) * 1000
+ * s->mtb_dividend / s->mtb_divisor;
+ printf("%-48s %d.%03d ns\n", "Minimum Recovery Delay (tRFC)",
+ trfc / 1000, trfc % 1000);
+ twtr = s->twtr_min * 1000 * s->mtb_dividend / s->mtb_divisor;
+ printf("%-48s %d.%03d ns\n", "Minimum Write to Read CMD Delay (tWTR)",
+ twtr / 1000, twtr % 1000);
+ trtp = s->trtp_min * 1000 * s->mtb_dividend / s->mtb_divisor;
+ printf("%-48s %d.%03d ns\n", "Minimum Read to Pre-charge CMD Delay (tRTP)",
+ trtp / 1000, trtp % 1000);
+ tfaw = (((s->tfaw_msb & 0xf) << 8) + s->tfaw_min) * 1000
+ * s->mtb_dividend / s->mtb_divisor;
+ printf("%-48s %d.%03d ns\n", "Minimum Four Activate Window Delay (tFAW)",
+ tfaw / 1000, tfaw % 1000);
+
+ printf("\n---=== Optional Features ===---\n");
+
+ printf("%-48s 1.5V%s%s%s\n", "Operable voltages",
+ (s->module_vdd & 0x1) ? " tolerant" : "",
+ (s->module_vdd & 0x2) ? ", 1.35V" : "",
+ (s->module_vdd & 0x4) ? ", 1.2X V" : "");
+ printf("%-48s %s\n", "RZQ/6 supported?",
+ (s->opt_features & 1) ? "Yes" : "No");
+ printf("%-48s %s\n", "RZQ/7 supported?",
+ (s->opt_features & 2) ? "Yes" : "No");
+ printf("%-48s %s\n", "DLL-Off Mode supported?",
+ (s->opt_features & 0x80) ? "Yes" : "No");
+ printf("%-48s 0-%d degrees C\n", "Operating temperature range",
+ (s->therm_ref_opt & 0x1) ? 95 : 85);
+ if (s->therm_ref_opt & 0x1)
+ printf("%-48s %s\n", "Refresh Rate in extended temp range",
+ (s->therm_ref_opt & 0x2) ? "1X" : "2X");
+ printf("%-48s %s\n", "Auto Self-Refresh?",
+ (s->therm_ref_opt & 0x4) ? "Yes" : "No");
+ printf("%-48s %s\n", "On-Die Thermal Sensor readout?",
+ (s->therm_ref_opt & 0x8) ? "Yes" : "No");
+ printf("%-48s %s\n", "Partial Array Self-Refresh?",
+ (s->therm_ref_opt & 0x80) ? "Yes" : "No");
+ printf("%-48s %s\n", "Module Thermal Sensor",
+ (s->therm_sensor & 0x80) ? "Yes" : "No");
+
+ printf("%-48s %s\n", "SDRAM Device Type",
+ (s->device_type & 0x80) ? "Non-Standard" : "Standard Monolithic");
+
+ die_count = (s->device_type >> 4) & 0x7;
+ if (die_count == 1)
+ printf("%-48s Single die\n", "");
+ else if (die_count == 2)
+ printf("%-48s 2 die\n", "");
+ else if (die_count == 3)
+ printf("%-48s 4 die\n", "");
+ else if (die_count == 4)
+ printf("%-48s 8 die\n", "");
+
+ loading = (s->device_type >> 2) & 0x3;
+ if (loading == 1)
+ printf("%-48s Multi load stack\n", "");
+ else if (loading == 2)
+ printf("%-48s Single load stack\n", "");
+
+ mac = s->res_39_59[2] & 0xf;
+ if (mac < ARRAY_SIZE(ddr3_maximum_activated_counts))
+ printf("%-48s %s\n", "Maximum Activate Count (MAC)",
+ ddr3_maximum_activated_counts[mac]);
+
+ /*
+ * The following bytes are type-specific, so don't continue if the type
+ * is unknown.
+ */
+ if (!s->module_type || s->module_type > ARRAY_SIZE(ddr3_spd_moduletypes))
+ return;
+
+ family = ddr3_spd_moduletypes_family[s->module_type];
+ if (family == DDR3_UNBUFFERED || family == DDR3_REGISTERED
+ || family == DDR3_CLOCKED || family == DDR3_LOAD_REDUCED) {
+ printf("\n---=== Physical Characteristics ===---\n");
+ printf("%-48s %d mm\n", "Module Height",
+ ((s->mod_section.unbuffered.mod_height & 0x1f) + 15));
+ printf("%-48s %d mm front, %d mm back\n", "Module Thickness",
+ (s->mod_section.unbuffered.mod_thickness & 0xf) + 1,
+ ((s->mod_section.unbuffered.mod_thickness >> 4) & 0xf) + 1);
+ printf("%-48s %s\n", "Module Width",
+ ddr3_spd_moduletypes_width[s->module_type]);
+ ddr3_print_reference_card(s->mod_section.unbuffered.ref_raw_card,
+ s->mod_section.unbuffered.mod_height);
+ }
+
+ if (family == DDR3_UNBUFFERED)
+ printf("%-48s %s\n", "Rank 1 Mapping",
+ (s->mod_section.unbuffered.addr_mapping) ? "Mirrored" : "Standard");
+
+ if (family == DDR3_REGISTERED) {
+ uint8_t rows = (s->mod_section.registered.modu_attr >> 2) & 0x3;
+ uint8_t registers = s->mod_section.registered.modu_attr & 0x3;
+
+ printf("\n---=== Registered DIMM ===---\n");
+
+ if (!rows)
+ printf("%-48s Undefined\n", "# DRAM Rows");
+ else
+ printf("%-48s %u\n", "# DRAM Rows", 1 << (rows - 1));
+
+ if (!registers)
+ printf("%-48s Undefined\n", "# Registers");
+ else
+ printf("%-48s %u\n", "# Registers", 1 << (registers - 1));
+ printf("%-48s 0x%02x%02x\n", "Register manufacturer ID",
+ s->mod_section.registered.reg_id_hi,
+ s->mod_section.registered.reg_id_lo);
+ printf("%-48s %s\n", "Register device type",
+ (!s->mod_section.registered.reg_type) ? "SSTE32882" : "Undefined");
+ if (s->mod_section.registered.reg_rev != 0xff)
+ ddr3_print_revision_number("Register revision",
+ s->mod_section.registered.reg_rev);
+ printf("%-48s %s\n", "Heat spreader",
+ (s->mod_section.registered.thermal & 0x80) ? "Yes" : "No");
+ }
+
+ if (family == DDR3_LOAD_REDUCED) {
+ uint8_t modu_attr = s->mod_section.loadreduced.modu_attr;
+ uint8_t rows = (modu_attr >> 2) & 0x3;
+ static const char *mirroring[] = {
+ "None", "Odd ranks", "Reserved", "Reserved"
+ };
+
+ printf("\n---=== Load Reduced DIMM ===---\n");
+
+ if (!rows)
+ printf("%-48s Undefined\n", "# DRAM Rows");
+ else if (rows == 0x3)
+ printf("%-48s Reserved\n", "# DRAM Rows");
+ else
+ printf("%-48s %u\n", "# DRAM Rows", 1 << (rows - 1));
+
+ printf("%-48s %s\n", "Mirroring",
+ mirroring[modu_attr & 0x3]);
+
+ printf("%-48s %s\n", "Rank Numbering",
+ (modu_attr & 0x20) ? "Even only" : "Contiguous");
+ printf("%-48s %s\n", "Buffer Orientation",
+ (modu_attr & 0x10) ? "Horizontal" : "Vertical");
+ printf("%-48s 0x%02x%02x\n", "Register Manufacturer ID",
+ s->mod_section.loadreduced.buf_id_hi,
+ s->mod_section.loadreduced.buf_id_lo);
+ if (s->mod_section.loadreduced.buf_rev_id != 0xff)
+ ddr3_print_revision_number("Buffer Revision",
+ s->mod_section.loadreduced.buf_rev_id);
+ printf("%-48s %s\n", "Heat spreader",
+ (s->mod_section.loadreduced.modu_attr & 0x80) ? "Yes" : "No");
+ }
+
+ printf("\n---=== Manufacturer Data ===---\n");
+
+ printf("%-48s 0x%02x%02x\n", "Module Manufacturer ID",
+ s->mmid_msb, s->mmid_lsb);
+
+ if (!((s->dmid_lsb == 0xff) && (s->dmid_msb == 0xff))
+ && !((s->dmid_lsb == 0x0) && (s->dmid_msb == 0x0)))
+ printf("%-48s 0x%02x%02x\n", "DRAM Manufacturer ID",
+ s->dmid_msb, s->dmid_lsb);
+
+ if (!(s->mloc == 0xff) && !(s->mloc == 0x0))
+ printf("%-48s 0x%02x\n", "Manufacturing Location Code",
+ s->mloc);
+
+ if (!((s->mdate[0] == 0xff) && (s->mdate[1] == 0xff))
+ && !((s->mdate[0] == 0x0) && (s->mdate[1] == 0x0)))
+ spd_print_manufacturing_date(s->mdate[0], s->mdate[1]);
+
+ if ((s->sernum[0] != s->sernum[1])
+ && (s->sernum[0] != s->sernum[2])
+ && (s->sernum[1] != s->sernum[3])
+ && ((s->sernum[0] != 0xff) || (s->sernum[0] != 0x0)))
+ printf("%-48s 0x%02X%02X%02X%02X\n", "Assembly Serial Number",
+ s->sernum[0], s->sernum[1], s->sernum[2], s->sernum[3]);
+
+ printf("%-48s ", "Part Number");
+ if (!(s->mpart[0] >= 32 && s->mpart[0] < 127)) {
+ printf("Undefined\n");
+ } else {
+ for (i = 0; i < ARRAY_SIZE(s->mpart); i++) {
+ if (s->mpart[i] >= 32 && s->mpart[i] < 127)
+ printf("%c", s->mpart[i]);
+ else
+ break;
+ }
+ printf("\n");
+ }
+
+ if (!((s->mrev[0] == 0xff) && (s->mrev[1] == 0xff))
+ && !((s->mrev[0] == 0x0) && (s->mrev[1] == 0x0)))
+ printf("%-48s 0x%02X%02X\n", "Revision Code", s->mrev[0], s->mrev[1]);
+}
+
+void ddr_spd_print(uint8_t *record)
+{
+ uint8_t mem_type = record[2];
+
+ switch (mem_type) {
+ case SPD_MEMTYPE_DDR2:
+ ddr2_spd_print(record);
+ break;
+ case SPD_MEMTYPE_DDR3:
+ ddr3_spd_print(record);
+ break;
+ default:
+ printf("Can only dump SPD information for DDR2 and DDR3 memory types\n");
+ }
+}
+
#define SPD_SPA0_ADDRESS 0x36
#define SPD_SPA1_ADDRESS 0x37
-static int select_page(void *ctx,
- int (*xfer)(void *ctx, struct i2c_msg *msgs, int num),
- uint8_t addr)
+static int select_page(struct pbl_i2c *i2c, uint8_t addr)
{
struct i2c_msg msg = {
.addr = addr,
@@ -440,15 +979,14 @@ static int select_page(void *ctx,
};
int ret;
- ret = xfer(ctx, &msg, 1);
+ ret = pbl_i2c_xfer(i2c, &msg, 1);
if (ret < 0)
return ret;
return 0;
}
-static int read_buf(void *ctx,
- int (*xfer)(void *ctx, struct i2c_msg *msgs, int num),
+static int read_buf(struct pbl_i2c *i2c,
uint8_t addr, int page, void *buf)
{
uint8_t pos = 0;
@@ -466,11 +1004,11 @@ static int read_buf(void *ctx,
}
};
- ret = select_page(ctx, xfer, page);
+ ret = select_page(i2c, page);
if (ret < 0)
return ret;
- ret = xfer(ctx, msg, 2);
+ ret = pbl_i2c_xfer(i2c, msg, 2);
if (ret < 0)
return ret;
@@ -479,29 +1017,32 @@ static int read_buf(void *ctx,
/**
* spd_read_eeprom - Read contents of a SPD EEPROM
- * @ctx: Context pointer for the xfer function
- * @xfer: I2C message transfer function
+ * @i2c: I2C controller handle
* @addr: I2C bus address for the EEPROM
* @buf: buffer to read the SPD data to
+ * @memtype: Memory type, such as SPD_MEMTYPE_DDR4
*
* This function takes a I2C message transfer function and reads the contents
* from a SPD EEPROM to the buffer provided at @buf. The buffer should at least
* have a size of 512 bytes. Returns 0 for success or a negative error code
* otherwise.
*/
-int spd_read_eeprom(void *ctx,
- int (*xfer)(void *ctx, struct i2c_msg *msgs, int num),
- uint8_t addr, void *buf)
+int spd_read_eeprom(struct pbl_i2c *i2c,
+ uint8_t addr, void *buf,
+ int memtype)
{
- unsigned char *buf8 = buf;
int ret;
- ret = read_buf(ctx, xfer, addr, SPD_SPA0_ADDRESS, buf);
- if (ret < 0)
- return ret;
+ if (memtype == SPD_MEMTYPE_DDR4) {
+ ret = read_buf(i2c, addr, SPD_SPA0_ADDRESS, buf);
+ if (ret < 0)
+ return ret;
- if (buf8[2] == SPD_MEMTYPE_DDR4) {
- ret = read_buf(ctx, xfer, addr, SPD_SPA1_ADDRESS, buf + 256);
+ ret = read_buf(i2c, addr, SPD_SPA1_ADDRESS, buf + 256);
+ if (ret < 0)
+ return ret;
+ } else {
+ ret = read_buf(i2c, addr, 0, buf);
if (ret < 0)
return ret;
}
diff --git a/common/deep-probe.c b/common/deep-probe.c
index 1020ad93b7..931e5a1770 100644
--- a/common/deep-probe.c
+++ b/common/deep-probe.c
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
+#define pr_fmt(fmt) "deep-probe: " fmt
+
#include <common.h>
#include <deep-probe.h>
#include <of.h>
@@ -27,7 +29,7 @@ bool deep_probe_is_supported(void)
for (; matches->compatible; matches++) {
if (of_machine_is_compatible(matches->compatible)) {
boardstate = DEEP_PROBE_SUPPORTED;
- printk("Deep probe supported due to %s\n", matches->compatible);
+ pr_info("supported due to %s\n", matches->compatible);
return true;
}
}
diff --git a/common/dlmalloc.c b/common/dlmalloc.c
index ae10c9ae30..c41487d54b 100644
--- a/common/dlmalloc.c
+++ b/common/dlmalloc.c
@@ -1,8 +1,10 @@
#include <config.h>
+#include <errno.h>
#include <malloc.h>
#include <string.h>
#include <memory.h>
+#include <linux/build_bug.h>
#include <stdio.h>
#include <module.h>
@@ -627,7 +629,13 @@ nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/* conversion from malloc headers to user pointers, and back */
#define chunk2mem(p) ((void*)((char*)(p) + 2*SIZE_SZ))
-#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - 2*SIZE_SZ))
+
+static inline mchunkptr mem2chunk(void *mem)
+{
+ OPTIMIZER_HIDE_VAR(mem);
+
+ return mem - 2 * SIZE_SZ;
+}
/* pad request bytes into a usable size */
@@ -884,6 +892,8 @@ static mbinptr av_[NAV * 2 + 2] = {
/* Other static bookkeeping data */
+static_assert(MALLOC_ALIGNMENT >= CONFIG_MALLOC_ALIGNMENT);
+
/* variables holding tunable values */
#ifndef __BAREBOX__
static unsigned long trim_threshold = DEFAULT_TRIM_THRESHOLD;
@@ -1158,8 +1168,10 @@ void *malloc(size_t bytes)
INTERNAL_SIZE_T nb;
- if ((long) bytes < 0)
+ if ((long) bytes < 0) {
+ errno = ENOMEM;
return NULL;
+ }
nb = request2size(bytes); /* padded request size; */
@@ -1313,8 +1325,10 @@ void *malloc(size_t bytes)
if ((remainder_size = chunksize (top) - nb) < (long) MINSIZE) {
/* Try to extend */
malloc_extend_top(nb);
- if ((remainder_size = chunksize(top) - nb) < (long) MINSIZE)
+ if ((remainder_size = chunksize(top) - nb) < (long) MINSIZE) {
+ errno = ENOMEM;
return NULL; /* propagate failure */
+ }
}
victim = top;
@@ -1478,8 +1492,10 @@ void *realloc(void *oldmem, size_t bytes)
}
#endif
- if ((long)bytes < 0)
+ if ((long)bytes < 0) {
+ errno = ENOMEM;
return NULL;
+ }
/* realloc of null is supposed to be same as malloc */
if (!oldmem)
@@ -1645,8 +1661,10 @@ void *memalign(size_t alignment, size_t bytes)
mchunkptr remainder; /* spare room at end to split off */
long remainder_size; /* its size */
- if ((long) bytes < 0)
+ if ((long) bytes < 0) {
+ errno = ENOMEM;
return NULL;
+ }
/* If need less alignment than we give anyway, just relay to malloc */
@@ -1680,8 +1698,8 @@ void *memalign(size_t alignment, size_t bytes)
this is always possible.
*/
- brk = (char*) mem2chunk(((unsigned long) (m + alignment - 1)) &
- -((signed) alignment));
+ brk = (char*) mem2chunk((void *)(((unsigned long) (m + alignment - 1)) &
+ -((signed) alignment)));
if ((long)(brk - (char*)(p)) < MINSIZE)
brk = brk + alignment;
@@ -1728,8 +1746,10 @@ void *calloc(size_t n, size_t elem_size)
mchunkptr oldtop = top;
INTERNAL_SIZE_T oldtopsize = chunksize(top);
- if ((long)n < 0)
+ if ((long)n < 0) {
+ errno = ENOMEM;
return NULL;
+ }
mem = malloc(sz);
diff --git a/common/dummy_malloc.c b/common/dummy_malloc.c
index d99b5059cf..7a96afec76 100644
--- a/common/dummy_malloc.c
+++ b/common/dummy_malloc.c
@@ -23,7 +23,7 @@ void *memalign(size_t alignment, size_t bytes)
void *malloc(size_t size)
{
- return memalign(8, size);
+ return memalign(CONFIG_MALLOC_ALIGNMENT, size);
}
void free(void *ptr)
diff --git a/common/efi-devicepath.c b/common/efi-devicepath.c
deleted file mode 100644
index f17b9294cc..0000000000
--- a/common/efi-devicepath.c
+++ /dev/null
@@ -1,1195 +0,0 @@
-#include <common.h>
-#include <efi.h>
-#include <malloc.h>
-#include <string.h>
-#include <wchar.h>
-
-struct string {
- char *str;
- int len;
-};
-
-char *cprintf(struct string *str, const char *fmt, ...)
- __attribute__ ((format(__printf__, 2, 3)));
-
-char *cprintf(struct string *str, const char *fmt, ...)
-{
- va_list args;
- int len;
-
- va_start(args, fmt);
- if (str->str)
- len = vsprintf(str->str + str->len, fmt, args);
- else
- len = vsnprintf(NULL, 0, fmt, args);
- va_end(args);
-
- str->len += len;
-
- return NULL;
-}
-
-#define MIN_ALIGNMENT_SIZE 8 /* FIXME: X86_64 specific */
-#define ALIGN_SIZE(a) ((a % MIN_ALIGNMENT_SIZE) ? MIN_ALIGNMENT_SIZE - (a % MIN_ALIGNMENT_SIZE) : 0)
-
-#define EFI_DP_TYPE_MASK 0x7f
-#define EFI_DP_TYPE_UNPACKED 0x80
-
-#define END_DEVICE_PATH_TYPE 0x7f
-
-#define END_ENTIRE_DEVICE_PATH_SUBTYPE 0xff
-#define END_INSTANCE_DEVICE_PATH_SUBTYPE 0x01
-#define END_DEVICE_PATH_LENGTH (sizeof(struct efi_device_path))
-
-#define DP_IS_END_TYPE(a)
-#define DP_IS_END_SUBTYPE(a) ( ((a)->sub_type == END_ENTIRE_DEVICE_PATH_SUBTYPE )
-
-#define device_path_type(a) ( ((a)->type) & EFI_DP_TYPE_MASK )
-#define next_device_path_node(a) ( (struct efi_device_path *) ( ((u8 *) (a)) + (a)->length))
-#define is_device_path_end_type(a) ( device_path_type(a) == END_DEVICE_PATH_TYPE )
-#define is_device_path_end_sub_type(a) ( (a)->sub_type == END_ENTIRE_DEVICE_PATH_SUBTYPE )
-#define is_device_path_end(a) ( is_device_path_end_type(a) && is_device_path_end_sub_type(a) )
-#define is_device_path_unpacked(a) ( (a)->type & EFI_DP_TYPE_UNPACKED )
-
-#define set_device_path_end_node(a) { \
- (a)->type = END_DEVICE_PATH_TYPE; \
- (a)->sub_type = END_ENTIRE_DEVICE_PATH_SUBTYPE; \
- (a)->length = sizeof(struct efi_device_path); \
- }
-
-/*
- * Hardware Device Path (UEFI 2.4 specification, version 2.4 § 9.3.2.)
- */
-
-#define HARDWARE_DEVICE_PATH 0x01
-
-#define HW_PCI_DP 0x01
-struct pci_device_path {
- struct efi_device_path header;
- u8 Function;
- u8 Device;
-};
-
-#define HW_PCCARD_DP 0x02
-struct pccard_device_path {
- struct efi_device_path header;
- u8 function_number;
-};
-
-#define HW_MEMMAP_DP 0x03
-struct memmap_device_path {
- struct efi_device_path header;
- u32 memory_type;
- efi_physical_addr_t starting_address;
- efi_physical_addr_t ending_address;
-};
-
-#define HW_VENDOR_DP 0x04
-struct vendor_device_path {
- struct efi_device_path header;
- efi_guid_t Guid;
-};
-
-struct unknown_device_vendor_device_path {
- struct vendor_device_path device_path;
- u8 legacy_drive_letter;
-};
-
-#define HW_CONTROLLER_DP 0x05
-struct controller_device_path {
- struct efi_device_path header;
- u32 Controller;
-};
-
-/*
- * ACPI Device Path (UEFI 2.4 specification, version 2.4 § 9.3.3 and 9.3.4.)
- */
-#define ACPI_DEVICE_PATH 0x02
-
-#define ACPI_DP 0x01
-struct acpi_hid_device_path {
- struct efi_device_path header;
- u32 HID;
- u32 UID;
-};
-
-#define EXPANDED_ACPI_DP 0x02
-struct expanded_acpi_hid_device_path {
- struct efi_device_path header;
- u32 HID;
- u32 UID;
- u32 CID;
- u8 hid_str[1];
-};
-
-#define ACPI_ADR_DP 3
-struct acpi_adr_device_path {
- struct efi_device_path header;
- u32 ADR;
-};
-
-/*
- * EISA ID Macro
- * EISA ID Definition 32-bits
- * bits[15:0] - three character compressed ASCII EISA ID.
- * bits[31:16] - binary number
- * Compressed ASCII is 5 bits per character 0b00001 = 'A' 0b11010 = 'Z'
- */
-#define PNP_EISA_ID_CONST 0x41d0
-#define EISA_ID(_Name, _Num) ((u32) ((_Name) | (_Num) << 16))
-#define EISA_PNP_ID(_PNPId) (EISA_ID(PNP_EISA_ID_CONST, (_PNPId)))
-
-#define PNP_EISA_ID_MASK 0xffff
-#define EISA_ID_TO_NUM(_Id) ((_Id) >> 16)
-
-/*
- * Messaging Device Path (UEFI 2.4 specification, version 2.4 § 9.3.5.)
- */
-#define MESSAGING_DEVICE_PATH 0x03
-
-#define MSG_ATAPI_DP 0x01
-struct atapi_device_path {
- struct efi_device_path header;
- u8 primary_secondary;
- u8 slave_master;
- u16 Lun;
-};
-
-#define MSG_SCSI_DP 0x02
-struct scsi_device_path {
- struct efi_device_path header;
- u16 Pun;
- u16 Lun;
-};
-
-#define MSG_FIBRECHANNEL_DP 0x03
-struct fibrechannel_device_path {
- struct efi_device_path header;
- u32 Reserved;
- u64 WWN;
- u64 Lun;
-};
-
-/**
- * Fibre Channel Ex sub_type.
- * UEFI 2.0 specification version 2.4 § 9.3.5.6.
- */
-#define MSG_FIBRECHANNELEX_DP 21
-struct fibrechannelex_device_path {
- struct efi_device_path header;
- u32 Reserved;
- u8 WWN[8]; /* World Wide Name */
- u8 Lun[8]; /* Logical unit, T-10 SCSI Architecture Model 4 specification */
-};
-
-#define MSG_1394_DP 0x04
-struct f1394_device_path {
- struct efi_device_path header;
- u32 Reserved;
- u64 Guid;
-};
-
-#define MSG_USB_DP 0x05
-struct usb_device_path {
- struct efi_device_path header;
- u8 Port;
- u8 Endpoint;
-};
-
-/**
- * SATA Device Path sub_type.
- * UEFI 2.0 specification version 2.4 § 9.3.5.6.
- */
-#define MSG_SATA_DP 18
-struct sata_device_path {
- struct efi_device_path header;
- u16 HBAPort_number;
- u16 port_multiplier_port_number;
- u16 Lun; /* Logical Unit Number */
-};
-
-/**
- * USB WWID Device Path sub_type.
- * UEFI 2.0 specification version 2.4 § 9.3.5.7.
- */
-#define MSG_USB_WWID_DP 16
-struct usb_wwid_device_path {
- struct efi_device_path header;
- u16 interface_number;
- u16 vendor_id;
- u16 product_id;
- s16 serial_number[1]; /* UTF-16 characters of the USB serial number */
-};
-
-/**
- * Device Logical Unit sub_type.
- * UEFI 2.0 specification version 2.4 § 9.3.5.8.
- */
-#define MSG_DEVICE_LOGICAL_UNIT_DP 17
-struct device_logical_unit_device_path {
- struct efi_device_path header;
- u8 Lun; /* Logical Unit Number */
-};
-
-#define MSG_USB_CLASS_DP 0x0_f
-struct usb_class_device_path {
- struct efi_device_path header;
- u16 vendor_id;
- u16 product_id;
- u8 device_class;
- u8 device_subclass;
- u8 device_protocol;
-};
-
-#define MSG_I2_o_DP 0x06
-struct i2_o_device_path {
- struct efi_device_path header;
- u32 Tid;
-};
-
-#define MSG_MAC_ADDR_DP 0x0b
-struct mac_addr_device_path {
- struct efi_device_path header;
- efi_mac_address mac_address;
- u8 if_type;
-};
-
-#define MSG_IPv4_DP 0x0c
-struct ipv4_device_path {
- struct efi_device_path header;
- efi_ipv4_address local_ip_address;
- efi_ipv4_address remote_ip_address;
- u16 local_port;
- u16 remote_port;
- u16 Protocol;
- bool static_ip_address;
- /* new from UEFI version 2, code must check length field in header */
- efi_ipv4_address gateway_ip_address;
- efi_ipv4_address subnet_mask;
-};
-
-#define MSG_IPv6_DP 0x0d
-struct ipv6_device_path {
- struct efi_device_path header;
- efi_ipv6_address local_ip_address;
- efi_ipv6_address remote_ip_address;
- u16 local_port;
- u16 remote_port;
- u16 Protocol;
- bool IPAddress_origin;
- /* new from UEFI version 2, code must check length field in header */
- u8 prefix_length;
- efi_ipv6_address gateway_ip_address;
-};
-
-/**
- * Device Logical Unit sub_type.
- * UEFI 2.0 specification version 2.4 § 9.3.5.8.
- */
-#define MSG_VLAN_DP 20
-struct vlan_device_path {
- struct efi_device_path header;
- u16 vlan_id;
-};
-
-#define MSG_INFINIBAND_DP 0x09
-struct infiniband_device_path {
- struct efi_device_path header;
- u32 resource_flags;
- efi_guid_t port_gid;
- u64 service_id;
- u64 target_port_id;
- u64 device_id;
-};
-
-#define MSG_UART_DP 0x0e
-struct uart_device_path {
- struct efi_device_path header;
- u32 Reserved;
- u64 baud_rate;
- u8 data_bits;
- u8 Parity;
- u8 stop_bits;
-};
-
-#define MSG_VENDOR_DP 0x0a
-/* Use VENDOR_DEVICE_PATH struct */
-
-#define DEVICE_PATH_MESSAGING_PC_ANSI \
- { 0xe0c14753, 0xf9be, 0x11d2, {0x9a, 0x0c, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d} }
-
-#define DEVICE_PATH_MESSAGING_VT_100 \
- { 0xdfa66065, 0xb419, 0x11d3, {0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d} }
-
-#define DEVICE_PATH_MESSAGING_VT_100_PLUS \
- { 0x7baec70b , 0x57e0 , 0x4c76 , { 0x8e , 0x87 , 0x2f , 0x9e , 0x28 , 0x08 , 0x83 , 0x43 } }
-
-#define DEVICE_PATH_MESSAGING_VT_UTF8 \
- { 0xad15a0d6 , 0x8bec , 0x4acf , { 0xa0 , 0x73 , 0xd0 , 0x1d , 0xe7 , 0x7e , 0x2d , 0x88 } }
-
-#define EFI_PC_ANSI_GUID \
- { 0xe0c14753 , 0xf9be , 0x11d2 , 0x9a , 0x0c , 0x00 , 0x90 , 0x27 , 0x3f , 0xc1 , 0x4d }
-
-#define EFI_VT_100_GUID \
- { 0xdfa66065 , 0xb419 , 0x11d3 , 0x9a , 0x2d , 0x00 , 0x90 , 0x27 , 0x3f , 0xc1 , 0x4d }
-
-#define EFI_VT_100_PLUS_GUID \
- { 0x7baec70b , 0x57e0 , 0x4c76 , 0x8e , 0x87 , 0x2f , 0x9e , 0x28 , 0x08 , 0x83 , 0x43 }
-
-#define EFI_VT_UTF8_GUID \
- { 0xad15a0d6 , 0x8bec , 0x4acf , 0xa0 , 0x73 , 0xd0 , 0x1d , 0xe7 , 0x7e , 0x2d , 0x88 }
-
-/*
- * Media Device Path (UEFI 2.4 specification, version 2.4 § 9.3.6.)
- */
-#define MEDIA_DEVICE_PATH 0x04
-
-#define MEDIA_HARDDRIVE_DP 0x01
-struct harddrive_device_path {
- struct efi_device_path header;
- u32 partition_number;
- u64 partition_start;
- u64 partition_size;
- u8 signature[16];
- u8 mbr_type;
- u8 signature_type;
-};
-
-#define MBR_TYPE_PCAT 0x01
-#define MBR_TYPE_EFI_PARTITION_TABLE_HEADER 0x02
-
-#define SIGNATURE_TYPE_MBR 0x01
-#define SIGNATURE_TYPE_GUID 0x02
-
-#define MEDIA_CDROM_DP 0x02
-struct cdrom_device_path {
- struct efi_device_path header;
- u32 boot_entry;
- u64 partition_start;
- u64 partition_size;
-};
-
-#define MEDIA_VENDOR_DP 0x03
-/* Use VENDOR_DEVICE_PATH struct */
-
-#define MEDIA_FILEPATH_DP 0x04
-struct filepath_device_path {
- struct efi_device_path header;
- s16 path_name[1];
-};
-
-#define SIZE_OF_FILEPATH_DEVICE_PATH offsetof(FILEPATH_DEVICE_PATH,path_name)
-
-#define MEDIA_PROTOCOL_DP 0x05
-struct media_protocol_device_path {
- struct efi_device_path header;
- efi_guid_t Protocol;
-};
-
-/**
- * PIWG Firmware File sub_type.
- * UEFI 2.0 specification version 2.4 § 9.3.6.6.
- */
-#define MEDIA_PIWG_FW_FILE_DP 6
-struct media_fw_vol_filepath_device_path {
- struct efi_device_path header;
- efi_guid_t fv_file_name;
-};
-
-/**
- * PIWG Firmware Volume Device Path sub_type.
- * UEFI 2.0 specification version 2.4 § 9.3.6.7.
- */
-#define MEDIA_PIWG_FW_VOL_DP 7
-struct media_fw_vol_device_path {
- struct efi_device_path header;
- efi_guid_t fv_name;
-};
-
-/**
- * Media relative offset range device path.
- * UEFI 2.0 specification version 2.4 § 9.3.6.8.
- */
-#define MEDIA_RELATIVE_OFFSET_RANGE_DP 8
-struct media_relative_offset_range_device_path {
- struct efi_device_path header;
- u32 Reserved;
- u64 starting_offset;
- u64 ending_offset;
-};
-
-/*
- * BIOS Boot Specification Device Path (UEFI 2.4 specification, version 2.4 § 9.3.7.)
- */
-#define BBS_DEVICE_PATH 0x05
-
-#define BBS_BBS_DP 0x01
-struct bbs_bbs_device_path {
- struct efi_device_path header;
- u16 device_type;
- u16 status_flag;
- s8 String[1];
-};
-
-/* device_type definitions - from BBS specification */
-#define BBS_TYPE_FLOPPY 0x01
-#define BBS_TYPE_HARDDRIVE 0x02
-#define BBS_TYPE_CDROM 0x03
-#define BBS_TYPE_PCMCIA 0x04
-#define BBS_TYPE_USB 0x05
-#define BBS_TYPE_EMBEDDED_NETWORK 0x06
-#define BBS_TYPE_DEV 0x80
-#define BBS_TYPE_UNKNOWN 0x_fF
-
-struct efi_device_path end_device_path = {
- .type = END_DEVICE_PATH_TYPE,
- .sub_type = END_ENTIRE_DEVICE_PATH_SUBTYPE,
- .length = END_DEVICE_PATH_LENGTH,
-};
-
-struct efi_device_path end_instance_device_path = {
- .type = END_DEVICE_PATH_TYPE,
- .sub_type = END_INSTANCE_DEVICE_PATH_SUBTYPE,
- .length = END_DEVICE_PATH_LENGTH,
-};
-
-struct efi_device_path *
-device_path_from_handle(efi_handle_t Handle)
-{
- efi_status_t Status;
- struct efi_device_path *device_path;
-
- Status = BS->handle_protocol(Handle, &efi_device_path_protocol_guid,
- (void *) &device_path);
- if (EFI_ERROR(Status))
- device_path = NULL;
-
- return device_path;
-}
-
-static struct efi_device_path *
-unpack_device_path(struct efi_device_path *dev_path)
-{
- struct efi_device_path *Src, *Dest, *new_path;
- unsigned long Size;
-
- /* Walk device path and round sizes to valid boundaries */
-
- Src = dev_path;
- Size = 0;
- for (;;) {
- Size += Src->length;
- Size += ALIGN_SIZE(Size);
-
- if (is_device_path_end(Src)) {
- break;
- }
-
- Src = next_device_path_node(Src);
- }
-
- new_path = xzalloc(Size);
-
- Src = dev_path;
- Dest = new_path;
- for (;;) {
- Size = Src->length;
- memcpy(Dest, Src, Size);
- Size += ALIGN_SIZE(Size);
- Dest->length = Size;
- Dest->type |= EFI_DP_TYPE_UNPACKED;
- Dest =
- (struct efi_device_path *) (((u8 *) Dest) + Size);
-
- if (is_device_path_end(Src))
- break;
-
- Src = next_device_path_node(Src);
- }
-
- return new_path;
-}
-
-static void
-dev_path_pci(struct string *str, void *dev_path)
-{
- struct pci_device_path *Pci;
-
- Pci = dev_path;
- cprintf(str, "Pci(0x%x,0x%x)", Pci->Device, Pci->Function);
-}
-
-static void
-dev_path_pccard(struct string *str, void *dev_path)
-{
- struct pccard_device_path *Pccard;
-
- Pccard = dev_path;
- cprintf(str, "Pccard(0x%x)", Pccard->function_number);
-}
-
-static void
-dev_path_mem_map(struct string *str, void *dev_path)
-{
- struct memmap_device_path *mem_map;
-
- mem_map = dev_path;
- cprintf(str, "mem_map(%d,0x%llx,0x%llx)",
- mem_map->memory_type,
- mem_map->starting_address, mem_map->ending_address);
-}
-
-static void
-dev_path_controller(struct string *str, void *dev_path)
-{
- struct controller_device_path *Controller;
-
- Controller = dev_path;
- cprintf(str, "Ctrl(%d)", Controller->Controller);
-}
-
-static void
-dev_path_vendor(struct string *str, void *dev_path)
-{
- struct vendor_device_path *Vendor;
- char *type;
- struct unknown_device_vendor_device_path *unknown_dev_path;
-
- Vendor = dev_path;
- switch (device_path_type(&Vendor->header)) {
- case HARDWARE_DEVICE_PATH:
- type = "Hw";
- break;
- case MESSAGING_DEVICE_PATH:
- type = "Msg";
- break;
- case MEDIA_DEVICE_PATH:
- type = "Media";
- break;
- default:
- type = "?";
- break;
- }
-
- cprintf(str, "Ven%s(%pU", type, &Vendor->Guid);
- if (efi_guidcmp(Vendor->Guid, efi_unknown_device_guid) == 0) {
- /* GUID used by EFI to enumerate an EDD 1.1 device */
- unknown_dev_path =
- (struct unknown_device_vendor_device_path *) Vendor;
- cprintf(str, ":%02x)", unknown_dev_path->legacy_drive_letter);
- } else {
- cprintf(str, ")");
- }
-}
-
-/*
- type: 2 (ACPI Device Path) sub_type: 1 (ACPI Device Path)
- */
-static void
-dev_path_acpi(struct string *str, void *dev_path)
-{
- struct acpi_hid_device_path *Acpi;
-
- Acpi = dev_path;
- if ((Acpi->HID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) {
- switch (EISA_ID_TO_NUM(Acpi->HID)) {
- case 0x301:
- cprintf(str, "Keyboard(%d)", Acpi->UID);
- break;
-
- case 0x401:
- cprintf(str, "parallel_port(%d)", Acpi->UID);
- break;
- case 0x501:
- cprintf(str, "Serial(%d)", Acpi->UID);
- break;
- case 0x604:
- cprintf(str, "Floppy(%d)", Acpi->UID);
- break;
- case 0xa03:
- cprintf(str, "pci_root(%d)", Acpi->UID);
- break;
- case 0xa08:
- cprintf(str, "pcie_root(%d)", Acpi->UID);
- break;
- default:
- cprintf(str, "Acpi(PNP%04x",
- EISA_ID_TO_NUM(Acpi->HID));
- if (Acpi->UID)
- cprintf(str, ",%d", Acpi->UID);
- cprintf(str, ")");
- break;
- }
- } else {
- cprintf(str, "Acpi(0x%X", Acpi->HID);
- if (Acpi->UID)
- cprintf(str, ",%d", Acpi->UID);
- cprintf(str, ")");
- }
-}
-
-static void
-dev_path_atapi(struct string *str, void *dev_path)
-{
- struct atapi_device_path *Atapi;
-
- Atapi = dev_path;
- cprintf(str, "Ata(%s,%s)",
- Atapi->primary_secondary ? "Secondary" : "Primary",
- Atapi->slave_master ? "Slave" : "Master");
-}
-
-static void
-dev_path_scsi(struct string *str, void *dev_path)
-{
- struct scsi_device_path *Scsi;
-
- Scsi = dev_path;
- cprintf(str, "Scsi(%d,%d)", Scsi->Pun, Scsi->Lun);
-}
-
-static void
-dev_path_fibre(struct string *str, void *dev_path)
-{
- struct fibrechannel_device_path *Fibre;
-
- Fibre = dev_path;
- cprintf(str, "Fibre%s(0x%016llx,0x%016llx)",
- device_path_type(&Fibre->header) ==
- MSG_FIBRECHANNEL_DP ? "" : "Ex", Fibre->WWN, Fibre->Lun);
-}
-
-static void
-dev_path1394(struct string *str, void *dev_path)
-{
- struct f1394_device_path *F1394;
-
- F1394 = dev_path;
- cprintf(str, "1394(%pU)", &F1394->Guid);
-}
-
-static void
-dev_path_usb(struct string *str, void *dev_path)
-{
- struct usb_device_path *Usb;
-
- Usb = dev_path;
- cprintf(str, "Usb(0x%x,0x%x)", Usb->Port, Usb->Endpoint);
-}
-
-static void
-dev_path_i2_o(struct string *str, void *dev_path)
-{
- struct i2_o_device_path *i2_o;
-
- i2_o = dev_path;
- cprintf(str, "i2_o(0x%X)", i2_o->Tid);
-}
-
-static void
-dev_path_mac_addr(struct string *str, void *dev_path)
-{
- struct mac_addr_device_path *MAC;
- unsigned long hw_address_size;
- unsigned long Index;
-
- MAC = dev_path;
-
- /* hw_address_size = sizeof(EFI_MAC_ADDRESS); */
- hw_address_size = MAC->header.length;
- hw_address_size -= sizeof (MAC->header);
- hw_address_size -= sizeof (MAC->if_type);
- if (MAC->if_type == 0x01 || MAC->if_type == 0x00)
- hw_address_size = 6;
-
- cprintf(str, "Mac(");
-
- for (Index = 0; Index < hw_address_size; Index++)
- cprintf(str, "%02x", MAC->mac_address.Addr[Index]);
-
- if (MAC->if_type != 0)
- cprintf(str, ",%d", MAC->if_type);
-
- cprintf(str, ")");
-}
-
-static void
-cat_print_iPv4(struct string *str, efi_ipv4_address * address)
-{
- cprintf(str, "%d.%d.%d.%d", address->Addr[0], address->Addr[1],
- address->Addr[2], address->Addr[3]);
-}
-
-static bool
-is_not_null_iPv4(efi_ipv4_address * address)
-{
- u8 val;
-
- val = address->Addr[0] | address->Addr[1];
- val |= address->Addr[2] | address->Addr[3];
-
- return val != 0;
-}
-
-static void
-cat_print_network_protocol(struct string *str, u16 Proto)
-{
- if (Proto == 6)
- cprintf(str, "TCP");
- else if (Proto == 17)
- cprintf(str, "UDP");
- else
- cprintf(str, "%d", Proto);
-}
-
-static void
-dev_path_iPv4(struct string *str, void *dev_path)
-{
- struct ipv4_device_path *ip;
- bool show;
-
- ip = dev_path;
- cprintf(str, "IPv4(");
- cat_print_iPv4(str, &ip->remote_ip_address);
- cprintf(str, ",");
- cat_print_network_protocol(str, ip->Protocol);
- cprintf(str, ",%s", ip->static_ip_address ? "Static" : "DHCP");
- show = is_not_null_iPv4(&ip->local_ip_address);
- if (!show
- && ip->header.length ==
- sizeof (struct ipv4_device_path)) {
- /* only version 2 includes gateway and netmask */
- show |= is_not_null_iPv4(&ip->gateway_ip_address);
- show |= is_not_null_iPv4(&ip->subnet_mask);
- }
- if (show) {
- cprintf(str, ",");
- cat_print_iPv4(str, &ip->local_ip_address);
- if (ip->header.length ==
- sizeof (struct ipv4_device_path)) {
- /* only version 2 includes gateway and netmask */
- show = is_not_null_iPv4(&ip->gateway_ip_address);
- show |= is_not_null_iPv4(&ip->subnet_mask);
- if (show) {
- cprintf(str, ",");
- cat_print_iPv4(str, &ip->gateway_ip_address);
- if (is_not_null_iPv4(&ip->subnet_mask)) {
- cprintf(str, ",");
- cat_print_iPv4(str, &ip->subnet_mask);
- }
- }
- }
- }
- cprintf(str, ")");
-}
-
-#define cat_print_iPv6_ADD( x , y ) ( ( (u16) ( x ) ) << 8 | ( y ) )
-static void
-cat_print_ipv6(struct string *str, efi_ipv6_address * address)
-{
- cprintf(str, "%x:%x:%x:%x:%x:%x:%x:%x",
- cat_print_iPv6_ADD(address->Addr[0], address->Addr[1]),
- cat_print_iPv6_ADD(address->Addr[2], address->Addr[3]),
- cat_print_iPv6_ADD(address->Addr[4], address->Addr[5]),
- cat_print_iPv6_ADD(address->Addr[6], address->Addr[7]),
- cat_print_iPv6_ADD(address->Addr[8], address->Addr[9]),
- cat_print_iPv6_ADD(address->Addr[10], address->Addr[11]),
- cat_print_iPv6_ADD(address->Addr[12], address->Addr[13]),
- cat_print_iPv6_ADD(address->Addr[14], address->Addr[15]));
-}
-
-static void
-dev_path_iPv6(struct string *str, void *dev_path)
-{
- struct ipv6_device_path *ip;
-
- ip = dev_path;
- cprintf(str, "IPv6(");
- cat_print_ipv6(str, &ip->remote_ip_address);
- cprintf(str, ",");
- cat_print_network_protocol(str, ip->Protocol);
- cprintf(str, ",%s,", ip->IPAddress_origin ?
- (ip->IPAddress_origin == 1 ? "stateless_auto_configure" :
- "stateful_auto_configure") : "Static");
- cat_print_ipv6(str, &ip->local_ip_address);
- if (ip->header.length ==
- sizeof (struct ipv6_device_path)) {
- cprintf(str, ",");
- cat_print_ipv6(str, &ip->gateway_ip_address);
- cprintf(str, ",");
- cprintf(str, "%d", ip->prefix_length);
- }
- cprintf(str, ")");
-}
-
-static void
-dev_path_infini_band(struct string *str, void *dev_path)
-{
- struct infiniband_device_path *infini_band;
-
- infini_band = dev_path;
- cprintf(str, "Infiniband(0x%x,%pU,0x%llx,0x%llx,0x%llx)",
- infini_band->resource_flags, &infini_band->port_gid,
- infini_band->service_id, infini_band->target_port_id,
- infini_band->device_id);
-}
-
-static void
-dev_path_uart(struct string *str, void *dev_path)
-{
- struct uart_device_path *Uart;
- s8 Parity;
-
- Uart = dev_path;
- switch (Uart->Parity) {
- case 0:
- Parity = 'D';
- break;
- case 1:
- Parity = 'N';
- break;
- case 2:
- Parity = 'E';
- break;
- case 3:
- Parity = 'O';
- break;
- case 4:
- Parity = 'M';
- break;
- case 5:
- Parity = 'S';
- break;
- default:
- Parity = 'x';
- break;
- }
-
- if (Uart->baud_rate == 0)
- cprintf(str, "Uart(DEFAULT %c", Parity);
- else
- cprintf(str, "Uart(%lld %c", Uart->baud_rate, Parity);
-
- if (Uart->data_bits == 0)
- cprintf(str, "D");
- else
- cprintf(str, "%d", Uart->data_bits);
-
- switch (Uart->stop_bits) {
- case 0:
- cprintf(str, "D)");
- break;
- case 1:
- cprintf(str, "1)");
- break;
- case 2:
- cprintf(str, "1.5)");
- break;
- case 3:
- cprintf(str, "2)");
- break;
- default:
- cprintf(str, "x)");
- break;
- }
-}
-
-static void
-dev_path_sata(struct string *str, void *dev_path)
-{
- struct sata_device_path *sata;
-
- sata = dev_path;
- cprintf(str, "Sata(0x%x,0x%x,0x%x)", sata->HBAPort_number,
- sata->port_multiplier_port_number, sata->Lun);
-}
-
-static void
-dev_path_hard_drive(struct string *str, void *dev_path)
-{
- struct harddrive_device_path *hd;
-
- hd = dev_path;
- switch (hd->signature_type) {
- case SIGNATURE_TYPE_MBR:
- cprintf(str, "HD(Part%d,Sig%08x)",
- hd->partition_number, *((u32 *) (&(hd->signature[0])))
- );
- break;
- case SIGNATURE_TYPE_GUID:
- cprintf(str, "HD(Part%d,Sig%pU)",
- hd->partition_number,
- (efi_guid_t *) & (hd->signature[0])
- );
- break;
- default:
- cprintf(str, "HD(Part%d,mbr_type=%02x,sig_type=%02x)",
- hd->partition_number, hd->mbr_type, hd->signature_type);
- break;
- }
-}
-
-static void
-dev_path_cdrom(struct string *str, void *dev_path)
-{
- struct cdrom_device_path *cd;
-
- cd = dev_path;
- cprintf(str, "CDROM(0x%x)", cd->boot_entry);
-}
-
-static void
-dev_path_file_path(struct string *str, void *dev_path)
-{
- struct filepath_device_path *Fp;
- char *dst;
-
- Fp = dev_path;
-
- dst = strdup_wchar_to_char(Fp->path_name);
-
- cprintf(str, "%s", dst);
-
- free(dst);
-}
-
-static void
-dev_path_media_protocol(struct string *str, void *dev_path)
-{
- struct media_protocol_device_path *media_prot;
-
- media_prot = dev_path;
- cprintf(str, "%pU", &media_prot->Protocol);
-}
-
-static void
-dev_path_bss_bss(struct string *str, void *dev_path)
-{
- struct bbs_bbs_device_path *Bss;
- char *type;
-
- Bss = dev_path;
- switch (Bss->device_type) {
- case BBS_TYPE_FLOPPY:
- type = "Floppy";
- break;
- case BBS_TYPE_HARDDRIVE:
- type = "Harddrive";
- break;
- case BBS_TYPE_CDROM:
- type = "CDROM";
- break;
- case BBS_TYPE_PCMCIA:
- type = "PCMCIA";
- break;
- case BBS_TYPE_USB:
- type = "Usb";
- break;
- case BBS_TYPE_EMBEDDED_NETWORK:
- type = "Net";
- break;
- default:
- type = "?";
- break;
- }
-
- cprintf(str, "Bss-%s(%s)", type, Bss->String);
-}
-
-static void
-dev_path_end_instance(struct string *str, void *dev_path)
-{
- cprintf(str, ",");
-}
-
-/**
- * Print unknown device node.
- * UEFI 2.4 § 9.6.1.6 table 89.
- */
-
-static void
-dev_path_node_unknown(struct string *str, void *dev_path)
-{
- struct efi_device_path *Path;
- u8 *value;
- int length, index;
- Path = dev_path;
- value = dev_path;
- value += 4;
- switch (Path->type) {
- case HARDWARE_DEVICE_PATH:{
- /* Unknown Hardware Device Path */
- cprintf(str, "hardware_path(%d", Path->sub_type);
- break;
- }
- case ACPI_DEVICE_PATH:{/* Unknown ACPI Device Path */
- cprintf(str, "acpi_path(%d", Path->sub_type);
- break;
- }
- case MESSAGING_DEVICE_PATH:{
- /* Unknown Messaging Device Path */
- cprintf(str, "Msg(%d", Path->sub_type);
- break;
- }
- case MEDIA_DEVICE_PATH:{
- /* Unknown Media Device Path */
- cprintf(str, "media_path(%d", Path->sub_type);
- break;
- }
- case BBS_DEVICE_PATH:{ /* Unknown BIOS Boot Specification Device Path */
- cprintf(str, "bbs_path(%d", Path->sub_type);
- break;
- }
- default:{ /* Unknown Device Path */
- cprintf(str, "Path(%d,%d", Path->type, Path->sub_type);
- break;
- }
- }
- length = Path->length;
- for (index = 0; index < length; index++) {
- if (index == 0)
- cprintf(str, ",0x");
- cprintf(str, "%02x", *value);
- value++;
- }
- cprintf(str, ")");
-}
-
-/*
- * Table to convert "type" and "sub_type" to a "convert to text" function/
- * Entries hold "type" and "sub_type" for know values.
- * Special "sub_type" 0 is used as default for known type with unknown subtype.
- */
-struct {
- u8 type;
- u8 sub_type;
- void (*Function) (struct string *, void *);
-} dev_path_table[] = {
- {
- HARDWARE_DEVICE_PATH, HW_PCI_DP, dev_path_pci}, {
- HARDWARE_DEVICE_PATH, HW_PCCARD_DP, dev_path_pccard}, {
- HARDWARE_DEVICE_PATH, HW_MEMMAP_DP, dev_path_mem_map}, {
- HARDWARE_DEVICE_PATH, HW_VENDOR_DP, dev_path_vendor}, {
- HARDWARE_DEVICE_PATH, HW_CONTROLLER_DP, dev_path_controller}, {
- ACPI_DEVICE_PATH, ACPI_DP, dev_path_acpi}, {
- MESSAGING_DEVICE_PATH, MSG_ATAPI_DP, dev_path_atapi}, {
- MESSAGING_DEVICE_PATH, MSG_SCSI_DP, dev_path_scsi}, {
- MESSAGING_DEVICE_PATH, MSG_FIBRECHANNEL_DP, dev_path_fibre}, {
- MESSAGING_DEVICE_PATH, MSG_1394_DP, dev_path1394}, {
- MESSAGING_DEVICE_PATH, MSG_USB_DP, dev_path_usb}, {
- MESSAGING_DEVICE_PATH, MSG_I2_o_DP, dev_path_i2_o}, {
- MESSAGING_DEVICE_PATH, MSG_MAC_ADDR_DP, dev_path_mac_addr}, {
- MESSAGING_DEVICE_PATH, MSG_IPv4_DP, dev_path_iPv4}, {
- MESSAGING_DEVICE_PATH, MSG_IPv6_DP, dev_path_iPv6}, {
- MESSAGING_DEVICE_PATH, MSG_INFINIBAND_DP, dev_path_infini_band}, {
- MESSAGING_DEVICE_PATH, MSG_UART_DP, dev_path_uart}, {
- MESSAGING_DEVICE_PATH, MSG_SATA_DP, dev_path_sata}, {
- MESSAGING_DEVICE_PATH, MSG_VENDOR_DP, dev_path_vendor}, {
- MEDIA_DEVICE_PATH, MEDIA_HARDDRIVE_DP, dev_path_hard_drive}, {
- MEDIA_DEVICE_PATH, MEDIA_CDROM_DP, dev_path_cdrom}, {
- MEDIA_DEVICE_PATH, MEDIA_VENDOR_DP, dev_path_vendor}, {
- MEDIA_DEVICE_PATH, MEDIA_FILEPATH_DP, dev_path_file_path}, {
- MEDIA_DEVICE_PATH, MEDIA_PROTOCOL_DP, dev_path_media_protocol}, {
- BBS_DEVICE_PATH, BBS_BBS_DP, dev_path_bss_bss}, {
- END_DEVICE_PATH_TYPE, END_INSTANCE_DEVICE_PATH_SUBTYPE,
- dev_path_end_instance}, {
- 0, 0, NULL}
-};
-
-static int __device_path_to_str(struct string *str, struct efi_device_path *dev_path)
-{
- struct efi_device_path *dev_path_node;
- void (*dump_node) (struct string *, void *);
- int i;
-
- dev_path = unpack_device_path(dev_path);
-
- dev_path_node = dev_path;
- while (!is_device_path_end(dev_path_node)) {
- dump_node = NULL;
- for (i = 0; dev_path_table[i].Function; i += 1) {
-
- if (device_path_type(dev_path_node) ==
- dev_path_table[i].type
- && dev_path_node->sub_type ==
- dev_path_table[i].sub_type) {
- dump_node = dev_path_table[i].Function;
- break;
- }
- }
-
- if (!dump_node)
- dump_node = dev_path_node_unknown;
-
- if (str->len && dump_node != dev_path_end_instance)
- cprintf(str, "/");
-
- dump_node(str, dev_path_node);
-
- dev_path_node = next_device_path_node(dev_path_node);
- }
-
- return 0;
-}
-
-char *device_path_to_str(struct efi_device_path *dev_path)
-{
- struct string str = {};
-
- __device_path_to_str(&str, dev_path);
-
- str.str = malloc(str.len + 1);
- if (!str.str)
- return NULL;
-
- str.len = 0;
-
- __device_path_to_str(&str, dev_path);
-
- return str.str;
-}
-
-u8 device_path_to_type(struct efi_device_path *dev_path)
-{
- struct efi_device_path *dev_path_next;
-
- dev_path = unpack_device_path(dev_path);
- dev_path_next = next_device_path_node(dev_path);
-
- while (!is_device_path_end(dev_path_next)) {
- dev_path = dev_path_next;
- dev_path_next = next_device_path_node(dev_path);
- }
-
- return device_path_type(dev_path);
-}
-
-char *device_path_to_partuuid(struct efi_device_path *dev_path)
-{
- struct efi_device_path *dev_path_node;
- struct harddrive_device_path *hd;
- char *str = NULL;;
-
- dev_path = unpack_device_path(dev_path);
-
- for (dev_path_node = dev_path; !is_device_path_end(dev_path_node);
- dev_path_node = next_device_path_node(dev_path_node)) {
-
- if (device_path_type(dev_path_node) != MEDIA_DEVICE_PATH)
- continue;
-
- if (dev_path_node->sub_type != MEDIA_HARDDRIVE_DP)
- continue;
-
- hd = (struct harddrive_device_path *)dev_path_node;
-
- if (hd->signature_type != SIGNATURE_TYPE_GUID)
- continue;
-
- str = xasprintf("%pUl", (efi_guid_t *)&(hd->signature[0]));
- break;
- }
-
- return str;
-}
-
diff --git a/common/efi-guid.c b/common/efi-guid.c
deleted file mode 100644
index 2bf2395e85..0000000000
--- a/common/efi-guid.c
+++ /dev/null
@@ -1,93 +0,0 @@
-#include <common.h>
-#include <efi.h>
-
-efi_guid_t efi_file_info_id = EFI_FILE_INFO_GUID;
-efi_guid_t efi_simple_file_system_protocol_guid = EFI_SIMPLE_FILE_SYSTEM_GUID;
-efi_guid_t efi_device_path_protocol_guid = EFI_DEVICE_PATH_PROTOCOL_GUID;
-efi_guid_t efi_loaded_image_protocol_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
-efi_guid_t efi_unknown_device_guid = EFI_UNKNOWN_DEVICE_GUID;
-efi_guid_t efi_null_guid = EFI_NULL_GUID;
-efi_guid_t efi_global_variable_guid = EFI_GLOBAL_VARIABLE_GUID;
-efi_guid_t efi_block_io_protocol_guid = EFI_BLOCK_IO_PROTOCOL_GUID;
-efi_guid_t efi_barebox_vendor_guid = EFI_BAREBOX_VENDOR_GUID;
-efi_guid_t efi_systemd_vendor_guid = EFI_SYSTEMD_VENDOR_GUID;
-
-#define EFI_GUID_STRING(guid, short, long) do { \
- if (!efi_guidcmp(guid, *g)) \
- return long; \
- } while(0)
-
-const char *efi_guid_string(efi_guid_t *g)
-{
- EFI_GUID_STRING(EFI_NULL_GUID, "NULL", "NULL GUID");
- EFI_GUID_STRING(EFI_MPS_TABLE_GUID, "MPS Table", "MPS Table GUID in EFI System Table");
- EFI_GUID_STRING(EFI_ACPI_TABLE_GUID, "ACPI Table", "ACPI 1.0 Table GUID in EFI System Table");
- EFI_GUID_STRING(EFI_ACPI_20_TABLE_GUID, "ACPI 2.0 Table", "ACPI 2.0 Table GUID in EFI System Table");
- EFI_GUID_STRING(EFI_SMBIOS_TABLE_GUID, "SMBIOS Table", "SMBIOS Table GUID in EFI System Table");
- EFI_GUID_STRING(EFI_SAL_SYSTEM_TABLE_GUID, "SAL System Table", "SAL System Table GUID in EFI System Table");
- EFI_GUID_STRING(EFI_HCDP_TABLE_GUID, "HDCP Table", "HDCP Table GUID in EFI System Table");
- EFI_GUID_STRING(EFI_UGA_IO_PROTOCOL_GUID, "UGA Protocol", "EFI 1.1 UGA Protocol");
- EFI_GUID_STRING(EFI_GLOBAL_VARIABLE_GUID, "Efi", "Efi Variable GUID");
- EFI_GUID_STRING(EFI_UV_SYSTEM_TABLE_GUID, "SAL System Table", "SAL System Table GUID in EFI System Table");
- EFI_GUID_STRING(EFI_LINUX_EFI_CRASH_GUID, "Linux EFI Crash", "Linux EFI Crash GUID");
- EFI_GUID_STRING(EFI_LOADED_IMAGE_PROTOCOL_GUID, "LoadedImage Protocol", "EFI 1.0 Loaded Image Protocol");
- EFI_GUID_STRING(EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID, "EFI Graphics Output Protocol", "UEFI Graphics Output Protocol");
- EFI_GUID_STRING(EFI_UGA_PROTOCOL_GUID, "UGA Draw Protocol", "EFI 1.1 UGA Draw Protocol");
- EFI_GUID_STRING(EFI_UGA_IO_PROTOCOL_GUID, "UGA Protocol", "EFI 1.1 UGA Protocol");
- EFI_GUID_STRING(EFI_PCI_IO_PROTOCOL_GUID, "PCI IO Protocol", "EFI 1.1 PCI IO Protocol");
- EFI_GUID_STRING(EFI_USB_IO_PROTOCOL_GUID, "USB IO Protocol", "EFI 1.0 USB IO Protocol");
- EFI_GUID_STRING(EFI_FILE_INFO_GUID, "File Info", "EFI File Infom");
- EFI_GUID_STRING(EFI_SIMPLE_FILE_SYSTEM_GUID, "Filesystem", "EFI 1.0 Simple FileSystem");
- EFI_GUID_STRING(EFI_DEVICE_TREE_GUID, "Device Tree", "EFI Device Tree GUID");
- EFI_GUID_STRING(EFI_DEVICE_PATH_PROTOCOL_GUID, "Device Path Protocol", "EFI 1.0 Device Path protocol");
- EFI_GUID_STRING(EFI_SIMPLE_NETWORK_PROTOCOL_GUID, "Simple Network Protocol", "EFI 1.0 Simple Network Protocol");
- EFI_GUID_STRING(EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID, "Filesystem Protocol", "EFI 1.0 Simple FileSystem Protocol");
- EFI_GUID_STRING(EFI_UNKNOWN_DEVICE_GUID, "Efi Unknown Device", "Efi Unknown Device GUID");
- EFI_GUID_STRING(EFI_BLOCK_IO_PROTOCOL_GUID, "BlockIo Protocol", "EFI 1.0 Block IO protocol");
-
- EFI_GUID_STRING(EFI_FIRMWARE_VOLUME2_PROTOCOL_GUID, "FirmwareVolume2Protocol", "Efi FirmwareVolume2Protocol");
- EFI_GUID_STRING(EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL_GUID, "FirmwareVolumeBlock Protocol", "Firmware Volume Block protocol");
- EFI_GUID_STRING(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GUID, "PciRootBridgeIo Protocol", "EFI 1.1 Pci Root Bridge IO Protocol");
- EFI_GUID_STRING(EFI_ISA_ACPI_PROTOCOL_GUID, "ISA Acpi Protocol", "ISA Acpi Protocol");
- EFI_GUID_STRING(EFI_ISA_IO_PROTOCOL_GUID, "ISA IO Protocol", "ISA IO Protocol");
- EFI_GUID_STRING(EFI_STANDARD_ERROR_DEVICE_GUID, "Standard Error Device Guid", "EFI Standard Error Device Guid");
- EFI_GUID_STRING(EFI_CONSOLE_OUT_DEVICE_GUID, "Console Out Device Guid", "EFI Console Out Device Guid");
- EFI_GUID_STRING(EFI_CONSOLE_IN_DEVICE_GUID, "Console In Device Guid", "EFI Console In Device Guid");
- EFI_GUID_STRING(EFI_SIMPLE_TEXT_OUT_PROTOCOL_GUID, "Simple Text Out Protocol", "EFI 1.0 Simple Text Out Protocol");
- EFI_GUID_STRING(EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID, "Simple Text Input Ex Protocol", "UEFI 2.1 Simple Text Input Ex Protocol");
- EFI_GUID_STRING(EFI_SIMPLE_TEXT_IN_PROTOCOL_GUID, "Simple Text In Protocol", "EFI 1.0 Simple Text In Protocol");
- EFI_GUID_STRING(EFI_DISK_IO_PROTOCOL_GUID, "DiskIo Protocol", "EFI 1.0 Disk IO Protocol");
- EFI_GUID_STRING(EFI_IDE_CONTROLLER_INIT_PROTOCOL_GUID, "IDE Controller Init Protocol", "Platform IDE Init Protocol");
- EFI_GUID_STRING(EFI_DISK_INFO_PROTOCOL_GUID, "Disk Info Protocol", "Disk Info Protocol");
- EFI_GUID_STRING(EFI_SERIAL_IO_PROTOCOL_GUID, "SerialIo Protocol", "EFI 1.0 Serial IO Protocol");
- EFI_GUID_STRING(EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL_GUID, "Bus Specific Driver Override Protocol", "EFI 1.1 Bus Specific Driver Override Protocol");
- EFI_GUID_STRING(EFI_LOAD_FILE2_PROTOCOL_GUID, "LoadFile2 Protocol", "EFI Load File 2 Protocol");
- EFI_GUID_STRING(EFI_MTFTP4_SERVICE_BINDING_PROTOCOL_GUID, "MTFTP4 Service Binding Protocol", "MTFTP4 Service Binding Protocol");
- EFI_GUID_STRING(EFI_DHCP4_PROTOCOL_GUID, "DHCP4 Protocol", "DHCP4 Protocol");
- EFI_GUID_STRING(EFI_UDP4_SERVICE_BINDING_PROTOCOL_GUID, "UDP4 Service Binding Protocol", "UDP4 Service Binding Protocol");
- EFI_GUID_STRING(EFI_TCP4_SERVICE_BINDING_PROTOCOL_GUID, "TCP4 Service Binding Protocol", "TCP4 Service Binding Protocol");
- EFI_GUID_STRING(EFI_IP4_SERVICE_BINDING_PROTOCOL_GUID, "IP4 Service Binding Protocol", "IP4 Service Binding Protocol");
- EFI_GUID_STRING(EFI_IP4_CONFIG_PROTOCOL_GUID, "Ip4Config Protocol", "Ip4Config Protocol");
- EFI_GUID_STRING(EFI_ARP_SERVICE_BINDING_PROTOCOL_GUID, "ARP Service Binding Protocol", "ARP Service Binding Protocol");
- EFI_GUID_STRING(EFI_MANAGED_NETWORK_SERVICE_BINDING_PROTOCOL_GUID, "Managed Network Service Binding Protocol", "Managed Network Service Binding Protocol");
- EFI_GUID_STRING(EFI_VLAN_CONFIG_PROTOCOL_GUID, "VlanConfig Protocol", "VlanConfig Protocol");
- EFI_GUID_STRING(EFI_HII_CONFIG_ACCESS_PROTOCOL_GUID, "HII Config Access Protocol", "HII Config Access 2.1 protocol");
- EFI_GUID_STRING(LOAD_FILE_PROTOCOL_GUID, "LoadFile Protocol", "EFI 1.0 Load File Protocol");
- EFI_GUID_STRING(EFI_COMPONENT_NAME2_PROTOCOL_GUID, "Component Name2 Protocol", "UEFI 2.0 Component Name2 Protocol");
- EFI_GUID_STRING(EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_GUID_31, "Network Interface Identifier Protocol_31", "EFI1.1 Network Interface Identifier Protocol");
- EFI_GUID_STRING(EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_GUID, "Network Interface Identifier Protocol", "EFI Network Interface Identifier Protocol");
- EFI_GUID_STRING(EFI_TIMESTAMP_PROTOCOL_GUID, "Timestamp", "Timestamp");
-
- /* TPM 1.2 */
- EFI_GUID_STRING( EFI_TCG_PROTOCOL_GUID, "TcgService", "TCGServices Protocol");
- /* TPM 2.0 */
- EFI_GUID_STRING( EFI_TCG2_PROTOCOL_GUID, "Tcg2Service", "TCG2Services Protocol");
-
- /* File */
- EFI_GUID_STRING(EFI_IDEBUSDXE_INF_GUID, "IdeBusDxe.inf", "EFI IdeBusDxe.inf File GUID");
- EFI_GUID_STRING(EFI_TERMINALDXE_INF_GUID, "TerminalDxe.inf", "EFI TerminalDxe.inf File GUID");
- EFI_GUID_STRING(EFI_ISCSIDXE_INF_GUID, "IScsiDxe.inf", "EFI IScsiDxe.inf File GUID");
- EFI_GUID_STRING(EFI_VLANCONFIGDXE_INF_GUID, "VlanConfigDxe.inf", "EFI VlanConfigDxe.inf File GUID");
-
- return "unknown";
-}
diff --git a/common/efi/Makefile b/common/efi/Makefile
deleted file mode 100644
index d746fabe21..0000000000
--- a/common/efi/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-obj-y += efi.o
-obj-y += efi-image.o
-bbenv-y += env-efi
-obj-$(CONFIG_CMD_IOMEM) += efi-iomem.o
diff --git a/common/efi/efi-image.c b/common/efi/efi-image.c
deleted file mode 100644
index bd1c58438e..0000000000
--- a/common/efi/efi-image.c
+++ /dev/null
@@ -1,289 +0,0 @@
-/*
- * efi-image.c - barebox EFI payload support
- *
- * Copyright (c) 2014 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#include <clock.h>
-#include <common.h>
-#include <linux/sizes.h>
-#include <memory.h>
-#include <command.h>
-#include <magicvar.h>
-#include <init.h>
-#include <driver.h>
-#include <io.h>
-#include <efi.h>
-#include <malloc.h>
-#include <string.h>
-#include <linux/err.h>
-#include <boot.h>
-#include <bootm.h>
-#include <fs.h>
-#include <libfile.h>
-#include <binfmt.h>
-#include <wchar.h>
-#include <efi/efi.h>
-#include <efi/efi-device.h>
-
-struct linux_kernel_header {
- /* first sector of the image */
- uint8_t code1[0x0020];
- uint16_t cl_magic; /**< Magic number 0xA33F */
- uint16_t cl_offset; /**< The offset of command line */
- uint8_t code2[0x01F1 - 0x0020 - 2 - 2];
- uint8_t setup_sects; /**< The size of the setup in sectors */
- uint16_t root_flags; /**< If the root is mounted readonly */
- uint16_t syssize; /**< obsolete */
- uint16_t swap_dev; /**< obsolete */
- uint16_t ram_size; /**< obsolete */
- uint16_t vid_mode; /**< Video mode control */
- uint16_t root_dev; /**< Default root device number */
- uint16_t boot_flag; /**< 0xAA55 magic number */
-
- /* second sector of the image */
- uint16_t jump; /**< Jump instruction (this is code!) */
- uint32_t header; /**< Magic signature "HdrS" */
- uint16_t version; /**< Boot protocol version supported */
- uint32_t realmode_swtch; /**< Boot loader hook */
- uint16_t start_sys; /**< The load-low segment (obsolete) */
- uint16_t kernel_version; /**< Points to kernel version string */
- uint8_t type_of_loader; /**< Boot loader identifier */
- uint8_t loadflags; /**< Boot protocol option flags */
- uint16_t setup_move_size; /**< Move to high memory size */
- uint32_t code32_start; /**< Boot loader hook */
- uint32_t ramdisk_image; /**< initrd load address */
- uint32_t ramdisk_size; /**< initrd size */
- uint32_t bootsect_kludge; /**< obsolete */
- uint16_t heap_end_ptr; /**< Free memory after setup end */
- uint8_t ext_loader_ver; /**< boot loader's extension of the version number */
- uint8_t ext_loader_type; /**< boot loader's extension of its type */
- uint32_t cmd_line_ptr; /**< Points to the kernel command line */
- uint32_t initrd_addr_max; /**< Highest address for initrd */
- uint32_t kernel_alignment; /**< Alignment unit required by the kernel */
- uint8_t relocatable_kernel; /** */
- uint8_t min_alignment; /** */
- uint16_t xloadflags; /** */
- uint32_t cmdline_size; /** */
- uint32_t hardware_subarch; /** */
- uint64_t hardware_subarch_data; /** */
- uint32_t payload_offset; /** */
- uint32_t payload_length; /** */
- uint64_t setup_data; /** */
- uint64_t pref_address; /** */
- uint32_t init_size; /** */
- uint32_t handover_offset; /** */
-} __attribute__ ((packed));
-
-static int efi_load_image(const char *file, efi_loaded_image_t **loaded_image,
- efi_handle_t *h)
-{
- void *exe;
- size_t size;
- efi_handle_t handle;
- efi_status_t efiret = EFI_SUCCESS;
-
- exe = read_file(file, &size);
- if (!exe)
- return -EINVAL;
-
- efiret = BS->load_image(false, efi_parent_image, efi_device_path, exe, size,
- &handle);
- if (EFI_ERROR(efiret)) {
- pr_err("failed to LoadImage: %s\n", efi_strerror(efiret));
- goto out;
- };
-
- efiret = BS->open_protocol(handle, &efi_loaded_image_protocol_guid,
- (void **)loaded_image,
- efi_parent_image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
- if (EFI_ERROR(efiret)) {
- pr_err("failed to OpenProtocol: %s\n", efi_strerror(efiret));
- BS->unload_image(handle);
- goto out;
- }
-
- *h = handle;
-out:
- memset(exe, 0, size);
- free(exe);
- return -efi_errno(efiret);
-}
-
-static int efi_execute_image(const char *file)
-{
- efi_handle_t handle;
- efi_loaded_image_t *loaded_image;
- efi_status_t efiret;
- struct linux_kernel_header *image_header;
- const char *options;
- bool is_driver;
- int ret;
-
- ret = efi_load_image(file, &loaded_image, &handle);
- if (ret)
- return ret;
-
- is_driver = (loaded_image->image_code_type == EFI_BOOT_SERVICES_CODE) ||
- (loaded_image->image_code_type == EFI_RUNTIME_SERVICES_CODE);
-
- image_header = (struct linux_kernel_header *)loaded_image->image_base;
- if (image_header->boot_flag == 0xAA55 &&
- image_header->header == 0x53726448) {
- pr_debug("Linux kernel detected. Adding bootargs.");
- options = linux_bootargs_get();
- pr_err("add linux options '%s'\n", options);
- loaded_image->load_options = xstrdup_char_to_wchar(options);
- loaded_image->load_options_size =
- (strlen(options) + 1) * sizeof(wchar_t);
- shutdown_barebox();
- }
-
- efiret = BS->start_image(handle, NULL, NULL);
- if (EFI_ERROR(efiret))
- pr_err("failed to StartImage: %s\n", efi_strerror(efiret));
-
- if (!is_driver)
- BS->unload_image(handle);
-
- efi_connect_all();
- efi_register_devices();
-
- return -efi_errno(efiret);
-}
-
-#ifdef __x86_64__
-typedef void(*handover_fn)(void *image, efi_system_table_t *table,
- struct linux_kernel_header *header);
-
-static inline void linux_efi_handover(efi_handle_t handle,
- struct linux_kernel_header *header)
-{
- handover_fn handover;
-
- handover = (handover_fn)((long)header->code32_start + 512 +
- header->handover_offset);
- handover(handle, efi_sys_table, header);
-}
-#else
-typedef void(*handover_fn)(VOID *image, EFI_SYSTEM_TABLE *table,
- struct SetupHeader *setup) __attribute__((regparm(0)));
-
-static inline void linux_efi_handover(efi_handle_t handle,
- struct linux_kernel_header *header)
-{
- handover_fn handover;
-
- handover = (handover_fn)((long)header->code32_start +
- header->handover_offset);
- handover(handle, efi_sys_table, header);
-}
-#endif
-
-static int do_bootm_efi(struct image_data *data)
-{
- void *tmp;
- void *initrd = NULL;
- size_t size;
- efi_handle_t handle;
- int ret;
- const char *options;
- efi_loaded_image_t *loaded_image;
- struct linux_kernel_header *image_header, *boot_header;
-
- ret = efi_load_image(data->os_file, &loaded_image, &handle);
- if (ret)
- return ret;
-
- image_header = (struct linux_kernel_header *)loaded_image->image_base;
-
- if (image_header->boot_flag != 0xAA55 ||
- image_header->header != 0x53726448 ||
- image_header->version < 0x20b ||
- !image_header->relocatable_kernel) {
- pr_err("Not a valid kernel image!\n");
- BS->unload_image(handle);
- return -EINVAL;
- }
-
- boot_header = xmalloc(0x4000);
- memset(boot_header, 0, 0x4000);
- memcpy(boot_header, image_header, sizeof(*image_header));
-
- boot_header->type_of_loader = 0xff;
-
- if (data->initrd_file) {
- tmp = read_file(data->initrd_file, &size);
- initrd = xmemalign(PAGE_SIZE, PAGE_ALIGN(size));
- memcpy(initrd, tmp, size);
- memset(initrd + size, 0, PAGE_ALIGN(size) - size);
- free(tmp);
- boot_header->ramdisk_image = (uint64_t)initrd;
- boot_header->ramdisk_size = PAGE_ALIGN(size);
- }
-
- options = linux_bootargs_get();
- boot_header->cmd_line_ptr = (uint64_t)options;
- boot_header->cmdline_size = strlen(options);
-
- boot_header->code32_start = (uint64_t)loaded_image->image_base +
- (image_header->setup_sects+1) * 512;
-
- if (bootm_verbose(data)) {
- printf("\nStarting kernel at 0x%p", loaded_image->image_base);
- if (data->initrd_file)
- printf(", initrd at 0x%08x",
- boot_header->ramdisk_image);
- printf("...\n");
- }
-
- if (data->dryrun) {
- BS->unload_image(handle);
- free(boot_header);
- free(initrd);
- return 0;
- }
-
- efi_set_variable_usec("LoaderTimeExecUSec", &efi_systemd_vendor_guid,
- get_time_ns()/1000);
-
- shutdown_barebox();
- linux_efi_handover(handle, boot_header);
-
- return 0;
-}
-
-static struct image_handler efi_handle_tr = {
- .name = "EFI Application",
- .bootm = do_bootm_efi,
- .filetype = filetype_exe,
-};
-
-static int efi_execute(struct binfmt_hook *b, char *file, int argc, char **argv)
-{
- return efi_execute_image(file);
-}
-
-static struct binfmt_hook binfmt_efi_hook = {
- .type = filetype_exe,
- .hook = efi_execute,
-};
-
-static int efi_register_image_handler(void)
-{
- register_image_handler(&efi_handle_tr);
- binfmt_register(&binfmt_efi_hook);
-
- return 0;
-}
-late_initcall(efi_register_image_handler);
diff --git a/common/efi/efi-iomem.c b/common/efi/efi-iomem.c
deleted file mode 100644
index e223c595c4..0000000000
--- a/common/efi/efi-iomem.c
+++ /dev/null
@@ -1,175 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-// Copyright (c) 2019 Ahmad Fatoum, Pengutronix
-
-#define pr_fmt(fmt) "efi-iomem: " fmt
-
-#include <common.h>
-#include <init.h>
-#include <efi.h>
-#include <efi/efi.h>
-#include <memory.h>
-#include <linux/sizes.h>
-
-static int efi_parse_mmap(struct efi_memory_desc *desc)
-{
- struct resource *res;
- u32 flags;
- const char *name;
- char *fullname;
- resource_size_t va_base, va_size;
- int ret = 0;
-
- va_size = desc->npages * SZ_4K;
- if (!va_size)
- return 0;
-
- /* XXX At least OVMF doesn't populate ->virt_start and leaves it at zero
- * for all mapping. Thus assume a 1:1 mapping and ignore virt_start
- */
- va_base = desc->phys_start;
-
- switch (desc->type) {
- case EFI_RESERVED_TYPE:
- if (!IS_ENABLED(DEBUG))
- return 0;
- name = "reserved";
- flags = IORESOURCE_MEM | IORESOURCE_DISABLED;
- break;
- case EFI_LOADER_CODE:
- return barebox_add_memory_bank("loader code", va_base, va_size);
- case EFI_LOADER_DATA:
- return barebox_add_memory_bank("loader data", va_base, va_size);
- case EFI_BOOT_SERVICES_CODE:
- if (!IS_ENABLED(DEBUG))
- return 0;
- name = "boot services code";
- flags = IORESOURCE_MEM | IORESOURCE_READONLY;
- break;
- case EFI_BOOT_SERVICES_DATA:
- if (!IS_ENABLED(DEBUG))
- return 0;
- name = "boot services data";
- flags = IORESOURCE_MEM;
- break;
- case EFI_RUNTIME_SERVICES_CODE:
- if (!IS_ENABLED(DEBUG))
- return 0;
- name = "runtime services code";
- flags = IORESOURCE_MEM | IORESOURCE_READONLY;
- break;
- case EFI_RUNTIME_SERVICES_DATA:
- if (!IS_ENABLED(DEBUG))
- return 0;
- name = "runtime services data";
- flags = IORESOURCE_MEM;
- break;
- case EFI_CONVENTIONAL_MEMORY:
- if (!IS_ENABLED(DEBUG))
- return 0;
- name = "conventional memory";
- flags = IORESOURCE_MEM | IORESOURCE_PREFETCH | IORESOURCE_CACHEABLE;
- break;
- case EFI_UNUSABLE_MEMORY:
- if (!IS_ENABLED(DEBUG))
- return 0;
- name = "unusable";
- flags = IORESOURCE_MEM | IORESOURCE_DISABLED;
- break;
- case EFI_ACPI_RECLAIM_MEMORY:
- if (!IS_ENABLED(DEBUG))
- return 0;
- name = "ACPI reclaim memory";
- flags = IORESOURCE_MEM | IORESOURCE_READONLY;
- break;
- case EFI_ACPI_MEMORY_NVS:
- if (!IS_ENABLED(DEBUG))
- return 0;
- name = "ACPI NVS memory";
- flags = IORESOURCE_MEM | IORESOURCE_READONLY;
- break;
- case EFI_MEMORY_MAPPED_IO:
- if (!IS_ENABLED(DEBUG))
- return 0;
- name = "MMIO";
- flags = IORESOURCE_MEM;
- break;
- case EFI_MEMORY_MAPPED_IO_PORT_SPACE:
- if (!IS_ENABLED(DEBUG))
- return 0;
- name = "MMIOPORT";
- flags = IORESOURCE_IO;
- break;
- case EFI_PAL_CODE:
- if (!IS_ENABLED(DEBUG))
- return 0;
- name = "PAL code";
- flags = IORESOURCE_MEM | IORESOURCE_ROM_BIOS_COPY;
- break;
- default:
- if (!(desc->type & (1U << 31))) {
- pr_warn("illegal memory type = %u >= %u\n",
- desc->type, EFI_MAX_MEMORY_TYPE);
- return -EINVAL;
- }
-
- if (!IS_ENABLED(DEBUG))
- return 0;
-
- name = "vendor reserved";
- flags = IORESOURCE_MEM | IORESOURCE_ROM_BIOS_COPY;
- }
-
- fullname = xasprintf("%s@%llx", name, desc->phys_start);
-
- pr_debug("%s: (0x%llx+0x%llx)\n", fullname, va_base, va_size);
-
- res = request_iomem_region(fullname, va_base, va_base + va_size - 1);
- if (IS_ERR(res)) {
- ret = PTR_ERR(res);
- goto out;
- }
-
- res->flags |= flags;
-
-out:
- free(fullname);
- return ret;
-}
-
-static int efi_barebox_populate_mmap(void)
-{
- void *desc;
- u8 *mmap_buf = NULL;
- efi_status_t efiret;
- size_t mmap_size;
- size_t mapkey;
- size_t descsz;
- u32 descver;
- int ret = 0;
-
- mmap_size = sizeof(struct efi_memory_desc);
-
- do {
- mmap_buf = xrealloc(mmap_buf, mmap_size);
- efiret = BS->get_memory_map(&mmap_size, mmap_buf,
- &mapkey, &descsz, &descver);
- } while (efiret == EFI_BUFFER_TOO_SMALL);
-
- if (EFI_ERROR(efiret)) {
- ret = -efi_errno(efiret);
- goto out;
- }
-
- if (descver != 1) {
- ret = -ENOSYS;
- goto out;
- }
-
- for (desc = mmap_buf; (u8 *)desc < &mmap_buf[mmap_size]; desc += descsz)
- efi_parse_mmap(desc);
-
-out:
- free(mmap_buf);
- return ret;
-}
-mem_initcall(efi_barebox_populate_mmap);
diff --git a/common/efi/efi.c b/common/efi/efi.c
deleted file mode 100644
index 7f12342cf9..0000000000
--- a/common/efi/efi.c
+++ /dev/null
@@ -1,481 +0,0 @@
-/*
- * efi.c - barebox EFI payload support
- *
- * Copyright (c) 2014 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/linkage.h>
-#include <common.h>
-#include <linux/sizes.h>
-#include <memory.h>
-#include <clock.h>
-#include <command.h>
-#include <magicvar.h>
-#include <init.h>
-#include <restart.h>
-#include <poweroff.h>
-#include <driver.h>
-#include <platform_data/serial-ns16550.h>
-#include <io.h>
-#include <efi.h>
-#include <malloc.h>
-#include <string.h>
-#include <linux/err.h>
-#include <boot.h>
-#include <fs.h>
-#include <binfmt.h>
-#include <wchar.h>
-#include <envfs.h>
-#include <efi.h>
-#include <efi/efi.h>
-#include <efi/efi-device.h>
-#include <libfile.h>
-#include <state.h>
-#include <bbu.h>
-
-efi_runtime_services_t *RT;
-efi_boot_services_t *BS;
-efi_system_table_t *efi_sys_table;
-efi_handle_t efi_parent_image;
-struct efi_device_path *efi_device_path;
-efi_loaded_image_t *efi_loaded_image;
-
-void *efi_get_variable(char *name, efi_guid_t *vendor, int *var_size)
-{
- efi_status_t efiret;
- void *buf;
- unsigned long size = 0;
- s16 *name16 = xstrdup_char_to_wchar(name);
-
- efiret = RT->get_variable(name16, vendor, NULL, &size, NULL);
-
- if (EFI_ERROR(efiret) && efiret != EFI_BUFFER_TOO_SMALL) {
- buf = ERR_PTR(-efi_errno(efiret));
- goto out;
- }
-
- buf = malloc(size);
- if (!buf) {
- buf = ERR_PTR(-ENOMEM);
- goto out;
- }
-
- efiret = RT->get_variable(name16, vendor, NULL, &size, buf);
- if (EFI_ERROR(efiret)) {
- free(buf);
- buf = ERR_PTR(-efi_errno(efiret));
- goto out;
- }
-
- if (var_size)
- *var_size = size;
-
-out:
- free(name16);
-
- return buf;
-}
-
-int efi_set_variable(char *name, efi_guid_t *vendor, uint32_t attributes,
- void *buf, unsigned long size)
-{
- efi_status_t efiret = EFI_SUCCESS;
- s16 *name16 = xstrdup_char_to_wchar(name);
-
- efiret = RT->set_variable(name16, vendor, attributes, size, buf);
-
- free(name16);
-
- return -efi_errno(efiret);
-}
-
-int efi_set_variable_usec(char *name, efi_guid_t *vendor, uint64_t usec)
-{
- char buf[20];
- wchar_t buf16[40];
-
- snprintf(buf, sizeof(buf), "%lld", usec);
- strcpy_char_to_wchar(buf16, buf);
-
- return efi_set_variable(name, vendor,
- EFI_VARIABLE_BOOTSERVICE_ACCESS |
- EFI_VARIABLE_RUNTIME_ACCESS, buf16,
- (strlen(buf)+1) * sizeof(wchar_t));
-}
-
-struct efi_boot {
- u32 attributes;
- u16 file_path_len;
- char *description;
- struct efi_device_path *path;
- void *binary;
-};
-
-static struct efi_boot *efi_get_boot(int num)
-{
- struct efi_boot *boot = xzalloc(sizeof(*boot));
- void *buf, *ptr;
- int size;
- char *name;
-
- name = xasprintf("Boot%04X", num);
-
- buf = efi_get_global_var(name, &size);
-
- free(name);
-
- if (IS_ERR(buf)) {
- free(boot);
- return NULL;
- }
-
- ptr = buf;
-
- boot->attributes = *(u32 *)ptr;
-
- ptr += sizeof(u32);
-
- boot->file_path_len = *(u16 *)ptr;
-
- ptr += sizeof(u16);
-
- boot->description = xstrdup_wchar_to_char(ptr);
-
- ptr += (strlen(boot->description) + 1) * 2;
-
- printf("description: %s\n", boot->description);
-
- boot->path = memdup(ptr, boot->file_path_len);
-
- printf("path: %s\n", device_path_to_str(boot->path));
-
- return boot;
-}
-
-static int misc_init(void)
-{
- efi_get_boot(1);
- efi_get_boot(2);
- efi_get_boot(3);
-
- return 0;
-}
-late_initcall(misc_init);
-
-const char *efi_strerror(efi_status_t err)
-{
- const char *str;
-
- switch (err) {
- case EFI_SUCCESS: str = "Success"; break;
- case EFI_LOAD_ERROR: str = "Load Error"; break;
- case EFI_INVALID_PARAMETER: str = "Invalid Parameter"; break;
- case EFI_UNSUPPORTED: str = "Unsupported"; break;
- case EFI_BAD_BUFFER_SIZE: str = "Bad Buffer Size"; break;
- case EFI_BUFFER_TOO_SMALL: str = "Buffer Too Small"; break;
- case EFI_NOT_READY: str = "Not Ready"; break;
- case EFI_DEVICE_ERROR: str = "Device Error"; break;
- case EFI_WRITE_PROTECTED: str = "Write Protected"; break;
- case EFI_OUT_OF_RESOURCES: str = "Out of Resources"; break;
- case EFI_VOLUME_CORRUPTED: str = "Volume Corrupt"; break;
- case EFI_VOLUME_FULL: str = "Volume Full"; break;
- case EFI_NO_MEDIA: str = "No Media"; break;
- case EFI_MEDIA_CHANGED: str = "Media changed"; break;
- case EFI_NOT_FOUND: str = "Not Found"; break;
- case EFI_ACCESS_DENIED: str = "Access Denied"; break;
- case EFI_NO_RESPONSE: str = "No Response"; break;
- case EFI_NO_MAPPING: str = "No mapping"; break;
- case EFI_TIMEOUT: str = "Time out"; break;
- case EFI_NOT_STARTED: str = "Not started"; break;
- case EFI_ALREADY_STARTED: str = "Already started"; break;
- case EFI_ABORTED: str = "Aborted"; break;
- case EFI_ICMP_ERROR: str = "ICMP Error"; break;
- case EFI_TFTP_ERROR: str = "TFTP Error"; break;
- case EFI_PROTOCOL_ERROR: str = "Protocol Error"; break;
- case EFI_INCOMPATIBLE_VERSION: str = "Incompatible Version"; break;
- case EFI_SECURITY_VIOLATION: str = "Security Violation"; break;
- case EFI_CRC_ERROR: str = "CRC Error"; break;
- case EFI_END_OF_MEDIA: str = "End of Media"; break;
- case EFI_END_OF_FILE: str = "End of File"; break;
- case EFI_INVALID_LANGUAGE: str = "Invalid Language"; break;
- case EFI_COMPROMISED_DATA: str = "Compromised Data"; break;
- default: str = "unknown error";
- }
-
- return str;
-}
-
-int efi_errno(efi_status_t err)
-{
- int ret;
-
- switch (err) {
- case EFI_SUCCESS: ret = 0; break;
- case EFI_LOAD_ERROR: ret = EIO; break;
- case EFI_INVALID_PARAMETER: ret = EINVAL; break;
- case EFI_UNSUPPORTED: ret = ENOTSUPP; break;
- case EFI_BAD_BUFFER_SIZE: ret = EINVAL; break;
- case EFI_BUFFER_TOO_SMALL: ret = EINVAL; break;
- case EFI_NOT_READY: ret = EAGAIN; break;
- case EFI_DEVICE_ERROR: ret = EIO; break;
- case EFI_WRITE_PROTECTED: ret = EROFS; break;
- case EFI_OUT_OF_RESOURCES: ret = ENOMEM; break;
- case EFI_VOLUME_CORRUPTED: ret = EIO; break;
- case EFI_VOLUME_FULL: ret = ENOSPC; break;
- case EFI_NO_MEDIA: ret = ENOMEDIUM; break;
- case EFI_MEDIA_CHANGED: ret = ENOMEDIUM; break;
- case EFI_NOT_FOUND: ret = ENODEV; break;
- case EFI_ACCESS_DENIED: ret = EACCES; break;
- case EFI_NO_RESPONSE: ret = ETIMEDOUT; break;
- case EFI_NO_MAPPING: ret = EINVAL; break;
- case EFI_TIMEOUT: ret = ETIMEDOUT; break;
- case EFI_NOT_STARTED: ret = EINVAL; break;
- case EFI_ALREADY_STARTED: ret = EINVAL; break;
- case EFI_ABORTED: ret = EINTR; break;
- case EFI_ICMP_ERROR: ret = EINVAL; break;
- case EFI_TFTP_ERROR: ret = EINVAL; break;
- case EFI_PROTOCOL_ERROR: ret = EPROTO; break;
- case EFI_INCOMPATIBLE_VERSION: ret = EINVAL; break;
- case EFI_SECURITY_VIOLATION: ret = EINVAL; break;
- case EFI_CRC_ERROR: ret = EINVAL; break;
- case EFI_END_OF_MEDIA: ret = EINVAL; break;
- case EFI_END_OF_FILE: ret = EINVAL; break;
- case EFI_INVALID_LANGUAGE: ret = EINVAL; break;
- case EFI_COMPROMISED_DATA: ret = EINVAL; break;
- default: ret = EINVAL;
- }
-
- return ret;
-}
-
-static struct NS16550_plat ns16550_plat = {
- .clock = 115200 * 16,
-};
-
-static int efi_console_init(void)
-{
- barebox_set_model("barebox EFI payload");
-
- add_generic_device("efi-stdio", DEVICE_ID_SINGLE, NULL, 0 , 0, 0, NULL);
-
- add_ns16550_device(0, 0x3f8, 0x10, IORESOURCE_IO | IORESOURCE_MEM_8BIT,
- &ns16550_plat);
-
- return 0;
-}
-console_initcall(efi_console_init);
-
-static void __noreturn efi_restart_system(struct restart_handler *rst)
-{
- RT->reset_system(EFI_RESET_WARM, EFI_SUCCESS, 0, NULL);
-
- hang();
-}
-
-static void __noreturn efi_poweroff_system(struct poweroff_handler *handler)
-{
- shutdown_barebox();
- RT->reset_system(EFI_RESET_SHUTDOWN, EFI_SUCCESS, 0, NULL);
-
- hang();
-}
-
-static int restart_register_feature(void)
-{
- restart_handler_register_fn("efi", efi_restart_system);
- poweroff_handler_register_fn(efi_poweroff_system);
-
- return 0;
-}
-coredevice_initcall(restart_register_feature);
-
-extern char image_base[];
-extern initcall_t __barebox_initcalls_start[], __barebox_early_initcalls_end[],
- __barebox_initcalls_end[];
-
-static int efi_init(void)
-{
- char *env;
-
- defaultenv_append_directory(env_efi);
-
- env = xasprintf("/efivars/barebox-env-%pUl", &efi_barebox_vendor_guid);
- default_environment_path_set(env);
-
- return 0;
-}
-device_initcall(efi_init);
-
-asmlinkage efi_status_t efi_main(efi_handle_t, efi_system_table_t *);
-
-/**
- * efi-main - Entry point for EFI images
- */
-efi_status_t efi_main(efi_handle_t image, efi_system_table_t *sys_table)
-{
- efi_physical_addr_t mem;
- size_t memsize;
- efi_status_t efiret;
-
-#ifdef DEBUG
- sys_table->con_out->output_string(sys_table->con_out, L"barebox\n");
-#endif
-
- BS = sys_table->boottime;
-
- efi_parent_image = image;
- efi_sys_table = sys_table;
- RT = sys_table->runtime;
-
- efiret = BS->open_protocol(efi_parent_image, &efi_loaded_image_protocol_guid,
- (void **)&efi_loaded_image,
- efi_parent_image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
- if (!EFI_ERROR(efiret))
- BS->handle_protocol(efi_loaded_image->device_handle,
- &efi_device_path_protocol_guid, (void **)&efi_device_path);
-
- mem = 0x3fffffff;
- for (memsize = SZ_256M; memsize >= SZ_8M; memsize /= 2) {
- efiret = BS->allocate_pages(EFI_ALLOCATE_MAX_ADDRESS,
- EFI_LOADER_DATA,
- memsize/PAGE_SIZE, &mem);
- if (!EFI_ERROR(efiret))
- break;
- if (efiret != EFI_OUT_OF_RESOURCES)
- panic("failed to allocate malloc pool: %s\n",
- efi_strerror(efiret));
- }
- if (EFI_ERROR(efiret))
- panic("failed to allocate malloc pool: %s\n",
- efi_strerror(efiret));
- mem_malloc_init((void *)mem, (void *)mem + memsize - 1);
-
- start_barebox();
-
- return EFI_SUCCESS;
-}
-
-static int efi_core_init(void)
-{
- struct device_d *dev;
- int ret;
-
- dev = device_alloc("efi-cs", DEVICE_ID_SINGLE);
- ret = platform_device_register(dev);
- if (ret)
- return ret;
-
- dev = device_alloc("efi-wdt", DEVICE_ID_SINGLE);
- return platform_device_register(dev);
-}
-core_initcall(efi_core_init);
-
-static int efi_postcore_init(void)
-{
- char *uuid;
-
- efi_set_variable_usec("LoaderTimeInitUSec", &efi_systemd_vendor_guid,
- get_time_ns()/1000);
-
- uuid = device_path_to_partuuid(device_path_from_handle(
- efi_loaded_image->device_handle));
- if (uuid) {
- wchar_t *uuid16 = xstrdup_char_to_wchar(uuid);
- efi_set_variable("LoaderDevicePartUUID",
- &efi_systemd_vendor_guid,
- EFI_VARIABLE_BOOTSERVICE_ACCESS |
- EFI_VARIABLE_RUNTIME_ACCESS,
- uuid16, (strlen(uuid)+1) * sizeof(wchar_t));
- free(uuid);
- free(uuid16);
- }
-
- bbu_register_std_file_update("fat", 0, "/boot/EFI/BOOT/BOOTx64.EFI",
- filetype_exe);
-
- return 0;
-}
-postcore_initcall(efi_postcore_init);
-
-static int efi_late_init(void)
-{
- char *state_desc;
- int ret;
-
- if (!IS_ENABLED(CONFIG_STATE))
- return 0;
-
- state_desc = xasprintf("/boot/EFI/barebox/state.dtb");
-
- if (state_desc) {
- void *fdt;
- size_t size;
- struct device_node *root = NULL;
- struct device_node *np = NULL;
- struct state *state;
-
- fdt = read_file(state_desc, &size);
- if (!fdt) {
- pr_err("unable to read %s: %s\n", state_desc,
- strerror(errno));
- return -errno;
- }
-
- if (file_detect_type(fdt, size) != filetype_oftree) {
- pr_err("%s is not an oftree file.\n", state_desc);
- free(fdt);
- return -EINVAL;
- }
-
- root = of_unflatten_dtb(fdt, size);
-
- free(fdt);
-
- if (IS_ERR(root))
- return PTR_ERR(root);
-
- of_set_root_node(root);
-
- np = of_find_node_by_alias(root, "state");
-
- state = state_new_from_node(np, false);
- if (IS_ERR(state))
- return PTR_ERR(state);
-
- ret = state_load(state);
- if (ret)
- pr_warn("Failed to load persistent state, continuing with defaults, %d\n",
- ret);
-
- return 0;
- }
-
- return 0;
-}
-late_initcall(efi_late_init);
-
-static int do_efiexit(int argc, char *argv[])
-{
- return BS->exit(efi_parent_image, EFI_SUCCESS, 0, NULL);
-}
-
-BAREBOX_CMD_HELP_START(efiexit)
-BAREBOX_CMD_HELP_TEXT("Leave barebox and return to the calling EFI process\n")
-BAREBOX_CMD_HELP_END
-
-BAREBOX_CMD_START(efiexit)
- .cmd = do_efiexit,
- BAREBOX_CMD_DESC("Usage: efiexit")
- BAREBOX_CMD_GROUP(CMD_GRP_MISC)
- BAREBOX_CMD_HELP(cmd_efiexit_help)
-BAREBOX_CMD_END
diff --git a/common/efi/env-efi/network/eth0-discover b/common/efi/env-efi/network/eth0-discover
deleted file mode 100644
index 62c31a553c..0000000000
--- a/common/efi/env-efi/network/eth0-discover
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/bin/sh
-
-for i in /boot/network-drivers/*; do
- $i;
-done
diff --git a/common/elf.c b/common/elf.c
index af22be37e6..62f793010f 100644
--- a/common/elf.c
+++ b/common/elf.c
@@ -10,6 +10,7 @@
#include <libfile.h>
#include <memory.h>
#include <unistd.h>
+#include <zero_page.h>
#include <linux/fs.h>
#include <linux/list_sort.h>
@@ -59,14 +60,13 @@ static int request_elf_segment(struct elf_image *elf, void *phdr)
{
void *dst = (void *) (phys_addr_t) elf_phdr_p_paddr(elf, phdr);
int ret;
- u64 p_filesz = elf_phdr_p_filesz(elf, phdr);
u64 p_memsz = elf_phdr_p_memsz(elf, phdr);
/* we care only about PT_LOAD segments */
if (elf_phdr_p_type(elf, phdr) != PT_LOAD)
return 0;
- if (!p_filesz)
+ if (!p_memsz)
return 0;
if (dst < elf->low_addr)
@@ -74,9 +74,9 @@ static int request_elf_segment(struct elf_image *elf, void *phdr)
if (dst + p_memsz > elf->high_addr)
elf->high_addr = dst + p_memsz;
- pr_debug("Requesting segment 0x%p (%llu bytes)\n", dst, p_filesz);
+ pr_debug("Requesting segment 0x%p (%llu bytes)\n", dst, p_memsz);
- ret = elf_request_region(elf, (resource_size_t)dst, p_filesz, phdr);
+ ret = elf_request_region(elf, (resource_size_t)dst, p_memsz, phdr);
if (ret)
return ret;
@@ -101,47 +101,57 @@ static int elf_section_cmp(void *priv, struct list_head *a, struct list_head *b)
static int load_elf_to_memory(struct elf_image *elf)
{
void *dst;
- int ret, fd;
+ int ret = 0, fd = -1;
u64 p_filesz, p_memsz, p_offset;
struct elf_section *r;
struct list_head *list = &elf->list;
- fd = open(elf->filename, O_RDONLY);
- if (fd < 0) {
- pr_err("could not open: %s\n", errno_str());
- return -errno;
+ if (elf->filename) {
+ fd = open(elf->filename, O_RDONLY);
+ if (fd < 0) {
+ pr_err("could not open: %m\n");
+ return -errno;
+ }
}
+ zero_page_access();
+
list_for_each_entry(r, list, list) {
p_offset = elf_phdr_p_offset(elf, r->phdr);
p_filesz = elf_phdr_p_filesz(elf, r->phdr);
p_memsz = elf_phdr_p_memsz(elf, r->phdr);
dst = (void *) (phys_addr_t) elf_phdr_p_paddr(elf, r->phdr);
- ret = lseek(fd, p_offset, SEEK_SET);
- if (ret == -1) {
- pr_err("lseek at offset 0x%llx failed\n", p_offset);
- close(fd);
- return ret;
- }
-
pr_debug("Loading phdr offset 0x%llx to 0x%p (%llu bytes)\n",
p_offset, dst, p_filesz);
- if (read_full(fd, dst, p_filesz) < 0) {
- pr_err("could not read elf segment: %s\n",
- errno_str());
- close(fd);
- return -errno;
+ if (fd >= 0) {
+ ret = lseek(fd, p_offset, SEEK_SET);
+ if (ret == -1) {
+ pr_err("lseek at offset 0x%llx failed\n",
+ p_offset);
+ goto out;
+ }
+
+ if (read_full(fd, dst, p_filesz) < 0) {
+ pr_err("could not read elf segment: %m\n");
+ ret = -errno;
+ goto out;
+ }
+ } else {
+ memcpy(dst, elf->hdr_buf + p_offset, p_filesz);
}
if (p_filesz < p_memsz)
memset(dst + p_filesz, 0x00, p_memsz - p_filesz);
}
+out:
+ zero_page_faulting();
+
close(fd);
- return 0;
+ return ret >= 0 ? 0 : ret;
}
static int load_elf_image_segments(struct elf_image *elf)
@@ -202,6 +212,37 @@ static int elf_check_image(struct elf_image *elf, void *buf)
return 0;
}
+static void elf_init_struct(struct elf_image *elf)
+{
+ INIT_LIST_HEAD(&elf->list);
+ elf->low_addr = (void *) (unsigned long) -1;
+ elf->high_addr = 0;
+ elf->filename = NULL;
+}
+
+struct elf_image *elf_open_binary(void *buf)
+{
+ int ret;
+ struct elf_image *elf;
+
+ elf = calloc(1, sizeof(*elf));
+ if (!elf)
+ return ERR_PTR(-ENOMEM);
+
+ elf_init_struct(elf);
+
+ elf->hdr_buf = buf;
+ ret = elf_check_image(elf, buf);
+ if (ret) {
+ free(elf);
+ return ERR_PTR(-EINVAL);
+ }
+
+ elf->entry = elf_hdr_e_entry(elf, elf->hdr_buf);
+
+ return elf;
+}
+
static struct elf_image *elf_check_init(const char *filename)
{
int ret, fd;
@@ -213,20 +254,18 @@ static struct elf_image *elf_check_init(const char *filename)
if (!elf)
return ERR_PTR(-ENOMEM);
- INIT_LIST_HEAD(&elf->list);
- elf->low_addr = (void *) (unsigned long) -1;
- elf->high_addr = 0;
+ elf_init_struct(elf);
/* First pass is to read elf header only */
fd = open(filename, O_RDONLY);
if (fd < 0) {
- pr_err("could not open: %s\n", errno_str());
+ pr_err("could not open: %m\n");
ret = -errno;
goto err_free_elf;
}
if (read_full(fd, &hdr, sizeof(hdr)) < 0) {
- pr_err("could not read elf header: %s\n", errno_str());
+ pr_err("could not read elf header: %m\n");
close(fd);
ret = -errno;
goto err_free_elf;
@@ -254,13 +293,13 @@ static struct elf_image *elf_check_init(const char *filename)
*/
fd = open(filename, O_RDONLY);
if (fd < 0) {
- pr_err("could not open: %s\n", errno_str());
+ pr_err("could not open: %m\n");
ret = -errno;
goto err_free_hdr_buf;
}
if (read_full(fd, elf->hdr_buf, hdr_size) < 0) {
- pr_err("could not read elf program headers: %s\n", errno_str());
+ pr_err("could not read elf program headers: %m\n");
ret = -errno;
close(fd);
goto err_free_hdr_buf;
@@ -299,7 +338,10 @@ void elf_close(struct elf_image *elf)
{
elf_release_regions(elf);
- free(elf->hdr_buf);
- free(elf->filename);
+ if (elf->filename) {
+ free(elf->hdr_buf);
+ free(elf->filename);
+ }
+
free(elf);
}
diff --git a/common/env.c b/common/env.c
index 05add63f62..7a213cadb2 100644
--- a/common/env.c
+++ b/common/env.c
@@ -80,7 +80,7 @@ int env_push_context(void)
*/
int env_pop_context(void)
{
- struct env_context *c = context;
+ struct env_context *c;
if (context->parent) {
c = context->parent;
@@ -127,7 +127,7 @@ static const char *dev_getenv(const char *name)
{
const char *pos, *val, *dot, *varname;
char *devname;
- struct device_d *dev;
+ struct device *dev;
pos = name;
@@ -215,7 +215,7 @@ static int dev_setenv(const char *name, const char *val)
{
const char *pos, *dot, *varname;
char *devname;
- struct device_d *dev;
+ struct device *dev;
pos = name;
@@ -244,13 +244,12 @@ static int dev_setenv(const char *name, const char *val)
/**
* setenv - set environment variables
- * @_name - Variable name
+ * @name - Variable name
* @value - the value to set, empty string not handled specially
*
* Returns 0 for success and a negative error code otherwise
* Use unsetenv() to unset.
*/
-
int setenv(const char *_name, const char *value)
{
char *name = strdup(_name);
@@ -277,6 +276,35 @@ out:
}
EXPORT_SYMBOL(setenv);
+/**
+ * pr_setenv - set environment variables
+ * @name - Variable name
+ * @fmt - the format string to use
+ *
+ * Returns 0 for success and a negative error code otherwise
+ * Use unsetenv() to unset.
+ */
+int pr_setenv(const char *name, const char *fmt, ...)
+{
+ va_list ap;
+ int ret = 0;
+ char *value;
+ int len;
+
+ va_start(ap, fmt);
+ len = vasprintf(&value, fmt, ap);
+ va_end(ap);
+
+ if (len < 0)
+ return -ENOMEM;
+
+ ret = setenv(name, value);
+ free(value);
+
+ return ret;
+}
+EXPORT_SYMBOL(pr_setenv);
+
int export(const char *varname)
{
const char *val = getenv_raw(&context->local, varname);
@@ -315,19 +343,30 @@ const char *getenv_nonempty(const char *var)
}
EXPORT_SYMBOL(getenv_nonempty);
-int getenv_ull(const char *var , unsigned long long *val)
+static int getenv_ull_base(const char *var, int base, unsigned long long *val)
{
const char *valstr = getenv(var);
if (!valstr || !*valstr)
return -EINVAL;
- *val = simple_strtoull(valstr, NULL, 0);
+ *val = simple_strtoull(valstr, NULL, base);
return 0;
}
+
+int getenv_ull(const char *var , unsigned long long *val)
+{
+ return getenv_ull_base(var, 0, val);
+}
EXPORT_SYMBOL(getenv_ull);
+int getenv_ullx(const char *var , unsigned long long *val)
+{
+ return getenv_ull_base(var, 16, val);
+}
+EXPORT_SYMBOL(getenv_ullx);
+
int getenv_ul(const char *var , unsigned long *val)
{
const char *valstr = getenv(var);
diff --git a/common/envfs-core.c b/common/envfs-core.c
index 1898c1c8cb..20b3e647d3 100644
--- a/common/envfs-core.c
+++ b/common/envfs-core.c
@@ -12,6 +12,8 @@
* the default environment when building the barebox binary. So
* do not add any new barebox related functions here!
*/
+#define pr_fmt(fmt) "envfs: " fmt
+
#ifdef __BAREBOX__
#include <common.h>
#include <fs.h>
@@ -22,7 +24,8 @@
#include <environment.h>
#include <libfile.h>
#else
-# define errno_str(x) ("void")
+#define pr_info(fmt, ...) printf(pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_warn(fmt, ...) printf(pr_fmt(fmt), ##__VA_ARGS__)
#endif
static int dir_remove_action(const char *filename, struct stat *statbuf,
@@ -39,17 +42,17 @@ static int dir_remove_action(const char *filename, struct stat *statbuf,
int envfs_check_super(struct envfs_super *super, size_t *size)
{
if (ENVFS_32(super->magic) != ENVFS_MAGIC) {
- printf("envfs: no envfs (magic mismatch) - envfs never written?\n");
+ pr_info("no envfs (magic mismatch) - envfs never written?\n");
return -EIO;
}
if (crc32(0, super, sizeof(*super) - 4) != ENVFS_32(super->sb_crc)) {
- printf("wrong crc on env superblock\n");
+ pr_warn("wrong crc on env superblock\n");
return -EIO;
}
if (super->major < ENVFS_MAJOR)
- printf("envfs version %d.%d loaded into %d.%d\n",
+ pr_info("version %d.%d loaded into %d.%d\n",
super->major, super->minor,
ENVFS_MAJOR, ENVFS_MINOR);
@@ -64,7 +67,7 @@ int envfs_check_data(struct envfs_super *super, const void *buf, size_t size)
crc = crc32(0, buf, size);
if (crc != ENVFS_32(super->crc)) {
- printf("wrong crc on env\n");
+ pr_warn("wrong crc on env\n");
return -EIO;
}
@@ -93,7 +96,7 @@ int envfs_load_data(struct envfs_super *super, void *buf, size_t size,
buf += sizeof(struct envfs_inode);
if (ENVFS_32(inode->magic) != ENVFS_INODE_MAGIC) {
- printf("envfs: wrong magic\n");
+ pr_warn("wrong magic\n");
ret = -EIO;
goto out;
}
@@ -147,7 +150,7 @@ int envfs_load_data(struct envfs_super *super, void *buf, size_t size,
fd = open(str, O_WRONLY | O_CREAT | O_TRUNC, 0644);
free(str);
if (fd < 0) {
- printf("Open %s\n", errno_str());
+ printf("Open %m\n");
ret = fd;
goto out;
}
diff --git a/common/environment.c b/common/environment.c
index 0d31f5b4f7..39cad0c16a 100644
--- a/common/environment.c
+++ b/common/environment.c
@@ -26,8 +26,10 @@
#include <environment.h>
#include <globalvar.h>
#include <libfile.h>
+#include <block.h>
+#include <efi/partition.h>
+#include <bootsource.h>
#else
-# define errno_str(x) ("void")
#define EXPORT_SYMBOL(x)
#endif
@@ -49,15 +51,83 @@ struct action_data {
#define TMPDIR "/.defaultenv"
-static char *default_environment_path = "/dev/env0";
+static char *default_environment_path;
-void default_environment_path_set(char *path)
+void default_environment_path_set(const char *path)
{
- default_environment_path = path;
+ free(default_environment_path);
+
+ default_environment_path = xstrdup(path);
}
-char *default_environment_path_get(void)
+static guid_t partition_barebox_env_guid = PARTITION_BAREBOX_ENVIRONMENT_GUID;
+
+/*
+ * default_environment_path_search - look for environment partition
+ *
+ * This searches for a barebox environment partition on block devices. barebox
+ * environment partitions are recognized by the guid
+ * 6c3737f2-07f8-45d1-ad45-15d260aab24d. The device barebox itself has booted
+ * from is preferred over other devices.
+ *
+ * @return: The cdev providing the environment of found, NULL otherwise
+ */
+static struct cdev *default_environment_path_search(void)
{
+ struct cdev *part;
+ struct device_node *boot_node;
+ int max_score = 0;
+ struct cdev *env_cdev = NULL;
+ struct block_device *blk;
+
+ if (!IS_ENABLED(CONFIG_BLOCK))
+ return NULL;
+
+ boot_node = bootsource_of_node_get(NULL);
+
+ if (boot_node) {
+ struct device *dev;
+
+ dev = of_find_device_by_node(boot_node);
+ if (dev)
+ device_detect(dev);
+ }
+
+ for_each_block_device(blk) {
+ int score = 0;
+
+ part = cdev_find_child_by_gpt_typeuuid(&blk->cdev,
+ &partition_barebox_env_guid);
+ if (IS_ERR(part))
+ continue;
+
+ score++;
+
+ if (boot_node && boot_node == blk->cdev.device_node)
+ score++;
+
+ if (score > max_score) {
+ max_score = score;
+ env_cdev = part;
+ }
+ }
+
+ return env_cdev;
+}
+
+const char *default_environment_path_get(void)
+{
+ struct cdev *cdev;
+
+ if (default_environment_path)
+ return default_environment_path;
+
+ cdev = default_environment_path_search();
+ if (cdev)
+ default_environment_path = basprintf("/dev/%s", cdev->name);
+ else
+ default_environment_path = xstrdup("/dev/env0");
+
return default_environment_path;
}
@@ -297,7 +367,7 @@ int envfs_save(const char *filename, const char *dirname, unsigned flags)
envfd = open(filename, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
if (envfd < 0) {
- printf("could not open %s: %s\n", filename, errno_str());
+ printf("could not open %s: %m\n", filename);
ret = -errno;
goto out1;
}
@@ -306,7 +376,7 @@ int envfs_save(const char *filename, const char *dirname, unsigned flags)
/* ENOSYS and EOPNOTSUPP aren't errors here, many devices don't need it */
if (ret && errno != ENOSYS && errno != EOPNOTSUPP) {
- printf("could not unprotect %s: %s\n", filename, errno_str());
+ printf("could not unprotect %s: %m\n", filename);
goto out;
}
@@ -314,7 +384,7 @@ int envfs_save(const char *filename, const char *dirname, unsigned flags)
/* ENOSYS and EOPNOTSUPP aren't errors here, many devices don't need it */
if (ret && errno != ENOSYS && errno != EOPNOTSUPP) {
- printf("could not erase %s: %s\n", filename, errno_str());
+ printf("could not erase %s: %m\n", filename);
goto out;
}
@@ -337,7 +407,7 @@ int envfs_save(const char *filename, const char *dirname, unsigned flags)
/* ENOSYS and EOPNOTSUPP aren't errors here, many devices don't need it */
if (ret && errno != ENOSYS && errno != EOPNOTSUPP) {
- printf("could not protect %s: %s\n", filename, errno_str());
+ printf("could not protect %s: %m\n", filename);
goto out;
}
@@ -385,7 +455,7 @@ int envfs_load(const char *filename, const char *dir, unsigned flags)
envfd = open(filename, O_RDONLY);
if (envfd < 0) {
- printf("environment load %s: %s\n", filename, errno_str());
+ printf("environment load %s: %m\n", filename);
if (errno == ENOENT)
printf("Maybe you have to create the partition.\n");
return -1;
diff --git a/common/fastboot.c b/common/fastboot.c
index 04a8573b4a..d8dabd89ab 100644
--- a/common/fastboot.c
+++ b/common/fastboot.c
@@ -30,7 +30,9 @@
#include <ubiformat.h>
#include <unistd.h>
#include <magicvar.h>
+#include <linux/log2.h>
#include <linux/sizes.h>
+#include <memory.h>
#include <progress.h>
#include <environment.h>
#include <globalvar.h>
@@ -45,7 +47,7 @@
#define FASTBOOT_VERSION "0.4"
-static unsigned int fastboot_max_download_size = SZ_8M;
+static unsigned int fastboot_max_download_size;
static int fastboot_bbu;
static char *fastboot_partitions;
@@ -64,7 +66,7 @@ static void fb_setvar(struct fb_variable *var, const char *fmt, ...)
va_end(ap);
}
-static struct fb_variable *fb_addvar(struct fastboot *fb, const char *fmt, ...)
+static struct fb_variable *fb_addvar(struct fastboot *fb, struct list_head *list, const char *fmt, ...)
{
struct fb_variable *var = xzalloc(sizeof(*var));
va_list ap;
@@ -73,12 +75,12 @@ static struct fb_variable *fb_addvar(struct fastboot *fb, const char *fmt, ...)
var->name = bvasprintf(fmt, ap);
va_end(ap);
- list_add_tail(&var->list, &fb->variables);
+ list_add_tail(&var->list, list);
return var;
}
-static int fastboot_add_partition_variables(struct fastboot *fb,
+static int fastboot_add_partition_variables(struct fastboot *fb, struct list_head *list,
struct file_list_entry *fentry)
{
struct stat s;
@@ -95,6 +97,14 @@ static int fastboot_add_partition_variables(struct fastboot *fb,
}
if (ret) {
+ if (fentry->flags & FILE_LIST_FLAG_OPTIONAL) {
+ pr_info("skipping unavailable optional partition %s for fastboot gadget\n",
+ fentry->filename);
+ ret = 0;
+ type = "unavailable";
+ goto out;
+ }
+
if (fentry->flags & FILE_LIST_FLAG_CREATE) {
ret = 0;
type = "file";
@@ -142,9 +152,9 @@ out:
if (ret)
return ret;
- var = fb_addvar(fb, "partition-size:%s", fentry->name);
+ var = fb_addvar(fb, list, "partition-size:%s", fentry->name);
fb_setvar(var, "%08zx", size);
- var = fb_addvar(fb, "partition-type:%s", fentry->name);
+ var = fb_addvar(fb, list, "partition-type:%s", fentry->name);
fb_setvar(var, "%s", type);
return ret;
@@ -152,18 +162,16 @@ out:
int fastboot_generic_init(struct fastboot *fb, bool export_bbu)
{
- int ret;
- struct file_list_entry *fentry;
struct fb_variable *var;
INIT_LIST_HEAD(&fb->variables);
- var = fb_addvar(fb, "version");
+ var = fb_addvar(fb, &fb->variables, "version");
fb_setvar(var, "0.4");
- var = fb_addvar(fb, "bootloader-version");
+ var = fb_addvar(fb, &fb->variables, "bootloader-version");
fb_setvar(var, release_string);
if (IS_ENABLED(CONFIG_FASTBOOT_SPARSE)) {
- var = fb_addvar(fb, "max-download-size");
+ var = fb_addvar(fb, &fb->variables, "max-download-size");
fb_setvar(var, "%u", fastboot_max_download_size);
}
@@ -171,28 +179,29 @@ int fastboot_generic_init(struct fastboot *fb, bool export_bbu)
if (!fb->tempname)
return -ENOMEM;
+ if (!fb->files)
+ fb->files = file_list_new();
if (export_bbu)
bbu_append_handlers_to_file_list(fb->files);
- file_list_for_each_entry(fb->files, fentry) {
- ret = fastboot_add_partition_variables(fb, fentry);
- if (ret)
- return ret;
- }
-
return 0;
}
-void fastboot_generic_free(struct fastboot *fb)
+static void fastboot_free_variables(struct list_head *list)
{
struct fb_variable *var, *tmp;
- list_for_each_entry_safe(var, tmp, &fb->variables, list) {
+ list_for_each_entry_safe(var, tmp, list, list) {
free(var->name);
free(var->value);
list_del(&var->list);
free(var);
}
+}
+
+void fastboot_generic_free(struct fastboot *fb)
+{
+ fastboot_free_variables(&fb->variables);
free(fb->tempname);
@@ -288,26 +297,51 @@ static int strcmp_l1(const char *s1, const char *s2)
static void cb_getvar(struct fastboot *fb, const char *cmd)
{
struct fb_variable *var;
+ LIST_HEAD(partition_list);
+ struct file_list_entry *fentry;
+
+ file_list_for_each_entry(fb->files, fentry) {
+ int ret;
+
+ ret = fastboot_add_partition_variables(fb, &partition_list, fentry);
+ if (ret) {
+ pr_warn("Failed to add partition variables: %pe", ERR_PTR(ret));
+ return;
+ }
+ }
pr_debug("getvar: \"%s\"\n", cmd);
if (!strcmp_l1(cmd, "all")) {
- list_for_each_entry(var, &fb->variables, list) {
+ list_for_each_entry(var, &fb->variables, list)
fastboot_tx_print(fb, FASTBOOT_MSG_INFO, "%s: %s",
var->name, var->value);
- }
+
+ list_for_each_entry(var, &partition_list, list)
+ fastboot_tx_print(fb, FASTBOOT_MSG_INFO, "%s: %s",
+ var->name, var->value);
+
fastboot_tx_print(fb, FASTBOOT_MSG_OKAY, "");
- return;
+ goto out;
}
list_for_each_entry(var, &fb->variables, list) {
if (!strcmp(cmd, var->name)) {
fastboot_tx_print(fb, FASTBOOT_MSG_OKAY, var->value);
- return;
+ goto out;
+ }
+ }
+
+ list_for_each_entry(var, &partition_list, list) {
+ if (!strcmp(cmd, var->name)) {
+ fastboot_tx_print(fb, FASTBOOT_MSG_OKAY, var->value);
+ goto out;
}
}
fastboot_tx_print(fb, FASTBOOT_MSG_OKAY, "");
+out:
+ fastboot_free_variables(&partition_list);
}
int fastboot_handle_download_data(struct fastboot *fb, const void *buffer,
@@ -586,7 +620,7 @@ static int fastboot_handle_sparse(struct fastboot *fb,
pos = lseek(fd, pos, SEEK_SET);
if (pos == -1) {
- ret = -errno;
+ ret = errno == EINVAL ? -ENOSPC : -errno;
goto out;
}
@@ -614,7 +648,11 @@ static void cb_flash(struct fastboot *fb, const char *cmd)
const char *filename = NULL;
enum filetype filetype;
- filetype = file_name_detect_type(fb->tempname);
+ ret = file_name_detect_type(fb->tempname, &filetype);
+ if (ret) {
+ fastboot_tx_print(fb, FASTBOOT_MSG_FAIL, "internal error");
+ goto out;
+ }
fastboot_tx_print(fb, FASTBOOT_MSG_INFO, "Copying file to %s...",
cmd);
@@ -673,7 +711,8 @@ static void cb_flash(struct fastboot *fb, const char *cmd)
goto out;
}
- if (IS_ENABLED(CONFIG_BAREBOX_UPDATE) && filetype_is_barebox_image(filetype)) {
+ if (IS_ENABLED(CONFIG_BAREBOX_UPDATE) &&
+ (filetype_is_barebox_image(filetype) || strstarts(fentry->name, "bbu-"))) {
void *buf;
struct bbu_handler *handler;
struct bbu_data data = {
@@ -916,20 +955,28 @@ bool get_fastboot_bbu(void)
return fastboot_bbu;
}
+void set_fastboot_bbu(unsigned int enable)
+{
+ fastboot_bbu = enable;
+}
+
struct file_list *get_fastboot_partitions(void)
{
if (fastboot_partitions && *fastboot_partitions)
return file_list_parse_null(fastboot_partitions);
- if (!system_partitions_empty())
- return system_partitions_get();
- return NULL;
+ return system_partitions_get_null();
}
static int fastboot_globalvars_init(void)
{
- if (IS_ENABLED(CONFIG_FASTBOOT_SPARSE))
+ if (IS_ENABLED(CONFIG_FASTBOOT_SPARSE)) {
+ fastboot_max_download_size
+ = roundup_pow_of_two(clamp_t(ulong, mem_malloc_size() / 8,
+ SZ_8M, SZ_128M));
globalvar_add_simple_int("fastboot.max_download_size",
&fastboot_max_download_size, "%u");
+ }
+
globalvar_add_simple_bool("fastboot.bbu", &fastboot_bbu);
globalvar_add_simple_string("fastboot.partitions",
&fastboot_partitions);
diff --git a/common/file-list.c b/common/file-list.c
index 407b312833..7ecc8d00bb 100644
--- a/common/file-list.c
+++ b/common/file-list.c
@@ -9,6 +9,7 @@
#include <stringlist.h>
#include <linux/err.h>
#include <driver.h>
+#include <block.h>
#define PARSE_DEVICE 0
#define PARSE_NAME 1
@@ -26,8 +27,8 @@ struct file_list_entry *file_list_entry_by_name(struct file_list *files, const c
return NULL;
}
-int file_list_add_entry(struct file_list *files, const char *name, const char *filename,
- unsigned long flags)
+static int __file_list_add_entry(struct file_list *files, char *name, char *filename,
+ unsigned long flags)
{
struct file_list_entry *entry;
@@ -37,8 +38,8 @@ int file_list_add_entry(struct file_list *files, const char *name, const char *f
entry = xzalloc(sizeof(*entry));
- entry->name = xstrdup(name);
- entry->filename = xstrdup(filename);
+ entry->name = name;
+ entry->filename = filename;
entry->flags = flags;
list_add_tail(&entry->list, &files->list);
@@ -46,12 +47,41 @@ int file_list_add_entry(struct file_list *files, const char *name, const char *f
return 0;
}
+int file_list_add_entry(struct file_list *files, const char *name, const char *filename,
+ unsigned long flags)
+{
+ return __file_list_add_entry(files, xstrdup(name), xstrdup(filename), flags);
+}
+
+int file_list_add_cdev_entry(struct file_list *files, struct cdev *cdev,
+ unsigned long flags)
+{
+ return __file_list_add_entry(files, xstrdup(cdev->name),
+ xasprintf("/dev/%s", cdev->name), flags);
+}
+
+static bool file_list_handle_spec(struct file_list *files, const char *spec)
+{
+ unsigned count = 0;
+ bool autoadd;
+
+ autoadd = !strcmp(spec, "auto");
+ if (autoadd || !strcmp(spec, "block"))
+ count += file_list_add_blockdevs(files);
+ else
+ return false;
+
+ pr_debug("'%s' spcifier resulted in %u entries\n", spec, count);
+ return true;
+}
+
static int file_list_parse_one(struct file_list *files, const char *partstr, const char **endstr)
{
int i = 0, state = PARSE_DEVICE;
char filename[PATH_MAX];
char name[PATH_MAX];
unsigned long flags = 0;
+ bool special = false;
memset(filename, 0, sizeof(filename));
memset(name, 0, sizeof(name));
@@ -88,6 +118,9 @@ static int file_list_parse_one(struct file_list *files, const char *partstr, con
case 'u':
flags |= FILE_LIST_FLAG_UBI;
break;
+ case 'o':
+ flags |= FILE_LIST_FLAG_OPTIONAL;
+ break;
default:
pr_err("Unknown flag '%c'\n", *partstr);
return -EINVAL;
@@ -99,7 +132,10 @@ static int file_list_parse_one(struct file_list *files, const char *partstr, con
partstr++;
}
- if (state != PARSE_FLAGS) {
+ if (state == PARSE_DEVICE)
+ special = file_list_handle_spec(files, filename);
+
+ if (!special && state != PARSE_FLAGS) {
pr_err("Missing ')'\n");
return -EINVAL;
}
@@ -108,12 +144,12 @@ static int file_list_parse_one(struct file_list *files, const char *partstr, con
partstr++;
*endstr = partstr;
- return file_list_add_entry(files, name, filename, flags);
+ return special ? 0 : file_list_add_entry(files, name, filename, flags);
}
static const char *flags_to_str(int flags)
{
- static char str[sizeof "srcu"];
+ static char str[sizeof "srcuo"];
char *s = str;;
if (flags & FILE_LIST_FLAG_SAFE)
@@ -124,22 +160,33 @@ static const char *flags_to_str(int flags)
*s++ = 'c';
if (flags & FILE_LIST_FLAG_UBI)
*s++ = 'u';
+ if (flags & FILE_LIST_FLAG_OPTIONAL)
+ *s++ = 'o';
*s = '\0';
return str;
}
-struct file_list *file_list_parse(const char *str)
+struct file_list *file_list_new(void)
{
struct file_list *files;
- int ret;
- const char *endptr;
files = xzalloc(sizeof(*files));
INIT_LIST_HEAD(&files->list);
+ return files;
+}
+
+struct file_list *file_list_parse(const char *str)
+{
+ struct file_list *files;
+ int ret;
+ const char *endptr;
+
+ files = file_list_new();
+
while (*str) {
ret = file_list_parse_one(files, str, &endptr);
if (ret) {
@@ -195,9 +242,7 @@ struct file_list *file_list_dup(struct file_list *old)
struct file_list_entry *old_entry;
struct file_list *new;
- new = xzalloc(sizeof(*new));
-
- INIT_LIST_HEAD(&new->list);
+ new = file_list_new();
list_for_each_entry(old_entry, &old->list, list) {
(void)file_list_add_entry(new, old_entry->name, old_entry->filename,
diff --git a/common/filetype.c b/common/filetype.c
index 8ffcd6adcd..f922494500 100644
--- a/common/filetype.c
+++ b/common/filetype.c
@@ -17,8 +17,9 @@
#include <disks.h>
#include <image-sparse.h>
#include <elf.h>
+#include <linux/zstd.h>
-#include <arm/mach-imx/include/mach/imx-header.h>
+#include <mach/imx/imx-header.h>
struct filetype_str {
const char *name; /* human readable filetype */
@@ -45,6 +46,7 @@ static const struct filetype_str filetype_str[] = {
[filetype_mbr] = { "MBR sector", "mbr" },
[filetype_bmp] = { "BMP image", "bmp" },
[filetype_png] = { "PNG image", "png" },
+ [filetype_qoi] = { "QOI image", "qoi" },
[filetype_ext] = { "EXT filesystem", "ext" },
[filetype_gpt] = { "GUID Partition Table", "gpt" },
[filetype_ubifs] = { "UBIFS image", "ubifs" },
@@ -61,19 +63,25 @@ static const struct filetype_str filetype_str[] = {
[filetype_kwbimage_v1] = { "MVEBU kwbimage (v1)", "kwb1" },
[filetype_android_sparse] = { "Android sparse image", "sparse" },
[filetype_arm64_linux_image] = { "ARM aarch64 Linux image", "aarch64-linux" },
+ [filetype_arm64_efi_linux_image] = { "ARM aarch64 Linux/EFI image", "aarch64-efi-linux" },
[filetype_riscv_linux_image] = { "RISC-V Linux image", "riscv-linux" },
+ [filetype_riscv_efi_linux_image] = { "RISC-V Linux/EFI image", "riscv-efi-linux" },
[filetype_riscv_barebox_image] = { "RISC-V barebox image", "riscv-barebox" },
[filetype_elf] = { "ELF", "elf" },
[filetype_imx_image_v1] = { "i.MX image (v1)", "imx-image-v1" },
[filetype_imx_image_v2] = { "i.MX image (v2)", "imx-image-v2" },
[filetype_layerscape_image] = { "Layerscape image", "layerscape-PBL" },
[filetype_layerscape_qspi_image] = { "Layerscape QSPI image", "layerscape-qspi-PBL" },
+ [filetype_nxp_fspi_image] = { "NXP FlexSPI image", "nxp-fspi-image" },
[filetype_ubootvar] = { "U-Boot environmemnt variable data",
"ubootvar" },
- [filetype_stm32_image_v1] = { "STM32 image (v1)", "stm32-image-v1" },
+ [filetype_stm32_image_fsbl_v1] = { "STM32MP FSBL image (v1)", "stm32-fsbl-v1" },
+ [filetype_stm32_image_ssbl_v1] = { "STM32MP SSBL image (v1)", "stm32-ssbl-v1" },
[filetype_zynq_image] = { "Zynq image", "zynq-image" },
[filetype_mxs_sd_image] = { "i.MX23/28 SD card image", "mxs-sd-image" },
[filetype_rockchip_rkns_image] = { "Rockchip boot image", "rk-image" },
+ [filetype_fip] = { "TF-A Firmware Image Package", "fip" },
+ [filetype_zstd_compressed] = { "ZSTD compressed", "zstd" },
};
const char *file_type_to_string(enum filetype f)
@@ -245,6 +253,11 @@ enum filetype file_detect_partition_table(const void *_buf, size_t bufsize)
return filetype_unknown;
}
+static bool is_dos_exe(const u8 *buf8)
+{
+ return buf8[0] == 'M' && buf8[1] == 'Z';
+}
+
#define CH_TOC_section_name 0x14
enum filetype file_detect_type(const void *_buf, size_t bufsize)
@@ -300,18 +313,25 @@ enum filetype file_detect_type(const void *_buf, size_t bufsize)
return filetype_aimage;
if (buf64[0] == le64_to_cpu(0x0a1a0a0d474e5089ull))
return filetype_png;
+ if (strncmp(buf8, "qoif", 4) == 0)
+ return filetype_qoi;
if (is_barebox_mips_head(_buf))
return filetype_mips_barebox;
if (buf[0] == be32_to_cpu(0x534F4659))
return filetype_bpk;
if (le32_to_cpu(buf[14]) == 0x644d5241)
- return filetype_arm64_linux_image;
+ return is_dos_exe(buf8) ? filetype_arm64_efi_linux_image : filetype_arm64_linux_image;
if (le32_to_cpu(buf[14]) == 0x05435352)
- return filetype_riscv_linux_image;
+ return is_dos_exe(buf8) ? filetype_riscv_efi_linux_image : filetype_riscv_linux_image;
if (le32_to_cpu(buf[14]) == 0x56435352 && !memcmp(&buf[12], "barebox", 8))
return filetype_riscv_barebox_image;
if (strncmp(buf8, "RKNS", 4) == 0)
return filetype_rockchip_rkns_image;
+ if (le32_to_cpu(buf[0]) == le32_to_cpu(0xaa640001))
+ return filetype_fip;
+ if (le32_to_cpu(buf[0]) == le32_to_cpu(ZSTD_MAGICNUMBER))
+ return filetype_zstd_compressed;
+
if ((buf8[0] == 0x5a || buf8[0] == 0x69 || buf8[0] == 0x78 ||
buf8[0] == 0x8b || buf8[0] == 0x9c) &&
buf8[0x1] == 0 && buf8[0x2] == 0 && buf8[0x3] == 0 &&
@@ -340,6 +360,8 @@ enum filetype file_detect_type(const void *_buf, size_t bufsize)
return filetype_layerscape_image;
if (buf[0] == 0x01ee0100 && buf[1] == 0xaa55aa55)
return filetype_layerscape_qspi_image;
+ if (buf[0] == 0xaa55aa55 && buf[1] == 0x80100000)
+ return filetype_layerscape_image;
if (le32_to_cpu(buf[0]) == 0x00112233 && le32_to_cpu(buf[1]) == 0x1)
return filetype_mxs_sd_image;
@@ -358,15 +380,21 @@ enum filetype file_detect_type(const void *_buf, size_t bufsize)
if (buf[9] == 0x016f2818 || buf[9] == 0x18286f01)
return filetype_arm_zimage;
- if (buf8[0] == 'M' && buf8[1] == 'Z')
+ if (is_dos_exe(buf8))
return filetype_exe;
if (bufsize < 256)
return filetype_unknown;
if (strncmp(buf8, "STM\x32", 4) == 0) {
- if (buf8[74] == 0x01)
- return filetype_stm32_image_v1;
+ if (buf8[74] == 0x01) {
+ switch(le32_to_cpu(buf[63])) {
+ case 0x00000000:
+ return filetype_stm32_image_ssbl_v1;
+ case 0x10000000:
+ return filetype_stm32_image_fsbl_v1;
+ }
+ }
}
if (bufsize < 512)
@@ -395,21 +423,24 @@ enum filetype file_detect_type(const void *_buf, size_t bufsize)
if (is_imx_flash_header_v2(_buf))
return filetype_imx_image_v2;
+ if (buf[0] == cpu_to_be32(FCFB_HEAD_TAG) &&
+ buf[1] == cpu_to_le32(FCFB_VERSION))
+ return filetype_nxp_fspi_image;
+
if (buf[8] == 0xAA995566 && buf[9] == 0x584C4E58)
return filetype_zynq_image;
return filetype_unknown;
}
-enum filetype file_name_detect_type_offset(const char *filename, loff_t pos)
+int file_name_detect_type_offset(const char *filename, loff_t pos, enum filetype *type)
{
int fd, ret;
void *buf;
- enum filetype type = filetype_unknown;
fd = open_and_lseek(filename, O_RDONLY, pos);
if (fd < 0)
- goto out;
+ return fd;
buf = xzalloc(FILE_TYPE_SAFE_BUFSIZE);
@@ -417,34 +448,29 @@ enum filetype file_name_detect_type_offset(const char *filename, loff_t pos)
if (ret < 0)
goto err_out;
- type = file_detect_type(buf, ret);
+ *type = file_detect_type(buf, ret);
+ ret = 0;
err_out:
close(fd);
free(buf);
-out:
- return type;
+
+ return ret;
}
-enum filetype file_name_detect_type(const char *filename)
+int file_name_detect_type(const char *filename, enum filetype *type)
{
- return file_name_detect_type_offset(filename, 0);
+ return file_name_detect_type_offset(filename, 0, type);
}
-enum filetype cdev_detect_type(const char *name)
+int cdev_detect_type(struct cdev *cdev, enum filetype *type)
{
- enum filetype type = filetype_unknown;
int ret;
- struct cdev *cdev;
void *buf;
- cdev = cdev_open(name, O_RDONLY);
- if (!cdev)
- return type;
-
if (cdev->filetype != filetype_unknown) {
- type = cdev->filetype;
- goto cdev_close;
+ *type = cdev->filetype;
+ return 0;
}
buf = xzalloc(FILE_TYPE_SAFE_BUFSIZE);
@@ -452,13 +478,12 @@ enum filetype cdev_detect_type(const char *name)
if (ret < 0)
goto err_out;
- type = file_detect_type(buf, ret);
+ *type = file_detect_type(buf, ret);
+ ret = 0;
err_out:
free(buf);
-cdev_close:
- cdev_close(cdev);
- return type;
+ return ret;
}
bool filetype_is_barebox_image(enum filetype ft)
@@ -470,6 +495,8 @@ bool filetype_is_barebox_image(enum filetype ft)
case filetype_ch_image_be:
case filetype_layerscape_image:
case filetype_layerscape_qspi_image:
+ case filetype_stm32_image_fsbl_v1:
+ case filetype_fip:
return true;
default:
return false;
diff --git a/common/firmware.c b/common/firmware.c
index b87d7da38f..3c7960581f 100644
--- a/common/firmware.c
+++ b/common/firmware.c
@@ -272,17 +272,18 @@ int firmwaremgr_load_file(struct firmware_mgr *mgr, const char *firmware)
firmwarefd = open(firmware, O_RDONLY);
if (firmwarefd < 0) {
- printf("could not open %s: %s\n", firmware,
- errno_str());
+ printf("could not open %s: %m\n", firmware);
ret = firmwarefd;
goto out;
}
- type = file_name_detect_type(firmware);
+ ret = file_name_detect_type(firmware, &type);
+ if (ret)
+ goto out;
devicefd = open(dst, O_WRONLY);
if (devicefd < 0) {
- printf("could not open %s: %s\n", dst, errno_str());
+ printf("could not open %s: %m\n", dst);
ret = devicefd;
goto out;
}
@@ -305,6 +306,38 @@ out:
return ret;
}
+/*
+ * request_firmware - load a firmware to a device
+ */
+int request_firmware(const struct firmware **out, const char *fw_name, struct device *dev)
+{
+ char fw_path[PATH_MAX + 1];
+ struct firmware *fw;
+ int ret;
+
+ fw = kzalloc(sizeof(struct firmware), GFP_KERNEL);
+ if (!fw)
+ return -ENOMEM;
+
+ snprintf(fw_path, sizeof(fw_path), "%s/%s", firmware_path, fw_name);
+
+ ret = read_file_2(fw_path, &fw->size, (void *)&fw->data, FILESIZE_MAX);
+ if (ret) {
+ kfree(fw);
+ return ret;
+ }
+
+ *out = fw;
+
+ return 0;
+}
+
+void release_firmware(const struct firmware *fw)
+{
+ kfree_const(fw->data);
+ kfree_const(fw);
+}
+
static int firmware_init(void)
{
firmware_path = strdup("/env/firmware");
diff --git a/common/globalvar.c b/common/globalvar.c
index 9e5a99f793..a83529f98f 100644
--- a/common/globalvar.c
+++ b/common/globalvar.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
#include <common.h>
#include <malloc.h>
#include <globalvar.h>
@@ -14,12 +16,12 @@
static int nv_dirty;
-struct device_d global_device = {
+struct device global_device = {
.name = "global",
.id = DEVICE_ID_SINGLE,
};
-struct device_d nv_device = {
+struct device nv_device = {
.name = "nv",
.id = DEVICE_ID_SINGLE,
};
@@ -99,7 +101,7 @@ static int nv_save(const char *name, const char *val)
* This function initializes a newly created device parameter from the corresponding
* nv.dev.<devname>.<paramname> variable.
*/
-void dev_param_init_from_nv(struct device_d *dev, const char *name)
+void dev_param_init_from_nv(struct device *dev, const char *name)
{
char *nvname;
const char *val;
@@ -128,19 +130,19 @@ void dev_param_init_from_nv(struct device_d *dev, const char *name)
/**
* nvvar_device_dispatch - dispatch dev.<dev>.<param> name into device and parameter name
* @name: The incoming name in the form dev.<dev>.<param>
- * @dev: The returned device_d * belonging to <dev>
+ * @dev: The returned device * belonging to <dev>
* @pname: the parameter name
*
- * Given a dev.<dev>.<param> string this function finds the device_d * belonging to
+ * Given a dev.<dev>.<param> string this function finds the device * belonging to
* <dev> and the parameter name from <param>.
*
* Return: When incoming string does not belong to the device namespace (does not begin
* with "dev." this function returns 0. A value > 0 is returned when the incoming string
- * is in the device namespace and the string can be dispatched into a device_d * and a
+ * is in the device namespace and the string can be dispatched into a device * and a
* parameter name. A negative error code is returned when the incoming string belongs to
* the device namespace, but cannot be dispatched.
*/
-static int nvvar_device_dispatch(const char *name, struct device_d **dev,
+static int nvvar_device_dispatch(const char *name, struct device **dev,
const char **pname)
{
char *devname;
@@ -175,7 +177,8 @@ static int nvvar_device_dispatch(const char *name, struct device_d **dev,
return 1;
}
-static int nv_set(struct device_d *dev, struct param_d *p, const char *name, const char *val)
+static int nv_set(struct device *dev, struct param_d *p, const char *name,
+ const char *val)
{
int ret;
@@ -193,12 +196,13 @@ static int nv_set(struct device_d *dev, struct param_d *p, const char *name, con
return 0;
}
-static const char *nv_param_get(struct device_d *dev, struct param_d *p)
+static const char *nv_param_get(struct device *dev, struct param_d *p)
{
return p->value ? p->value : "";
}
-static int nv_param_set(struct device_d *dev, struct param_d *p, const char *val)
+static int nv_param_set(struct device *dev, struct param_d *p,
+ const char *val)
{
int ret;
@@ -212,7 +216,7 @@ static int nv_param_set(struct device_d *dev, struct param_d *p, const char *val
static int __nvvar_add(const char *name, const char *value)
{
struct param_d *p;
- struct device_d *dev = NULL;
+ struct device *dev = NULL;
const char *pname;
int ret;
@@ -373,7 +377,7 @@ int nvvar_load(void)
return 0;
}
-static void device_param_print(struct device_d *dev)
+static void device_param_print(struct device *dev)
{
struct param_d *param;
@@ -450,9 +454,10 @@ void globalvar_set(const char *name, const char *val)
dev_set_param(&global_device, name, val);
}
-static int globalvar_simple_set(struct device_d *dev, struct param_d *p, const char *val)
+static int globalvar_simple_set(struct device *dev, struct param_d *p,
+ const char *val)
{
- struct device_d *rdev;
+ struct device *rdev;
const char *pname = NULL;
int ret;
@@ -742,8 +747,9 @@ static void nv_exit(void)
}
predevshutdown_exitcall(nv_exit);
-static int nv_global_param_complete(struct device_d *dev, struct string_list *sl,
- char *instr, int eval)
+static int nv_global_param_complete(struct device *dev,
+ struct string_list *sl,
+ char *instr, int eval)
{
struct param_d *param;
int len;
@@ -764,7 +770,7 @@ static int nv_global_param_complete(struct device_d *dev, struct string_list *sl
int nv_complete(struct string_list *sl, char *instr)
{
- struct device_d *dev;
+ struct device *dev;
struct param_d *param;
char *str;
int len;
diff --git a/common/hush.c b/common/hush.c
index d80df7a181..608c0e4937 100644
--- a/common/hush.c
+++ b/common/hush.c
@@ -112,7 +112,6 @@
#include <slice.h>
#include <getopt.h>
#include <libfile.h>
-#include <libbb.h>
#include <magicvar.h>
#include <linux/list.h>
#include <binfmt.h>
@@ -618,6 +617,7 @@ static int builtin_exit(struct p_context *ctx, struct child_prog *child,
static void remove_quotes_in_str(char *src)
{
char *trg = src;
+ bool in_double_quotes = false;
while (*src) {
if (*src == '\'') {
@@ -630,6 +630,7 @@ static void remove_quotes_in_str(char *src)
/* drop quotes */
if (*src == '"') {
+ in_double_quotes = !in_double_quotes;
src++;
continue;
}
@@ -655,6 +656,13 @@ static void remove_quotes_in_str(char *src)
continue;
}
+ /* replace '\ ' with ' ' */
+ if (!in_double_quotes && *src == '\\' && *(src + 1) == ' ') {
+ *trg++ = ' ';
+ src += 2;
+ continue;
+ }
+
*trg++ = *src++;
}
*trg = 0;
@@ -1829,7 +1837,7 @@ static char **make_list_in(char **inp, char *name)
p3 = insert_var_value(inp[i]);
p1 = p3;
while (*p1) {
- if ((*p1 == ' ')) {
+ if (*p1 == ' ') {
p1++;
continue;
}
diff --git a/common/image-fit.c b/common/image-fit.c
index 38a372ff52..251fda97b3 100644
--- a/common/image-fit.c
+++ b/common/image-fit.c
@@ -21,6 +21,7 @@
#include <linux/err.h>
#include <stringlist.h>
#include <rsa.h>
+#include <uncompress.h>
#include <image-fit.h>
#define FDT_MAX_DEPTH 32
@@ -255,53 +256,44 @@ static struct digest *fit_alloc_digest(struct device_node *sig_node,
static int fit_check_rsa_signature(struct device_node *sig_node,
enum hash_algo algo, void *hash)
{
- struct rsa_public_key *key;
- const char *key_name;
- char *key_path;
- struct device_node *key_node;
+ const struct rsa_public_key *key;
+ const char *key_name = NULL;
int sig_len;
const char *sig_value;
int ret;
sig_value = of_get_property(sig_node, "value", &sig_len);
if (!sig_value) {
- pr_err("signature value not found in %s\n", sig_node->full_name);
+ pr_err("signature value not found in %pOF\n", sig_node);
return -EINVAL;
}
- if (of_property_read_string(sig_node, "key-name-hint", &key_name)) {
- pr_err("key name not found in %s\n", sig_node->full_name);
- return -EINVAL;
- }
-
- key = rsa_get_key(key_name);
- if (IS_ERR(key)) {
- key_path = xasprintf("/signature/key-%s", key_name);
- key_node = of_find_node_by_path(key_path);
- if (!key_node) {
- pr_info("failed to find key node %s\n", key_path);
- free(key_path);
- return -ENOENT;
+ of_property_read_string(sig_node, "key-name-hint", &key_name);
+ if (key_name) {
+ key = rsa_get_key(key_name);
+ if (key) {
+ ret = rsa_verify(key, sig_value, sig_len, hash, algo);
+ if (!ret)
+ goto ok;
}
- free(key_path);
+ }
- key = rsa_of_read_key(key_node);
+ for_each_rsa_key(key) {
+ if (key_name && !strcmp(key->key_name_hint, key_name))
+ continue;
- if (IS_ERR(key)) {
- pr_info("failed to read key in %s\n", key_node->full_name);
- return -ENOENT;
- }
+ ret = rsa_verify(key, sig_value, sig_len, hash, algo);
+ if (!ret)
+ goto ok;
}
- ret = rsa_verify(key, sig_value, sig_len, hash, algo);
- if (ret)
- pr_err("image signature BAD\n");
- else
- pr_info("image signature OK\n");
+ pr_err("image signature BAD\n");
- rsa_key_free(key);
+ return -EBADMSG;
+ok:
+ pr_info("image signature OK\n");
- return ret;
+ return 0;
}
/*
@@ -318,12 +310,12 @@ static int fit_verify_signature(struct device_node *sig_node, const void *fit)
if (of_property_read_u32_index(sig_node, "hashed-strings", 0,
&hashed_strings_start)) {
- pr_err("hashed-strings start not found in %s\n", sig_node->full_name);
+ pr_err("hashed-strings start not found in %pOF\n", sig_node);
return -EINVAL;
}
if (of_property_read_u32_index(sig_node, "hashed-strings", 1,
&hashed_strings_size)) {
- pr_err("hashed-strings size not found in %s\n", sig_node->full_name);
+ pr_err("hashed-strings size not found in %pOF\n", sig_node);
return -EINVAL;
}
@@ -331,7 +323,7 @@ static int fit_verify_signature(struct device_node *sig_node, const void *fit)
string_list_init(&exc_props);
if (of_read_string_list(sig_node, "hashed-nodes", &inc_nodes)) {
- pr_err("hashed-nodes property not found in %s\n", sig_node->full_name);
+ pr_err("hashed-nodes property not found in %pOF\n", sig_node);
ret = -EINVAL;
goto out_sl;
}
@@ -389,30 +381,29 @@ static int fit_verify_hash(struct fit_handle *handle, struct device_node *image,
hash = of_get_child_by_name(image, "hash@1");
if (!hash) {
if (ret)
- pr_err("image %s does not have hashes\n",
- image->full_name);
+ pr_err("image %pOF does not have hashes\n", image);
return ret;
}
value_read = of_get_property(hash, "value", &hash_len);
if (!value_read) {
- pr_err("%s: \"value\" property not found\n", hash->full_name);
+ pr_err("%pOF: \"value\" property not found\n", hash);
return -EINVAL;
}
if (of_property_read_string(hash, "algo", &algo)) {
- pr_err("%s: \"algo\" property not found\n", hash->full_name);
+ pr_err("%pOF: \"algo\" property not found\n", hash);
return -EINVAL;
}
d = digest_alloc(algo);
if (!d) {
- pr_err("%s: unsupported algo %s\n", hash->full_name, algo);
+ pr_err("%pOF: unsupported algo %s\n", hash, algo);
return -EINVAL;
}
if (hash_len != digest_length(d)) {
- pr_err("%s: invalid hash length %d\n", hash->full_name, hash_len);
+ pr_err("%pOF: invalid hash length %d\n", hash, hash_len);
ret = -EINVAL;
goto err_digest_free;
}
@@ -421,10 +412,10 @@ static int fit_verify_hash(struct fit_handle *handle, struct device_node *image,
digest_update(d, data, data_len);
if (digest_verify(d, value_read)) {
- pr_info("%s: hash BAD\n", hash->full_name);
+ pr_info("%pOF: hash BAD\n", hash);
ret = -EBADMSG;
} else {
- pr_info("%s: hash OK\n", hash->full_name);
+ pr_info("%pOF: hash OK\n", hash);
ret = 0;
}
@@ -461,7 +452,7 @@ static int fit_image_verify_signature(struct fit_handle *handle,
if (!sig_node)
sig_node = of_get_child_by_name(image, "signature@1");
if (!sig_node) {
- pr_err("Image %s has no signature\n", image->full_name);
+ pr_err("Image %pOF has no signature\n", image);
return ret;
}
@@ -554,6 +545,7 @@ int fit_get_image_address(struct fit_handle *handle, void *configuration,
{
struct device_node *image;
const char *unit = name;
+ const char *type;
int ret;
if (!address || !property || !name)
@@ -563,11 +555,62 @@ int fit_get_image_address(struct fit_handle *handle, void *configuration,
if (ret)
return ret;
+ /* Treat type = "kernel_noload" as if entry/load address is missing */
+ ret = of_property_read_string(image, "type", &type);
+ if (!ret && !strcmp(type, "kernel_noload"))
+ return -ENOENT;
+
ret = fit_get_address(image, property, address);
return ret;
}
+static void fit_uncompress_error_fn(char *x)
+{
+ pr_err("%s\n", x);
+}
+
+static int fit_handle_decompression(struct device_node *image,
+ const char *type,
+ const void **data,
+ int *data_len)
+{
+ const char *compression = NULL;
+ void *uc_data;
+ int ret;
+
+ of_property_read_string(image, "compression", &compression);
+ if (!compression || !strcmp(compression, "none"))
+ return 0;
+
+ if (!strcmp(type, "ramdisk")) {
+ pr_warn("compression != \"none\" for ramdisks is deprecated,"
+ " please fix your .its file!\n");
+ return 0;
+ }
+
+ if (!IS_ENABLED(CONFIG_UNCOMPRESS)) {
+ pr_err("image has compression = \"%s\", but support not compiled in\n",
+ compression);
+ return -ENOSYS;
+ }
+
+ ret = uncompress_buf_to_buf(*data, *data_len, &uc_data,
+ fit_uncompress_error_fn);
+ if (ret < 0) {
+ pr_err("data couldn't be decompressed\n");
+ return ret;
+ }
+
+ *data = uc_data;
+ *data_len = ret;
+
+ /* associate buffer with FIT, so it's not leaked */
+ __of_new_property(image, "uncompressed-data", uc_data, *data_len);
+
+ return 0;
+}
+
/**
* fit_open_image - Open an image in a FIT image
* @handle: The FIT image handle
@@ -604,7 +647,7 @@ int fit_open_image(struct fit_handle *handle, void *configuration,
of_property_read_string(image, "type", &type);
if (!type) {
- pr_err("No \"type\" property found in %s\n", image->full_name);
+ pr_err("No \"type\" property found in %pOF\n", image);
return -EINVAL;
}
@@ -622,6 +665,10 @@ int fit_open_image(struct fit_handle *handle, void *configuration,
if (ret < 0)
return ret;
+ ret = fit_handle_decompression(image, type, &data, &data_len);
+ if (ret)
+ return ret;
+
*outdata = data;
*outsize = data_len;
@@ -649,27 +696,32 @@ static int fit_config_verify_signature(struct fit_handle *handle, struct device_
}
for_each_child_of_node(conf_node, sig_node) {
+ if (!of_node_has_prefix(sig_node, "signature"))
+ continue;
+
if (handle->verbose)
- of_print_nodes(sig_node, 0);
+ of_print_nodes(sig_node, 0, ~0);
+
ret = fit_verify_signature(sig_node, handle->fit);
if (ret < 0)
return ret;
}
if (ret < 0) {
- pr_err("configuration '%s' does not have a signature\n",
- conf_node->full_name);
+ pr_err("configuration '%pOF' does not have a signature\n", conf_node);
return ret;
}
return ret;
}
-static int fit_find_compatible_unit(struct device_node *conf_node,
+static int fit_find_compatible_unit(struct fit_handle *handle,
+ struct device_node *conf_node,
const char **unit)
{
struct device_node *child = NULL;
struct device_node *barebox_root;
+ int best_score = 0;
const char *machine;
int ret;
@@ -682,13 +734,55 @@ static int fit_find_compatible_unit(struct device_node *conf_node,
return -ENOENT;
for_each_child_of_node(conf_node, child) {
- if (of_device_is_compatible(child, machine)) {
+ int score = of_device_is_compatible(child, machine);
+
+ if (!score && !of_property_present(child, "compatible") &&
+ of_property_present(child, "fdt")) {
+ struct device_node *image;
+ const char *unit = "fdt";
+ int data_len;
+ const void *data;
+ int ret;
+
+ ret = fit_get_image(handle, child, &unit, &image);
+ if (ret)
+ goto next;
+
+ data = of_get_property(image, "data", &data_len);
+ if (!data) {
+ ret = -EINVAL;
+ goto next;
+ }
+
+ ret = fit_handle_decompression(image, "fdt", &data, &data_len);
+ if (ret) {
+ ret = -EILSEQ;
+ goto next;
+ }
+
+ score = fdt_machine_is_compatible(data, data_len, machine);
+
+ of_delete_property_by_name(image, "uncompressed-data");
+next:
+ if (ret)
+ pr_warn("skipping malformed configuration: %pOF (%pe)\n",
+ child, ERR_PTR(ret));
+ }
+
+ if (score > best_score) {
+ best_score = score;
*unit = child->name;
- pr_info("matching unit '%s' found\n", *unit);
- return 0;
+
+ if (score == OF_DEVICE_COMPATIBLE_MAX_SCORE)
+ break;
}
}
+ if (best_score) {
+ pr_info("matching unit '%s' found\n", *unit);
+ return 0;
+ }
+
default_unit:
pr_info("No match found. Trying default.\n");
if (of_property_read_string(conf_node, "default", unit) == 0)
@@ -720,7 +814,7 @@ void *fit_open_configuration(struct fit_handle *handle, const char *name)
if (name) {
unit = name;
} else {
- ret = fit_find_compatible_unit(conf_node, &unit);
+ ret = fit_find_compatible_unit(handle, conf_node, &unit);
if (ret) {
pr_info("Couldn't get a valid configuration. Aborting.\n");
return ERR_PTR(ret);
@@ -806,6 +900,7 @@ struct fit_handle *fit_open_buf(const void *buf, size_t size, bool verbose,
* @filename: The filename of the FIT image
* @verbose: If true, be more verbose
* @verify: The verify mode
+ * @max_size: maximum length to read from file
*
* This opens a FIT image found in @filename. The returned handle is used as
* context for the other FIT functions.
@@ -813,7 +908,7 @@ struct fit_handle *fit_open_buf(const void *buf, size_t size, bool verbose,
* Return: A handle to a FIT image or a ERR_PTR
*/
struct fit_handle *fit_open(const char *filename, bool verbose,
- enum bootm_verify verify)
+ enum bootm_verify verify, loff_t max_size)
{
struct fit_handle *handle;
int ret;
@@ -824,8 +919,8 @@ struct fit_handle *fit_open(const char *filename, bool verbose,
handle->verify = verify;
ret = read_file_2(filename, &handle->size, &handle->fit_alloc,
- FILESIZE_MAX);
- if (ret) {
+ max_size);
+ if (ret && ret != -EFBIG) {
pr_err("unable to read %s: %s\n", filename, strerror(-ret));
return ERR_PTR(ret);
}
diff --git a/common/imd-barebox.c b/common/imd-barebox.c
index 06731d0600..7877c8de39 100644
--- a/common/imd-barebox.c
+++ b/common/imd-barebox.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
#include <common.h>
#include <image-metadata.h>
#include <generated/compile.h>
@@ -21,6 +23,16 @@ __BAREBOX_IMD_SECTION(.barebox_imd_end) = {
.type = cpu_to_le32(IMD_TYPE_END),
};
+#ifdef CONFIG_IMD_ENDIANNESS
+#ifdef CONFIG_CPU_LITTLE_ENDIAN
+#define IMD_ENDIANNESS "little"
+#else
+#define IMD_ENDIANNESS "big"
+#endif
+BAREBOX_IMD_TAG_STRING(imd_endianness_tag, IMD_TYPE_PARAMETER,
+ "endianness=" IMD_ENDIANNESS, 1);
+#endif /* CONFIG_IMD_ENDIANNESS */
+
BAREBOX_IMD_TAG_STRING(imd_build_tag, IMD_TYPE_BUILD, UTS_VERSION, 1);
BAREBOX_IMD_TAG_STRING(imd_release_tag, IMD_TYPE_RELEASE, UTS_RELEASE, 1);
BAREBOX_IMD_TAG_STRING(imd_buildsystem_version_tag, IMD_TYPE_BUILDSYSTEM, BUILDSYSTEM_VERSION, 1);
diff --git a/common/imd.c b/common/imd.c
index e1d5733c6b..1100e6878a 100644
--- a/common/imd.c
+++ b/common/imd.c
@@ -21,6 +21,12 @@ static inline void read_file_2_free(void *buf)
{
free(buf);
}
+
+static int imd_read_file(const char *filename, size_t *size, void **outbuf,
+ bool allow_mmap)
+{
+ return read_file_2(filename, size, outbuf, 0x100000);
+}
#endif
/*
@@ -317,7 +323,7 @@ static int imd_calculate_crc32(void *input, const struct imd_header *imd_start,
length = ALIGN(length, 4);
length += sizeof(struct imd_header);
- if (imd_read_type(imd) == IMD_TYPE_CRC32) {
+ if (imd_is_crc32(imd_read_type(imd))) {
*imd_crc = (struct imd_header *)imd;
debug("Found crc token at %d\n", end_ofs);
break;
@@ -434,6 +440,7 @@ int imd_command(int argc, char *argv[])
char *str;
uint32_t checksum = 0;
uint32_t verify = 0;
+ bool allow_mmap = true;
imd_command_verbose = 0;
@@ -457,6 +464,7 @@ int imd_command(int argc, char *argv[])
break;
case 'c':
checksum = 1;
+ allow_mmap = false;
break;
case 'V':
verify = 1;
@@ -473,7 +481,7 @@ int imd_command(int argc, char *argv[])
filename = argv[optind];
- ret = read_file_2(filename, &size, &buf, 0x100000);
+ ret = imd_read_file(filename, &size, &buf, allow_mmap);
if (ret && ret != -EFBIG)
return -errno;
diff --git a/common/imx-bbu-nand-fcb.c b/common/imx-bbu-nand-fcb.c
index 3b07d539ee..0d46192720 100644
--- a/common/imx-bbu-nand-fcb.c
+++ b/common/imx-bbu-nand-fcb.c
@@ -14,6 +14,8 @@
#include <linux/sizes.h>
#include <bbu.h>
#include <fs.h>
+#include <command.h>
+#include <complete.h>
#include <linux/mtd/mtd-abi.h>
#include <linux/mtd/nand_mxs.h>
#include <linux/mtd/mtd.h>
@@ -23,28 +25,27 @@
#include <linux/bitops.h>
#include <io.h>
#include <crc.h>
-#include <mach/generic.h>
#include <mtd/mtd-peb.h>
#include <soc/imx/imx-nand-bcb.h>
+#ifdef CONFIG_ARCH_IMX
+#include <mach/imx/imx6.h>
+#include <mach/imx/generic.h>
+#else
+#include <mach/mxs/generic.h>
+#endif
-#ifdef CONFIG_ARCH_IMX6
-#include <mach/imx6.h>
static inline int fcb_is_bch_encoded(void)
{
return cpu_is_mx6ul() || cpu_is_mx6ull();
}
-#else
-static inline int fcb_is_bch_encoded(void)
-{
- return 0;
-}
-#endif
struct imx_nand_fcb_bbu_handler {
struct bbu_handler handler;
void (*fcb_create)(struct imx_nand_fcb_bbu_handler *imx_handler,
struct fcb_block *fcb, struct mtd_info *mtd);
+ int (*fcb_read)(struct mtd_info *mtd, int block, struct fcb_block **retfcb);
+ int (*fcb_write)(struct mtd_info *mtd, int block, struct fcb_block *fcb);
enum filetype filetype;
};
@@ -123,7 +124,7 @@ static void encode_bch_ecc(void *buf, struct fcb_block *fcb, int eccbits)
free_bch(bch);
}
-static struct fcb_block *read_fcb_bch(void *rawpage, int eccbits)
+static struct fcb_block *fcb_decode_bch(void *rawpage, int eccbits)
{
int i, j, ret, errbit, m = 13;
int blocksize = 128;
@@ -227,7 +228,7 @@ static uint32_t calc_chksum(void *buf, size_t size)
return ~chksum;
}
-static struct fcb_block *read_fcb_hamming_13_8(void *rawpage)
+static struct fcb_block *fcb_decode_hamming_13_8(void *rawpage)
{
int i;
int bitflips = 0, bit_to_flip;
@@ -282,57 +283,57 @@ static __maybe_unused void dump_fcb(void *buf)
{
struct fcb_block *fcb = buf;
- pr_debug("Checksum: 0x%08x\n", fcb->Checksum);
- pr_debug("FingerPrint: 0x%08x\n", fcb->FingerPrint);
- pr_debug("Version: 0x%08x\n", fcb->Version);
- pr_debug("DataSetup: 0x%02x\n", fcb->DataSetup);
- pr_debug("DataHold: 0x%02x\n", fcb->DataHold);
- pr_debug("AddressSetup: 0x%02x\n", fcb->AddressSetup);
- pr_debug("DSAMPLE_TIME: 0x%02x\n", fcb->DSAMPLE_TIME);
- pr_debug("NandTimingState: 0x%02x\n", fcb->NandTimingState);
- pr_debug("REA: 0x%02x\n", fcb->REA);
- pr_debug("RLOH: 0x%02x\n", fcb->RLOH);
- pr_debug("RHOH: 0x%02x\n", fcb->RHOH);
- pr_debug("PageDataSize: 0x%08x\n", fcb->PageDataSize);
- pr_debug("TotalPageSize: 0x%08x\n", fcb->TotalPageSize);
- pr_debug("SectorsPerBlock: 0x%08x\n", fcb->SectorsPerBlock);
- pr_debug("NumberOfNANDs: 0x%08x\n", fcb->NumberOfNANDs);
- pr_debug("TotalInternalDie: 0x%08x\n", fcb->TotalInternalDie);
- pr_debug("CellType: 0x%08x\n", fcb->CellType);
- pr_debug("EccBlockNEccType: 0x%08x\n", fcb->EccBlockNEccType);
- pr_debug("EccBlock0Size: 0x%08x\n", fcb->EccBlock0Size);
- pr_debug("EccBlockNSize: 0x%08x\n", fcb->EccBlockNSize);
- pr_debug("EccBlock0EccType: 0x%08x\n", fcb->EccBlock0EccType);
- pr_debug("MetadataBytes: 0x%08x\n", fcb->MetadataBytes);
- pr_debug("NumEccBlocksPerPage: 0x%08x\n", fcb->NumEccBlocksPerPage);
- pr_debug("EccBlockNEccLevelSDK: 0x%08x\n", fcb->EccBlockNEccLevelSDK);
- pr_debug("EccBlock0SizeSDK: 0x%08x\n", fcb->EccBlock0SizeSDK);
- pr_debug("EccBlockNSizeSDK: 0x%08x\n", fcb->EccBlockNSizeSDK);
- pr_debug("EccBlock0EccLevelSDK: 0x%08x\n", fcb->EccBlock0EccLevelSDK);
- pr_debug("NumEccBlocksPerPageSDK: 0x%08x\n", fcb->NumEccBlocksPerPageSDK);
- pr_debug("MetadataBytesSDK: 0x%08x\n", fcb->MetadataBytesSDK);
- pr_debug("EraseThreshold: 0x%08x\n", fcb->EraseThreshold);
- pr_debug("BootPatch: 0x%08x\n", fcb->BootPatch);
- pr_debug("PatchSectors: 0x%08x\n", fcb->PatchSectors);
- pr_debug("Firmware1_startingPage: 0x%08x\n", fcb->Firmware1_startingPage);
- pr_debug("Firmware2_startingPage: 0x%08x\n", fcb->Firmware2_startingPage);
- pr_debug("PagesInFirmware1: 0x%08x\n", fcb->PagesInFirmware1);
- pr_debug("PagesInFirmware2: 0x%08x\n", fcb->PagesInFirmware2);
- pr_debug("DBBTSearchAreaStartAddress: 0x%08x\n", fcb->DBBTSearchAreaStartAddress);
- pr_debug("BadBlockMarkerByte: 0x%08x\n", fcb->BadBlockMarkerByte);
- pr_debug("BadBlockMarkerStartBit: 0x%08x\n", fcb->BadBlockMarkerStartBit);
- pr_debug("BBMarkerPhysicalOffset: 0x%08x\n", fcb->BBMarkerPhysicalOffset);
- pr_debug("BCHType: 0x%08x\n", fcb->BCHType);
- pr_debug("TMTiming2_ReadLatency: 0x%08x\n", fcb->TMTiming2_ReadLatency);
- pr_debug("TMTiming2_PreambleDelay: 0x%08x\n", fcb->TMTiming2_PreambleDelay);
- pr_debug("TMTiming2_CEDelay: 0x%08x\n", fcb->TMTiming2_CEDelay);
- pr_debug("TMTiming2_PostambleDelay: 0x%08x\n", fcb->TMTiming2_PostambleDelay);
- pr_debug("TMTiming2_CmdAddPause: 0x%08x\n", fcb->TMTiming2_CmdAddPause);
- pr_debug("TMTiming2_DataPause: 0x%08x\n", fcb->TMTiming2_DataPause);
- pr_debug("TMSpeed: 0x%08x\n", fcb->TMSpeed);
- pr_debug("TMTiming1_BusyTimeout: 0x%08x\n", fcb->TMTiming1_BusyTimeout);
- pr_debug("DISBBM: 0x%08x\n", fcb->DISBBM);
- pr_debug("BBMarkerPhysOfsInSpareData: 0x%08x\n", fcb->BBMarkerPhysicalOffsetInSpareData);
+ printf("Checksum: 0x%08x\n", fcb->Checksum);
+ printf("FingerPrint: 0x%08x\n", fcb->FingerPrint);
+ printf("Version: 0x%08x\n", fcb->Version);
+ printf("DataSetup: 0x%02x\n", fcb->DataSetup);
+ printf("DataHold: 0x%02x\n", fcb->DataHold);
+ printf("AddressSetup: 0x%02x\n", fcb->AddressSetup);
+ printf("DSAMPLE_TIME: 0x%02x\n", fcb->DSAMPLE_TIME);
+ printf("NandTimingState: 0x%02x\n", fcb->NandTimingState);
+ printf("REA: 0x%02x\n", fcb->REA);
+ printf("RLOH: 0x%02x\n", fcb->RLOH);
+ printf("RHOH: 0x%02x\n", fcb->RHOH);
+ printf("PageDataSize: 0x%08x\n", fcb->PageDataSize);
+ printf("TotalPageSize: 0x%08x\n", fcb->TotalPageSize);
+ printf("SectorsPerBlock: 0x%08x\n", fcb->SectorsPerBlock);
+ printf("NumberOfNANDs: 0x%08x\n", fcb->NumberOfNANDs);
+ printf("TotalInternalDie: 0x%08x\n", fcb->TotalInternalDie);
+ printf("CellType: 0x%08x\n", fcb->CellType);
+ printf("EccBlockNEccType: 0x%08x\n", fcb->EccBlockNEccType);
+ printf("EccBlock0Size: 0x%08x\n", fcb->EccBlock0Size);
+ printf("EccBlockNSize: 0x%08x\n", fcb->EccBlockNSize);
+ printf("EccBlock0EccType: 0x%08x\n", fcb->EccBlock0EccType);
+ printf("MetadataBytes: 0x%08x\n", fcb->MetadataBytes);
+ printf("NumEccBlocksPerPage: 0x%08x\n", fcb->NumEccBlocksPerPage);
+ printf("EccBlockNEccLevelSDK: 0x%08x\n", fcb->EccBlockNEccLevelSDK);
+ printf("EccBlock0SizeSDK: 0x%08x\n", fcb->EccBlock0SizeSDK);
+ printf("EccBlockNSizeSDK: 0x%08x\n", fcb->EccBlockNSizeSDK);
+ printf("EccBlock0EccLevelSDK: 0x%08x\n", fcb->EccBlock0EccLevelSDK);
+ printf("NumEccBlocksPerPageSDK: 0x%08x\n", fcb->NumEccBlocksPerPageSDK);
+ printf("MetadataBytesSDK: 0x%08x\n", fcb->MetadataBytesSDK);
+ printf("EraseThreshold: 0x%08x\n", fcb->EraseThreshold);
+ printf("BootPatch: 0x%08x\n", fcb->BootPatch);
+ printf("PatchSectors: 0x%08x\n", fcb->PatchSectors);
+ printf("Firmware1_startingPage: 0x%08x\n", fcb->Firmware1_startingPage);
+ printf("Firmware2_startingPage: 0x%08x\n", fcb->Firmware2_startingPage);
+ printf("PagesInFirmware1: 0x%08x\n", fcb->PagesInFirmware1);
+ printf("PagesInFirmware2: 0x%08x\n", fcb->PagesInFirmware2);
+ printf("DBBTSearchAreaStartAddress: 0x%08x\n", fcb->DBBTSearchAreaStartAddress);
+ printf("BadBlockMarkerByte: 0x%08x\n", fcb->BadBlockMarkerByte);
+ printf("BadBlockMarkerStartBit: 0x%08x\n", fcb->BadBlockMarkerStartBit);
+ printf("BBMarkerPhysicalOffset: 0x%08x\n", fcb->BBMarkerPhysicalOffset);
+ printf("BCHType: 0x%08x\n", fcb->BCHType);
+ printf("TMTiming2_ReadLatency: 0x%08x\n", fcb->TMTiming2_ReadLatency);
+ printf("TMTiming2_PreambleDelay: 0x%08x\n", fcb->TMTiming2_PreambleDelay);
+ printf("TMTiming2_CEDelay: 0x%08x\n", fcb->TMTiming2_CEDelay);
+ printf("TMTiming2_PostambleDelay: 0x%08x\n", fcb->TMTiming2_PostambleDelay);
+ printf("TMTiming2_CmdAddPause: 0x%08x\n", fcb->TMTiming2_CmdAddPause);
+ printf("TMTiming2_DataPause: 0x%08x\n", fcb->TMTiming2_DataPause);
+ printf("TMSpeed: 0x%08x\n", fcb->TMSpeed);
+ printf("TMTiming1_BusyTimeout: 0x%08x\n", fcb->TMTiming1_BusyTimeout);
+ printf("DISBBM: 0x%08x\n", fcb->DISBBM);
+ printf("BBMarkerPhysOfsInSpareData: 0x%08x\n", fcb->BBMarkerPhysicalOffsetInSpareData);
}
static __maybe_unused ssize_t raw_read_page(struct mtd_info *mtd, void *dst, loff_t offset)
@@ -367,7 +368,7 @@ static ssize_t raw_write_page(struct mtd_info *mtd, void *buf, loff_t offset)
return ret;
}
-static int read_fcb(struct mtd_info *mtd, int num, struct fcb_block **retfcb)
+static int fcb_read_hamming_13_8(struct mtd_info *mtd, int block, struct fcb_block **retfcb)
{
int ret;
struct fcb_block *fcb;
@@ -377,19 +378,71 @@ static int read_fcb(struct mtd_info *mtd, int num, struct fcb_block **retfcb)
rawpage = xmalloc(mtd->writesize + mtd->oobsize);
- ret = raw_read_page(mtd, rawpage, mtd->erasesize * num);
+ ret = raw_read_page(mtd, rawpage, mtd->erasesize * block);
if (ret) {
- pr_err("Cannot read block %d\n", num);
+ pr_err("Cannot read block %d\n", block);
goto err;
}
- if (fcb_is_bch_encoded())
- fcb = read_fcb_bch(rawpage, 40);
- else
- fcb = read_fcb_hamming_13_8(rawpage);
+ fcb = fcb_decode_hamming_13_8(rawpage);
+ if (IS_ERR(fcb)) {
+ pr_err("Cannot decode fcb on block %d\n", block);
+ ret = PTR_ERR(fcb);
+ goto err;
+ }
+
+ *retfcb = fcb;
+ ret = 0;
+err:
+ free(rawpage);
+
+ return ret;
+}
+
+static int fcb_write_hamming_13_8(struct mtd_info *mtd, int block, struct fcb_block *fcb)
+{
+ void *fcb_raw_page = xzalloc(mtd->writesize + mtd->oobsize);
+ int ret;
+
+ memcpy(fcb_raw_page + 12, fcb, sizeof(struct fcb_block));
+ /*
+ * Set the first and second byte of OOB data to 0xFF, not 0x00. These
+ * bytes are used as the Manufacturers Bad Block Marker (MBBM). Since
+ * the FCB is mostly written to the first page in a block, a scan for
+ * factory bad blocks will detect these blocks as bad, e.g. when
+ * function nand_scan_bbt() is executed to build a new bad block table.
+ */
+ memset(fcb_raw_page + mtd->writesize, 0xFF, 2);
+
+ encode_hamming_13_8(fcb_raw_page + 12, fcb_raw_page + 12 + 512, 512);
+
+ ret = raw_write_page(mtd, fcb_raw_page, block * mtd->erasesize);
+
+ free(fcb_raw_page);
+
+ return ret;
+}
+
+static int fcb_read_bch(struct mtd_info *mtd, int block, struct fcb_block **retfcb)
+{
+ int ret;
+ struct fcb_block *fcb;
+ void *rawpage;
+
+ *retfcb = NULL;
+
+ rawpage = xmalloc(mtd->writesize + mtd->oobsize);
+
+ ret = raw_read_page(mtd, rawpage, mtd->erasesize * block);
+ if (ret) {
+ pr_err("Cannot read block %d\n", block);
+ goto err;
+ }
+
+ fcb = fcb_decode_bch(rawpage, 40);
if (IS_ERR(fcb)) {
- pr_err("Cannot read fcb on block %d\n", num);
+ pr_err("Cannot decode fcb on block %d\n", block);
ret = PTR_ERR(fcb);
goto err;
}
@@ -402,6 +455,31 @@ err:
return ret;
}
+static int fcb_write_bch(struct mtd_info *mtd, int block, struct fcb_block *fcb)
+{
+ void *fcb_raw_page = xzalloc(mtd->writesize + mtd->oobsize);
+ int ret;
+
+ /* 40 bit BCH, for i.MX6UL(L) */
+ encode_bch_ecc(fcb_raw_page + 32, fcb, 40);
+
+ /*
+ * Set the first and second byte of OOB data to 0xFF, not 0x00. These
+ * bytes are used as the Manufacturers Bad Block Marker (MBBM). Since
+ * the FCB is mostly written to the first page in a block, a scan for
+ * factory bad blocks will detect these blocks as bad, e.g. when
+ * function nand_scan_bbt() is executed to build a new bad block table.
+ */
+ memset(fcb_raw_page + mtd->writesize, 0xFF, 2);
+
+ ret = raw_write_page(mtd, fcb_raw_page, block * mtd->erasesize);
+
+ free(fcb_raw_page);
+
+ return ret;
+}
+
+
static int fcb_create(struct imx_nand_fcb_bbu_handler *imx_handler,
struct fcb_block *fcb, struct mtd_info *mtd)
{
@@ -438,6 +516,9 @@ static int fcb_create(struct imx_nand_fcb_bbu_handler *imx_handler,
imx_handler->fcb_create(imx_handler, fcb, mtd);
+ fcb->DISBBM = 0;
+ fcb->disbbm_search = 0;
+
fcb->Checksum = calc_chksum((void *)fcb + 4, sizeof(*fcb) - 4);
return 0;
@@ -651,7 +732,7 @@ static void imx28_dbbt_create(struct dbbt_block *dbbt, int num_bad_blocks)
* imx_bbu_write_fcb - Write FCB and DBBT raw data to the device
* @mtd: The mtd Nand device
* @block: The block to write to
- * @fcb_raw_page: The raw FCB data
+ * @fcb: FCB
* @dbbt_data_page: The DBBT data
*
* This function writes the FCB/DBBT data to the block given in @block
@@ -660,7 +741,8 @@ static void imx28_dbbt_create(struct dbbt_block *dbbt, int num_bad_blocks)
*
* return: 0 on success or a negative error code otherwise.
*/
-static int imx_bbu_write_fcb(struct mtd_info *mtd, int block, void *fcb_raw_page,
+static int imx_bbu_write_fcb(struct imx_nand_fcb_bbu_handler *imx_handler,
+ struct mtd_info *mtd, int block, struct fcb_block *fcb,
void *dbbt_data_page)
{
struct dbbt_block *dbbt;
@@ -682,7 +764,7 @@ again:
if (ret)
return ret;
- ret = raw_write_page(mtd, fcb_raw_page, block * mtd->erasesize);
+ ret = imx_handler->fcb_write(mtd, block, fcb);
if (ret) {
pr_err("Writing FCB on block %d failed with %s\n",
block, strerror(-ret));
@@ -843,13 +925,14 @@ out:
*
* return: 0 if the FCB/DBBT are valid, a negative error code otherwise
*/
-static int fcb_dbbt_check(struct mtd_info *mtd, int num, struct fcb_block *fcb)
+static int fcb_dbbt_check(struct imx_nand_fcb_bbu_handler *imx_handler,
+ struct mtd_info *mtd, int num, struct fcb_block *fcb)
{
int ret;
struct fcb_block *f;
int pages_per_block = mtd->erasesize / mtd->writesize;
- ret = read_fcb(mtd, num, &f);
+ ret = imx_handler->fcb_read(mtd, num, &f);
if (ret)
return ret;
@@ -885,11 +968,11 @@ out:
*
* return: 0 for success or a negative error code otherwise.
*/
-static int imx_bbu_write_fcbs_dbbts(struct mtd_info *mtd, struct fcb_block *fcb)
+static int imx_bbu_write_fcbs_dbbts(struct imx_nand_fcb_bbu_handler *imx_handler,
+ struct mtd_info *mtd, struct fcb_block *fcb)
{
void *dbbt = NULL;
int i, ret, valid = 0;
- void *fcb_raw_page;
/*
* The DBBT search start page is configurable in the FCB block.
@@ -899,28 +982,8 @@ static int imx_bbu_write_fcbs_dbbts(struct mtd_info *mtd, struct fcb_block *fcb)
if (fcb->DBBTSearchAreaStartAddress != 1)
return -EINVAL;
- fcb_raw_page = xzalloc(mtd->writesize + mtd->oobsize);
-
- if (fcb_is_bch_encoded()) {
- /* 40 bit BCH, for i.MX6UL(L) */
- encode_bch_ecc(fcb_raw_page + 32, fcb, 40);
- } else {
- memcpy(fcb_raw_page + 12, fcb, sizeof(struct fcb_block));
- encode_hamming_13_8(fcb_raw_page + 12,
- fcb_raw_page + 12 + 512, 512);
- }
-
dbbt = dbbt_data_create(mtd);
- /*
- * Set the first and second byte of OOB data to 0xFF, not 0x00. These
- * bytes are used as the Manufacturers Bad Block Marker (MBBM). Since
- * the FCB is mostly written to the first page in a block, a scan for
- * factory bad blocks will detect these blocks as bad, e.g. when
- * function nand_scan_bbt() is executed to build a new bad block table.
- */
- memset(fcb_raw_page + mtd->writesize, 0xFF, 2);
-
pr_info("Writing FCBs/DBBTs with primary/secondary Firmwares at pages %d/%d\n",
fcb->Firmware1_startingPage, fcb->Firmware2_startingPage);
@@ -928,7 +991,7 @@ static int imx_bbu_write_fcbs_dbbts(struct mtd_info *mtd, struct fcb_block *fcb)
if (mtd_peb_is_bad(mtd, i))
continue;
- if (!fcb_dbbt_check(mtd, i, fcb)) {
+ if (!fcb_dbbt_check(imx_handler, mtd, i, fcb)) {
valid++;
pr_info("FCB/DBBT on block %d still valid\n", i);
continue;
@@ -936,14 +999,13 @@ static int imx_bbu_write_fcbs_dbbts(struct mtd_info *mtd, struct fcb_block *fcb)
pr_info("Writing FCB/DBBT on block %d\n", i);
- ret = imx_bbu_write_fcb(mtd, i, fcb_raw_page, dbbt);
+ ret = imx_bbu_write_fcb(imx_handler, mtd, i, fcb, dbbt);
if (ret)
pr_err("Writing FCB/DBBT %d failed with: %s\n", i, strerror(-ret));
else
valid++;
}
- free(fcb_raw_page);
free(dbbt);
if (!valid)
@@ -1155,7 +1217,7 @@ static int imx_bbu_nand_update(struct bbu_handler *handler, struct bbu_data *dat
enum filetype filetype;
unsigned num_blocks_fw, fw_size;
int used = 0;
- int fw_orig_len;
+ int fw_orig_len = 0;
int used_refresh = 0, unused_refresh = 0;
if (data->image) {
@@ -1183,7 +1245,7 @@ static int imx_bbu_nand_update(struct bbu_handler *handler, struct bbu_data *dat
}
for (i = 0; i < 4; i++) {
- read_fcb(mtd, i, &fcb);
+ imx_handler->fcb_read(mtd, i, &fcb);
if (fcb)
break;
}
@@ -1326,7 +1388,7 @@ static int imx_bbu_nand_update(struct bbu_handler *handler, struct bbu_data *dat
* just written as primary firmware. From now on the new
* firmware will be booted.
*/
- ret = imx_bbu_write_fcbs_dbbts(mtd, fcb);
+ ret = imx_bbu_write_fcbs_dbbts(imx_handler, mtd, fcb);
if (ret < 0)
goto out;
@@ -1347,7 +1409,7 @@ static int imx_bbu_nand_update(struct bbu_handler *handler, struct bbu_data *dat
*/
if (ret > 0) {
pr_info("New bad blocks detected, writing FCBs/DBBTs again\n");
- ret = imx_bbu_write_fcbs_dbbts(mtd, fcb);
+ ret = imx_bbu_write_fcbs_dbbts(imx_handler, mtd, fcb);
if (ret < 0)
goto out;
}
@@ -1380,6 +1442,14 @@ int imx6_bbu_nand_register_handler(const char *name, unsigned long flags)
imx_handler->fcb_create = imx6_fcb_create;
imx_handler->filetype = filetype_arm_barebox;
+ if (fcb_is_bch_encoded()) {
+ imx_handler->fcb_read = fcb_read_bch;
+ imx_handler->fcb_write = fcb_write_bch;
+ } else {
+ imx_handler->fcb_read = fcb_read_hamming_13_8;
+ imx_handler->fcb_write = fcb_write_hamming_13_8;
+ }
+
handler = &imx_handler->handler;
handler->devicefile = "nand0.barebox";
handler->name = name;
@@ -1393,9 +1463,6 @@ int imx6_bbu_nand_register_handler(const char *name, unsigned long flags)
return ret;
}
-#ifdef CONFIG_ARCH_IMX28
-#include <mach/imx28-regs.h>
-
#define GPMI_TIMING0 0x00000070
#define GPMI_TIMING0_ADDRESS_SETUP_MASK (0xff << 16)
#define GPMI_TIMING0_ADDRESS_SETUP_OFFSET 16
@@ -1413,18 +1480,31 @@ int imx6_bbu_nand_register_handler(const char *name, unsigned long flags)
#define BCH_FLASHLAYOUT0_NBLOCKS_OFFSET 24
#define BCH_FLASHLAYOUT0_META_SIZE_MASK (0xff << 16)
#define BCH_FLASHLAYOUT0_META_SIZE_OFFSET 16
-#define BCH_FLASHLAYOUT0_ECC0_MASK (0xf << 12)
-#define BCH_FLASHLAYOUT0_ECC0_OFFSET 12
-#define BCH_FLASHLAYOUT0_DATA0_SIZE_MASK 0xfff
+#define MX28_BCH_FLASHLAYOUT0_ECC0_MASK (0xf << 12)
+#define MX28_BCH_FLASHLAYOUT0_ECC0_OFFSET 12
+#define BCH_FLASHLAYOUT0_ECC0_MASK (0x1f << 11)
+#define BCH_FLASHLAYOUT0_ECC0_OFFSET 11
+#define BCH_FLASHLAYOUT0_GF13_0_GF14_1_MASK BIT(10)
+#define BCH_FLASHLAYOUT0_GF13_0_GF14_1_OFFSET 10
+#define BCH_FLASHLAYOUT0_DATA0_SIZE_MASK 0x3ff
#define BCH_FLASHLAYOUT0_DATA0_SIZE_OFFSET 0
+#define MX28_BCH_FLASHLAYOUT0_DATA0_SIZE_MASK 0xfff
#define BCH_FLASH0LAYOUT1 0x00000090
#define BCH_FLASHLAYOUT1_PAGE_SIZE_MASK (0xffff << 16)
#define BCH_FLASHLAYOUT1_PAGE_SIZE_OFFSET 16
-#define BCH_FLASHLAYOUT1_ECCN_MASK (0xf << 12)
-#define BCH_FLASHLAYOUT1_ECCN_OFFSET 12
-#define BCH_FLASHLAYOUT1_DATAN_SIZE_MASK 0xfff
+#define BCH_FLASHLAYOUT1_ECCN_MASK (0x1f << 11)
+#define BCH_FLASHLAYOUT1_ECCN_OFFSET 11
+#define MX28_BCH_FLASHLAYOUT1_ECCN_MASK (0xf << 12)
+#define MX28_BCH_FLASHLAYOUT1_ECCN_OFFSET 12
+#define BCH_FLASHLAYOUT1_GF13_0_GF14_1_MASK BIT(10)
+#define BCH_FLASHLAYOUT1_GF13_0_GF14_1_OFFSET 10
#define BCH_FLASHLAYOUT1_DATAN_SIZE_OFFSET 0
+#define BCH_FLASHLAYOUT1_DATAN_SIZE_MASK 0x3ff
+#define MX28_BCH_FLASHLAYOUT1_DATAN_SIZE_MASK 0xfff
+
+#ifdef CONFIG_ARCH_IMX28
+#include <mach/mxs/imx28-regs.h>
static void imx28_fcb_create(struct imx_nand_fcb_bbu_handler *imx_handler,
struct fcb_block *fcb, struct mtd_info *mtd)
@@ -1454,6 +1534,8 @@ int imx28_bbu_nand_register_handler(const char *name, unsigned long flags)
imx_handler = xzalloc(sizeof(*imx_handler));
imx_handler->fcb_create = imx28_fcb_create;
+ imx_handler->fcb_read = fcb_read_hamming_13_8;
+ imx_handler->fcb_write = fcb_write_hamming_13_8;
imx_handler->filetype = filetype_mxs_bootstream;
@@ -1470,3 +1552,159 @@ int imx28_bbu_nand_register_handler(const char *name, unsigned long flags)
return ret;
}
#endif
+
+static int imx7_fcb_read(struct mtd_info *mtd, int block, struct fcb_block **retfcb)
+{
+ struct fcb_block *fcb = xzalloc(mtd->writesize);
+ int ret;
+
+ ret = mxs_nand_read_fcb_bch62(block, fcb, sizeof(*fcb));
+ if (ret)
+ free(fcb);
+ else
+ *retfcb = fcb;
+
+ return ret;
+}
+
+#ifdef CONFIG_ARCH_IMX7
+#include <mach/imx/imx7-regs.h>
+
+static void imx7_fcb_create(struct imx_nand_fcb_bbu_handler *imx_handler,
+ struct fcb_block *fcb, struct mtd_info *mtd)
+{
+ void __iomem *bch_regs = IOMEM(MX7_BCH_BASE);
+ u32 fl0, fl1;
+
+ /* Also hardcoded in kobs-ng */
+ fcb->DataSetup = 10;
+ fcb->DataHold = 7;
+ fcb->AddressSetup = 15;
+ fcb->DSAMPLE_TIME = 6;
+
+ fl0 = readl(bch_regs + BCH_FLASH0LAYOUT0);
+ fcb->MetadataBytes = BF_VAL(fl0, BCH_FLASHLAYOUT0_META_SIZE);
+ fcb->NumEccBlocksPerPage = BF_VAL(fl0, BCH_FLASHLAYOUT0_NBLOCKS);
+ fcb->EccBlock0Size = 4 * BF_VAL(fl0, BCH_FLASHLAYOUT0_DATA0_SIZE);
+ fcb->EccBlock0EccType = BF_VAL(fl0, BCH_FLASHLAYOUT0_ECC0);
+
+ fl1 = readl(bch_regs + BCH_FLASH0LAYOUT1);
+ fcb->EccBlockNSize = 4 * BF_VAL(fl1, BCH_FLASHLAYOUT1_DATAN_SIZE);
+ fcb->EccBlockNEccType = BF_VAL(fl1, BCH_FLASHLAYOUT1_ECCN);
+ fcb->BCHType = BF_VAL(fl1, BCH_FLASHLAYOUT1_GF13_0_GF14_1);
+}
+
+static int imx7_fcb_write(struct mtd_info *mtd, int block, struct fcb_block *fcb)
+{
+ return mxs_nand_write_fcb_bch62(block, fcb, sizeof(*fcb));
+}
+
+int imx7_bbu_nand_register_handler(const char *name, unsigned long flags)
+{
+ struct imx_nand_fcb_bbu_handler *imx_handler;
+ struct bbu_handler *handler;
+ int ret;
+
+ imx_handler = xzalloc(sizeof(*imx_handler));
+ imx_handler->fcb_create = imx7_fcb_create;
+ imx_handler->fcb_read = imx7_fcb_read;
+ imx_handler->fcb_write = imx7_fcb_write;
+ imx_handler->filetype = filetype_arm_barebox;
+
+ handler = &imx_handler->handler;
+ handler->devicefile = "nand0.barebox";
+ handler->name = name;
+ handler->flags = flags | BBU_HANDLER_CAN_REFRESH;
+ handler->handler = imx_bbu_nand_update;
+
+ ret = bbu_register_handler(handler);
+ if (ret)
+ free(handler);
+
+ return ret;
+}
+#endif
+
+static void dump_fcb_n(struct fcb_block **fcbs, int n)
+{
+ int i;
+
+ if (!n || !fcbs[n])
+ goto skip_compare;
+
+ for (i = 0; i < n; i++) {
+ if (!fcbs[i] || !fcbs[n])
+ continue;
+
+ if (!memcmp(fcbs[i], fcbs[n], sizeof(struct fcb_block))) {
+ printf("FCB block#%d: same as FCB block#%d\n", n, i);
+ return;
+ }
+ }
+
+skip_compare:
+ if (fcbs[n]) {
+ printf("FCB block#%d:\n", n);
+ dump_fcb(fcbs[n]);
+ } else {
+ printf("FCB block#%d: NULL\n", n);
+ }
+}
+
+static int fcb_read(struct mtd_info *mtd, int block, struct fcb_block **retfcb)
+{
+ if (cpu_is_mx7())
+ return imx7_fcb_read(mtd, block, retfcb);
+ else if (fcb_is_bch_encoded())
+ return fcb_read_bch(mtd, block, retfcb);
+ else
+ return fcb_read_hamming_13_8(mtd, block, retfcb);
+}
+
+static int cmd_fcb(int argc, char *argv[])
+{
+ struct cdev *cdev;
+ struct mtd_info *mtd;
+ struct fcb_block *fcb[4] = {};
+ int i, ret;
+
+ cdev = cdev_open_by_name("nand0", O_RDONLY);
+ if (!cdev) {
+ printf("Cannot open nand0\n");
+ return COMMAND_ERROR;
+ }
+
+ mtd = cdev->mtd;
+ if (!mtd) {
+ ret = COMMAND_ERROR;
+ goto out;
+ }
+
+ for (i = 0; i < 4; i++)
+ fcb_read(mtd, i, &fcb[i]);
+
+ for (i = 0; i < 4; i++)
+ dump_fcb_n(fcb, i);
+
+ for (i = 0; i < 4; i++)
+ free(fcb[i]);
+
+ ret = 0;
+
+out:
+ cdev_close(cdev);
+
+ return ret;
+}
+
+BAREBOX_CMD_HELP_START(fcb)
+BAREBOX_CMD_HELP_TEXT("Dump FCB as found on /dev/nand0")
+BAREBOX_CMD_HELP_END
+
+BAREBOX_CMD_START(fcb)
+ .cmd = cmd_fcb,
+ BAREBOX_CMD_DESC("Dump Flash Control Block (FCB)")
+ BAREBOX_CMD_GROUP(CMD_GRP_MISC)
+ BAREBOX_CMD_HELP(cmd_fcb_help)
+ BAREBOX_CMD_COMPLETE(empty_complete)
+BAREBOX_CMD_END
diff --git a/common/kallsyms.c b/common/kallsyms.c
index f641903147..3c5904f8a8 100644
--- a/common/kallsyms.c
+++ b/common/kallsyms.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
#include <common.h>
#include <init.h>
#include <kallsyms.h>
@@ -163,10 +165,10 @@ static unsigned long get_symbol_pos(unsigned long addr,
* It resides in a module.
* - We also guarantee that modname will be valid until rescheduled.
*/
-static const char *kallsyms_lookup(unsigned long addr,
- unsigned long *symbolsize,
- unsigned long *offset,
- char **modname, char *namebuf)
+const char *kallsyms_lookup(unsigned long addr,
+ unsigned long *symbolsize,
+ unsigned long *offset,
+ char **modname, char *namebuf)
{
namebuf[KSYM_NAME_LEN - 1] = 0;
namebuf[0] = 0;
diff --git a/common/machine_id.c b/common/machine_id.c
index 6480806cd2..e670886d85 100644
--- a/common/machine_id.c
+++ b/common/machine_id.c
@@ -13,30 +13,120 @@
#define MACHINE_ID_LENGTH 32
+static bool __machine_id_initialized;
static void *__machine_id_hashable;
static size_t __machine_id_hashable_length;
+const void *machine_id_get_hashable(size_t *len)
+{
+ *len = __machine_id_hashable_length;
+ return __machine_id_hashable;
+}
+/**
+ * machine_id_set_hashable - Provide per-board unique data
+ * @hashable: Buffer
+ * @len: size of buffer
+ *
+ * The data supplied to the last call of this function prior to
+ * late_initcall will be hashed and stored into global.machine_id,
+ * which can be later used for fixup into the kernel command line
+ * or for deriving application specific unique IDs via
+ * machine_id_get_app_specific().
+ */
void machine_id_set_hashable(const void *hashable, size_t len)
{
-
__machine_id_hashable = xmemdup(hashable, len);
__machine_id_hashable_length = len;
}
+/**
+ * machine_id_get_app_specific - Generates an application-specific UUID
+ * @result: UUID output of the function
+ * @...: pairs of (const void *, size_t) arguments of data to factor
+ * into the UUID followed by a NULL sentinel value.
+ *
+ * Combines the machine ID with the application specific varargs data
+ * to arrive at an application-specific and board-specific UUID that is
+ * stable and unique.
+ *
+ * The function returns 0 if a UUID was successfully written into @result
+ * and a negative error code otherwise.
+ */
+int machine_id_get_app_specific(uuid_t *result, ...)
+{
+ static u8 hmac[SHA256_DIGEST_SIZE];
+ const void *data;
+ size_t size;
+ va_list args;
+ struct digest *d;
+ int ret;
+
+ if (!__machine_id_initialized)
+ return -ENODATA;
+
+ d = digest_alloc("hmac(sha256)");
+ if (!d)
+ return -ENOSYS;
+
+ ret = digest_set_key(d, __machine_id_hashable, __machine_id_hashable_length);
+ if (ret)
+ goto out;
+
+ ret = digest_init(d);
+ if (ret)
+ goto out;
+
+ ret = -ENODATA;
+
+ va_start(args, result);
+
+ while ((data = va_arg(args, const void *))) {
+ size = va_arg(args, size_t);
+
+ ret = digest_update(d, data, size);
+ if (ret)
+ break;
+ }
+
+ va_end(args);
+
+ if (ret)
+ goto out;
+
+ ret = digest_final(d, hmac);
+ if (ret)
+ goto out;
+
+ /* Take only the first half. */
+ memcpy(result, hmac, min(sizeof(hmac), sizeof(*result)));
+
+ uuid_make_v4(result);
+
+out:
+ digest_free(d);
+
+ return ret;
+}
+
static int machine_id_set_globalvar(void)
{
struct digest *digest = NULL;
unsigned char machine_id[SHA1_DIGEST_SIZE];
char hex_machine_id[MACHINE_ID_LENGTH];
char *env_machine_id;
- int ret = 0;
+ int ret;
/* nothing to do if no hashable information provided */
if (!__machine_id_hashable)
- goto out;
+ return 0;
digest = digest_alloc_by_algo(HASH_ALGO_SHA1);
+ if (!digest) {
+ ret = -EOPNOTSUPP;
+ goto out;
+ }
+
ret = digest_init(digest);
if (ret)
goto out;
@@ -56,10 +146,9 @@ static int machine_id_set_globalvar(void)
env_machine_id = basprintf("%.*s", MACHINE_ID_LENGTH, hex_machine_id);
globalvar_add_simple("machine_id", env_machine_id);
free(env_machine_id);
+ __machine_id_initialized = true;
out:
- globalvar_add_simple("machine_id", NULL);
-
digest_free(digest);
return ret;
diff --git a/common/meminfo.c b/common/meminfo.c
index d239fde582..3ceb0ba4cf 100644
--- a/common/meminfo.c
+++ b/common/meminfo.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
#include <common.h>
#include <init.h>
#include <memory.h>
@@ -10,8 +12,10 @@ static int display_meminfo(void)
ulong mend = mem_malloc_end();
ulong msize = mend - mstart + 1;
- pr_debug("barebox code: 0x%p -> 0x%p\n", _stext, _etext - 1);
- pr_debug("bss segment: 0x%p -> 0x%p\n", __bss_start, __bss_stop - 1);
+ if (!IS_ENABLED(CONFIG_SANDBOX)) {
+ pr_debug("barebox code: 0x%lx -> 0x%lx\n", (ulong)_stext, (ulong)_etext - 1);
+ pr_debug("bss segment: 0x%lx -> 0x%lx\n", (ulong)__bss_start, (ulong)__bss_stop - 1);
+ }
pr_info("malloc space: 0x%08lx -> 0x%08lx (size %s)\n",
mstart, mend, size_human_readable(msize));
return 0;
diff --git a/common/memory.c b/common/memory.c
index 95995bb6e3..583843cc34 100644
--- a/common/memory.c
+++ b/common/memory.c
@@ -3,6 +3,8 @@
* Copyright (c) 2011 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
*/
+#define pr_fmt(fmt) "memory: " fmt
+
#include <common.h>
#include <memory.h>
#include <of.h>
@@ -12,6 +14,8 @@
#include <asm-generic/memory_layout.h>
#include <asm/sections.h>
#include <malloc.h>
+#include <of.h>
+#include <mmu.h>
/*
* Begin and End of memory area for malloc(), and current "brk"
@@ -53,9 +57,9 @@ void mem_malloc_init(void *start, void *end)
mem_malloc_initialized = 1;
}
-#if !defined __SANDBOX__
static int mem_malloc_resource(void)
{
+#if !defined __SANDBOX__
/*
* Normally it's a bug when one of these fails,
* but we have some setups where some of these
@@ -77,13 +81,14 @@ static int mem_malloc_resource(void)
(unsigned long)&__bss_start,
(unsigned long)&__bss_stop -
(unsigned long)&__bss_start);
+#endif
#ifdef STACK_BASE
request_sdram_region("stack", STACK_BASE, STACK_SIZE);
#endif
+
return 0;
}
coredevice_initcall(mem_malloc_resource);
-#endif
static void *sbrk_no_zero(ptrdiff_t increment)
{
@@ -145,6 +150,7 @@ int barebox_add_memory_bank(const char *name, resource_size_t start,
struct resource newres = {
.start = start,
.end = start + size - 1,
+ .flags = IORESOURCE_MEM,
};
for_each_memory_bank(bank) {
@@ -158,6 +164,8 @@ int barebox_add_memory_bank(const char *name, resource_size_t start,
if (IS_ERR(res))
return PTR_ERR(res);
+ res->flags = IORESOURCE_MEM;
+
bank = xzalloc(sizeof(*bank));
bank->res = res;
@@ -180,21 +188,23 @@ static int add_mem_devices(void)
return 0;
}
-mmu_initcall(add_mem_devices);
+postmem_initcall(add_mem_devices);
/*
* Request a region from the registered sdram
*/
-struct resource *request_sdram_region(const char *name, resource_size_t start,
- resource_size_t size)
+struct resource *__request_sdram_region(const char *name, unsigned flags,
+ resource_size_t start, resource_size_t size)
{
struct memory_bank *bank;
+ flags |= IORESOURCE_MEM;
+
for_each_memory_bank(bank) {
struct resource *res;
- res = __request_region(bank->res, name, start,
- start + size - 1);
+ res = __request_region(bank->res, start, start + size - 1,
+ name, flags);
if (!IS_ERR(res))
return res;
}
@@ -202,6 +212,31 @@ struct resource *request_sdram_region(const char *name, resource_size_t start,
return NULL;
}
+/* use for secure firmware to inhibit speculation */
+struct resource *reserve_sdram_region(const char *name, resource_size_t start,
+ resource_size_t size)
+{
+ struct resource *res;
+
+ if (!IS_ALIGNED(start, PAGE_SIZE)) {
+ pr_err("%s: %s start is not page aligned\n", __func__, name);
+ start = ALIGN_DOWN(start, PAGE_SIZE);
+ }
+
+ if (!IS_ALIGNED(size, PAGE_SIZE)) {
+ pr_err("%s: %s size is not page aligned\n", __func__, name);
+ size = ALIGN(size, PAGE_SIZE);
+ }
+
+ res = __request_sdram_region(name, IORESOURCE_BUSY, start, size);
+ if (!res)
+ return NULL;
+
+ remap_range((void *)start, size, MAP_UNCACHED);
+
+ return res;
+}
+
int release_sdram_region(struct resource *res)
{
return release_region(res);
diff --git a/common/memory_display.c b/common/memory_display.c
index fbb8bbb6fa..c0ca469703 100644
--- a/common/memory_display.c
+++ b/common/memory_display.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
#include <common.h>
#include <errno.h>
#include <abort.h>
@@ -121,9 +123,9 @@ int __pr_memory_display(int level, const void *addr, loff_t offs, unsigned nbyte
} while (nbytes > 0);
- va_end(args);
ret = 0;
out:
+ va_end(args);
return ret;
}
@@ -132,4 +134,4 @@ int memory_display(const void *addr, loff_t offs, unsigned nbytes,
int size, int swab)
{
return pr_memory_display(-1, addr, offs, nbytes, size, swab);
-} \ No newline at end of file
+}
diff --git a/common/memtest.c b/common/memtest.c
index d47e4a672e..aa16d94eed 100644
--- a/common/memtest.c
+++ b/common/memtest.c
@@ -160,7 +160,7 @@ static void mem_test_report_failure(const char *failure_description,
}
int mem_test_bus_integrity(resource_size_t _start,
- resource_size_t _end)
+ resource_size_t _end, unsigned int flags)
{
static const uint64_t bitpattern[] = {
0x0000000000000001ULL, /* single bit */
@@ -190,7 +190,8 @@ int mem_test_bus_integrity(resource_size_t _start,
dummy = start + 1;
num_words = (_end - _start + 1)/sizeof(resource_size_t);
- printf("Starting data line test.\n");
+ if (flags & MEMTEST_VERBOSE)
+ printf("Starting data line test.\n");
/*
* Data line test: write a pattern to the first
@@ -294,7 +295,8 @@ int mem_test_bus_integrity(resource_size_t _start,
*/
start[0] = anti_pattern;
- printf("Check for address bits stuck high.\n");
+ if (flags & MEMTEST_VERBOSE)
+ printf("Check for address bits stuck high.\n");
/*
* Check for address bits stuck high.
@@ -313,8 +315,8 @@ int mem_test_bus_integrity(resource_size_t _start,
*/
start[0] = pattern;
- printf("Check for address bits stuck "
- "low or shorted.\n");
+ if (flags & MEMTEST_VERBOSE)
+ printf("Check for address bits stuck low or shorted.\n");
/*
* Check for address bits stuck low or shorted.
@@ -340,7 +342,7 @@ int mem_test_bus_integrity(resource_size_t _start,
return 0;
}
-static int update_progress(resource_size_t offset)
+static int update_progress(resource_size_t offset, unsigned flags)
{
/* Only check every 4k to reduce overhead */
if (offset & (SZ_4K - 1))
@@ -349,12 +351,14 @@ static int update_progress(resource_size_t offset)
if (ctrlc())
return -EINTR;
- show_progress(offset);
+ if (flags & MEMTEST_VERBOSE)
+ show_progress(offset);
return 0;
}
-int mem_test_moving_inversions(resource_size_t _start, resource_size_t _end)
+int mem_test_moving_inversions(resource_size_t _start, resource_size_t _end,
+ unsigned flags)
{
volatile resource_size_t *start, num_words, offset, temp, anti_pattern;
int ret;
@@ -368,8 +372,12 @@ int mem_test_moving_inversions(resource_size_t _start, resource_size_t _end)
start = (resource_size_t *)_start;
num_words = (_end - _start + 1)/sizeof(resource_size_t);
- printf("Starting moving inversions test of RAM:\n"
- "Fill with address, compare, fill with inverted address, compare again\n");
+ if (flags & MEMTEST_VERBOSE) {
+ printf("Starting moving inversions test of RAM:\n"
+ "Fill with address, compare, fill with inverted address, compare again\n");
+
+ init_progression_bar(3 * num_words);
+ }
/*
* Description: Test the integrity of a physical
@@ -382,11 +390,9 @@ int mem_test_moving_inversions(resource_size_t _start, resource_size_t _end)
* selected by the caller.
*/
- init_progression_bar(3 * num_words);
-
/* Fill memory with a known pattern */
for (offset = 0; offset < num_words; offset++) {
- ret = update_progress(offset);
+ ret = update_progress(offset, flags);
if (ret)
return ret;
start[offset] = offset + 1;
@@ -394,7 +400,7 @@ int mem_test_moving_inversions(resource_size_t _start, resource_size_t _end)
/* Check each location and invert it for the second pass */
for (offset = 0; offset < num_words; offset++) {
- ret = update_progress(num_words + offset);
+ ret = update_progress(num_words + offset, flags);
if (ret)
return ret;
@@ -413,7 +419,7 @@ int mem_test_moving_inversions(resource_size_t _start, resource_size_t _end)
/* Check each location for the inverted pattern and zero it */
for (offset = 0; offset < num_words; offset++) {
- ret = update_progress(2 * num_words + offset);
+ ret = update_progress(2 * num_words + offset, flags);
if (ret)
return ret;
@@ -430,10 +436,12 @@ int mem_test_moving_inversions(resource_size_t _start, resource_size_t _end)
start[offset] = 0;
}
- show_progress(3 * num_words);
+ if (flags & MEMTEST_VERBOSE) {
+ show_progress(3 * num_words);
- /* end of progressbar */
- printf("\n");
+ /* end of progressbar */
+ printf("\n");
+ }
return 0;
}
diff --git a/common/menutree.c b/common/menutree.c
index 9a14005ea2..751350d754 100644
--- a/common/menutree.c
+++ b/common/menutree.c
@@ -34,14 +34,7 @@ static void menutree_action(struct menu *m, struct menu_entry *me)
static void setenv_bool(const char *var, bool val)
{
- const char *str;
-
- if (val)
- str = "1";
- else
- str = "0";
-
- setenv(var, str);
+ pr_setenv(var, "%d", val);
}
static void menutree_box(struct menu *m, struct menu_entry *me)
@@ -87,7 +80,6 @@ int menutree(const char *path, int toplevel)
glob_t g = {};
int i;
char *globpath, *display;
- size_t size;
menu = menu_alloc();
@@ -100,7 +92,7 @@ int menutree(const char *path, int toplevel)
}
globpath = basprintf("%s/title", path);
- display = read_file(globpath, &size);
+ display = read_file(globpath, NULL);
free(globpath);
if (!display) {
eprintf("no title found in %s/title\n", path);
diff --git a/common/misc.c b/common/misc.c
index 226635f0d4..04ff4e6eb5 100644
--- a/common/misc.c
+++ b/common/misc.c
@@ -13,6 +13,7 @@
#include <led.h>
#include <of.h>
#include <restart.h>
+#include <poweroff.h>
#include <linux/stringify.h>
int errno;
@@ -105,16 +106,10 @@ const char *strerror(int errnum)
}
EXPORT_SYMBOL(strerror);
-const char *errno_str(void)
-{
- return strerror(errno);
-}
-EXPORT_SYMBOL(errno_str);
-
void perror(const char *s)
{
#ifdef CONFIG_ERRNO_MESSAGES
- printf("%s: %s\n", s, errno_str());
+ printf("%s: %m\n", s);
#else
printf("%s returned with %d\n", s, errno);
#endif
@@ -149,6 +144,8 @@ EXPORT_SYMBOL(barebox_get_model);
BAREBOX_MAGICVAR(global.model, "Product name of this hardware");
static char *hostname;
+static char *serial_number;
+static char *of_machine_compatible;
/*
* The hostname is supposed to be the shortname of a board. It should
@@ -179,23 +176,84 @@ EXPORT_SYMBOL(barebox_set_hostname_no_overwrite);
BAREBOX_MAGICVAR(global.hostname,
"shortname of the board. Also used as hostname for DHCP requests");
-void __noreturn panic(const char *fmt, ...)
+void barebox_set_serial_number(const char *__serial_number)
{
- va_list args;
- va_start(args, fmt);
- vprintf(fmt, args);
+ globalvar_add_simple_string("serial_number", &serial_number);
+
+ free(serial_number);
+ serial_number = xstrdup(__serial_number);
+}
+
+const char *barebox_get_serial_number(void)
+{
+ if (!serial_number || *serial_number == '\0')
+ return NULL;
+ return serial_number;
+}
+
+BAREBOX_MAGICVAR(global.serial_number, "Board serial number");
+
+void barebox_set_of_machine_compatible(const char *__compatible)
+{
+ free(of_machine_compatible);
+ of_machine_compatible = xstrdup(__compatible);
+}
+
+const char *barebox_get_of_machine_compatible(void)
+{
+ if (!of_machine_compatible || *of_machine_compatible == '\0')
+ return NULL;
+ return of_machine_compatible;
+}
+
+static int of_kernel_init(void)
+{
+ globalvar_add_simple_string("of.kernel.add_machine_compatible",
+ &of_machine_compatible);
+
+ return 0;
+}
+device_initcall(of_kernel_init);
+
+BAREBOX_MAGICVAR(global.of.kernel.add_machine_compatible, "Additional machine/board compatible");
+
+static void __noreturn do_panic(bool stacktrace, const char *fmt, va_list ap)
+{
+ vprintf(fmt, ap);
putchar('\n');
- va_end(args);
- dump_stack();
+ if (stacktrace)
+ dump_stack();
led_trigger(LED_TRIGGER_PANIC, TRIGGER_ENABLE);
- if (IS_ENABLED(CONFIG_PANIC_HANG)) {
+ if (IS_ENABLED(CONFIG_PANIC_HANG))
hang();
- } else {
- udelay(100000); /* allow messages to go out */
+
+ udelay(100000); /* allow messages to go out */
+
+ if (IS_ENABLED(CONFIG_PANIC_POWEROFF))
+ poweroff_machine();
+ else
restart_machine();
- }
+}
+
+void __noreturn panic(const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ do_panic(true, fmt, args);
+ va_end(args);
}
EXPORT_SYMBOL(panic);
+
+void __noreturn panic_no_stacktrace(const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ do_panic(false, fmt, args);
+ va_end(args);
+}
+EXPORT_SYMBOL(panic_no_stacktrace);
diff --git a/common/module.lds.S b/common/module.lds.S
index 76f3b6d1bb..b2d685670b 100644
--- a/common/module.lds.S
+++ b/common/module.lds.S
@@ -15,7 +15,7 @@
*
*/
-#include <asm-generic/barebox.lds.h>
+#include <asm/barebox.lds.h>
SECTIONS
{
diff --git a/common/oftree.c b/common/oftree.c
index 962fff244d..c12b3cfb16 100644
--- a/common/oftree.c
+++ b/common/oftree.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
#include <common.h>
#include <environment.h>
#include <fdt.h>
@@ -122,14 +124,10 @@ void of_print_cmdline(struct device_node *root)
static int of_fixup_bootargs_bootsource(struct device_node *root,
struct device_node *chosen)
{
- char *alias_name = bootsource_get_alias_name();
struct device_node *bootsource;
int ret = 0;
- if (!alias_name)
- return 0;
-
- bootsource = of_find_node_by_alias(root, alias_name);
+ bootsource = bootsource_of_node_get(root);
/*
* If kernel DTB doesn't have the appropriate alias set up,
* give up and exit early. No error is reported.
@@ -138,7 +136,6 @@ static int of_fixup_bootargs_bootsource(struct device_node *root,
ret = of_set_property(chosen, "bootsource", bootsource->full_name,
strlen(bootsource->full_name) + 1, true);
- free(alias_name);
return ret;
}
@@ -203,7 +200,17 @@ static int of_fixup_bootargs(struct device_node *root, void *unused)
struct device_node *node;
int err;
int instance = reset_source_get_instance();
- struct device_d *dev;
+ struct device *dev;
+ const char *serialno;
+ const char *compat;
+
+ serialno = barebox_get_serial_number();
+ if (serialno)
+ of_property_write_string(root, "serial-number", serialno);
+
+ compat = barebox_get_of_machine_compatible();
+ if (compat)
+ of_prepend_machine_compatible(root, compat);
node = of_create_node(root, "/chosen");
if (!node)
@@ -221,10 +228,10 @@ static int of_fixup_bootargs(struct device_node *root, void *unused)
dev = reset_source_get_device();
- if (dev && dev->device_node) {
+ if (dev && dev->of_node) {
phandle phandle;
- phandle = of_node_create_phandle(dev->device_node);
+ phandle = of_node_create_phandle(dev->of_node);
err = of_property_write_u32(node,
"reset-source-device", phandle);
@@ -259,6 +266,49 @@ static int of_register_bootargs_fixup(void)
}
late_initcall(of_register_bootargs_fixup);
+int of_fixup_reserved_memory(struct device_node *root, void *_res)
+{
+ struct resource *res = _res;
+ struct device_node *node, *child;
+ struct property *pp;
+ unsigned addr_n_cells = sizeof(void *) / sizeof(__be32),
+ size_n_cells = sizeof(void *) / sizeof(__be32);
+ unsigned rangelen = 0;
+ __be32 reg[4];
+ int ret;
+
+ node = of_get_child_by_name(root, "reserved-memory") ?: of_new_node(root, "reserved-memory");
+
+ ret = of_property_read_u32(node, "#address-cells", &addr_n_cells);
+ if (ret)
+ of_property_write_u32(node, "#address-cells", addr_n_cells);
+
+ ret = of_property_read_u32(node, "#size-cells", &size_n_cells);
+ if (ret)
+ of_property_write_u32(node, "#size-cells", size_n_cells);
+
+ pp = of_find_property(node, "ranges", &rangelen);
+ if (!pp) {
+ of_new_property(node, "ranges", NULL, 0);
+ } else if (rangelen) {
+ pr_warn("reserved-memory ranges not 1:1 mapped. Aborting fixup\n");
+ return -EINVAL;
+ }
+
+ child = of_get_child_by_name(node, res->name) ?: of_new_node(node, res->name);
+
+ if (res->flags & IORESOURCE_BUSY)
+ of_property_write_bool(child, "no-map", true);
+
+ of_write_number(reg, res->start, addr_n_cells);
+ of_write_number(reg + addr_n_cells, resource_size(res), size_n_cells);
+
+ of_set_property(child, "reg", reg,
+ (addr_n_cells + size_n_cells) * sizeof(*reg), true);
+
+ return 0;
+}
+
struct of_fixup_status_data {
const char *path;
bool status;
@@ -295,13 +345,12 @@ int of_register_set_status_fixup(const char *path, bool status)
return of_register_fixup(of_fixup_status, (void *)data);
}
-struct of_fixup {
- int (*fixup)(struct device_node *, void *);
- void *context;
- struct list_head list;
-};
+LIST_HEAD(of_fixup_list);
-static LIST_HEAD(of_fixup_list);
+static inline bool of_fixup_disabled(struct of_fixup *fixup)
+{
+ return fixup->disabled;
+}
int of_register_fixup(int (*fixup)(struct device_node *, void *), void *context)
{
@@ -338,7 +387,7 @@ int of_unregister_fixup(int (*fixup)(struct device_node *, void *),
* Apply registered fixups for the given fdt. The fdt must have
* enough free space to apply the fixups.
*/
-int of_fix_tree(struct device_node *node)
+void of_fix_tree(struct device_node *node)
{
struct of_fixup *of_fixup;
int ret;
@@ -346,13 +395,14 @@ int of_fix_tree(struct device_node *node)
of_overlay_load_firmware_clear();
list_for_each_entry(of_fixup, &of_fixup_list, list) {
+ if (of_fixup_disabled(of_fixup))
+ continue;
+
ret = of_fixup->fixup(node, of_fixup->context);
if (ret)
pr_warn("Failed to fixup node in %pS: %s\n",
of_fixup->fixup, strerror(-ret));
}
-
- return 0;
}
/*
@@ -361,30 +411,27 @@ int of_fix_tree(struct device_node *node)
* It increases the size of the tree and applies the registered
* fixups.
*/
-struct fdt_header *of_get_fixed_tree(struct device_node *node)
+struct fdt_header *of_get_fixed_tree(const struct device_node *node)
{
- int ret;
struct fdt_header *fdt = NULL;
- struct device_node *freenp = NULL;
+ struct device_node *np;
if (!node) {
node = of_get_root_node();
if (!node)
return NULL;
-
- freenp = node = of_dup(node);
- if (!node)
- return NULL;
}
- ret = of_fix_tree(node);
- if (ret)
- goto out;
+ np = of_dup(node);
+
+ if (!np)
+ return NULL;
- fdt = of_flatten_dtb(node);
+ of_fix_tree(np);
-out:
- of_delete_node(freenp);
+ fdt = of_flatten_dtb(np);
+
+ of_delete_node(np);
return fdt;
}
@@ -403,7 +450,7 @@ int of_autoenable_device_by_path(char *path)
struct device_node *node;
int ret;
- node = of_find_node_by_name(NULL, path);
+ node = of_find_node_by_name_address(NULL, path);
if (!node)
node = of_find_node_by_path(path);
@@ -440,7 +487,7 @@ int of_autoenable_i2c_by_component(char *path)
if (!IS_ENABLED(CONFIG_I2C))
return -ENODEV;
- node = of_find_node_by_name(NULL, path);
+ node = of_find_node_by_name_address(NULL, path);
if (!node)
node = of_find_node_by_path(path);
if (!node)
@@ -476,3 +523,34 @@ int of_autoenable_i2c_by_component(char *path)
return ret;
}
+
+int of_prepend_machine_compatible(struct device_node *root, const char *compat)
+{
+ int cclen = 0, clen = strlen(compat) + 1;
+ const char *curcompat;
+ void *buf;
+
+ if (!root) {
+ root = of_get_root_node();
+ if (!root)
+ return -ENODEV;
+ }
+
+ if (of_device_is_compatible(root, compat))
+ return 0;
+
+ curcompat = of_get_property(root, "compatible", &cclen);
+
+ buf = xzalloc(cclen + clen);
+
+ memcpy(buf, compat, clen);
+
+ if (curcompat)
+ memcpy(buf + clen, curcompat, cclen);
+
+ of_set_property(root, "compatible", buf, cclen + clen, true);
+
+ free(buf);
+
+ return 0;
+}
diff --git a/common/optee.c b/common/optee.c
index d542dde118..7fe93e4419 100644
--- a/common/optee.c
+++ b/common/optee.c
@@ -3,21 +3,59 @@
#define pr_fmt(fmt) "optee: " fmt
#include <tee/optee.h>
-#include <printk.h>
-#include <asm-generic/errno.h>
+#include <linux/printk.h>
+#include <linux/errno.h>
-int optee_verify_header(struct optee_header *hdr)
+static u64 optee_membase = U64_MAX;
+
+int optee_verify_header(const struct optee_header *hdr)
{
+ if (IS_ERR_OR_NULL(hdr))
+ return -EINVAL;
+
if (hdr->magic != OPTEE_MAGIC) {
- pr_err("Invalid header magic 0x%08x, expected 0x%08x\n",
- hdr->magic, OPTEE_MAGIC);
+ pr_debug("Invalid header magic 0x%08x, expected 0x%08x\n",
+ hdr->magic, OPTEE_MAGIC);
+ return -EINVAL;
+ }
+
+ if (hdr->version != OPTEE_VERSION_V1) {
+ pr_err("Only V1 headers are supported right now\n");
return -EINVAL;
}
- if (hdr->arch != OPTEE_ARCH_ARM32 || hdr->init_load_addr_hi) {
- pr_err("Only 32bit supported\n");
+ if (IS_ENABLED(CPU_V7) &&
+ (hdr->arch != OPTEE_ARCH_ARM32 || hdr->init_load_addr_hi)) {
+ pr_err("Wrong OP-TEE Arch for ARM v7 CPU\n");
+ return -EINVAL;
+ }
+
+ if (IS_ENABLED(CPU_V8) && hdr->arch != OPTEE_ARCH_ARM64) {
+ pr_err("Wrong OP-TEE Arch for ARM v8 CPU\n");
return -EINVAL;
}
return 0;
}
+
+int optee_get_membase(u64 *membase)
+{
+ if (optee_membase == U64_MAX)
+ return -EINVAL;
+
+ *membase = optee_membase;
+
+ return 0;
+}
+
+void optee_set_membase(const struct optee_header *hdr)
+{
+ int ret;
+
+ ret = optee_verify_header(hdr);
+ if (ret)
+ return;
+
+ optee_membase = (u64)hdr->init_load_addr_hi << 32;
+ optee_membase |= hdr->init_load_addr_lo;
+}
diff --git a/common/parser.c b/common/parser.c
index 584d4b0efe..387cd64c42 100644
--- a/common/parser.c
+++ b/common/parser.c
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
#include <common.h>
#include <command.h>
#include <password.h>
diff --git a/common/partitions.c b/common/partitions.c
index d80878e065..17c2f1eb28 100644
--- a/common/partitions.c
+++ b/common/partitions.c
@@ -15,8 +15,7 @@
#include <disks.h>
#include <filetype.h>
#include <linux/err.h>
-
-#include "partitions/parser.h"
+#include <partitions.h>
static LIST_HEAD(partition_parser_list);
@@ -27,30 +26,33 @@ static LIST_HEAD(partition_parser_list);
* @param no Partition number
* @return 0 on success
*/
-static int register_one_partition(struct block_device *blk,
- struct partition *part, int no)
+static int register_one_partition(struct block_device *blk, struct partition *part)
{
char *partition_name;
int ret;
- uint64_t start = part->first_sec * SECTOR_SIZE;
- uint64_t size = part->size * SECTOR_SIZE;
struct cdev *cdev;
+ struct devfs_partition partinfo = {
+ .offset = part->first_sec * SECTOR_SIZE,
+ .size = part->size * SECTOR_SIZE,
+ };
- partition_name = basprintf("%s.%d", blk->cdev.name, no);
+ partition_name = basprintf("%s.%d", blk->cdev.name, part->num);
if (!partition_name)
return -ENOMEM;
+
+ partinfo.name = partition_name;
+
dev_dbg(blk->dev, "Registering partition %s on drive %s (partuuid=%s)\n",
partition_name, blk->cdev.name, part->partuuid);
- cdev = devfs_add_partition(blk->cdev.name,
- start, size, 0, partition_name);
+ cdev = cdevfs_add_partition(&blk->cdev, &partinfo);
if (IS_ERR(cdev)) {
ret = PTR_ERR(cdev);
goto out;
}
- cdev->flags |= DEVFS_PARTITION_FROM_TABLE;
-
- cdev->dos_partition_type = part->dos_partition_type;
+ cdev->flags |= DEVFS_PARTITION_FROM_TABLE | part->flags;
+ cdev->typeflags |= part->typeflags;
+ cdev->typeuuid = part->typeuuid;
strcpy(cdev->partuuid, part->partuuid);
free(partition_name);
@@ -100,42 +102,157 @@ static struct partition_parser *partition_parser_get_by_filetype(uint8_t *buf)
return NULL;
}
-/**
- * Try to collect partition information on the given block device
- * @param blk Block device to examine
- * @return 0 most of the time, negative value else
- *
- * It is not a failure if no partition information is found
- */
-int parse_partition_table(struct block_device *blk)
+struct partition_desc *partition_table_new(struct block_device *blk, const char *type)
{
struct partition_desc *pdesc;
- int i;
- int rc = 0;
struct partition_parser *parser;
+
+ list_for_each_entry(parser, &partition_parser_list, list) {
+ if (!strcmp(parser->name, type))
+ goto found;
+ }
+
+ pr_err("Cannot find partition parser \"%s\"\n", type);
+
+ return ERR_PTR(-ENOSYS);
+
+found:
+ pdesc = parser->create(blk);
+ if (IS_ERR(pdesc))
+ return ERR_CAST(pdesc);
+
+ pdesc->parser = parser;
+
+ return pdesc;
+}
+
+struct partition_desc *partition_table_read(struct block_device *blk)
+{
+ struct partition_parser *parser;
+ struct partition_desc *pdesc = NULL;
uint8_t *buf;
+ int ret;
- pdesc = xzalloc(sizeof(*pdesc));
buf = malloc(2 * SECTOR_SIZE);
- rc = block_read(blk, buf, 0, 2);
- if (rc != 0) {
- dev_err(blk->dev, "Cannot read MBR/partition table: %pe\n", ERR_PTR(rc));
- goto on_error;
+ ret = block_read(blk, buf, 0, 2);
+ if (ret != 0) {
+ dev_err(blk->dev, "Cannot read MBR/partition table: %pe\n", ERR_PTR(ret));
+ goto err;
}
parser = partition_parser_get_by_filetype(buf);
if (!parser)
- goto on_error;
+ goto err;
+
+ pdesc = parser->parse(buf, blk);
+ if (!pdesc)
+ goto err;
+
+ pdesc->parser = parser;
+err:
+ free(buf);
+
+ return pdesc;
+}
- parser->parse(buf, blk, pdesc);
+int partition_table_write(struct partition_desc *pdesc)
+{
+ if (!pdesc->parser->write)
+ return -ENOSYS;
+
+ return pdesc->parser->write(pdesc);
+}
+
+static bool overlap(uint64_t s1, uint64_t e1, uint64_t s2, uint64_t e2)
+{
+ if (e1 < s2)
+ return false;
+ if (s1 > e2)
+ return false;
+ return true;
+}
- if (!pdesc->used_entries)
- goto on_error;
+int partition_create(struct partition_desc *pdesc, const char *name,
+ const char *fs_type, uint64_t lba_start, uint64_t lba_end)
+{
+ struct partition *part;
+
+ if (!pdesc->parser->mkpart)
+ return -ENOSYS;
+
+ if (lba_end < lba_start) {
+ pr_err("lba_end < lba_start: %llu < %llu\n", lba_end, lba_start);
+ return -EINVAL;
+ }
+
+ if (lba_end >= pdesc->blk->num_blocks) {
+ pr_err("lba_end exceeds device: %llu >= %llu\n", lba_end, pdesc->blk->num_blocks);
+ return -EINVAL;
+ }
+
+ list_for_each_entry(part, &pdesc->partitions, list) {
+ if (overlap(part->first_sec,
+ part->first_sec + part->size - 1,
+ lba_start, lba_end)) {
+ pr_err("new partition %llu-%llu overlaps with partition %s (%llu-%llu)\n",
+ lba_start, lba_end, part->name, part->first_sec,
+ part->first_sec + part->size - 1);
+ return -EINVAL;
+ }
+ }
+
+ return pdesc->parser->mkpart(pdesc, name, fs_type, lba_start, lba_end);
+}
+
+int partition_remove(struct partition_desc *pdesc, int num)
+{
+ struct partition *part;
+
+ if (!pdesc->parser->rmpart)
+ return -ENOSYS;
+
+ list_for_each_entry(part, &pdesc->partitions, list) {
+ if (part->num == num)
+ return pdesc->parser->rmpart(pdesc, part);
+ }
+
+ pr_err("Partition %d doesn't exist\n", num);
+ return -ENOENT;
+}
+
+void partition_table_free(struct partition_desc *pdesc)
+{
+ pdesc->parser->partition_free(pdesc);
+}
+
+void partition_desc_init(struct partition_desc *pd, struct block_device *blk)
+{
+ pd->blk = blk;
+ INIT_LIST_HEAD(&pd->partitions);
+}
+
+/**
+ * Try to collect partition information on the given block device
+ * @param blk Block device to examine
+ * @return 0 most of the time, negative value else
+ *
+ * It is not a failure if no partition information is found
+ */
+int parse_partition_table(struct block_device *blk)
+{
+ int i;
+ int rc = 0;
+ struct partition *part;
+ struct partition_desc *pdesc;
+
+ pdesc = partition_table_read(blk);
+ if (!pdesc)
+ return 0;
/* at least one partition description found */
- for (i = 0; i < pdesc->used_entries; i++) {
- rc = register_one_partition(blk, &pdesc->parts[i], i);
+ list_for_each_entry(part, &pdesc->partitions, list) {
+ rc = register_one_partition(blk, part);
if (rc != 0)
dev_err(blk->dev,
"Failed to register partition %d on %s (%d)\n",
@@ -144,15 +261,61 @@ int parse_partition_table(struct block_device *blk)
rc = 0;
}
-on_error:
- free(buf);
- free(pdesc);
+ partition_table_free(pdesc);
+
return rc;
}
+int reparse_partition_table(struct block_device *blk)
+{
+ struct cdev *cdev = &blk->cdev;
+ struct cdev *c, *tmp;
+
+ list_for_each_entry(c, &cdev->partitions, partition_entry) {
+ if (c->open) {
+ pr_warn("%s is busy, will continue to use old partition table\n", c->name);
+ return -EBUSY;
+ }
+ }
+
+ list_for_each_entry_safe(c, tmp, &cdev->partitions, partition_entry) {
+ if (c->flags & DEVFS_PARTITION_FROM_TABLE)
+ cdevfs_del_partition(c);
+ }
+
+ return parse_partition_table(blk);
+}
+
int partition_parser_register(struct partition_parser *p)
{
list_add_tail(&p->list, &partition_parser_list);
return 0;
}
+
+/**
+ * cdev_unallocated_space - return unallocated space
+ * cdev: The cdev
+ *
+ * This function returns the space that is not allocated by any partition
+ * at the start of a device.
+ *
+ * Return: The unallocated space at the start of the device in bytes
+ */
+loff_t cdev_unallocated_space(struct cdev *cdev)
+{
+ struct cdev *partcdev;
+ loff_t start;
+
+ if (!cdev)
+ return 0;
+
+ start = cdev->size;
+
+ list_for_each_entry(partcdev, &cdev->partitions, partition_entry) {
+ if (partcdev->offset < start)
+ start = partcdev->offset;
+ }
+
+ return start;
+}
diff --git a/common/partitions/Kconfig b/common/partitions/Kconfig
index be9405a649..3bbcceedc1 100644
--- a/common/partitions/Kconfig
+++ b/common/partitions/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
config PARTITION_DISK
depends on PARTITION
depends on BLOCK
@@ -17,6 +19,7 @@ config PARTITION_DISK_EFI
depends on PARTITION_DISK
select CRC32
select PRINTF_UUID
+ select PARTITION_DISK_DOS if PARTITION_MANIPULATION
bool "EFI: GPT partition support"
help
Add support to handle partitions in GUID Partition Table style.
diff --git a/common/partitions/Makefile b/common/partitions/Makefile
index 2b0c5b4b9c..d304b6f8d5 100644
--- a/common/partitions/Makefile
+++ b/common/partitions/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
obj-$(CONFIG_PARTITION_DISK_DOS) += dos.o
obj-$(CONFIG_PARTITION_DISK_EFI) += efi.o
diff --git a/common/partitions/dos.c b/common/partitions/dos.c
index 6c76aac371..8e4edd885b 100644
--- a/common/partitions/dos.c
+++ b/common/partitions/dos.c
@@ -15,11 +15,26 @@
#include <common.h>
#include <disks.h>
#include <init.h>
+#include <stdlib.h>
#include <asm/unaligned.h>
#include <linux/err.h>
+#include <partitions.h>
-#include "parser.h"
+struct dos_partition_desc {
+ struct partition_desc pd;
+ uint32_t signature;
+};
+struct dos_partition {
+ struct partition part;
+ bool extended;
+ bool logical;
+
+ uint8_t boot_indicator;
+ uint8_t chs_begin[3];
+ uint8_t type;
+ uint8_t chs_end[3];
+};
enum {
/* These three have identical behaviour; use the second one if DOS FDISK gets
@@ -106,17 +121,18 @@ static int dos_get_disk_signature(struct param_d *p, void *_priv)
return 0;
}
-static void dos_extended_partition(struct block_device *blk, struct partition_desc *pd,
+static void dos_extended_partition(struct block_device *blk, struct dos_partition_desc *dpd,
struct partition *partition, uint32_t signature)
{
uint8_t *buf = malloc(SECTOR_SIZE);
uint32_t ebr_sector = partition->first_sec;
struct partition_entry *table = (struct partition_entry *)&buf[0x1be];
- unsigned partno = 5;
+ unsigned partno = 4;
+ struct dos_partition *dpart;
+ struct partition *pentry;
- while (pd->used_entries < ARRAY_SIZE(pd->parts)) {
+ while (1) {
int rc, i;
- int n = pd->used_entries;
dev_dbg(blk->dev, "expect EBR in sector %x\n", ebr_sector);
@@ -139,15 +155,25 @@ static void dos_extended_partition(struct block_device *blk, struct partition_de
}
/* /sanity checks */
+ dpart = xzalloc(sizeof(*dpart));
+ dpart->logical = true;
+ dpart->boot_indicator = table[0].boot_indicator;
+ memcpy(dpart->chs_begin, table[0].chs_begin, sizeof(table[0].chs_begin));
+ dpart->type = table[0].type;
+ memcpy(dpart->chs_end, table[0].chs_end, sizeof(table[0].chs_end));
+
+ pentry = &dpart->part;
+
/* the first entry defines the extended partition */
- pd->parts[n].first_sec = ebr_sector +
+ pentry->first_sec = ebr_sector +
get_unaligned_le32(&table[0].partition_start);
- pd->parts[n].size = get_unaligned_le32(&table[0].partition_size);
- pd->parts[n].dos_partition_type = table[0].type;
- if (signature)
- sprintf(pd->parts[n].partuuid, "%08x-%02u",
- signature, partno);
- pd->used_entries++;
+ pentry->size = get_unaligned_le32(&table[0].partition_size);
+ pentry->dos_partition_type = table[0].type;
+ pentry->num = partno;
+ sprintf(pentry->partuuid, "%08x-%02u", signature, partno + 1);
+
+ list_add_tail(&pentry->list, &dpd->pd.partitions);
+
partno++;
/* the second entry defines the start of the next ebr if != 0 */
@@ -163,6 +189,15 @@ out:
return;
}
+static void extract_flags(const struct partition_entry *p,
+ struct partition *pentry)
+{
+ if (p->boot_indicator == 0x80)
+ pentry->flags |= DEVFS_PARTITION_BOOTABLE_LEGACY;
+ if (p->type == 0xef)
+ pentry->flags |= DEVFS_PARTITION_BOOTABLE_ESP;
+}
+
/**
* Check if a DOS like partition describes this block device
* @param blk Block device to register to
@@ -171,53 +206,72 @@ out:
* It seems at least on ARM this routine cannot use temp. stack space for the
* sector. So, keep the malloc/free.
*/
-static void dos_partition(void *buf, struct block_device *blk,
- struct partition_desc *pd)
+static struct partition_desc *dos_partition(void *buf, struct block_device *blk)
{
struct partition_entry *table;
- struct partition pentry;
+ struct dos_partition *dpart;
+ struct partition *pentry;
struct partition *extended_partition = NULL;
uint8_t *buffer = buf;
int i;
struct disk_signature_priv *dsp;
uint32_t signature = get_unaligned_le32(buf + 0x1b8);
+ struct dos_partition_desc *dpd;
+
+ sprintf(blk->cdev.diskuuid, "%08x", signature);
+
+ blk->cdev.flags |= DEVFS_IS_MBR_PARTITIONED;
table = (struct partition_entry *)&buffer[446];
+ dpd = xzalloc(sizeof(*dpd));
+ partition_desc_init(&dpd->pd, blk);
+
for (i = 0; i < 4; i++) {
- pentry.first_sec = get_unaligned_le32(&table[i].partition_start);
- pentry.size = get_unaligned_le32(&table[i].partition_size);
- pentry.dos_partition_type = table[i].type;
-
- if (pentry.first_sec != 0) {
- int n = pd->used_entries;
- pd->parts[n].first_sec = pentry.first_sec;
- pd->parts[n].size = pentry.size;
- pd->parts[n].dos_partition_type = pentry.dos_partition_type;
- if (signature)
- sprintf(pd->parts[n].partuuid, "%08x-%02d",
- signature, i + 1);
- pd->used_entries++;
-
- if (is_extended_partition(&pentry)) {
- if (!extended_partition)
- extended_partition = &pd->parts[n];
- else
- /*
- * An DOS MBR must only contain a single
- * extended partition. Just ignore all
- * but the first.
- */
- dev_warn(blk->dev, "Skipping additional extended partition\n");
- }
+ uint64_t first_sec = get_unaligned_le32(&table[i].partition_start);
- } else {
+ if (first_sec == 0) {
dev_dbg(blk->dev, "Skipping empty partition %d\n", i);
+ continue;
+ }
+
+ dpart = xzalloc(sizeof(*dpart));
+ dpart->boot_indicator = table[i].boot_indicator;
+ memcpy(dpart->chs_begin, table[i].chs_begin, sizeof(table[i].chs_begin));
+ dpart->type = table[i].type;
+ memcpy(dpart->chs_end, table[i].chs_end, sizeof(table[i].chs_end));
+
+ pentry = &dpart->part;
+
+ pentry->first_sec = first_sec;
+ pentry->size = get_unaligned_le32(&table[i].partition_size);
+ pentry->dos_partition_type = table[i].type;
+ extract_flags(&table[i], pentry);
+ pentry->num = i;
+
+ sprintf(pentry->partuuid, "%08x-%02d", signature, i + 1);
+ dpd->signature = signature;
+
+ if (is_extended_partition(pentry)) {
+ dpart->extended = true;
+ pentry->size = 2;
+
+ if (!extended_partition)
+ extended_partition = pentry;
+ else
+ /*
+ * An DOS MBR must only contain a single
+ * extended partition. Just ignore all
+ * but the first.
+ */
+ dev_warn(blk->dev, "Skipping additional extended partition\n");
}
+
+ list_add_tail(&pentry->list, &dpd->pd.partitions);
}
if (extended_partition)
- dos_extended_partition(blk, pd, extended_partition, signature);
+ dos_extended_partition(blk, dpd, extended_partition, signature);
dsp = xzalloc(sizeof(*dsp));
dsp->blk = blk;
@@ -235,11 +289,219 @@ static void dos_partition(void *buf, struct block_device *blk,
dev_add_param_uint32(blk->dev, "nt_signature",
dos_set_disk_signature, dos_get_disk_signature,
&dsp->signature, "%08x", dsp);
+
+ return &dpd->pd;
+}
+
+static void dos_partition_free(struct partition_desc *pd)
+{
+ struct partition *part, *tmp;
+
+ list_for_each_entry_safe(part, tmp, &pd->partitions, list) {
+ struct dos_partition *dpart = container_of(part, struct dos_partition, part);
+
+ free(dpart);
+ }
+
+ free(pd);
+}
+
+static __maybe_unused struct partition_desc *dos_partition_create_table(struct block_device *blk)
+{
+ struct dos_partition_desc *dpd = xzalloc(512);
+
+ partition_desc_init(&dpd->pd, blk);
+
+ dpd->signature = random32();
+
+ return &dpd->pd;
+}
+
+static int fs_type_to_type(const char *fstype)
+{
+ unsigned long type;
+ int ret;
+
+ if (!strcmp(fstype, "ext2"))
+ return 0x83;
+ if (!strcmp(fstype, "ext3"))
+ return 0x83;
+ if (!strcmp(fstype, "ext4"))
+ return 0x83;
+ if (!strcmp(fstype, "fat16"))
+ return 0xe;
+ if (!strcmp(fstype, "fat32"))
+ return 0xc;
+
+ ret = kstrtoul(fstype, 16, &type);
+ if (ret)
+ return ret;
+
+ if (type > 0xff)
+ return -EINVAL;
+
+ return type;
+}
+
+static __maybe_unused int dos_partition_mkpart(struct partition_desc *pd,
+ const char *name, const char *fs_type,
+ uint64_t start_lba, uint64_t end_lba)
+{
+ struct dos_partition *dpart;
+ struct partition *part, *part_extended = NULL;
+ int npart = 0, npart_logical = 0;
+ uint64_t size;
+ int mask_free = 0xf;
+ int type = fs_type_to_type(fs_type);
+
+ if (type < 0) {
+ pr_err("invalid fs_type \"%s\"\n", fs_type);
+ return -EINVAL;
+ }
+
+ if (start_lba < 1) {
+ pr_err("invalid start LBA, minimum is 1\n");
+ return -EINVAL;
+ }
+
+ list_for_each_entry(part, &pd->partitions, list) {
+ dpart = container_of(part, struct dos_partition, part);
+
+ mask_free &= ~(1 << npart);
+
+ if (dpart->extended)
+ part_extended = part;
+ if (dpart->logical)
+ npart_logical++;
+ else
+ npart++;
+ }
+
+ if (!strcmp(name, "extended")) {
+ if (part_extended) {
+ pr_err("extended partition already exists\n");
+ return -ENOSPC;
+ }
+ goto create;
+ } else if (!strcmp(name, "primary")) {
+ if (npart == 4) {
+ pr_err("Can't create any more partitions\n");
+ return -ENOSPC;
+ }
+
+ goto create;
+ } else if (!strcmp(name, "logical")) {
+ if (!part_extended) {
+ pr_err("No extended partition\n");
+ return -EINVAL;
+ }
+
+ if (npart_logical >= 4) {
+ pr_err("Can't create any more partitions\n");
+ return -ENOSPC;
+ }
+
+ pr_err("Can't create logical partitions yet\n");
+ return -EINVAL;
+ } else {
+ pr_err("Invalid name \"%s\"\n", name);
+ return -EINVAL;
+ }
+
+ return 0;
+
+create:
+ dpart = xzalloc(sizeof(*dpart));
+ part = &dpart->part;
+
+ if (start_lba > UINT_MAX)
+ return -ENOSPC;
+ size = end_lba - start_lba + 1;
+
+ if (size > UINT_MAX)
+ return -ENOSPC;
+
+ dpart->type = fs_type_to_type(fs_type);
+
+ part->first_sec = start_lba;
+ part->size = size;
+ part->num = ffs(mask_free);
+
+ list_add_tail(&part->list, &pd->partitions);
+
+ return 0;
+}
+
+static __maybe_unused int dos_partition_rmpart(struct partition_desc *pd, struct partition *part)
+{
+ struct dos_partition *dpart = container_of(part, struct dos_partition, part);
+
+ list_del(&part->list);
+ free(dpart);
+
+ return 0;
+}
+
+static __maybe_unused int dos_partition_write(struct partition_desc *pd)
+{
+ struct dos_partition_desc *dpd = container_of(pd, struct dos_partition_desc, pd);
+ struct dos_partition *dpart;
+ struct partition *part;
+ void *buf;
+ struct partition_entry *table, *entry;
+ int ret;
+
+ list_for_each_entry(part, &pd->partitions, list) {
+ dpart = container_of(part, struct dos_partition, part);
+ if (dpart->logical) {
+ pr_err("Cannot write tables with logical partitions yet\n");
+ return -EINVAL;
+ }
+ }
+
+ buf = read_mbr(pd->blk);
+ if (!buf)
+ return -EIO;
+
+ put_unaligned_le32(dpd->signature, buf + 0x1b8);
+
+ table = buf + 0x1be;
+ memset(table, 0x0, sizeof(*table) * 4);
+
+ *(u8 *)(buf + 0x1fe) = 0x55;
+ *(u8 *)(buf + 0x1ff) = 0xaa;
+
+ list_for_each_entry(part, &pd->partitions, list) {
+ dpart = container_of(part, struct dos_partition, part);
+
+ entry = &table[part->num - 1];
+
+ entry->boot_indicator = dpart->boot_indicator;
+ memcpy(entry->chs_begin, dpart->chs_begin, sizeof(entry->chs_begin));
+ entry->type = dpart->type;
+ memcpy(entry->chs_end, dpart->chs_end, sizeof(entry->chs_end));
+ put_unaligned_le32(part->first_sec, &entry->partition_start);
+ put_unaligned_le32(part->size, &entry->partition_size);
+ }
+
+ ret = block_write(pd->blk, buf, 0, 1);
+
+ free(buf);
+
+ return ret;
}
static struct partition_parser dos = {
.parse = dos_partition,
+ .partition_free = dos_partition_free,
+#ifdef CONFIG_PARTITION_MANIPULATION
+ .create = dos_partition_create_table,
+ .mkpart = dos_partition_mkpart,
+ .rmpart = dos_partition_rmpart,
+ .write = dos_partition_write,
+#endif
.type = filetype_mbr,
+ .name = "msdos",
};
static int dos_partition_init(void)
diff --git a/common/partitions/efi.c b/common/partitions/efi.c
index 135b08901a..829360da6e 100644
--- a/common/partitions/efi.c
+++ b/common/partitions/efi.c
@@ -19,8 +19,19 @@
#include <crc.h>
#include <linux/ctype.h>
-#include "efi.h"
-#include "parser.h"
+#include <efi/partition.h>
+#include <partitions.h>
+
+struct efi_partition_desc {
+ struct partition_desc pd;
+ gpt_header *gpt;
+ gpt_entry *ptes;
+};
+
+struct efi_partition {
+ struct partition part;
+ gpt_entry *pte;
+};
static const int force_gpt = IS_ENABLED(CONFIG_PARTITION_DISK_EFI_GPT_NO_FORCE);
@@ -80,6 +91,7 @@ static gpt_entry *alloc_read_gpt_entries(struct block_device *blk,
if (!count)
return NULL;
+
pte = kzalloc(count, GFP_KERNEL);
if (!pte)
return NULL;
@@ -154,8 +166,8 @@ static int is_gpt_valid(struct block_device *blk, u64 lba,
/* Check the GPT header signature */
if (le64_to_cpu((*gpt)->signature) != GPT_HEADER_SIGNATURE) {
- dev_dbg(blk->dev, "GUID Partition Table Header signature is wrong:"
- "0x%llX != 0x%llX\n",
+ dev_dbg(blk->dev, "GUID Partition Table Header signature at LBA"
+ "%llu is wrong: 0x%llX != 0x%llX\n", lba,
(unsigned long long)le64_to_cpu((*gpt)->signature),
(unsigned long long)GPT_HEADER_SIGNATURE);
goto fail;
@@ -206,7 +218,8 @@ static int is_gpt_valid(struct block_device *blk, u64 lba,
le32_to_cpu((*gpt)->sizeof_partition_entry));
if (crc != le32_to_cpu((*gpt)->partition_entry_array_crc32)) {
- dev_dbg(blk->dev, "GUID Partitition Entry Array CRC check failed.\n");
+ dev_dbg(blk->dev, "GUID Partitition Entry Array CRC check failed: 0x%08x 0x%08x\n",
+ crc, le32_to_cpu((*gpt)->partition_entry_array_crc32));
goto fail_ptes;
}
@@ -232,7 +245,7 @@ static int is_gpt_valid(struct block_device *blk, u64 lba,
static inline int
is_pte_valid(const gpt_entry *pte, const u64 lastlba)
{
- if ((!efi_guidcmp(pte->partition_type_guid, EFI_NULL_GUID)) ||
+ if (guid_is_null(&pte->partition_type_guid) ||
le64_to_cpu(pte->starting_lba) > lastlba ||
le64_to_cpu(pte->ending_lba) > lastlba)
return 0;
@@ -249,7 +262,8 @@ is_pte_valid(const gpt_entry *pte, const u64 lastlba)
*
*/
static void
-compare_gpts(struct device_d *dev, gpt_header *pgpt, gpt_header *agpt, u64 lastlba)
+compare_gpts(struct device *dev, gpt_header *pgpt, gpt_header *agpt,
+ u64 lastlba)
{
int error_found = 0;
if (!pgpt || !agpt)
@@ -286,7 +300,7 @@ compare_gpts(struct device_d *dev, gpt_header *pgpt, gpt_header *agpt, u64 lastl
(unsigned long long)le64_to_cpu(agpt->last_usable_lba));
error_found++;
}
- if (efi_guidcmp(pgpt->disk_guid, agpt->disk_guid)) {
+ if (!guid_equal(&pgpt->disk_guid, &agpt->disk_guid)) {
dev_warn(dev, "GPT:disk_guids don't match.\n");
error_found++;
}
@@ -430,20 +444,53 @@ static void part_set_efi_name(gpt_entry *pte, char *dest)
dest[i] = 0;
}
-static void efi_partition(void *buf, struct block_device *blk,
- struct partition_desc *pd)
+static void extract_flags(const gpt_entry *p, struct partition *pentry)
+{
+ static const guid_t system_guid = PARTITION_SYSTEM_GUID;
+
+ if (p->attributes.required_to_function)
+ pentry->flags |= DEVFS_PARTITION_REQUIRED;
+ if (p->attributes.no_block_io_protocol)
+ pentry->flags |= DEVFS_PARTITION_NO_EXPORT;
+ if (p->attributes.legacy_bios_bootable)
+ pentry->flags |= DEVFS_PARTITION_BOOTABLE_LEGACY;
+
+ if (guid_equal(&p->partition_type_guid, &system_guid))
+ pentry->flags |= DEVFS_PARTITION_BOOTABLE_ESP;
+
+ pentry->typeflags = p->attributes.type_guid_specific;
+}
+
+static void part_get_efi_name(gpt_entry *pte, const char *src)
+{
+ int i;
+ int len = strlen(src);
+
+ for (i = 0; i < GPT_PARTNAME_MAX_SIZE ; i++) {
+ if (i <= len)
+ pte->partition_name[i] = src[i];
+ else
+ pte->partition_name[i] = 0;
+ }
+}
+
+static struct partition_desc *efi_partition(void *buf, struct block_device *blk)
{
gpt_header *gpt = NULL;
gpt_entry *ptes = NULL;
int i = 0;
int nb_part;
+ struct efi_partition *epart;
struct partition *pentry;
+ struct efi_partition_desc *epd;
- if (!find_valid_gpt(buf, blk, &gpt, &ptes) || !gpt || !ptes) {
- kfree(gpt);
- kfree(ptes);
- return;
- }
+ if (!find_valid_gpt(buf, blk, &gpt, &ptes) || !gpt || !ptes)
+ return NULL;
+
+ snprintf(blk->cdev.diskuuid, sizeof(blk->cdev.diskuuid), "%pUl", &gpt->disk_guid);
+ dev_add_param_string_fixed(blk->dev, "guid", blk->cdev.diskuuid);
+
+ blk->cdev.flags |= DEVFS_IS_GPT_PARTITIONED;
nb_part = le32_to_cpu(gpt->num_partition_entries);
@@ -453,25 +500,286 @@ static void efi_partition(void *buf, struct block_device *blk,
nb_part = MAX_PARTITION;
}
+ epd = xzalloc(sizeof(*epd));
+ partition_desc_init(&epd->pd, blk);
+
+ epd->gpt = gpt;
+ epd->ptes = ptes;
+
for (i = 0; i < nb_part; i++) {
if (!is_pte_valid(&ptes[i], last_lba(blk))) {
dev_dbg(blk->dev, "Invalid pte %d\n", i);
- return;
+ continue;
}
- pentry = &pd->parts[pd->used_entries];
+ epart = xzalloc(sizeof(*epart));
+ epart->pte = &ptes[i];
+ pentry = &epart->part;
+ extract_flags(&ptes[i], pentry);
pentry->first_sec = le64_to_cpu(ptes[i].starting_lba);
pentry->size = le64_to_cpu(ptes[i].ending_lba) - pentry->first_sec;
pentry->size++;
part_set_efi_name(&ptes[i], pentry->name);
snprintf(pentry->partuuid, sizeof(pentry->partuuid), "%pUl", &ptes[i].unique_partition_guid);
- pd->used_entries++;
+ pentry->typeuuid = ptes[i].partition_type_guid;
+ pentry->num = i;
+ list_add_tail(&pentry->list, &epd->pd.partitions);
+ }
+
+ return &epd->pd;
+}
+
+static void efi_partition_free(struct partition_desc *pd)
+{
+ struct efi_partition_desc *epd = container_of(pd, struct efi_partition_desc, pd);
+ struct partition *part, *tmp;
+
+ list_for_each_entry_safe(part, tmp, &pd->partitions, list) {
+ struct efi_partition *epart = container_of(part, struct efi_partition, part);
+
+ free(epart);
+ }
+
+ free(epd->ptes);
+ free(epd->gpt);
+ free(epd);
+}
+
+static __maybe_unused struct partition_desc *efi_partition_create_table(struct block_device *blk)
+{
+ struct efi_partition_desc *epd = xzalloc(sizeof(*epd));
+ gpt_header *gpt;
+
+ partition_desc_init(&epd->pd, blk);
+
+ epd->gpt = xzalloc(512);
+ gpt = epd->gpt;
+
+ gpt->signature = cpu_to_le64(GPT_HEADER_SIGNATURE);
+ gpt->revision = cpu_to_le32(0x100);
+ gpt->header_size = cpu_to_le32(sizeof(*gpt));
+ gpt->my_lba = cpu_to_le64(1);
+ gpt->alternate_lba = cpu_to_le64(last_lba(blk));
+ gpt->first_usable_lba = cpu_to_le64(34);
+ gpt->last_usable_lba = cpu_to_le64(last_lba(blk) - 34);;
+ generate_random_guid((unsigned char *)&gpt->disk_guid);
+ gpt->partition_entry_lba = cpu_to_le64(2);
+ gpt->num_partition_entries = cpu_to_le32(128);
+ gpt->sizeof_partition_entry = cpu_to_le32(sizeof(gpt_entry));
+
+ pr_info("Created new disk label with GUID %pU\n", &gpt->disk_guid);
+
+ epd->ptes = xzalloc(128 * sizeof(gpt_entry));
+
+ return &epd->pd;
+}
+
+static guid_t partition_linux_data_guid = PARTITION_LINUX_DATA_GUID;
+static guid_t partition_basic_data_guid = PARTITION_BASIC_DATA_GUID;
+static guid_t partition_barebox_env_guid = PARTITION_BAREBOX_ENVIRONMENT_GUID;
+
+static const guid_t *fs_type_to_guid(const char *fstype)
+{
+ if (!strcmp(fstype, "ext2"))
+ return &partition_linux_data_guid;
+ if (!strcmp(fstype, "ext3"))
+ return &partition_linux_data_guid;
+ if (!strcmp(fstype, "ext4"))
+ return &partition_linux_data_guid;
+ if (!strcmp(fstype, "fat16"))
+ return &partition_basic_data_guid;
+ if (!strcmp(fstype, "fat32"))
+ return &partition_basic_data_guid;
+ if (!strcmp(fstype, "bbenv"))
+ return &partition_barebox_env_guid;
+
+ return NULL;
+}
+
+static __maybe_unused int efi_partition_mkpart(struct partition_desc *pd,
+ const char *name, const char *fs_type,
+ uint64_t start_lba, uint64_t end_lba)
+{
+ struct efi_partition_desc *epd = container_of(pd, struct efi_partition_desc, pd);
+ struct efi_partition *epart;
+ struct partition *part;
+ gpt_header *gpt = epd->gpt;
+ int num_parts = le32_to_cpu(gpt->num_partition_entries);
+ gpt_entry *pte;
+ int i;
+ const guid_t *guid;
+
+ if (start_lba < 34) {
+ pr_err("invalid start LBA %lld, minimum is 34\n", start_lba);
+ return -EINVAL;
}
+
+ if (end_lba >= last_lba(pd->blk) - 33) {
+ pr_err("invalid end LBA %lld, maximum is %lld\n", start_lba,
+ last_lba(pd->blk) - 33);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < num_parts; i++) {
+ if (!is_pte_valid(&epd->ptes[i], last_lba(pd->blk)))
+ break;
+ }
+
+ if (i == num_parts) {
+ pr_err("partition table is full\n");
+ return -ENOSPC;
+ }
+
+ guid = fs_type_to_guid(fs_type);
+ if (!guid) {
+ pr_err("Unknown fs type %s\n", fs_type);
+ return -EINVAL;
+ }
+
+ pte = &epd->ptes[i];
+ epart = xzalloc(sizeof(*epart));
+ part = &epart->part;
+
+ part->first_sec = start_lba;
+ part->size = end_lba - start_lba + 1;
+ part->typeuuid = *guid;
+
+ pte->partition_type_guid = *guid;
+ generate_random_guid((unsigned char *)&pte->unique_partition_guid);
+ pte->starting_lba = cpu_to_le64(start_lba);
+ pte->ending_lba = cpu_to_le64(end_lba);
+ part_get_efi_name(pte, name);
+ part_set_efi_name(pte, part->name);
+ part->num = i;
+
+ list_add_tail(&part->list, &pd->partitions);
+
+ return 0;
+}
+
+static __maybe_unused int efi_partition_rmpart(struct partition_desc *pd, struct partition *part)
+{
+ struct efi_partition *epart = container_of(part, struct efi_partition, part);
+
+ memset(epart->pte, 0, sizeof(*epart->pte));
+
+ list_del(&part->list);
+ free(epart);
+
+ return 0;
+}
+
+static int efi_protective_mbr(struct block_device *blk)
+{
+ struct partition_desc *pdesc;
+ int ret;
+
+ pdesc = partition_table_new(blk, "msdos");
+ if (IS_ERR(pdesc)) {
+ printf("Error: Cannot create partition table: %pe\n", pdesc);
+ return PTR_ERR(pdesc);
+ }
+
+ ret = partition_create(pdesc, "primary", "0xee", 1, last_lba(blk));
+ if (ret) {
+ pr_err("Cannot create partition: %pe\n", ERR_PTR(ret));
+ goto out;
+ }
+
+ ret = partition_table_write(pdesc);
+ if (ret) {
+ pr_err("Cannot write partition: %pe\n", ERR_PTR(ret));
+ goto out;
+ }
+out:
+ partition_table_free(pdesc);
+
+ return ret;
+}
+
+static __maybe_unused int efi_partition_write(struct partition_desc *pd)
+{
+ struct block_device *blk = pd->blk;
+ struct efi_partition_desc *epd = container_of(pd, struct efi_partition_desc, pd);
+ gpt_header *gpt = epd->gpt, *altgpt;
+ int ret;
+ uint32_t count;
+ uint64_t from, size;
+
+ if (le32_to_cpu(gpt->num_partition_entries) != 128) {
+ /*
+ * This is not yet properly implemented. At least writing of the
+ * alternative GPT is not correctly implemented for this case as
+ * we can't assume that the partition entries are written at
+ * last_lba() - 32, we would have to calculate that from the number
+ * of partition entries.
+ */
+ pr_err("num_partition_entries is != 128. This is not yet supported for writing\n");
+ return -EINVAL;
+ }
+
+ count = le32_to_cpu(gpt->num_partition_entries) *
+ le32_to_cpu(gpt->sizeof_partition_entry);
+
+ gpt->my_lba = cpu_to_le64(1);
+ gpt->partition_entry_array_crc32 = cpu_to_le32(efi_crc32(
+ (const unsigned char *)epd->ptes, count));
+ gpt->header_crc32 = 0;
+ gpt->header_crc32 = cpu_to_le32(efi_crc32((const unsigned char *)gpt,
+ le32_to_cpu(gpt->header_size)));
+
+ ret = efi_protective_mbr(blk);
+ if (ret)
+ return ret;
+
+ ret = block_write(blk, gpt, 1, 1);
+ if (ret)
+ goto err_block_write;
+
+ from = le64_to_cpu(gpt->partition_entry_lba);
+ size = count / GPT_BLOCK_SIZE;
+
+ ret = block_write(blk, epd->ptes, from, size);
+ if (ret)
+ goto err_block_write;
+
+ altgpt = xmemdup(gpt, SECTOR_SIZE);
+
+ altgpt->alternate_lba = cpu_to_le64(1);
+ altgpt->my_lba = cpu_to_le64(last_lba(blk));
+ altgpt->partition_entry_lba = cpu_to_le64(last_lba(blk) - 32);
+ altgpt->header_crc32 = 0;
+ altgpt->header_crc32 = cpu_to_le32(efi_crc32((const unsigned char *)altgpt,
+ le32_to_cpu(altgpt->header_size)));
+ ret = block_write(blk, altgpt, last_lba(blk), 1);
+
+ free(altgpt);
+
+ if (ret)
+ goto err_block_write;
+ ret = block_write(blk, epd->ptes, last_lba(blk) - 32, 32);
+ if (ret)
+ goto err_block_write;
+
+ return 0;
+
+err_block_write:
+ pr_err("Cannot write to block device: %pe\n", ERR_PTR(ret));
+
+ return ret;
}
static struct partition_parser efi_partition_parser = {
.parse = efi_partition,
+ .partition_free = efi_partition_free,
+#ifdef CONFIG_PARTITION_MANIPULATION
+ .create = efi_partition_create_table,
+ .mkpart = efi_partition_mkpart,
+ .rmpart = efi_partition_rmpart,
+ .write = efi_partition_write,
+#endif
.type = filetype_gpt,
+ .name = "gpt",
};
static int efi_partition_init(void)
diff --git a/common/partitions/efi.h b/common/partitions/efi.h
deleted file mode 100644
index a9b10c1266..0000000000
--- a/common/partitions/efi.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/************************************************************
- * EFI GUID Partition Table
- * Per Intel EFI Specification v1.02
- * http://developer.intel.com/technology/efi/efi.htm
- *
- * By Matt Domsch <Matt_Domsch@dell.com> Fri Sep 22 22:15:56 CDT 2000
- * Copyright 2000,2001 Dell Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- ************************************************************/
-
-#ifndef FS_PART_EFI_H_INCLUDED
-#define FS_PART_EFI_H_INCLUDED
-
-#include <efi.h>
-
-#define MSDOS_MBR_SIGNATURE 0xaa55
-#define EFI_PMBR_OSTYPE_EFI 0xEF
-#define EFI_PMBR_OSTYPE_EFI_GPT 0xEE
-
-#define GPT_BLOCK_SIZE 512
-#define GPT_HEADER_SIGNATURE 0x5452415020494645ULL
-#define GPT_HEADER_REVISION_V1 0x00010000
-#define GPT_PRIMARY_PARTITION_TABLE_LBA 1
-
-#define PARTITION_SYSTEM_GUID \
- EFI_GUID( 0xC12A7328, 0xF81F, 0x11d2, \
- 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B)
-#define LEGACY_MBR_PARTITION_GUID \
- EFI_GUID( 0x024DEE41, 0x33E7, 0x11d3, \
- 0x9D, 0x69, 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F)
-#define PARTITION_MSFT_RESERVED_GUID \
- EFI_GUID( 0xE3C9E316, 0x0B5C, 0x4DB8, \
- 0x81, 0x7D, 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE)
-#define PARTITION_BASIC_DATA_GUID \
- EFI_GUID( 0xEBD0A0A2, 0xB9E5, 0x4433, \
- 0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7)
-#define PARTITION_LINUX_RAID_GUID \
- EFI_GUID( 0xa19d880f, 0x05fc, 0x4d3b, \
- 0xa0, 0x06, 0x74, 0x3f, 0x0f, 0x84, 0x91, 0x1e)
-#define PARTITION_LINUX_SWAP_GUID \
- EFI_GUID( 0x0657fd6d, 0xa4ab, 0x43c4, \
- 0x84, 0xe5, 0x09, 0x33, 0xc8, 0x4b, 0x4f, 0x4f)
-#define PARTITION_LINUX_LVM_GUID \
- EFI_GUID( 0xe6d6d379, 0xf507, 0x44c2, \
- 0xa2, 0x3c, 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28)
-
-/* based on linux/include/genhd.h */
-struct legacy_partition {
- unsigned char boot_ind; /* 0x80 - active */
- unsigned char head; /* starting head */
- unsigned char sector; /* starting sector */
- unsigned char cyl; /* starting cylinder */
- unsigned char sys_ind; /* What partition type */
- unsigned char end_head; /* end head */
- unsigned char end_sector; /* end sector */
- unsigned char end_cyl; /* end cylinder */
- __le32 start_sect; /* starting sector counting from 0 */
- __le32 nr_sects; /* nr of sectors in partition */
-} __attribute__ ((packed));
-
-/* based on linux/fs/partitions/efi.h */
-typedef struct _gpt_header {
- __le64 signature;
- __le32 revision;
- __le32 header_size;
- __le32 header_crc32;
- __le32 reserved1;
- __le64 my_lba;
- __le64 alternate_lba;
- __le64 first_usable_lba;
- __le64 last_usable_lba;
- efi_guid_t disk_guid;
- __le64 partition_entry_lba;
- __le32 num_partition_entries;
- __le32 sizeof_partition_entry;
- __le32 partition_entry_array_crc32;
-
- /* The rest of the logical block is reserved by UEFI and must be zero.
- * EFI standard handles this by:
- *
- * uint8_t reserved2[ BlockSize - 92 ];
- */
-} __attribute__ ((packed)) gpt_header;
-
-typedef struct _gpt_entry_attributes {
- u64 required_to_function:1;
- u64 reserved:47;
- u64 type_guid_specific:16;
-} __attribute__ ((packed)) gpt_entry_attributes;
-
-#define GPT_PARTNAME_MAX_SIZE (72 / sizeof (efi_char16_t))
-typedef struct _gpt_entry {
- efi_guid_t partition_type_guid;
- efi_guid_t unique_partition_guid;
- __le64 starting_lba;
- __le64 ending_lba;
- gpt_entry_attributes attributes;
- efi_char16_t partition_name[GPT_PARTNAME_MAX_SIZE];
-} __attribute__ ((packed)) gpt_entry;
-
-typedef struct _legacy_mbr {
- u8 boot_code[440];
- __le32 unique_mbr_signature;
- __le16 unknown;
- struct legacy_partition partition_record[4];
- __le16 signature;
-} __attribute__ ((packed)) legacy_mbr;
-
-#endif /* _DISK_PART_EFI_H */
diff --git a/common/partitions/parser.h b/common/partitions/parser.h
deleted file mode 100644
index 69508932b3..0000000000
--- a/common/partitions/parser.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2013 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
- *
- * Under GPLv2 only
- */
-
-#ifndef __PARTITIONS_PARSER_H__
-#define __PARTITIONS_PARSER_H__
-
-#include <block.h>
-#include <filetype.h>
-#include <linux/list.h>
-
-#define MAX_PARTITION 128
-#define MAX_PARTITION_NAME 38
-
-struct partition {
- char name[MAX_PARTITION_NAME];
- u8 dos_partition_type;
- char partuuid[MAX_PARTUUID_STR];
- uint64_t first_sec;
- uint64_t size;
-};
-
-struct partition_desc {
- int used_entries;
- struct partition parts[MAX_PARTITION];
-};
-
-struct partition_parser {
- void (*parse)(void *buf, struct block_device *blk, struct partition_desc *pd);
- enum filetype type;
-
- struct list_head list;
-};
-
-int partition_parser_register(struct partition_parser *p);
-
-#endif /* __PARTITIONS_PARSER_H__ */
diff --git a/common/password.c b/common/password.c
index aea7c7ff5d..55b2d1093a 100644
--- a/common/password.c
+++ b/common/password.c
@@ -148,8 +148,7 @@ static unsigned char to_hexa(unsigned char c)
static int read_default_passwd(unsigned char *sum, size_t length)
{
- int i = 0;
- int len = strlen(default_passwd);
+ int len, i = 0;
unsigned char *buf = (unsigned char *)default_passwd;
unsigned char c;
@@ -159,6 +158,7 @@ static int read_default_passwd(unsigned char *sum, size_t length)
if (!sum || length < 1)
return -EINVAL;
+ len = strlen(default_passwd);
for (i = 0; i < len && length > 0; i++) {
c = buf[i];
i++;
diff --git a/common/pe.c b/common/pe.c
new file mode 100644
index 0000000000..5c33665dfa
--- /dev/null
+++ b/common/pe.c
@@ -0,0 +1,379 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * PE image loader
+ *
+ * based partly on wine code
+ *
+ * Copyright (c) 2016 Alexander Graf
+ */
+
+#define pr_fmt(fmt) "pe: " fmt
+
+#include <common.h>
+#include <pe.h>
+#include <linux/sizes.h>
+#include <libfile.h>
+#include <memory.h>
+#include <linux/err.h>
+
+static int machines[] = {
+#if defined(__aarch64__)
+ IMAGE_FILE_MACHINE_ARM64,
+#elif defined(__arm__)
+ IMAGE_FILE_MACHINE_ARM,
+ IMAGE_FILE_MACHINE_THUMB,
+ IMAGE_FILE_MACHINE_ARMNT,
+#endif
+
+#if defined(__x86_64__)
+ IMAGE_FILE_MACHINE_AMD64,
+#elif defined(__i386__)
+ IMAGE_FILE_MACHINE_I386,
+#endif
+
+#if defined(__riscv) && (__riscv_xlen == 32)
+ IMAGE_FILE_MACHINE_RISCV32,
+#endif
+
+#if defined(__riscv) && (__riscv_xlen == 64)
+ IMAGE_FILE_MACHINE_RISCV64,
+#endif
+ 0 };
+
+/**
+ * pe_loader_relocate() - relocate PE binary
+ *
+ * @rel: pointer to the relocation table
+ * @rel_size: size of the relocation table in bytes
+ * @pe_reloc: actual load address of the image
+ * @pref_address: preferred load address of the image
+ * Return: status code
+ */
+static int pe_loader_relocate(const IMAGE_BASE_RELOCATION *rel,
+ unsigned long rel_size, void *pe_reloc,
+ unsigned long pref_address)
+{
+ unsigned long delta = (unsigned long)pe_reloc - pref_address;
+ const IMAGE_BASE_RELOCATION *end;
+ int i;
+
+ if (delta == 0)
+ return 0;
+
+ end = (const IMAGE_BASE_RELOCATION *)((const char *)rel + rel_size);
+ while (rel < end && rel->SizeOfBlock) {
+ const uint16_t *relocs = (const uint16_t *)(rel + 1);
+ i = (rel->SizeOfBlock - sizeof(*rel)) / sizeof(uint16_t);
+ while (i--) {
+ uint32_t offset = (uint32_t)(*relocs & 0xfff) +
+ rel->VirtualAddress;
+ int type = *relocs >> PAGE_SHIFT;
+ uint64_t *x64 = pe_reloc + offset;
+ uint32_t *x32 = pe_reloc + offset;
+ uint16_t *x16 = pe_reloc + offset;
+
+ switch (type) {
+ case IMAGE_REL_BASED_ABSOLUTE:
+ break;
+ case IMAGE_REL_BASED_HIGH:
+ *x16 += ((uint32_t)delta) >> 16;
+ break;
+ case IMAGE_REL_BASED_LOW:
+ *x16 += (uint16_t)delta;
+ break;
+ case IMAGE_REL_BASED_HIGHLOW:
+ *x32 += (uint32_t)delta;
+ break;
+ case IMAGE_REL_BASED_DIR64:
+ *x64 += (uint64_t)delta;
+ break;
+#ifdef __riscv
+ case IMAGE_REL_BASED_RISCV_HI20:
+ *x32 = ((*x32 & 0xfffff000) + (uint32_t)delta) |
+ (*x32 & 0x00000fff);
+ break;
+ case IMAGE_REL_BASED_RISCV_LOW12I:
+ case IMAGE_REL_BASED_RISCV_LOW12S:
+ /* We know that we're 4k aligned */
+ if (delta & 0xfff) {
+ pr_err("Unsupported reloc offset\n");
+ return -ENOEXEC;
+ }
+ break;
+#endif
+ default:
+ pr_err("Unknown Relocation off %x type %x\n",
+ offset, type);
+ return -ENOEXEC;
+ }
+ relocs++;
+ }
+ rel = (const IMAGE_BASE_RELOCATION *)relocs;
+ }
+ return 0;
+}
+
+/**
+ * pe_check_header() - check if a memory buffer contains a PE-COFF image
+ *
+ * @buffer: buffer to check
+ * @size: size of buffer
+ * @nt_header: on return pointer to NT header of PE-COFF image
+ * Return: 0 if the buffer contains a PE-COFF image
+ */
+static int pe_check_header(void *buffer, size_t size, void **nt_header)
+{
+ struct mz_hdr *dos = buffer;
+ IMAGE_NT_HEADERS32 *nt;
+
+ if (size < sizeof(*dos))
+ return -EINVAL;
+
+ /* Check for DOS magix */
+ if (dos->magic != MZ_MAGIC)
+ return -EINVAL;
+
+ /*
+ * Check if the image section header fits into the file. Knowing that at
+ * least one section header follows we only need to check for the length
+ * of the 64bit header which is longer than the 32bit header.
+ */
+ if (size < dos->peaddr + sizeof(IMAGE_NT_HEADERS32))
+ return -EINVAL;
+ nt = (IMAGE_NT_HEADERS32 *)((u8 *)buffer + dos->peaddr);
+
+ /* Check for PE-COFF magic */
+ if (nt->FileHeader.magic != PE_MAGIC)
+ return -EINVAL;
+
+ if (nt_header)
+ *nt_header = nt;
+
+ return 0;
+}
+
+/**
+ * section_size() - determine size of section
+ *
+ * The size of a section in memory if normally given by VirtualSize.
+ * If VirtualSize is not provided, use SizeOfRawData.
+ *
+ * @sec: section header
+ * Return: size of section in memory
+ */
+static u32 section_size(IMAGE_SECTION_HEADER *sec)
+{
+ if (sec->Misc.VirtualSize)
+ return sec->Misc.VirtualSize;
+ else
+ return sec->SizeOfRawData;
+}
+
+struct pe_image *pe_open_buf(void *bin, size_t pe_size)
+{
+ struct pe_image *pe;
+ int i;
+ int supported = 0;
+ int ret;
+
+ pe = calloc(1, sizeof(*pe));
+ if (!pe)
+ return ERR_PTR(-ENOMEM);
+
+ ret = pe_check_header(bin, pe_size, (void **)&pe->nt);
+ if (ret) {
+ pr_err("Not a PE-COFF file\n");
+ ret = -ENOEXEC;
+ goto err;
+ }
+
+ for (i = 0; machines[i]; i++)
+ if (machines[i] == pe->nt->FileHeader.machine) {
+ supported = 1;
+ break;
+ }
+
+ if (!supported) {
+ pr_err("Machine type 0x%04x is not supported\n",
+ pe->nt->FileHeader.machine);
+ ret = -ENOEXEC;
+ goto err;
+ }
+
+ pe->num_sections = pe->nt->FileHeader.sections;
+ pe->sections = (void *)&pe->nt->OptionalHeader +
+ pe->nt->FileHeader.opt_hdr_size;
+
+ if (pe_size < ((void *)pe->sections + sizeof(pe->sections[0]) * pe->num_sections - bin)) {
+ pr_err("Invalid number of sections: %d\n", pe->num_sections);
+ ret = -ENOEXEC;
+ goto err;
+ }
+
+ pe->bin = bin;
+
+ return pe;
+err:
+ return ERR_PTR(ret);
+}
+
+struct pe_image *pe_open(const char *filename)
+{
+ struct pe_image *pe;
+ size_t size;
+ void *bin;
+
+ bin = read_file(filename, &size);
+ if (!bin)
+ return ERR_PTR(-errno);
+
+ pe = pe_open_buf(bin, size);
+ if (IS_ERR(pe))
+ free(bin);
+
+ return pe;
+}
+
+static struct resource *pe_alloc(size_t virt_size)
+{
+ resource_size_t start, end;
+ int ret;
+
+ ret = memory_bank_first_find_space(&start, &end);
+ if (ret)
+ return NULL;
+
+ start = ALIGN(start, SZ_64K);
+
+ if (start + virt_size > end)
+ return NULL;
+
+ return request_sdram_region("pe-code", start, virt_size);
+}
+
+unsigned long pe_get_mem_size(struct pe_image *pe)
+{
+ unsigned long virt_size = 0;
+ int i;
+
+ /* Calculate upper virtual address boundary */
+ for (i = pe->num_sections - 1; i >= 0; i--) {
+ IMAGE_SECTION_HEADER *sec = &pe->sections[i];
+
+ virt_size = max_t(unsigned long, virt_size,
+ sec->VirtualAddress + section_size(sec));
+ }
+
+ /* Read 32/64bit specific header bits */
+ if (pe->nt->OptionalHeader.magic == PE_OPT_MAGIC_PE32PLUS) {
+ IMAGE_NT_HEADERS64 *nt64 = (void *)pe->nt;
+ struct pe32plus_opt_hdr *opt = &nt64->OptionalHeader;
+
+ virt_size = ALIGN(virt_size, opt->section_align);
+ } else if (pe->nt->OptionalHeader.magic == PE_OPT_MAGIC_PE32) {
+ struct pe32_opt_hdr *opt = &pe->nt->OptionalHeader;
+
+ virt_size = ALIGN(virt_size, opt->section_align);
+ } else {
+ pr_err("Invalid optional header magic %x\n",
+ pe->nt->OptionalHeader.magic);
+ return 0;
+ }
+
+ return virt_size;
+}
+
+int pe_load(struct pe_image *pe)
+{
+ int rel_idx = IMAGE_DIRECTORY_ENTRY_BASERELOC;
+ uint64_t image_base;
+ unsigned long virt_size;
+ unsigned long rel_size;
+ const IMAGE_BASE_RELOCATION *rel;
+ struct mz_hdr *dos;
+ struct resource *code;
+ void *pe_reloc;
+ int i;
+
+ virt_size = pe_get_mem_size(pe);
+ if (!virt_size)
+ return -ENOEXEC;
+
+ /* Read 32/64bit specific header bits */
+ if (pe->nt->OptionalHeader.magic == PE_OPT_MAGIC_PE32PLUS) {
+ IMAGE_NT_HEADERS64 *nt64 = (void *)pe->nt;
+ struct pe32plus_opt_hdr *opt = &nt64->OptionalHeader;
+ image_base = opt->image_base;
+ pe->image_type = opt->subsys;
+
+ code = pe_alloc(virt_size);
+ if (!code)
+ return -ENOMEM;
+
+ pe_reloc = (void *)code->start;
+
+ pe->entry = code->start + opt->entry_point;
+ rel_size = nt64->DataDirectory[rel_idx].size;
+ rel = pe_reloc + nt64->DataDirectory[rel_idx].virtual_address;
+ } else if (pe->nt->OptionalHeader.magic == PE_OPT_MAGIC_PE32) {
+ struct pe32_opt_hdr *opt = &pe->nt->OptionalHeader;
+ image_base = opt->image_base;
+ pe->image_type = opt->subsys;
+ virt_size = ALIGN(virt_size, opt->section_align);
+
+ code = pe_alloc(virt_size);
+ if (!code)
+ return -ENOMEM;
+
+ pe_reloc = (void *)code->start;
+
+ pe->entry = code->start + opt->entry_point;
+ rel_size = pe->nt->DataDirectory[rel_idx].size;
+ rel = pe_reloc + pe->nt->DataDirectory[rel_idx].virtual_address;
+ } else {
+ pr_err("Invalid optional header magic %x\n",
+ pe->nt->OptionalHeader.magic);
+ return -ENOEXEC;
+ }
+
+ /* Copy PE headers */
+ memcpy(pe_reloc, pe->bin,
+ sizeof(*dos)
+ + sizeof(*pe->nt)
+ + pe->nt->FileHeader.opt_hdr_size
+ + pe->num_sections * sizeof(IMAGE_SECTION_HEADER));
+
+ /* Load sections into RAM */
+ for (i = pe->num_sections - 1; i >= 0; i--) {
+ IMAGE_SECTION_HEADER *sec = &pe->sections[i];
+ u32 copy_size = section_size(sec);
+
+ if (copy_size > sec->SizeOfRawData) {
+ copy_size = sec->SizeOfRawData;
+ memset(pe_reloc + sec->VirtualAddress, 0,
+ sec->Misc.VirtualSize);
+ }
+
+ memcpy(pe_reloc + sec->VirtualAddress,
+ pe->bin + sec->PointerToRawData,
+ copy_size);
+ }
+
+ /* Run through relocations */
+ if (pe_loader_relocate(rel, rel_size, pe_reloc,
+ (unsigned long)image_base) != 0) {
+ release_sdram_region(code);
+ return -EINVAL;
+ }
+
+ pe->code = code;
+
+ return 0;
+}
+
+void pe_close(struct pe_image *pe)
+{
+ release_sdram_region(pe->code);
+ free(pe->bin);
+ free(pe);
+}
diff --git a/common/ratp/Kconfig b/common/ratp/Kconfig
index 25150addfd..43720e30a0 100644
--- a/common/ratp/Kconfig
+++ b/common/ratp/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
config CONSOLE_RATP
bool
@@ -28,4 +29,4 @@ config RATP_CMD_GPIO
depends on GENERIC_GPIO
prompt "RATP GPIO support"
help
- This option adds support for GPIO get/set/direction commands via RATP. \ No newline at end of file
+ This option adds support for GPIO get/set/direction commands via RATP.
diff --git a/common/ratp/Makefile b/common/ratp/Makefile
index 71288bcb8c..e37ccca1fa 100644
--- a/common/ratp/Makefile
+++ b/common/ratp/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
obj-y += ratp.o
obj-y += ping.o
obj-y += getenv.o
diff --git a/common/ratp/getenv.c b/common/ratp/getenv.c
index 7b38d2e363..9617ab1b43 100644
--- a/common/ratp/getenv.c
+++ b/common/ratp/getenv.c
@@ -32,6 +32,9 @@ static int ratp_cmd_getenv(const struct ratp_bb *req, int req_len,
value = getenv(varname);
free(varname);
+ if (!value)
+ value = "";
+
dlen = strlen(value);
*rsp_len = sizeof(struct ratp_bb) + dlen;
diff --git a/common/ratp/i2c.c b/common/ratp/i2c.c
index c14bbbf9b9..404ddd2ece 100644
--- a/common/ratp/i2c.c
+++ b/common/ratp/i2c.c
@@ -162,7 +162,7 @@ out:
*rsp = (struct ratp_bb *)i2c_read_rsp;
*rsp_len = i2c_read_rsp_len;
- return ret;
+ return 0;
}
BAREBOX_RATP_CMD_START(I2C_READ)
@@ -271,7 +271,7 @@ out:
*rsp = (struct ratp_bb *)i2c_write_rsp;
*rsp_len = sizeof(*i2c_write_rsp);
- return ret;
+ return 0;
}
BAREBOX_RATP_CMD_START(I2C_WRITE)
diff --git a/common/ratp/md.c b/common/ratp/md.c
index 3e258c59a0..8221afaebc 100644
--- a/common/ratp/md.c
+++ b/common/ratp/md.c
@@ -68,8 +68,10 @@ static int do_ratp_mem_md(const char *filename,
char *buf = NULL;
fd = open_and_lseek(filename, O_RWSIZE_1 | O_RDONLY, start);
- if (fd < 0)
+ if (fd < 0) {
+ printf("Could not open \"%s\": %m\n", filename);
return -errno;
+ }
map = memmap(fd, PROT_READ);
if (map != MAP_FAILED) {
diff --git a/common/ratp/mw.c b/common/ratp/mw.c
index 8945799f1d..87dc8cb95c 100644
--- a/common/ratp/mw.c
+++ b/common/ratp/mw.c
@@ -133,6 +133,7 @@ static int ratp_cmd_mw(const struct ratp_bb *req, int req_len,
fd = open_and_lseek(path, O_RWSIZE_1 | O_WRONLY, addr);
if (fd < 0) {
+ printf("Could not open \"%s\": %m\n", path);
ret = -errno;
goto out;
}
diff --git a/common/ratp/ratp.c b/common/ratp/ratp.c
index 424c9406d2..fddb286e01 100644
--- a/common/ratp/ratp.c
+++ b/common/ratp/ratp.c
@@ -486,7 +486,7 @@ int barebox_ratp(struct console_device *cdev)
ctx->cdev = cdev;
ctx->have_synch = 1;
- ret = ratp_establish(&ctx->ratp, false, 100);
+ ret = ratp_establish(&ctx->ratp, false, 1000);
if (ret < 0)
goto out;
diff --git a/common/reset_source.c b/common/reset_source.c
index 3554cbd0fb..f28be90dcb 100644
--- a/common/reset_source.c
+++ b/common/reset_source.c
@@ -25,7 +25,7 @@ static const char * const reset_src_names[] = {
static enum reset_src_type reset_source;
static unsigned int reset_source_priority;
static int reset_source_instance;
-static struct device_d *reset_source_device;
+static struct device *reset_source_device;
enum reset_src_type reset_source_get(void)
{
@@ -45,13 +45,13 @@ int reset_source_get_instance(void)
}
EXPORT_SYMBOL(reset_source_get_instance);
-struct device_d *reset_source_get_device(void)
+struct device *reset_source_get_device(void)
{
return reset_source_device;
}
EXPORT_SYMBOL(reset_source_get_device);
-static void __reset_source_set(struct device_d *dev,
+static void __reset_source_set(struct device *dev,
enum reset_src_type st,
unsigned int priority, int instance)
{
@@ -74,9 +74,11 @@ void reset_source_set_prinst(enum reset_src_type st,
}
EXPORT_SYMBOL(reset_source_set_prinst);
-void reset_source_set_device(struct device_d *dev, enum reset_src_type st)
+void reset_source_set_device(struct device *dev, enum reset_src_type st)
{
- int priority = of_get_reset_source_priority(dev->device_node);
+ unsigned int priority = RESET_SOURCE_DEFAULT_PRIORITY;
+
+ of_property_read_u32(dev->of_node, "reset-source-priority", &priority);
__reset_source_set(dev, st, priority, -1);
}
@@ -92,19 +94,3 @@ static int reset_source_init(void)
return 0;
}
coredevice_initcall(reset_source_init);
-
-/**
- * of_get_reset_source_priority() - get the desired reset source priority from
- * device tree
- * @node: The device_node to read the property from
- *
- * return: The priority
- */
-unsigned int of_get_reset_source_priority(struct device_node *node)
-{
- unsigned int priority = RESET_SOURCE_DEFAULT_PRIORITY;
-
- of_property_read_u32(node, "reset-source-priority", &priority);
-
- return priority;
-}
diff --git a/common/resource.c b/common/resource.c
index f96cb94b50..8678609229 100644
--- a/common/resource.c
+++ b/common/resource.c
@@ -28,8 +28,8 @@ static int init_resource(struct resource *res, const char *name)
* resources.
*/
struct resource *__request_region(struct resource *parent,
- const char *name, resource_size_t start,
- resource_size_t end)
+ resource_size_t start, resource_size_t end,
+ const char *name, unsigned flags)
{
struct resource *r, *new;
@@ -73,15 +73,16 @@ struct resource *__request_region(struct resource *parent,
}
ok:
- debug("%s ok: 0x%08llx:0x%08llx\n", __func__,
+ debug("%s ok: 0x%08llx:0x%08llx flags=0x%x\n", __func__,
(unsigned long long)start,
- (unsigned long long)end);
+ (unsigned long long)end, flags);
new = xzalloc(sizeof(*new));
init_resource(new, name);
new->start = start;
new->end = end;
new->parent = parent;
+ new->flags = flags;
list_add_tail(&new->sibling, &r->sibling);
return new;
@@ -138,7 +139,7 @@ struct resource iomem_resource = {
struct resource *request_iomem_region(const char *name,
resource_size_t start, resource_size_t end)
{
- return __request_region(&iomem_resource, name, start, end);
+ return __request_region(&iomem_resource, start, end, name, 0);
}
/* The root resource for the whole io-mapped io space */
@@ -157,7 +158,7 @@ struct resource *request_ioport_region(const char *name,
{
struct resource *res;
- res = __request_region(&ioport_resource, name, start, end);
+ res = __request_region(&ioport_resource, start, end, name, 0);
if (IS_ERR(res))
return ERR_CAST(res);
diff --git a/common/restart.c b/common/restart.c
index b6f2bbf25b..35cfb54251 100644
--- a/common/restart.c
+++ b/common/restart.c
@@ -27,6 +27,14 @@ int restart_handler_register(struct restart_handler *rst)
if (!rst->priority)
rst->priority = RESTART_DEFAULT_PRIORITY;
+ if (rst->of_node) {
+ of_property_read_u32(rst->of_node, "restart-priority",
+ &rst->priority);
+ if (of_property_read_bool(rst->of_node,
+ "barebox,restart-warm-bootrom"))
+ rst->flags |= RESTART_FLAG_WARM_BOOTROM;
+ }
+
list_add_tail(&rst->list, &restart_handler_list);
pr_debug("registering restart handler \"%s\" with priority %d\n",
@@ -66,9 +74,9 @@ int restart_handler_register_fn(const char *name,
}
/**
- * restart_handler_get_by_name() - reset the whole system
+ * restart_handler_get_by_name() - get highest priority `name'
*/
-struct restart_handler *restart_handler_get_by_name(const char *name)
+struct restart_handler *restart_handler_get_by_name(const char *name, int flags)
{
struct restart_handler *rst = NULL, *tmp;
unsigned int priority = 0;
@@ -76,6 +84,8 @@ struct restart_handler *restart_handler_get_by_name(const char *name)
list_for_each_entry(tmp, &restart_handler_list, list) {
if (name && tmp->name && strcmp(name, tmp->name))
continue;
+ if (flags && (tmp->flags & flags) != flags)
+ continue;
if (tmp->priority > priority) {
priority = tmp->priority;
rst = tmp;
@@ -92,7 +102,7 @@ void __noreturn restart_machine(void)
{
struct restart_handler *rst;
- rst = restart_handler_get_by_name(NULL);
+ rst = restart_handler_get_by_name(NULL, 0);
if (rst) {
pr_debug("%s: using restart handler %s\n", __func__, rst->name);
console_flush();
@@ -102,21 +112,6 @@ void __noreturn restart_machine(void)
hang();
}
-/**
- * of_get_restart_priority() - get the desired restart priority from device tree
- * @node: The device_node to read the property from
- *
- * return: The priority
- */
-unsigned int of_get_restart_priority(struct device_node *node)
-{
- unsigned int priority = RESTART_DEFAULT_PRIORITY;
-
- of_property_read_u32(node, "restart-priority", &priority);
-
- return priority;
-}
-
/*
* restart_handlers_print - print informations about all restart handlers
*/
@@ -124,6 +119,10 @@ void restart_handlers_print(void)
{
struct restart_handler *tmp;
- list_for_each_entry(tmp, &restart_handler_list, list)
- printf("%-20s %6d\n", tmp->name, tmp->priority);
+ list_for_each_entry(tmp, &restart_handler_list, list) {
+ printf("%-20s %6d ", tmp->name, tmp->priority);
+ if (tmp->flags & RESTART_FLAG_WARM_BOOTROM)
+ putchar('W');
+ putchar('\n');
+ }
}
diff --git a/common/serdev.c b/common/serdev.c
index 4bf11b1618..5399a20627 100644
--- a/common/serdev.c
+++ b/common/serdev.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
#include <common.h>
#include <serdev.h>
@@ -131,7 +132,7 @@ static int serdev_device_reader_receive_buf(struct serdev_device *serdev,
const unsigned char *buf,
size_t size)
{
- struct device_d *dev = serdev->dev;
+ struct device *dev = serdev->dev;
struct serdev_device_reader *r = dev->priv;
const size_t room = min(r->capacity - r->len, size);
@@ -185,7 +186,7 @@ int serdev_device_reader_open(struct serdev_device *serdev, size_t capacity)
int serdev_device_read(struct serdev_device *serdev, unsigned char *buf,
size_t count, unsigned long timeout)
{
- struct device_d *dev = serdev->dev;
+ struct device *dev = serdev->dev;
struct serdev_device_reader *r = dev->priv;
int ret;
diff --git a/common/startup.c b/common/startup.c
index f72902fc53..47b70a7756 100644
--- a/common/startup.c
+++ b/common/startup.c
@@ -37,6 +37,8 @@
#include <linux/ctype.h>
#include <watchdog.h>
#include <glob.h>
+#include <net.h>
+#include <efi/efi-mode.h>
#include <bselftest.h>
extern initcall_t __barebox_initcalls_start[], __barebox_early_initcalls_end[],
@@ -53,7 +55,7 @@ static int mount_root(void)
mkdir("/tmp", 0);
mount("none", "devfs", "/dev", NULL);
- if (IS_ENABLED(CONFIG_FS_EFIVARFS)) {
+ if (IS_ENABLED(CONFIG_FS_EFIVARFS) && efi_is_payload()) {
mkdir("/efivars", 0);
mount("none", "efivarfs", "/efivars", NULL);
}
@@ -68,70 +70,6 @@ static int mount_root(void)
fs_initcall(mount_root);
#endif
-#ifdef CONFIG_ENV_HANDLING
-static bool region_overlap(loff_t starta, loff_t lena,
- loff_t startb, loff_t lenb)
-{
- if (starta + lena <= startb)
- return 0;
- if (startb + lenb <= starta)
- return 0;
- return 1;
-}
-
-static int check_overlap(const char *path)
-{
- struct cdev *cenv, *cdisk, *cpart;
- const char *name;
-
- name = devpath_to_name(path);
-
- if (name == path)
- /*
- * no /dev/ in front, so *path is some file. No need to
- * check further.
- */
- return 0;
-
- cenv = cdev_by_name(name);
- if (!cenv)
- return -EINVAL;
-
- if (cenv->mtd)
- return 0;
-
- cdisk = cenv->master;
-
- if (!cdisk)
- return 0;
-
- list_for_each_entry(cpart, &cdisk->partitions, partition_entry) {
- if (cpart == cenv)
- continue;
-
- if (region_overlap(cpart->offset, cpart->size,
- cenv->offset, cenv->size))
- goto conflict;
- }
-
- return 0;
-
-conflict:
- pr_err("Environment partition (0x%08llx-0x%08llx) "
- "overlaps with partition %s (0x%08llx-0x%08llx), not using it\n",
- cenv->offset, cenv->offset + cenv->size - 1,
- cpart->name,
- cpart->offset, cpart->offset + cpart->size - 1);
-
- return -EINVAL;
-}
-#else
-static int check_overlap(const char *path)
-{
- return 0;
-}
-#endif
-
static int load_environment(void)
{
const char *default_environment_path;
@@ -143,11 +81,7 @@ static int load_environment(void)
defaultenv_load("/env", 0);
if (IS_ENABLED(CONFIG_ENV_HANDLING)) {
- ret = check_overlap(default_environment_path);
- if (ret)
- default_environment_path_set(NULL);
- else
- envfs_load(default_environment_path, "/env", 0);
+ envfs_load(default_environment_path, "/env", 0);
} else {
if (IS_ENABLED(CONFIG_DEFAULT_ENVIRONMENT))
pr_notice("No support for persistent environment. Using default environment\n");
@@ -241,7 +175,8 @@ enum autoboot_state do_autoboot_countdown(void)
if (autoboot_state != AUTOBOOT_UNKNOWN)
return autoboot_state;
- if (IS_ENABLED(CONFIG_CONSOLE_DISABLE_INPUT)) {
+ if (!console_get_first_active() &&
+ global_autoboot_state != AUTOBOOT_ABORT) {
printf("\nNon-interactive console, booting system\n");
return autoboot_state = AUTOBOOT_BOOT;
}
@@ -375,6 +310,9 @@ static int run_init(void)
if (autoboot == AUTOBOOT_BOOT)
run_command("boot");
+ if (IS_ENABLED(CONFIG_NET))
+ eth_open_all();
+
if (autoboot == AUTOBOOT_MENU)
run_command(MENUFILE);
diff --git a/common/state/Makefile b/common/state/Makefile
index fcf9add52c..93215dd069 100644
--- a/common/state/Makefile
+++ b/common/state/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
obj-y += state.o
obj-y += state_variables.o
obj-y += backend_format_dtb.o
diff --git a/common/state/backend_bucket_circular.c b/common/state/backend_bucket_circular.c
index 735510e0d3..2ac5bf6a82 100644
--- a/common/state/backend_bucket_circular.c
+++ b/common/state/backend_bucket_circular.c
@@ -62,7 +62,7 @@ struct state_backend_storage_bucket_circular {
#endif
/* For outputs */
- struct device_d *dev;
+ struct device *dev;
};
/*
@@ -456,7 +456,7 @@ static int bucket_circular_is_block_bad(struct state_backend_storage_bucket_circ
}
#endif
-int state_backend_bucket_circular_create(struct device_d *dev, const char *path,
+int state_backend_bucket_circular_create(struct device *dev, const char *path,
struct state_backend_storage_bucket **bucket,
unsigned int eraseblock,
ssize_t writesize,
diff --git a/common/state/backend_bucket_direct.c b/common/state/backend_bucket_direct.c
index 4522f0170f..03c752d6fe 100644
--- a/common/state/backend_bucket_direct.c
+++ b/common/state/backend_bucket_direct.c
@@ -17,7 +17,7 @@
#include <libfile.h>
#include <linux/kernel.h>
#include <malloc.h>
-#include <printk.h>
+#include <linux/printk.h>
#include "state.h"
@@ -29,7 +29,7 @@ struct state_backend_storage_bucket_direct {
int fd;
- struct device_d *dev;
+ struct device *dev;
};
struct __attribute__((__packed__)) state_backend_storage_bucket_direct_meta {
@@ -52,7 +52,7 @@ static int state_backend_bucket_direct_read(struct state_backend_storage_bucket
struct state_backend_storage_bucket_direct *direct =
get_bucket_direct(bucket);
struct state_backend_storage_bucket_direct_meta meta;
- uint32_t read_len;
+ uint32_t read_len, header_len = 0;
void *buf;
int ret;
@@ -72,13 +72,15 @@ static int state_backend_bucket_direct_read(struct state_backend_storage_bucket
return -EINVAL;
}
+
+ header_len = sizeof(meta);
} else {
if (meta.magic != ~0 && !!meta.magic)
bucket->wrong_magic = 1;
if (!IS_ENABLED(CONFIG_STATE_BACKWARD_COMPATIBLE)) {
- dev_err(direct->dev, "No meta data header found\n");
dev_dbg(direct->dev, "Enable backward compatibility or increase stride size\n");
- return -EINVAL;
+ return dev_err_state_init(direct->dev, meta.magic ? -EINVAL : -ENOMEDIUM,
+ "No meta data header found\n");
}
read_len = direct->max_size;
if (lseek(direct->fd, direct->offset, SEEK_SET) !=
@@ -87,12 +89,16 @@ static int state_backend_bucket_direct_read(struct state_backend_storage_bucket
-errno);
return -errno;
}
+
}
buf = xmalloc(read_len);
if (!buf)
return -ENOMEM;
+ dev_dbg(direct->dev, "Read state from %lld length %d\n", (long long) direct->offset,
+ header_len + read_len);
+
ret = read_full(direct->fd, buf, read_len);
if (ret < 0) {
dev_err(direct->dev, "Failed to read from file, %d\n", ret);
@@ -112,6 +118,7 @@ static int state_backend_bucket_direct_write(struct state_backend_storage_bucket
{
struct state_backend_storage_bucket_direct *direct =
get_bucket_direct(bucket);
+ size_t header_len = 0;
int ret;
struct state_backend_storage_bucket_direct_meta meta;
@@ -129,6 +136,8 @@ static int state_backend_bucket_direct_write(struct state_backend_storage_bucket
dev_err(direct->dev, "Failed to write metadata to file, %d\n", ret);
return ret;
}
+
+ header_len = sizeof(meta);
} else {
if (!IS_ENABLED(CONFIG_STATE_BACKWARD_COMPATIBLE)) {
dev_dbg(direct->dev, "Too small stride size: must skip metadata! Increase stride size\n");
@@ -148,6 +157,9 @@ static int state_backend_bucket_direct_write(struct state_backend_storage_bucket
return ret;
}
+ dev_dbg(direct->dev, "Written state to offset %lld length %zu data length %zu\n",
+ (long long)direct->offset, len + header_len, len);
+
return 0;
}
@@ -162,14 +174,14 @@ static void state_backend_bucket_direct_free(struct
free(direct);
}
-int state_backend_bucket_direct_create(struct device_d *dev, const char *path,
+int state_backend_bucket_direct_create(struct device *dev, const char *path,
struct state_backend_storage_bucket **bucket,
- off_t offset, ssize_t max_size)
+ off_t offset, ssize_t max_size, bool readonly)
{
int fd;
struct state_backend_storage_bucket_direct *direct;
- fd = open(path, O_RDWR);
+ fd = open(path, readonly ? O_RDONLY : O_RDWR);
if (fd < 0) {
dev_err(dev, "Failed to open file '%s', %d\n", path, -errno);
return -errno;
diff --git a/common/state/backend_format_dtb.c b/common/state/backend_format_dtb.c
index d0fc948859..b41b896aac 100644
--- a/common/state/backend_format_dtb.c
+++ b/common/state/backend_format_dtb.c
@@ -28,7 +28,7 @@ struct state_backend_format_dtb {
struct device_node *root;
/* For outputs */
- struct device_d *dev;
+ struct device *dev;
};
static inline struct state_backend_format_dtb *get_format_dtb(struct
@@ -131,7 +131,7 @@ static void state_backend_format_dtb_free(struct state_backend_format *format)
}
int backend_format_dtb_create(struct state_backend_format **format,
- struct device_d *dev)
+ struct device *dev)
{
struct state_backend_format_dtb *dtb;
diff --git a/common/state/backend_format_raw.c b/common/state/backend_format_raw.c
index ea962606cc..105f7dd444 100644
--- a/common/state/backend_format_raw.c
+++ b/common/state/backend_format_raw.c
@@ -16,14 +16,12 @@
*/
#include <common.h>
-#include <common.h>
#include <crypto/keystore.h>
#include <digest.h>
#include <linux/kernel.h>
#include <malloc.h>
#include <crc.h>
#include <of.h>
-#include <crc.h>
#include "state.h"
@@ -34,7 +32,7 @@ struct state_backend_format_raw {
unsigned int digest_length;
/* For outputs */
- struct device_d *dev;
+ struct device *dev;
char *secret_name;
int needs_secret;
@@ -115,11 +113,10 @@ static int backend_format_raw_verify(struct state_backend_format *format,
header = (struct backend_raw_header *)buf;
crc = crc32(0, header, sizeof(*header) - sizeof(uint32_t));
- if (crc != header->header_crc) {
- dev_err(backend_raw->dev, "Error, invalid header crc in raw format, calculated 0x%08x, found 0x%08x\n",
+ if (crc != header->header_crc)
+ return dev_err_state_init(backend_raw->dev, header->header_crc ? -EINVAL : -ENOMEDIUM,
+ "header crc in raw format, calculated 0x%08x, found 0x%08x\n",
crc, header->header_crc);
- return -EINVAL;
- }
if (magic && magic != header->magic) {
dev_err(backend_raw->dev, "Error, invalid magic in raw format 0x%08x, should be 0x%08x\n",
@@ -302,7 +299,7 @@ static int backend_format_raw_init_digest(struct state_backend_format_raw *raw,
int backend_format_raw_create(struct state_backend_format **format,
struct device_node *node, const char *secret_name,
- struct device_d *dev)
+ struct device *dev)
{
struct state_backend_format_raw *raw;
int ret;
diff --git a/common/state/backend_storage.c b/common/state/backend_storage.c
index fe7e89e8fb..df81902bf7 100644
--- a/common/state/backend_storage.c
+++ b/common/state/backend_storage.c
@@ -21,7 +21,7 @@
#include <linux/mtd/mtd-abi.h>
#include <sys/stat.h>
#include <malloc.h>
-#include <printk.h>
+#include <linux/printk.h>
#include "state.h"
@@ -144,6 +144,7 @@ int state_storage_read(struct state_backend_storage *storage,
enum state_flags flags)
{
struct state_backend_storage_bucket *bucket, *bucket_used = NULL;
+ int zerobuckets = 0, totalbuckets = 0;
int ret;
dev_dbg(storage->dev, "Checking redundant buckets...\n");
@@ -152,30 +153,35 @@ int state_storage_read(struct state_backend_storage *storage,
* one we want to use.
*/
list_for_each_entry(bucket, &storage->buckets, bucket_list) {
+ totalbuckets++;
+
ret = bucket->read(bucket, &bucket->buf, &bucket->len);
- if (ret == -EUCLEAN)
+ if (ret == -EUCLEAN) {
bucket->needs_refresh = 1;
- else if (ret)
+ } else if (ret) {
+ if (ret == -ENOMEDIUM)
+ zerobuckets++;
continue;
+ }
/*
* Verify the buffer crcs. The buffer length is passed in the len argument,
* .verify overwrites it with the length actually used.
*/
ret = format->verify(format, magic, bucket->buf, &bucket->len, flags);
- if (!ret && !bucket_used)
+ if (ret == -ENOMEDIUM)
+ zerobuckets++;
+ else if (!ret && !bucket_used)
bucket_used = bucket;
- if (ret)
+ else if (ret)
dev_info(storage->dev, "Ignoring broken bucket %d@0x%08llx...\n", bucket->num, (long long) bucket->offset);
}
dev_dbg(storage->dev, "Checking redundant buckets finished.\n");
- if (!bucket_used) {
- dev_err(storage->dev, "Failed to find any valid state copy in any bucket\n");
-
- return -ENOENT;
- }
+ if (!bucket_used)
+ return dev_err_state_init(storage->dev, zerobuckets == totalbuckets ? -ENOMEDIUM : -ENOENT,
+ "no valid state copy in any bucket\n");
dev_info(storage->dev, "Using bucket %d@0x%08llx\n", bucket_used->num, (long long) bucket_used->offset);
@@ -326,7 +332,7 @@ static int state_storage_file_buckets_init(struct state_backend_storage *storage
offset = storage->offset + n * stridesize;
ret = state_backend_bucket_direct_create(storage->dev, storage->path,
&bucket, offset,
- stridesize);
+ stridesize, storage->readonly);
if (ret) {
dev_warn(storage->dev, "Failed to create direct bucket at '%s' offset %lld\n",
storage->path, (long long) offset);
diff --git a/common/state/state.c b/common/state/state.c
index 469ee62d40..219309d715 100644
--- a/common/state/state.c
+++ b/common/state/state.c
@@ -21,8 +21,10 @@
#include <fs.h>
#include <crc.h>
#include <init.h>
+#include <block.h>
#include <linux/err.h>
#include <linux/list.h>
+#include <linux/uuid.h>
#include <linux/mtd/mtd-abi.h>
#include <malloc.h>
@@ -101,8 +103,8 @@ static int state_do_load(struct state *state, enum state_flags flags)
ret = state_storage_read(&state->storage, state->format,
state->magic, &buf, &len, flags);
if (ret) {
- dev_err(&state->dev, "Failed to read state with format %s, %d\n",
- state->format->name, ret);
+ dev_err_state_init(&state->dev, ret, "format %s read failed\n",
+ state->format->name);
goto out;
}
@@ -333,8 +335,10 @@ static int state_convert_node_variable(struct state *state,
goto out;
return 0;
- out_free:free(name);
- out: return ret;
+out_free:
+ free(name);
+out:
+ return ret;
}
struct device_node *state_to_node(struct state *state,
@@ -361,7 +365,8 @@ struct device_node *state_to_node(struct state *state,
}
return root;
- out: of_delete_node(root);
+out:
+ of_delete_node(root);
return ERR_PTR(ret);
}
@@ -556,12 +561,12 @@ static int of_state_fixup(struct device_node *root, void *ctx)
goto out;
/* delete existing node */
- if (node)
- of_delete_node(node);
+ of_delete_node(node);
return 0;
- out: of_delete_node(new_node);
+out:
+ of_delete_node(new_node);
return ret;
}
@@ -578,6 +583,22 @@ void state_release(struct state *state)
free(state);
}
+#ifdef __BAREBOX__
+static char *cdev_to_devpath(struct cdev *cdev, off_t *offset, size_t *size)
+{
+ /*
+ * We only accept partitions exactly mapping the barebox-state,
+ * but dt-utils may need to set non-zero values here
+ */
+ *offset = 0;
+ *size = 0;
+
+ return basprintf("/dev/%s", cdev->name);
+}
+#endif
+
+static guid_t barebox_state_partition_guid = BAREBOX_STATE_PARTITION_GUID;
+
/*
* state_new_from_node - create a new state instance from a device_node
*
@@ -594,12 +615,13 @@ struct state *state_new_from_node(struct device_node *node, bool readonly)
const char *alias;
uint32_t stridesize;
struct device_node *partition_node;
- off_t offset = 0;
- size_t size = 0;
+ struct cdev *cdev;
+ off_t offset;
+ size_t size;
alias = of_alias_get(node);
if (!alias) {
- pr_err("State node %s does not have an alias in the /aliases/ node\n", node->full_name);
+ pr_err("State node %pOF does not have an alias in the /aliases/ node\n", node);
return ERR_PTR(-EINVAL);
}
@@ -614,15 +636,8 @@ struct state *state_new_from_node(struct device_node *node, bool readonly)
goto out_release_state;
}
-#ifdef __BAREBOX__
- ret = of_partition_ensure_probed(partition_node);
- if (ret)
- goto out_release_state;
-
- ret = of_find_path_by_node(partition_node, &state->backend_path, 0);
-#else
- ret = of_get_devicepath(partition_node, &state->backend_path, &offset, &size);
-#endif
+ cdev = of_cdev_find(partition_node);
+ ret = PTR_ERR_OR_ZERO(cdev);
if (ret) {
if (ret != -EPROBE_DEFER)
dev_err(&state->dev, "state failed to parse path to backend: %s\n",
@@ -630,6 +645,22 @@ struct state *state_new_from_node(struct device_node *node, bool readonly)
goto out_release_state;
}
+ /* Is the backend referencing an on-disk partitionable block device? */
+ if (cdev_is_block_disk(cdev)) {
+ cdev = cdev_find_child_by_gpt_typeuuid(cdev, &barebox_state_partition_guid);
+ if (IS_ERR(cdev)) {
+ ret = -EINVAL;
+ goto out_release_state;
+ }
+
+ pr_debug("%pOF: backend GPT partition looked up via PartitionTypeGUID\n",
+ node);
+ }
+
+ state->backend_path = cdev_to_devpath(cdev, &offset, &size);
+
+ pr_debug("%pOF: backend resolved to %s\n", node, state->backend_path);
+
state->backend_reproducible_name = of_get_reproducible_name(partition_node);
ret = of_property_read_string(node, "backend-type", &backend_type);
@@ -653,14 +684,14 @@ struct state *state_new_from_node(struct device_node *node, bool readonly)
if (ret)
goto out_release_state;
+ if (readonly)
+ state_backend_set_readonly(state);
+
ret = state_storage_init(state, state->backend_path, offset,
size, stridesize, storage_type);
if (ret)
goto out_release_state;
- if (readonly)
- state_backend_set_readonly(state);
-
ret = state_from_node(state, node, 1);
if (ret) {
goto out_release_state;
@@ -704,10 +735,12 @@ struct state *state_by_name(const char *name)
*
* @node The of node of the state instance
*/
-struct state *state_by_node(const struct device_node *node)
+struct state *state_by_node(struct device_node *node)
{
struct state *state;
+ of_device_ensure_probed(node);
+
list_for_each_entry(state, &state_list, list) {
if (!strcmp(state->of_path, node->full_name))
return state;
@@ -716,6 +749,22 @@ struct state *state_by_node(const struct device_node *node)
return NULL;
}
+/*
+ * state_by_alias - find a state instance by alias
+ *
+ * @name The DT alias of the state instance
+ */
+struct state *state_by_alias(const char *alias)
+{
+ struct device_node *node;
+
+ node = of_find_node_by_alias(NULL, alias);
+ if (!node)
+ return NULL;
+
+ return state_by_node(node);
+}
+
int state_read_mac(struct state *state, const char *name, u8 *buf)
{
struct state_variable *svar;
diff --git a/common/state/state.h b/common/state/state.h
index 1881d92ea7..f0c5b1de41 100644
--- a/common/state/state.h
+++ b/common/state/state.h
@@ -1,5 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
#include <linux/types.h>
#include <linux/list.h>
+#include <linux/err.h>
#include <driver.h>
struct state;
@@ -87,7 +90,7 @@ struct state_backend_storage {
struct list_head buckets;
/* For outputs */
- struct device_d *dev;
+ struct device *dev;
const char *name;
@@ -102,7 +105,7 @@ struct state_backend_storage {
struct state {
struct list_head list; /* Entry to enqueue on list of states */
- struct device_d dev;
+ struct device dev;
char *of_path;
const char *name;
uint32_t magic;
@@ -199,21 +202,21 @@ struct device_node *state_to_node(struct state *state,
enum state_convert conv);
int backend_format_raw_create(struct state_backend_format **format,
struct device_node *node, const char *secret_name,
- struct device_d *dev);
+ struct device *dev);
int backend_format_dtb_create(struct state_backend_format **format,
- struct device_d *dev);
+ struct device *dev);
int state_storage_init(struct state *state, const char *path,
off_t offset, size_t max_size, uint32_t stridesize,
const char *storagetype);
void state_storage_set_readonly(struct state_backend_storage *storage);
void state_add_var(struct state *state, struct state_variable *var);
struct variable_type *state_find_type_by_name(const char *name);
-int state_backend_bucket_circular_create(struct device_d *dev, const char *path,
+int state_backend_bucket_circular_create(struct device *dev, const char *path,
struct state_backend_storage_bucket **bucket,
unsigned int eraseblock,
ssize_t writesize,
struct mtd_info_user *mtd_uinfo);
-int state_backend_bucket_cached_create(struct device_d *dev,
+int state_backend_bucket_cached_create(struct device *dev,
struct state_backend_storage_bucket *raw,
struct state_backend_storage_bucket **out);
struct state_variable *state_find_var(struct state *state, const char *name);
@@ -221,9 +224,9 @@ struct digest *state_backend_format_raw_get_digest(struct state_backend_format
*format);
void state_backend_set_readonly(struct state *state);
void state_storage_free(struct state_backend_storage *storage);
-int state_backend_bucket_direct_create(struct device_d *dev, const char *path,
+int state_backend_bucket_direct_create(struct device *dev, const char *path,
struct state_backend_storage_bucket **bucket,
- off_t offset, ssize_t max_size);
+ off_t offset, ssize_t max_size, bool readonly);
int state_storage_write(struct state_backend_storage *storage,
const void * buf, ssize_t len);
int state_storage_read(struct state_backend_storage *storage,
@@ -266,3 +269,16 @@ static inline int state_string_copy_to_raw(struct state_string *string,
return 0;
}
+
+#ifdef DEBUG
+#define MSG_STATE_ZERO_INIT MSG_INFO
+#else
+#define MSG_STATE_ZERO_INIT MSG_DEBUG
+#endif
+
+#define dev_err_state_init(dev, ret, fmt, ...) ({ \
+ int __ret = (ret); \
+ __dev_printf(__ret == -ENOMEDIUM ? MSG_STATE_ZERO_INIT : MSG_ERR, \
+ (dev), "init error: %pe: " fmt, ERR_PTR(__ret), ##__VA_ARGS__); \
+ __ret; \
+})
diff --git a/common/state/state_variables.c b/common/state/state_variables.c
index 66c66f38bd..77946206cd 100644
--- a/common/state/state_variables.c
+++ b/common/state/state_variables.c
@@ -21,7 +21,7 @@
#include <linux/types.h>
#include <malloc.h>
#include <net.h>
-#include <printk.h>
+#include <linux/printk.h>
#include <of.h>
#include <stdio.h>
@@ -180,6 +180,8 @@ static int state_enum32_export(struct state_variable *var,
str += sprintf(str, "%s", enum32->names[i]) + 1;
ret = of_set_property(node, "names", prop, len, 1);
+ if (ret)
+ return ret;
free(prop);
@@ -261,7 +263,8 @@ static struct state_variable *state_enum32_create(struct state *state,
}
return &enum32->var;
- out: for (i--; i >= 0; i--)
+out:
+ for (i--; i >= 0; i--)
free((char *)enum32->names[i]);
free(enum32->names);
free(enum32);
@@ -327,7 +330,8 @@ static struct state_variable *state_mac_create(struct state *state,
}
return &mac->var;
- out: free(mac);
+out:
+ free(mac);
return ERR_PTR(ret);
}
@@ -442,7 +446,8 @@ static struct state_variable *state_string_create(struct state *state,
}
return &string->var;
- out: free(string);
+out:
+ free(string);
return ERR_PTR(ret);
}
diff --git a/common/tlsf.c b/common/tlsf.c
index 4247a9d3c7..ba2ed367c0 100644
--- a/common/tlsf.c
+++ b/common/tlsf.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -28,13 +30,8 @@ enum tlsf_public
/* Private constants: do not modify. */
enum tlsf_private
{
-#if defined (TLSF_64BIT)
/* All allocation sizes and addresses are aligned to 8 bytes. */
ALIGN_SIZE_LOG2 = 3,
-#else
- /* All allocation sizes and addresses are aligned to 4 bytes. */
- ALIGN_SIZE_LOG2 = 2,
-#endif
ALIGN_SIZE = (1 << ALIGN_SIZE_LOG2),
/*
@@ -99,6 +96,8 @@ tlsf_static_assert(sizeof(unsigned int) * CHAR_BIT >= SL_INDEX_COUNT);
/* Ensure we've properly tuned our sizes. */
tlsf_static_assert(ALIGN_SIZE == SMALL_BLOCK_SIZE / SL_INDEX_COUNT);
+tlsf_static_assert(ALIGN_SIZE >= CONFIG_MALLOC_ALIGNMENT);
+
/*
** Data structures and associated constants.
*/
@@ -120,6 +119,7 @@ typedef struct block_header_t
/* The size of this block, excluding the block header. */
size_t size;
+ u32 : BYTES_TO_BITS(ALIGN_SIZE - sizeof(size_t));
/* Next and previous free blocks. */
struct block_header_t* next_free;
@@ -132,28 +132,29 @@ typedef struct block_header_t
** - bit 0: whether block is busy or free
** - bit 1: whether previous block is busy or free
*/
-static const size_t block_header_free_bit = 1 << 0;
-static const size_t block_header_prev_free_bit = 1 << 1;
+#define block_header_free_bit (1 << 0)
+#define block_header_prev_free_bit (1 << 1)
/*
** The size of the block header exposed to used blocks is the size field.
** The prev_phys_block field is stored *inside* the previous free block.
*/
-static const size_t block_header_overhead = sizeof(size_t);
+#define block_header_shift offsetof(block_header_t, size)
+#define block_header_overhead ALIGN_SIZE
/* User data starts directly after the size field in a used block. */
-static const size_t block_start_offset =
- offsetof(block_header_t, size) + sizeof(size_t);
+#define block_start_offset (block_header_shift + block_header_overhead)
/*
** A free block must be large enough to store its header minus the size of
** the prev_phys_block field, and no larger than the number of addressable
** bits for FL_INDEX.
*/
-static const size_t block_size_min =
- sizeof(block_header_t) - sizeof(block_header_t*);
-static const size_t block_size_max = tlsf_cast(size_t, 1) << FL_INDEX_MAX;
+#define block_size_min (sizeof(block_header_t) - sizeof(block_header_t*))
+#define block_size_max (tlsf_cast(size_t, 1) << FL_INDEX_MAX)
+tlsf_static_assert(block_size_min % ALIGN_SIZE == 0);
+tlsf_static_assert(block_size_max % ALIGN_SIZE == 0);
/* The TLSF control structure. */
typedef struct control_t
@@ -164,10 +165,12 @@ typedef struct control_t
/* Bitmaps for free lists. */
unsigned int fl_bitmap;
unsigned int sl_bitmap[FL_INDEX_COUNT];
+ u32 : BYTES_TO_BITS(ALIGN_SIZE - sizeof(size_t));
/* Head of free lists. */
block_header_t* blocks[FL_INDEX_COUNT][SL_INDEX_COUNT];
} control_t;
+tlsf_static_assert(sizeof(control_t) % ALIGN_SIZE == 0);
/* A type used for casting when doing pointer arithmetic. */
typedef ptrdiff_t tlsfptr_t;
@@ -251,7 +254,7 @@ static block_header_t* block_prev(const block_header_t* block)
static block_header_t* block_next(const block_header_t* block)
{
block_header_t* next = offset_to_block(block_to_ptr(block),
- block_size(block) - block_header_overhead);
+ block_size(block) - block_header_shift);
tlsf_assert(!block_is_last(block));
return next;
}
@@ -311,7 +314,7 @@ static size_t adjust_request_size(size_t size, size_t align)
const size_t aligned = align_up(size, align);
/* aligned sized must not exceed block_size_max or we'll go out of bounds on sl_bitmap */
- if (aligned < block_size_max)
+ if (aligned >= size && aligned < block_size_max)
{
adjust = tlsf_max(aligned, block_size_min);
}
@@ -462,7 +465,7 @@ static block_header_t* block_split(block_header_t* block, size_t size)
{
/* Calculate the amount of space left in the remaining block. */
block_header_t* remaining =
- offset_to_block(block_to_ptr(block), size - block_header_overhead);
+ offset_to_block(block_to_ptr(block), size - block_header_shift);
const size_t remain_size = block_size(block) - (size + block_header_overhead);
@@ -728,7 +731,7 @@ void tlsf_walk_pool(pool_t pool, tlsf_walker walker, void* user)
{
tlsf_walker pool_walker = walker ? walker : default_walker;
block_header_t* block =
- offset_to_block(pool, -(int)block_header_overhead);
+ offset_to_block(pool, -(int)block_header_shift);
while (block && !block_is_last(block))
{
@@ -763,11 +766,11 @@ int tlsf_check_pool(pool_t pool)
/*
** Size of the TLSF structures in a given memory block passed to
-** tlsf_create, equal to the size of a control_t
+** tlsf_create, equal to aligned size of a control_t
*/
size_t tlsf_size(void)
{
- return sizeof(control_t);
+ return align_up(sizeof(control_t), ALIGN_SIZE);
}
size_t tlsf_align_size(void)
@@ -834,7 +837,7 @@ pool_t tlsf_add_pool(tlsf_t tlsf, void* mem, size_t bytes)
** so that the prev_phys_block field falls outside of the pool -
** it will never be used.
*/
- block = offset_to_block(mem, -(tlsfptr_t)block_header_overhead);
+ block = offset_to_block(mem, -(tlsfptr_t)block_header_shift);
block_set_size(block, pool_bytes);
block_set_free(block);
block_set_prev_used(block);
@@ -852,7 +855,7 @@ pool_t tlsf_add_pool(tlsf_t tlsf, void* mem, size_t bytes)
void tlsf_remove_pool(tlsf_t tlsf, pool_t pool)
{
control_t* control = tlsf_cast(control_t*, tlsf);
- block_header_t* block = offset_to_block(pool, -(int)block_header_overhead);
+ block_header_t* block = offset_to_block(pool, -(int)block_header_shift);
int fl = 0, sl = 0;
@@ -940,7 +943,12 @@ void* tlsf_malloc(tlsf_t tlsf, size_t size)
{
control_t* control = tlsf_cast(control_t*, tlsf);
const size_t adjust = adjust_request_size(size, ALIGN_SIZE);
- block_header_t* block = block_locate_free(control, adjust);
+ block_header_t* block;
+
+ if (!adjust)
+ return NULL;
+
+ block = block_locate_free(control, adjust);
return block_prepare_used(control, block, adjust, size);
}
@@ -967,10 +975,15 @@ void* tlsf_memalign(tlsf_t tlsf, size_t align, size_t size)
*/
const size_t aligned_size = (adjust && align > ALIGN_SIZE) ? size_with_gap : adjust;
- block_header_t* block = block_locate_free(control, aligned_size);
+ block_header_t* block;
+
+ if (!adjust || !size_with_gap)
+ return NULL;
+
+ block = block_locate_free(control, aligned_size);
/* This can't be a static assert. */
- tlsf_assert(sizeof(block_header_t) == block_size_min + block_header_overhead);
+ tlsf_assert(sizeof(block_header_t) == block_size_min + block_header_shift);
if (block)
{
@@ -1057,6 +1070,9 @@ void* tlsf_realloc(tlsf_t tlsf, void* ptr, size_t size)
tlsf_assert(!block_is_free(block) && "block already marked as free");
+ if (!adjust)
+ return NULL;
+
/*
** If the next block is used, or when combined with the current
** block, does not offer enough space, we must reallocate and copy.
diff --git a/common/tlsfbits.h b/common/tlsfbits.h
index edbac80636..8633fb5959 100644
--- a/common/tlsfbits.h
+++ b/common/tlsfbits.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
#ifndef INCLUDED_tlsfbits
#define INCLUDED_tlsfbits
diff --git a/common/ubiformat.c b/common/ubiformat.c
index e10ce31ce6..d8399ad9d6 100644
--- a/common/ubiformat.c
+++ b/common/ubiformat.c
@@ -444,7 +444,7 @@ static int format(struct ubiformat_args *args, struct mtd_info *mtd,
}
if (!args->quiet && !args->verbose)
- printf("\n");
+ printf("\rubiformat: formatted all eraseblocks -- 100 %% complete\n");
if (!novtbl) {
if (eb1 == -1 || eb2 == -1) {
@@ -745,6 +745,7 @@ int ubiformat_write(struct mtd_info *mtd, const void *buf, size_t count,
while (count) {
size_t now = mtd->erasesize - offset_in_peb;
+ int new_len;
if (now > count)
now = count;
@@ -780,7 +781,8 @@ int ubiformat_write(struct mtd_info *mtd, const void *buf, size_t count,
}
}
- ret = mtd_peb_write(mtd, buf, peb, offset_in_peb, now);
+ new_len = drop_ffs(mtd, buf, now);
+ ret = mtd_peb_write(mtd, buf, peb, offset_in_peb, new_len);
if (ret < 0)
return ret;
diff --git a/common/uimage.c b/common/uimage.c
index 42e9d9023f..cc9e5e510a 100644
--- a/common/uimage.c
+++ b/common/uimage.c
@@ -29,17 +29,19 @@ static inline int uimage_is_multi_image(struct uimage_handle *handle)
void uimage_print_contents(struct uimage_handle *handle)
{
struct image_header *hdr = &handle->header;
-#if defined(CONFIG_TIMESTAMP)
- struct rtc_time tm;
-#endif
+
printf(" Image Name: %.*s\n", IH_NMLEN, hdr->ih_name);
-#if defined(CONFIG_TIMESTAMP)
- printf(" Created: ");
- to_tm(hdr->ih_time, &tm);
- printf("%4d-%02d-%02d %2d:%02d:%02d UTC\n",
- tm.tm_year, tm.tm_mon, tm.tm_mday,
- tm.tm_hour, tm.tm_min, tm.tm_sec);
-#endif
+
+ if (IS_ENABLED(CONFIG_TIMESTAMP)) {
+ struct rtc_time tm;
+
+ printf(" Created: ");
+ to_tm(hdr->ih_time, &tm);
+ printf("%4d-%02d-%02d %2d:%02d:%02d UTC\n",
+ tm.tm_year, tm.tm_mon, tm.tm_mday,
+ tm.tm_hour, tm.tm_min, tm.tm_sec);
+ }
+
#if defined(CONFIG_BOOTM_SHOW_TYPE)
printf(" OS: %s\n", image_get_os_name(hdr->ih_os));
printf(" Architecture: %s\n", image_get_arch_name(hdr->ih_arch));
@@ -98,7 +100,7 @@ struct uimage_handle *uimage_open(const char *filename)
fd = open(filename, O_RDONLY);
if (fd < 0) {
- printf("could not open: %s\n", errno_str());
+ printf("could not open: %m\n");
free(copy);
return NULL;
}
@@ -109,7 +111,7 @@ struct uimage_handle *uimage_open(const char *filename)
handle->copy = copy;
if (read(fd, header, sizeof(*header)) < 0) {
- printf("could not read: %s\n", errno_str());
+ printf("could not read: %m\n");
goto err_out;
}
@@ -216,23 +218,23 @@ EXPORT_SYMBOL(uimage_close);
static int uimage_fd;
-static int uimage_fill(void *buf, unsigned int len)
+static long uimage_fill(void *buf, unsigned long len)
{
return read_full(uimage_fd, buf, len);
}
-static int uncompress_copy(unsigned char *inbuf_unused, int len,
- int(*fill)(void*, unsigned int),
- int(*flush)(void*, unsigned int),
+static int uncompress_copy(unsigned char *inbuf_unused, long len,
+ long(*fill)(void*, unsigned long),
+ long(*flush)(void*, unsigned long),
unsigned char *outbuf_unused,
- int *pos,
+ long *pos,
void(*error_fn)(char *x))
{
int ret;
void *buf = xmalloc(PAGE_SIZE);
while (len) {
- int now = min(len, PAGE_SIZE);
+ int now = min_t(long, len, PAGE_SIZE);
ret = fill(buf, now);
if (ret < 0)
goto err;
@@ -293,17 +295,17 @@ EXPORT_SYMBOL(uimage_verify);
* Load a uimage, flushing output to flush function
*/
int uimage_load(struct uimage_handle *handle, unsigned int image_no,
- int(*flush)(void*, unsigned int))
+ long(*flush)(void*, unsigned long))
{
image_header_t *hdr = &handle->header;
struct uimage_handle_data *iha;
int ret;
loff_t off;
- int (*uncompress_fn)(unsigned char *inbuf, int len,
- int(*fill)(void*, unsigned int),
- int(*flush)(void*, unsigned int),
+ int (*uncompress_fn)(unsigned char *inbuf, long len,
+ long(*fill)(void*, unsigned long),
+ long(*flush)(void*, unsigned long),
unsigned char *output,
- int *pos,
+ long *pos,
void(*error)(char *x));
if (image_no >= handle->nb_data_entries)
@@ -334,7 +336,7 @@ static void *uimage_buf;
static size_t uimage_size;
static struct resource *uimage_resource;
-static int uimage_sdram_flush(void *buf, unsigned int len)
+static long uimage_sdram_flush(void *buf, unsigned long len)
{
if (uimage_size + len > resource_size(uimage_resource)) {
resource_size_t start = uimage_resource->start;
diff --git a/common/usbgadget.c b/common/usbgadget.c
index e8c9f7d236..3713551163 100644
--- a/common/usbgadget.c
+++ b/common/usbgadget.c
@@ -12,14 +12,15 @@
#include <getopt.h>
#include <fs.h>
#include <xfuncs.h>
-#include <usb/usbserial.h>
-#include <usb/dfu.h>
-#include <usb/gadget-multi.h>
+#include <linux/usb/usbserial.h>
+#include <linux/usb/dfu.h>
+#include <linux/usb/gadget-multi.h>
#include <globalvar.h>
#include <magicvar.h>
#include <system-partitions.h>
static int autostart;
+static int nv_loaded;
static int acm;
static char *dfu_function;
@@ -27,16 +28,14 @@ static inline struct file_list *get_dfu_function(void)
{
if (dfu_function && *dfu_function)
return file_list_parse_null(dfu_function);
- if (!system_partitions_empty())
- return system_partitions_get();
- return NULL;
+ return system_partitions_get_null();
}
int usbgadget_register(const struct usbgadget_funcs *funcs)
{
int ret;
int flags = funcs->flags;
- struct device_d *dev;
+ struct device *dev;
struct f_multi_opts *opts;
opts = xzalloc(sizeof(*opts));
@@ -54,7 +53,7 @@ int usbgadget_register(const struct usbgadget_funcs *funcs)
opts->ums_opts.files = file_list_parse_null(funcs->ums_opts);
if (IS_ENABLED(CONFIG_USB_GADGET_MASS_STORAGE) && file_list_empty(opts->ums_opts.files)) {
file_list_free(opts->ums_opts.files);
- opts->ums_opts.files = system_partitions_get();
+ opts->ums_opts.files = system_partitions_get_null();
}
}
@@ -100,13 +99,20 @@ err:
return ret;
}
-static int usbgadget_autostart_set(struct param_d *param, void *ctx)
+static int usbgadget_do_autostart(void)
{
struct usbgadget_funcs funcs = {};
static bool started;
int err;
- if (!autostart || started)
+ if (!IS_ENABLED(CONFIG_USB_GADGET_AUTOSTART))
+ return 0;
+
+ /*
+ * We want to run this function exactly once when the
+ * environment is loaded and autostart is requested
+ */
+ if (!nv_loaded || !autostart || started)
return 0;
if (get_fastboot_bbu())
@@ -123,19 +129,38 @@ static int usbgadget_autostart_set(struct param_d *param, void *ctx)
return err;
}
+static int usbgadget_autostart_set(struct param_d *param, void *ctx)
+{
+ usbgadget_do_autostart();
+
+ return 0;
+}
+
+void usbgadget_autostart(bool enable)
+{
+ autostart = enable;
+
+ usbgadget_do_autostart();
+}
+
static int usbgadget_globalvars_init(void)
{
globalvar_add_simple_bool("usbgadget.acm", &acm);
globalvar_add_simple_string("usbgadget.dfu_function", &dfu_function);
+ if (IS_ENABLED(CONFIG_USB_GADGET_AUTOSTART))
+ globalvar_add_bool("usbgadget.autostart", usbgadget_autostart_set,
+ &autostart, NULL);
return 0;
}
-device_initcall(usbgadget_globalvars_init);
+coredevice_initcall(usbgadget_globalvars_init);
static int usbgadget_autostart_init(void)
{
- if (IS_ENABLED(CONFIG_USB_GADGET_AUTOSTART))
- globalvar_add_bool("usbgadget.autostart", usbgadget_autostart_set, &autostart, NULL);
+ nv_loaded = true;
+
+ usbgadget_do_autostart();
+
return 0;
}
postenvironment_initcall(usbgadget_autostart_init);
diff --git a/common/version.c b/common/version.c
index 54cec5335d..0cac5ee609 100644
--- a/common/version.c
+++ b/common/version.c
@@ -1,9 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
#include <common.h>
#include <generated/compile.h>
#include <generated/utsrelease.h>
const char version_string[] =
- "barebox " UTS_RELEASE " " UTS_VERSION "\n";
+ "barebox " UTS_RELEASE " " UTS_VERSION;
EXPORT_SYMBOL(version_string);
const char release_string[] =
@@ -18,9 +20,9 @@ EXPORT_SYMBOL(buildsystem_version_string);
void barebox_banner (void)
{
printf("\n\n");
- pr_info("%s", version_string);
+ pr_info("%s\n", version_string);
if (strlen(buildsystem_version_string) > 0)
- pr_info("Buildsystem version: %s", buildsystem_version_string);
+ pr_info("Buildsystem version: %s\n", buildsystem_version_string);
printf("\n\n");
pr_info("Board: %s\n", barebox_get_model());
}