summaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
Diffstat (limited to 'common')
-rw-r--r--common/Kconfig598
-rw-r--r--common/Kconfig.debug153
-rw-r--r--common/Kconfig.debug_ll430
-rw-r--r--common/Makefile15
-rw-r--r--common/bbu.c134
-rw-r--r--common/binfmt.c6
-rw-r--r--common/block.c80
-rw-r--r--common/blspec.c46
-rw-r--r--common/boards/Kconfig15
-rw-r--r--common/boards/Makefile3
-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/Makefile10
-rw-r--r--common/boards/qemu-virt/board.c66
-rw-r--r--common/boards/qemu-virt/fitimage-pubkey.dts7
-rw-r--r--common/boards/qemu-virt/overlay-of-flash.dts113
-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/boards/wolfvision/Makefile2
-rw-r--r--common/boards/wolfvision/common.c142
-rw-r--r--common/boot.c25
-rw-r--r--common/bootchooser.c11
-rw-r--r--common/booti.c6
-rw-r--r--common/bootm.c265
-rw-r--r--common/bootsource.c36
-rw-r--r--common/complete.c105
-rw-r--r--common/console.c36
-rw-r--r--common/console_common.c49
-rw-r--r--common/console_simple.c2
-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.c593
-rw-r--r--common/deep-probe.c10
-rw-r--r--common/dlmalloc.c36
-rw-r--r--common/dummy_malloc.c2
-rw-r--r--common/efi/Kconfig27
-rw-r--r--common/efi/Makefile6
-rw-r--r--common/efi/devicepath.c830
-rw-r--r--common/efi/efivar-filename.c116
-rw-r--r--common/efi/errno.c90
-rw-r--r--common/efi/guid.c95
-rw-r--r--common/efi/payload/Makefile6
-rw-r--r--common/efi/payload/env-efi/network/eth0-discover5
-rw-r--r--common/efi/payload/image.c283
-rw-r--r--common/efi/payload/init.c387
-rw-r--r--common/efi/payload/iomem.c179
-rw-r--r--common/elf.c37
-rw-r--r--common/env.c31
-rw-r--r--common/envfs-core.c3
-rw-r--r--common/environment.c90
-rw-r--r--common/fastboot.c92
-rw-r--r--common/file-list.c51
-rw-r--r--common/filetype.c61
-rw-r--r--common/firmware.c41
-rw-r--r--common/globalvar.c38
-rw-r--r--common/hush.c11
-rw-r--r--common/image-fit.c170
-rw-r--r--common/imx-bbu-nand-fcb.c474
-rw-r--r--common/kallsyms.c8
-rw-r--r--common/machine_id.c88
-rw-r--r--common/meminfo.c4
-rw-r--r--common/memory.c27
-rw-r--r--common/memory_display.c2
-rw-r--r--common/memtest.c44
-rw-r--r--common/misc.c115
-rw-r--r--common/module.lds.S2
-rw-r--r--common/oftree.c58
-rw-r--r--common/optee.c50
-rw-r--r--common/partitions.c210
-rw-r--r--common/partitions/Kconfig1
-rw-r--r--common/partitions/dos.c349
-rw-r--r--common/partitions/efi.c339
-rw-r--r--common/partitions/parser.h39
-rw-r--r--common/pe.c379
-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.c10
-rw-r--r--common/resource.c16
-rw-r--r--common/restart.c39
-rw-r--r--common/serdev.c4
-rw-r--r--common/startup.c10
-rw-r--r--common/state/backend_bucket_circular.c4
-rw-r--r--common/state/backend_bucket_direct.c22
-rw-r--r--common/state/backend_format_dtb.c4
-rw-r--r--common/state/backend_format_raw.c4
-rw-r--r--common/state/backend_storage.c2
-rw-r--r--common/state/state.c73
-rw-r--r--common/state/state.h16
-rw-r--r--common/state/state_variables.c9
-rw-r--r--common/tlsf.c43
-rw-r--r--common/ubiformat.c6
-rw-r--r--common/uimage.c50
-rw-r--r--common/usbgadget.c8
-rw-r--r--common/version.c6
100 files changed, 6555 insertions, 3570 deletions
diff --git a/common/Kconfig b/common/Kconfig
index 43dd92b08a..98a5e99b75 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -27,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()
@@ -78,7 +78,7 @@ config ARCH_DMA_ADDR_T_64BIT
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
@@ -144,6 +144,9 @@ config MEMINFO
bool "display memory info"
default y
+config MEMTEST
+ bool
+
config ENVIRONMENT_VARIABLES
bool "environment variables support"
@@ -185,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
@@ -201,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"
@@ -276,6 +277,11 @@ config MALLOC_SIZE
hex
default 0x400000
prompt "malloc area size"
+
+config MALLOC_ALIGNMENT
+ hex
+ default 8
+
endmenu
config BROKEN
@@ -347,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
@@ -518,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"
@@ -536,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
@@ -603,6 +623,9 @@ 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
@@ -643,9 +666,10 @@ 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 public key for verifying
- FIT images signature is taken from environment which allows for
- better integration with build systems.
+ 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:
@@ -663,6 +687,10 @@ 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
@@ -683,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
@@ -714,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
@@ -812,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
@@ -840,6 +878,9 @@ config PARTITION
bool
prompt "Enable Partitions"
+config PARTITION_MANIPULATION
+ bool
+
source "common/partitions/Kconfig"
config ENV_HANDLING
@@ -1004,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
@@ -1016,6 +1057,8 @@ 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
@@ -1119,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.
@@ -1144,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.
@@ -1177,448 +1239,8 @@ endif
endmenu
-menu "Debugging"
-
-config COMPILE_LOGLEVEL
- int "compile loglevel"
- default 6
- help
- This defines the maximum loglevel compiled into the binary. Less important
- messages will be compiled away resulting in a smaller binary.
-
- 0 system is unusable (emerg)
- 1 action must be taken immediately (alert)
- 2 critical conditions (crit)
- 3 error conditions (err)
- 4 warning conditions (warn)
- 5 normal but significant condition (notice)
- 6 informational (info)
- 7 debug-level messages (debug)
- 8 verbose debug messages (vdebug)
-
-config DEFAULT_LOGLEVEL
- int "default loglevel"
- default 7
- help
- This defines the default runtime loglevel. It can be changed using the
- global.loglevel variable. Available logelevels are:
-
- 0 system is unusable (emerg)
- 1 action must be taken immediately (alert)
- 2 critical conditions (crit)
- 3 error conditions (err)
- 4 warning conditions (warn)
- 5 normal but significant condition (notice)
- 6 informational (info)
- 7 debug-level messages (debug)
- 8 verbose debug messages (vdebug)
-
-config DEBUG_LL
- bool
- depends on HAS_DEBUG_LL
- prompt "Low level debug messages (read help)"
- help
- Enable this to get low level debug messages during barebox
- initialization. This is helpful if you are debugging code that
- executes before the console is initialized.
-
- This requires SoC specific support. Most SoCs require the
- debug UART to be initialized by a debugger or first stage
- bootloader.
-
- Note that selecting this option will limit barebox to a single
- UART definition, as specified below under "low-level debugging
- port". Attempting to boot the resulting image on a different
- 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.
-
-choice
- prompt "Kernel low-level debugging port"
- depends on DEBUG_LL
-
-config DEBUG_IMX1_UART
- bool "i.MX1 Debug UART"
- depends on ARCH_IMX1
- help
- Say Y here if you want kernel low-level debugging support
- on i.MX1.
-
-config DEBUG_IMX21_UART
- bool "i.MX21 Debug UART"
- depends on ARCH_IMX21
- help
- Say Y here if you want kernel low-level debugging support
- on i.MX21.
-
-config DEBUG_IMX25_UART
- bool "i.MX25 Debug UART"
- depends on ARCH_IMX25
- help
- Say Y here if you want kernel low-level debugging support
- on i.MX25.
-
-config DEBUG_IMX27_UART
- bool "i.MX27 Debug UART"
- depends on ARCH_IMX27
- help
- Say Y here if you want kernel low-level debugging support
- on i.MX27.
-
-config DEBUG_IMX31_UART
- bool "i.MX31 Debug UART"
- depends on ARCH_IMX31
- help
- Say Y here if you want kernel low-level debugging support
- on i.MX31.
-
-config DEBUG_IMX35_UART
- bool "i.MX35 Debug UART"
- depends on ARCH_IMX35
- help
- Say Y here if you want kernel low-level debugging support
- on i.MX35.
-
-config DEBUG_IMX50_UART
- bool "i.MX50 Debug UART"
- depends on ARCH_IMX50
- help
- Say Y here if you want kernel low-level debugging support
- on i.MX50.
-
-config DEBUG_IMX51_UART
- bool "i.MX51 Debug UART"
- depends on ARCH_IMX51
- help
- Say Y here if you want kernel low-level debugging support
- on i.MX51.
-
-config DEBUG_IMX53_UART
- bool "i.MX53 Debug UART"
- depends on ARCH_IMX53
- help
- Say Y here if you want kernel low-level debugging support
- on i.MX53.
-
-config DEBUG_IMX6Q_UART
- bool "i.MX6Q Debug UART"
- depends on ARCH_IMX6
- help
- Say Y here if you want kernel low-level debugging support
- on i.MX6Q.
-
-config DEBUG_IMX7D_UART
- bool "i.MX7D Debug UART"
- depends on ARCH_IMX7
- help
- Say Y here if you want barebox low-level debugging support
- on i.MX7D.
-
-config DEBUG_IMX8M_UART
- bool "i.MX8M Debug UART"
- depends on ARCH_IMX8M
- help
- Say Y here if you want barebox low-level debugging support
- on i.MX8M*.
-
-config DEBUG_VF610_UART
- bool "VF610 Debug UART"
- depends on ARCH_VF610
- help
- Say Y here if you want kernel low-level debugging support
- on VF610.
-
-config DEBUG_OMAP3_UART
- bool "OMAP3 Debug UART"
- depends on ARCH_OMAP3
- help
- Say Y here if you want kernel low-level debugging support
- on OMAP3.
-
-config DEBUG_OMAP4_UART
- bool "OMAP4 Debug UART"
- depends on ARCH_OMAP4
- help
- Say Y here if you want kernel low-level debugging support
- on OMAP4.
-
-config DEBUG_AM33XX_UART
- bool "AM33XX Debug UART"
- depends on ARCH_AM33XX
- help
- Say Y here if you want kernel low-level debugging support
- on AM33XX.
-
-config DEBUG_ROCKCHIP_RK3188_UART
- bool "RK3188 Debug UART"
- depends on ARCH_RK3188
- help
- Say Y here if you want kernel low-level debugging support
- on RK3188.
-
-config DEBUG_ROCKCHIP_RK3288_UART
- bool "RK3288 Debug UART"
- depends on ARCH_RK3288
- help
- Say Y here if you want kernel low-level debugging support
- on RK3288.
-
-config DEBUG_ROCKCHIP_RK3568_UART
- bool "RK3568 Debug UART"
- depends on ARCH_RK3568
- help
- Say Y here if you want kernel low-level debugging support
- on RK3568.
-
-config DEBUG_ROCKCHIP_RK3399_UART
- bool "RK3399 Debug UART"
- depends on ARCH_RK3399
- 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
- help
- Say Y here if you want kernel low-level debugging support
- on SOCFPGA(Cyclone 5 and Arria 5) based platforms.
-
-config DEBUG_SOCFPGA_UART1
- bool "Use SOCFPGA UART1 for low-level debug"
- depends on ARCH_SOCFPGA
- help
- Say Y here if you want kernel low-level debugging support
- on SOCFPGA(Arria 10) based platforms.
-
-config DEBUG_RPI1_UART
- bool "RaspberryPi 1 PL011 UART"
- depends on ARCH_BCM283X
- help
- Say Y here if you want low-level debugging support on
- RaspberryPi 1 boards.
-
-config DEBUG_AT91_UART
- bool "AT91 Debug UART"
- depends on ARCH_AT91
- help
- Say Y here if you want barebox low-level debugging support
- on AT91 based platforms.
-
-config DEBUG_RPI2_3_UART
- bool "RaspberryPi 2/3 PL011 UART"
- depends on ARCH_BCM283X
- help
- Say Y here if you want low-level debugging support on
- RaspberryPi 2 and 3 boards.
-
-config DEBUG_RPI3_MINI_UART
- bool "RaspberryPi 3 mini UART"
- depends on ARCH_BCM283X
- 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
- help
- Say Y here if you want low-level debugging support on
- RaspberryPi 4 board mini UART.
-
-config DEBUG_ERIZO
- bool "Erizo ns16550 port"
- depends on SOC_ERIZO
- select DEBUG_LL_NS16550
-
-config DEBUG_STARFIVE
- bool "Starfive ns16550 serial0 port"
- 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
-
-config DEBUG_LITEX
- bool "LiteX serial port"
- depends on SOC_LITEX
-
-endchoice
-
-config DEBUG_LL_NS16550
- bool
- help
- Selected by RISC-V platforms that use ns16550 for debug_ll
-
-config DEBUG_IMX_UART_PORT
- int "i.MX Debug UART Port Selection" if DEBUG_IMX1_UART || \
- DEBUG_IMX21_UART || \
- DEBUG_IMX25_UART || \
- DEBUG_IMX27_UART || \
- DEBUG_IMX31_UART || \
- DEBUG_IMX35_UART || \
- DEBUG_IMX51_UART || \
- DEBUG_IMX53_UART || \
- DEBUG_IMX6Q_UART || \
- DEBUG_IMX7D_UART || \
- DEBUG_IMX8M_UART || \
- DEBUG_VF610_UART
- default 1
- depends on ARCH_IMX
- help
- Choose UART port on which kernel low-level debug messages
- should be output.
-
-config DEBUG_OMAP_UART_PORT
- int "OMAP Debug UART Port Selection" if DEBUG_OMAP3_UART || \
- DEBUG_OMAP4_UART || \
- DEBUG_AM33XX_UART
- default 1
- depends on ARCH_OMAP
- help
- Choose UART port on which kernel low-level debug messages
- should be output. Possible values are:
- OMAP3: 1 - 3
- OMAP4: 1 - 3
- AM33XX: 0 - 2
-
-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_RK3399_UART
- default 2
- depends on ARCH_ROCKCHIP
- help
- Choose UART port on which kernel low-level debug messages
- should be output.
-
-config DEBUG_SOCFPGA_UART_PHYS_ADDR
- hex "Physical base address of debug UART" if DEBUG_LL
- default 0xffc02000 if DEBUG_SOCFPGA_UART0
- default 0xffc02100 if DEBUG_SOCFPGA_UART1
- depends on ARCH_SOCFPGA
-
-config DEBUG_SOCFPGA_UART_CLOCK
- int "SoCFPGA UART debug clock" if DEBUG_LL
- default 100000000 if ARCH_SOCFPGA_CYCLONE5
- default 50000000 if ARCH_SOCFPGA_ARRIA10
- depends on ARCH_SOCFPGA
- help
- Choose UART root clock.
-
-
-config DEBUG_LAYERSCAPE_UART_PORT
- int "Layerscape UART port selection"
- depends on ARCH_LAYERSCAPE
- default 1
- help
- Select the UART port number used for early debugging here. Port
- numbers start counting from 1.
-
-config DEBUG_AT91_UART_BASE
- hex "AT91 Debug UART Port Selection" if DEBUG_AT91_UART
- default 0xfffff200 if SOC_AT91RM9200 || SOC_AT91SAM9260 \
- || SOC_AT91SAM9261 || SOC_AT91SAM9X5 \
- || SOC_AT91SAM9N12
- default 0xffffee00 if SOC_AT91SAM9263 || SOC_AT91SAM9G45 || SOC_SAMA5D3
- default 0xfc069000 if SOC_SAMA5D4
- default 0xf8020000 if SOC_SAMA5D2
- default 0xfffff200
- depends on ARCH_AT91
- help
- Specify UART port base address on which barebox low-level
- debug messages should be output.
-
-config DEBUG_INITCALLS
- bool "Trace initcalls"
- help
- If enabled this will print initcall traces.
-
-config DEBUG_PROBES
- bool "Trace driver probes/removes"
- help
- 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 PBL_BREAK
- bool "Execute software break on pbl start"
- depends on ARM && (!CPU_32v4T && !ARCH_TEGRA)
- help
- 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"
-
-config ASAN
- bool "ASAN: runtime memory debugger"
- depends on HAVE_ARCH_ASAN
- help
- Enables ASAN (AddressSANitizer) - runtime memory debugger,
- designed to find out-of-bounds accesses and use-after-free bugs.
-
-config COMPILE_TEST
- bool "compile-test drivers of other platforms"
- default n
- help
- Some drivers can be compiled on a different platform than they are
- intended to be run on. Despite they cannot be used there due to
- missing HW support, developers still, opposing to users, might want
- to build such drivers to compile-test them.
-
- If you are a developer and want to build as much as currently possible,
- say Y here. If you are a user, say N here to avoid being prompted for
- inclusion of unrelated drivers.
-
-endmenu
-
-source "common/efi/Kconfig"
-
-config HAS_DEBUG_LL
- bool
-
-config HAS_ASM_DEBUG_LL
- bool
- select HAS_DEBUG_LL
+source "common/Kconfig.debug"
+source "common/boards/Kconfig"
config DDR_SPD
bool
@@ -1626,3 +1248,9 @@ config DDR_SPD
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/Kconfig.debug b/common/Kconfig.debug
new file mode 100644
index 0000000000..5d245de23c
--- /dev/null
+++ b/common/Kconfig.debug
@@ -0,0 +1,153 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+menu "Debugging"
+
+config COMPILE_LOGLEVEL
+ int "compile loglevel"
+ default 6
+ help
+ This defines the maximum loglevel compiled into the binary. Less important
+ messages will be compiled away resulting in a smaller binary.
+
+ 0 system is unusable (emerg)
+ 1 action must be taken immediately (alert)
+ 2 critical conditions (crit)
+ 3 error conditions (err)
+ 4 warning conditions (warn)
+ 5 normal but significant condition (notice)
+ 6 informational (info)
+ 7 debug-level messages (debug)
+ 8 verbose debug messages (vdebug)
+
+config DEFAULT_LOGLEVEL
+ int "default loglevel"
+ default 7
+ help
+ This defines the default runtime loglevel. It can be changed using the
+ global.loglevel variable. Available logelevels are:
+
+ 0 system is unusable (emerg)
+ 1 action must be taken immediately (alert)
+ 2 critical conditions (crit)
+ 3 error conditions (err)
+ 4 warning conditions (warn)
+ 5 normal but significant condition (notice)
+ 6 informational (info)
+ 7 debug-level messages (debug)
+ 8 verbose debug messages (vdebug)
+
+source "common/Kconfig.debug_ll"
+
+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_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/removes"
+ select CONSOLE_FLUSH_LINE_BREAK
+ help
+ 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"
+ depends on ARM && (!CPU_32v4T && !ARCH_TEGRA)
+ help
+ 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"
+
+config ASAN
+ bool "ASAN: runtime memory debugger"
+ depends on HAVE_ARCH_ASAN
+ help
+ Enables ASAN (AddressSANitizer) - runtime memory debugger,
+ designed to find out-of-bounds accesses and use-after-free bugs.
+
+config COMPILE_TEST
+ bool "compile-test drivers of other platforms"
+ default n
+ help
+ Some drivers can be compiled on a different platform than they are
+ intended to be run on. Despite they cannot be used there due to
+ missing HW support, developers still, opposing to users, might want
+ to build such drivers to compile-test them.
+
+ If you are a developer and want to build as much as currently possible,
+ 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
diff --git a/common/Kconfig.debug_ll b/common/Kconfig.debug_ll
new file mode 100644
index 0000000000..bdc1a7f3a6
--- /dev/null
+++ b/common/Kconfig.debug_ll
@@ -0,0 +1,430 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config HAS_DEBUG_LL
+ bool
+
+config DEBUG_LL
+ bool
+ depends on HAS_DEBUG_LL
+ prompt "Low level debug messages (read help)"
+ help
+ Enable this to get low level debug messages during barebox
+ initialization. This is helpful if you are debugging code that
+ executes before the console is initialized.
+
+ This requires SoC specific support. Most SoCs require the
+ debug UART to be initialized by a debugger or first stage
+ bootloader.
+
+ Note that selecting this option will limit barebox to a single
+ UART definition, as specified below under "low-level debugging
+ port". Attempting to boot the resulting image on a different
+ platform *will not work*, so this option should not be enabled
+ for builds that are intended to be portable.
+
+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
+
+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.
+
+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.
+
+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.
+
+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.
+
+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.
+
+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.
+
+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.
+
+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.
+
+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.
+
+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.
+
+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.
+
+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.
+
+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.
+
+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.
+
+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.
+
+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.
+
+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.
+
+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
+ help
+ Say Y here if you want kernel low-level debugging support
+ on SOCFPGA(Cyclone 5 and Arria 5) based platforms.
+
+config DEBUG_SOCFPGA_UART1
+ bool "Use SOCFPGA UART1 for low-level debug"
+ depends on ARCH_SOCFPGA
+ help
+ 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.
+
+config DEBUG_AT91_UART
+ bool "AT91 Debug UART"
+ depends on ARCH_AT91
+ help
+ Say Y here if you want barebox low-level debugging support
+ on AT91 based platforms.
+
+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.
+
+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
+ select DEBUG_LL_NS16550
+
+config DEBUG_STARFIVE
+ bool "Starfive ns16550 serial0 port"
+ 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
+
+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
+ bool
+ help
+ Selected by RISC-V platforms that use ns16550 for debug_ll
+
+config DEBUG_IMX_UART_PORT
+ int "i.MX Debug UART Port Selection" if DEBUG_IMX1_UART || \
+ DEBUG_IMX21_UART || \
+ DEBUG_IMX25_UART || \
+ DEBUG_IMX27_UART || \
+ DEBUG_IMX31_UART || \
+ DEBUG_IMX35_UART || \
+ DEBUG_IMX51_UART || \
+ DEBUG_IMX53_UART || \
+ DEBUG_IMX6Q_UART || \
+ DEBUG_IMX7D_UART || \
+ DEBUG_IMX8M_UART || \
+ DEBUG_IMX9_UART || \
+ DEBUG_VF610_UART
+ default 1
+ depends on ARCH_IMX
+ help
+ 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_AM62X_UART
+ default 1
+ depends on ARCH_OMAP
+ help
+ Choose UART port on which kernel low-level debug messages
+ should be output. Possible values are:
+ OMAP3: 1 - 3
+ OMAP4: 1 - 3
+ AM33XX: 0 - 2
+
+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_RK3588_UART || \
+ DEBUG_ROCKCHIP_RK3399_UART
+ default 2
+ depends on ARCH_ROCKCHIP
+ help
+ Choose UART port on which kernel low-level debug messages
+ should be output.
+
+config DEBUG_SOCFPGA_UART_PHYS_ADDR
+ hex "Physical base address of debug UART" if DEBUG_LL
+ default 0xffc02000 if DEBUG_SOCFPGA_UART0
+ default 0xffc02100 if DEBUG_SOCFPGA_UART1
+ depends on ARCH_SOCFPGA
+
+config DEBUG_SOCFPGA_UART_CLOCK
+ int "SoCFPGA UART debug clock" if DEBUG_LL
+ default 100000000 if ARCH_SOCFPGA_CYCLONE5
+ default 50000000 if ARCH_SOCFPGA_ARRIA10
+ depends on ARCH_SOCFPGA
+ help
+ Choose UART root clock.
+
+
+config DEBUG_LAYERSCAPE_UART_PORT
+ int "Layerscape UART port selection"
+ depends on ARCH_LAYERSCAPE
+ default 1
+ help
+ Select the UART port number used for early debugging here. Port
+ numbers start counting from 1.
+
+config DEBUG_AT91_UART_BASE
+ hex "AT91 Debug UART Port Selection" if DEBUG_AT91_UART
+ default 0xfffff200 if SOC_AT91RM9200 || SOC_AT91SAM9260 \
+ || SOC_AT91SAM9261 || SOC_AT91SAM9X5 \
+ || SOC_AT91SAM9N12
+ default 0xffffee00 if SOC_AT91SAM9263 || SOC_AT91SAM9G45 || SOC_SAMA5D3
+ default 0xfc069000 if SOC_SAMA5D4
+ default 0xf8020000 if SOC_SAMA5D2
+ default 0xfffff200
+ depends on ARCH_AT91
+ help
+ Specify UART port base address on which barebox low-level
+ debug messages should be output.
diff --git a/common/Makefile b/common/Makefile
index 35f2120496..96498790b3 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -6,13 +6,14 @@ 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
@@ -27,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
@@ -66,7 +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) += efi/
lwl-$(CONFIG_IMD) += imd-barebox.o
obj-$(CONFIG_IMD) += imd.o
obj-y += file-list.o
@@ -76,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 d243ac89dd..ba2566acdf 100644
--- a/common/bbu.c
+++ b/common/bbu.c
@@ -24,43 +24,42 @@
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);
}
}
@@ -96,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();
@@ -155,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;
@@ -192,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;
@@ -212,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;
@@ -221,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;
@@ -346,11 +366,7 @@ int bbu_mmcboot_handler(struct bbu_handler *handler, struct bbu_data *data,
if (ret < 0)
goto out;
- /*
- * This flag can be set in the chained handler or by
- * bbu_mmcboot_handler's caller
- */
- if ((_data.flags | data->flags) & BBU_FLAG_MMC_BOOT_ACK) {
+ if (handler->flags & BBU_HANDLER_FLAG_MMC_BOOT_ACK) {
ret = asprintf(&bootackvar, "%s.boot_ack", devname);
if (ret < 0)
goto out;
@@ -371,6 +387,38 @@ out:
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)
{
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 19bb81df2c..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,12 +384,12 @@ static struct cdev_operations block_ops = {
.discard_range = block_op_discard_range,
};
-struct block_device *cdev_get_block_device(struct cdev *cdev)
+struct block_device *cdev_get_block_device(const struct cdev *cdev)
{
if (!cdev || cdev->ops != &block_ops)
return NULL;
- return container_of(cdev, struct block_device, cdev);
+ return cdev->priv;
}
int blockdevice_register(struct block_device *blk)
@@ -388,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);
@@ -403,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;
}
@@ -449,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 d391f690ad..23a24c63db 100644
--- a/common/blspec.c
+++ b/common/blspec.c
@@ -88,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");
@@ -316,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))
@@ -426,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;
@@ -459,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;
}
@@ -622,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);
@@ -677,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)
@@ -698,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;
@@ -726,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;
@@ -742,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;
@@ -790,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);
diff --git a/common/boards/Kconfig b/common/boards/Kconfig
index e27273b767..a2a51155ea 100644
--- a/common/boards/Kconfig
+++ b/common/boards/Kconfig
@@ -2,3 +2,18 @@
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
+
+config BOARD_WOLFVISION
+ bool
diff --git a/common/boards/Makefile b/common/boards/Makefile
index 5b4e429c13..3f8ac57b2f 100644
--- a/common/boards/Makefile
+++ b/common/boards/Makefile
@@ -1,3 +1,6 @@
# 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/
+obj-$(CONFIG_BOARD_WOLFVISION) += wolfvision/
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
index 88184e9a79..30bf4f1955 100644
--- a/common/boards/qemu-virt/Makefile
+++ b/common/boards/qemu-virt/Makefile
@@ -1,7 +1,13 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-y += board.o
-obj-y += overlay-of-flash.dtb.o
+obj-y += qemu-virt-flash.dtbo.o fitimage-pubkey.dtb.o
ifeq ($(CONFIG_RISCV),y)
-DTC_CPP_FLAGS_overlay-of-flash.dtb := -DRISCV_VIRT=1
+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
index 4064409c80..4f2f7374c5 100644
--- a/common/boards/qemu-virt/board.c
+++ b/common/boards/qemu-virt/board.c
@@ -7,6 +7,7 @@
#include <init.h>
#include <of.h>
#include <deep-probe.h>
+#include "qemu-virt-flash.h"
#ifdef CONFIG_64BIT
#define MACHINE "virt64"
@@ -34,35 +35,56 @@ static inline void arm_virt_init(void)
static inline void arm_virt_init(void) {}
#endif
-extern char __dtb_overlay_of_flash_start[];
+extern char __dtbo_qemu_virt_flash_start[];
+extern char __dtb_fitimage_pubkey_start[];
-static int virt_probe(struct device_d *dev)
+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 *overlay;
+ struct device_node *root = of_get_root_node();
+ struct device_node *flash, *overlay, *pubkey;
+ const struct of_device_id *id;
void (*init)(void);
- init = device_get_match_data(dev);
- if (init)
+ id = of_match_node(virt_of_match, root);
+ if (!id)
+ return 0;
+
+ if (id->data) {
+ init = id->data;
init();
+ }
- overlay = of_unflatten_dtb(__dtb_overlay_of_flash_start, INT_MAX);
- of_overlay_apply_tree(dev->device_node, overlay);
- /* of_probe() will happen later at of_populate_initcall */
+ /*
+ * 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);
+ }
- return 0;
-}
+ pubkey = of_unflatten_dtb(__dtb_fitimage_pubkey_start, INT_MAX);
+ of_merge_nodes(root, pubkey);
-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);
+ /* fragment may have added aliases to the DT */
+ of_alias_scan();
-static struct driver_d virt_board_driver = {
- .name = "board-qemu-virt",
- .probe = virt_probe,
- .of_compatible = virt_of_match,
-};
+ /* of_probe() will happen later at of_populate_initcall */
-postcore_platform_driver(virt_board_driver);
+ 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/overlay-of-flash.dts b/common/boards/qemu-virt/overlay-of-flash.dts
deleted file mode 100644
index ace2c7026b..0000000000
--- a/common/boards/qemu-virt/overlay-of-flash.dts
+++ /dev/null
@@ -1,113 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-
-/dts-v1/;
-/plugin/;
-
-#ifdef RISCV_VIRT
-#define PARTS_TARGET_PATH "/soc/flash@20000000"
-#define ENV_DEVICE_PATH "/soc/flash@20000000/partitions/partition@3c00000"
-#else
-#define PARTS_TARGET_PATH "/flash@0"
-#define ENV_DEVICE_PATH "/flash@0/partitions/partition@3c00000"
-#endif
-
-/ {
- fragment@0 {
- target-path = PARTS_TARGET_PATH;
- __overlay__ {
- 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>;
- };
- };
- };
- };
-
- fragment@1 {
- target-path = "/chosen";
- __overlay__ {
- environment {
- compatible = "barebox,environment";
- device-path = ENV_DEVICE_PATH;
- };
- };
- };
-
- fragment@2 {
- target-path = "/";
- __overlay__ {
- 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.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/boards/wolfvision/Makefile b/common/boards/wolfvision/Makefile
new file mode 100644
index 0000000000..b2be4b73f4
--- /dev/null
+++ b/common/boards/wolfvision/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0-only
+obj-pbl-y += common.o
diff --git a/common/boards/wolfvision/common.c b/common/boards/wolfvision/common.c
new file mode 100644
index 0000000000..f483918cec
--- /dev/null
+++ b/common/boards/wolfvision/common.c
@@ -0,0 +1,142 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Common board code functions WolfVision boards.
+ *
+ * Copyright (C) 2024 WolfVision GmbH.
+ */
+
+#define pr_fmt(fmt) "boards: wolfvision: " fmt
+
+#include <common.h>
+#include <aiodev.h>
+#include <net.h>
+#include <state.h>
+
+#include <boards/wolfvision/common.h>
+
+#define WV_RK3568_HWID_TOLERANCE 50
+
+int wolfvision_apply_overlay(const struct wv_overlay *overlay, char **files)
+{
+ int ret;
+
+ if (overlay->filename) {
+ if (*files) {
+ char *old = *files;
+ *files = basprintf("%s %s", old, overlay->filename);
+ free(old);
+ } else {
+ *files = basprintf("%s", overlay->filename);
+ }
+ }
+
+ if (overlay->data) {
+ struct device_node *node =
+ of_unflatten_dtb(overlay->data, INT_MAX);
+
+ if (IS_ERR(node)) {
+ pr_err("Cannot unflatten dtbo\n");
+ return PTR_ERR(node);
+ }
+
+ ret = of_overlay_apply_tree(of_get_root_node(), node);
+
+ of_delete_node(node);
+
+ if (ret) {
+ pr_err("Cannot apply overlay: %pe\n", ERR_PTR(ret));
+ return ret;
+ }
+
+ of_clk_init();
+ of_probe();
+ }
+
+ return 0;
+}
+
+int wolfvision_register_ethaddr(void)
+{
+ struct device_node *eth0;
+ struct state *state;
+ char mac[ETH_ALEN];
+ int ret;
+
+ ret = of_device_ensure_probed_by_alias("state");
+ if (ret)
+ return ret;
+
+ state = state_by_name("state");
+ if (!state)
+ return -ENOENT;
+
+ ret = state_read_mac(state, "mac-address", mac);
+ if (ret)
+ return ret;
+
+ if (!is_valid_ether_addr(mac))
+ return -EINVAL;
+
+ eth0 = of_find_node_by_alias(of_get_root_node(), "ethernet0");
+ if (eth0)
+ of_eth_register_ethaddr(eth0, mac);
+
+ return 0;
+}
+
+static int wolfvision_rk3568_get_hwid(int chan_idx)
+{
+ const int values[WV_RK3568_HWID_MAX] = {
+ 0, 112, 225, 337, 450, 562, 675, 787, 900,
+ 1012, 1125, 1237, 1350, 1462, 1575, 1687, 1800,
+ };
+ int ret, hwid, voltage;
+ char *chan_name;
+
+ chan_name = basprintf("saradc.in_value%d_mV", chan_idx);
+ ret = aiochannel_name_get_value(chan_name, &voltage);
+ free(chan_name);
+ if (ret)
+ return ret;
+
+ for (hwid = 0; hwid < ARRAY_SIZE(values); hwid++)
+ if (abs(voltage - values[hwid]) < WV_RK3568_HWID_TOLERANCE)
+ return hwid;
+
+ return -EINVAL;
+};
+
+int wolfvision_rk3568_detect_hw(const struct wv_rk3568_extension *extensions,
+ int num_extensions, char **overlays)
+{
+ int i, hwid, ret;
+
+ ret = of_device_ensure_probed_by_alias("saradc");
+ if (ret)
+ return ret;
+
+ for (i = 0; i < num_extensions; i++) {
+ const struct wv_rk3568_extension *extension = &extensions[i];
+ const struct wv_overlay *overlay;
+
+ ret = wolfvision_rk3568_get_hwid(extension->adc_chan);
+ if (ret < 0) {
+ pr_warning("Could not retrieve %s HWID (%d)\n",
+ extension->name, ret);
+ continue;
+ }
+
+ hwid = ret;
+ overlay = &extension->overlays[hwid];
+ if (overlay->name) {
+ pr_info("Detected %s %s\n", overlay->name,
+ extension->name);
+ wolfvision_apply_overlay(overlay, overlays);
+ } else {
+ pr_warning("Detected unknown %s HWID %d\n",
+ extension->name, hwid);
+ }
+ }
+
+ return 0;
+}
diff --git a/common/boot.c b/common/boot.c
index 9c6fc30442..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;
diff --git a/common/bootchooser.c b/common/bootchooser.c
index eb3dda52ab..022e225165 100644
--- a/common/bootchooser.c
+++ b/common/bootchooser.c
@@ -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;
@@ -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;
@@ -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 302d7440ab..e745ff6963 100644
--- a/common/booti.c
+++ b/common/booti.c
@@ -33,7 +33,7 @@ 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;
- unsigned long text_offset, image_size, devicetree, kernel;
+ unsigned long text_offset, image_size, kernel;
unsigned long image_end;
int ret;
void *fdt;
@@ -57,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)
@@ -84,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 2f02c156e5..c851ab0456 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);
@@ -43,6 +44,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_provide_hostname;
static int bootm_verbosity;
void bootm_data_init_defaults(struct bootm_data *data)
@@ -60,6 +62,7 @@ void bootm_data_init_defaults(struct bootm_data *data)
data->verify = bootm_get_verify_mode();
data->appendroot = bootm_appendroot;
data->provide_machine_id = bootm_provide_machine_id;
+ data->provide_hostname = bootm_provide_hostname;
data->verbose = bootm_verbosity;
}
@@ -70,6 +73,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",
@@ -79,6 +87,29 @@ static const char * const bootm_verify_names[] = {
[BOOTM_VERIFY_SIGNATURE] = "signature",
};
+static bool force_signed_images = IS_ENABLED(CONFIG_BOOTM_FORCE_SIGNED_IMAGES);
+
+void bootm_force_signed_images(void)
+{
+ static unsigned int verify_mode = 0;
+
+ if (force_signed_images)
+ return;
+
+ /* recreate bootm.verify with a single enumeration as option */
+ globalvar_remove("bootm.verify");
+ globalvar_add_simple_enum("bootm.verify", &verify_mode,
+ &bootm_verify_names[BOOTM_VERIFY_SIGNATURE], 1);
+
+ bootm_verify_mode = BOOTM_VERIFY_SIGNATURE;
+ force_signed_images = true;
+}
+
+bool bootm_signed_images_are_forced(void)
+{
+ return force_signed_images;
+}
+
static int uimage_part_num(const char *partname)
{
if (!partname)
@@ -119,7 +150,7 @@ int bootm_load_os(struct image_data *data, unsigned 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;
}
@@ -244,12 +275,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) {
@@ -366,12 +395,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) {
@@ -401,10 +429,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");
}
@@ -415,7 +446,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);
@@ -460,8 +493,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)
+ if (bootm_verbose(data) > 1) {
of_print_nodes(data->of_root_node, 0, ~0);
+ fdt_print_reserve_map(fdt);
+ }
return 0;
}
@@ -519,18 +554,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;
}
@@ -616,7 +717,7 @@ int bootm_boot(struct bootm_data *bootm_data)
goto err_out;
}
- if (IS_ENABLED(CONFIG_BOOTM_FORCE_SIGNED_IMAGES)) {
+ if (bootm_signed_images_are_forced()) {
data->verify = BOOTM_VERIFY_SIGNATURE;
/*
@@ -633,74 +734,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) {
@@ -717,7 +769,7 @@ int bootm_boot(struct bootm_data *bootm_data)
if (!root_cdev)
pr_err("no cdev found for %s, cannot set root= option\n",
root_dev_name);
- else if (!root_cdev->uuid[0])
+ else if (!root_cdev->partuuid[0])
pr_err("%s doesn't have a PARTUUID, cannot set root= option\n",
root_dev_name);
}
@@ -770,6 +822,27 @@ int bootm_boot(struct bootm_data *bootm_data)
free(machine_id_bootarg);
}
+ if (bootm_data->provide_hostname) {
+ const char *hostname = getenv_nonempty("global.hostname");
+ char *hostname_bootarg;
+
+ if (!hostname) {
+ pr_err("Providing hostname is enabled but no hostname is set\n");
+ ret = -EINVAL;
+ goto err_out;
+ }
+
+ if (!barebox_hostname_is_valid(hostname)) {
+ pr_err("Provided hostname is not compatible to systemd hostname requirements\n");
+ ret = -EINVAL;
+ goto err_out;
+ }
+
+ hostname_bootarg = basprintf("systemd.hostname=%s", hostname);
+ globalvar_add_simple("linux.bootargs.hostname", hostname_bootarg);
+ free(hostname_bootarg);
+ }
+
pr_info("\nLoading %s '%s'", file_type_to_string(os_type),
data->os_file);
if (os_type == filetype_uimage &&
@@ -818,7 +891,7 @@ 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");
@@ -913,6 +986,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);
@@ -923,12 +1002,13 @@ static int bootm_init(void)
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);
+ globalvar_add_simple_bool("bootm.provide_hostname", &bootm_provide_hostname);
if (IS_ENABLED(CONFIG_BOOTM_INITRD)) {
globalvar_add_simple("bootm.initrd", NULL);
globalvar_add_simple("bootm.initrd.loadaddr", NULL);
}
- if (IS_ENABLED(CONFIG_BOOTM_FORCE_SIGNED_IMAGES))
+ if (bootm_signed_images_are_forced())
bootm_verify_mode = BOOTM_VERIFY_SIGNATURE;
globalvar_add_simple_int("bootm.verbose", &bootm_verbosity, "%u");
@@ -947,6 +1027,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;
}
@@ -965,3 +1047,4 @@ BAREBOX_MAGICVAR(global.bootm.earlycon, "Add earlycon option to Kernel for early
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");
+BAREBOX_MAGICVAR(global.bootm.provide_hostname, "If true, append systemd.hostname=$global.hostname to Kernel command line");
diff --git a/common/bootsource.c b/common/bootsource.c
index 70bac945de..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,14 @@ 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) {
@@ -100,6 +108,22 @@ 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;
@@ -107,12 +131,12 @@ void bootsource_set_alias_name(const char *name)
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);
}
@@ -129,7 +153,7 @@ void bootsource_set_raw_instance(int instance)
int bootsource_of_alias_xlate(enum bootsource src, int instance)
{
- char alias[sizeof("barebox,bootsource-harddisk4294967295")];
+ char chosen[sizeof("barebox,bootsource-harddisk4294967295")];
const char *bootsource_stem;
struct device_node *np;
int alias_id;
@@ -145,10 +169,10 @@ int bootsource_of_alias_xlate(enum bootsource src, int instance)
if (!bootsource_stem)
return BOOTSOURCE_INSTANCE_UNKNOWN;
- scnprintf(alias, sizeof(alias), "barebox,bootsource-%s%u",
+ scnprintf(chosen, sizeof(chosen), "barebox,bootsource-%s%u",
bootsource_stem, instance);
- np = of_find_node_by_alias(NULL, alias);
+ np = of_find_node_by_chosen(chosen, NULL);
if (!np)
return BOOTSOURCE_INSTANCE_UNKNOWN;
diff --git a/common/complete.c b/common/complete.c
index ab3c985493..3911535621 100644
--- a/common/complete.c
+++ b/common/complete.c
@@ -14,6 +14,27 @@
#include <command.h>
#include <environment.h>
+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)
{
@@ -35,7 +56,7 @@ static int file_complete(struct string_list *sl, char *instr,
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);
@@ -94,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))
@@ -135,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));
@@ -154,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;
@@ -230,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);
@@ -267,7 +294,7 @@ 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;
@@ -308,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;
}
@@ -323,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;
@@ -342,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);
@@ -416,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 c442c2dde1..73b4c4d4db 100644
--- a/common/console.c
+++ b/common/console.c
@@ -227,15 +227,15 @@ static void console_add_earlycon_param(struct console_device *cdev, unsigned bau
if (!cdev->linux_earlycon_name)
return;
- str = basprintf("earlycon=%s,0x%lx,%dn8", cdev->linux_earlycon_name,
- (ulong)cdev->phys_base, baudrate);
+ 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)
+void console_set_stdoutpath(struct console_device *cdev, unsigned baudrate)
{
int id;
char *str;
@@ -243,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;
@@ -254,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++;
@@ -309,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;
@@ -406,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;
/*
@@ -608,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 7bef74c543..0113a64138 100644
--- a/common/console_common.c
+++ b/common/console_common.c
@@ -10,15 +10,19 @@
#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
@@ -35,11 +39,10 @@ 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 afa9a0f186..702087bd23 100644
--- a/common/console_simple.c
+++ b/common/console_simple.c
@@ -70,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 52773178e7..b7693f3fd2 100644
--- a/common/ddr_spd.c
+++ b/common/ddr_spd.c
@@ -65,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
@@ -77,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;
@@ -96,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"
@@ -117,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) {
@@ -231,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;
@@ -246,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);
@@ -420,14 +435,539 @@ 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
@@ -480,6 +1020,7 @@ static int read_buf(struct pbl_i2c *i2c,
* @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
@@ -487,19 +1028,23 @@ static int read_buf(struct pbl_i2c *i2c,
* otherwise.
*/
int spd_read_eeprom(struct pbl_i2c *i2c,
- uint8_t addr, void *buf)
+ uint8_t addr, void *buf,
+ int memtype)
{
- unsigned char *buf8 = buf;
int ret;
- ret = read_buf(i2c, 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(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;
}
return 0;
diff --git a/common/deep-probe.c b/common/deep-probe.c
index 1020ad93b7..b270a10f7f 100644
--- a/common/deep-probe.c
+++ b/common/deep-probe.c
@@ -1,22 +1,24 @@
// SPDX-License-Identifier: GPL-2.0-only
+#define pr_fmt(fmt) "deep-probe: " fmt
+
#include <common.h>
#include <deep-probe.h>
#include <of.h>
enum deep_probe_state {
- DEEP_PROBE_UNKONWN = -1,
+ DEEP_PROBE_UNKNOWN = -1,
DEEP_PROBE_NOT_SUPPORTED,
DEEP_PROBE_SUPPORTED
};
-static enum deep_probe_state boardstate = DEEP_PROBE_UNKONWN;
+static enum deep_probe_state boardstate = DEEP_PROBE_UNKNOWN;
bool deep_probe_is_supported(void)
{
struct deep_probe_entry *board;
- if (boardstate > DEEP_PROBE_UNKONWN)
+ if (boardstate > DEEP_PROBE_UNKNOWN)
return boardstate;
/* determine boardstate */
@@ -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/Kconfig b/common/efi/Kconfig
deleted file mode 100644
index 15246ccbf0..0000000000
--- a/common/efi/Kconfig
+++ /dev/null
@@ -1,27 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-
-menu "EFI (Extensible Firmware Interface) Support"
-
-config EFI_BOOTUP
- bool
- select EFI
- select EFI_GUID
- select EFI_DEVICEPATH
- select PRINTF_UUID
- select PRINTF_WCHAR
- select BLOCK
- select PARTITION_DISK
- select HW_HAS_PCI
-
-config EFI
- bool
-
-config EFI_GUID
- bool
- help
- With this option a table of EFI guids is compiled in.
-
-config EFI_DEVICEPATH
- bool
-
-endmenu
diff --git a/common/efi/Makefile b/common/efi/Makefile
deleted file mode 100644
index a7cebde4f1..0000000000
--- a/common/efi/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-
-obj-$(CONFIG_EFI_BOOTUP) += payload/
-obj-$(CONFIG_EFI_GUID) += guid.o
-obj-$(CONFIG_EFI_DEVICEPATH) += devicepath.o
-obj-y += errno.o efivar-filename.o
diff --git a/common/efi/devicepath.c b/common/efi/devicepath.c
deleted file mode 100644
index 584f1fbd1d..0000000000
--- a/common/efi/devicepath.c
+++ /dev/null
@@ -1,830 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-
-#include <common.h>
-#include <efi.h>
-#include <malloc.h>
-#include <string.h>
-#include <wchar.h>
-#include <efi/device-path.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); \
- }
-
-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(const struct efi_device_path *dev_path)
-{
- const struct efi_device_path *Src;
- struct efi_device_path *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);
-}
-
-u8 device_path_to_subtype(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 dev_path->sub_type;
-}
-
-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/efivar-filename.c b/common/efi/efivar-filename.c
deleted file mode 100644
index 51d0130fa7..0000000000
--- a/common/efi/efivar-filename.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-
-#include <linux/ctype.h>
-#include <string.h>
-#include <efi/efi-util.h>
-
-static int char_to_nibble(char c)
-{
- int ret = tolower(c);
-
- return ret <= '9' ? ret - '0' : ret - 'a' + 10;
-}
-
-static int read_byte_str(const char *str, u8 *out)
-{
- if (!isxdigit(*str) || !isxdigit(*(str + 1)))
- return -EINVAL;
-
- *out = (char_to_nibble(*str) << 4) | char_to_nibble(*(str + 1));
-
- return 0;
-}
-
-static int efi_guid_parse(const char *str, efi_guid_t *guid)
-{
- int i, ret;
- u8 idx[] = { 3, 2, 1, 0, 5, 4, 7, 6, 8, 9, 10, 11, 12, 13, 14, 15 };
-
- for (i = 0; i < 16; i++) {
- ret = read_byte_str(str, &guid->b[idx[i]]);
- if (ret)
- return ret;
- str += 2;
-
- switch (i) {
- case 3:
- case 5:
- case 7:
- case 9:
- if (*str != '-')
- return -EINVAL;
- str++;
- break;
- }
- }
-
- return 0;
-}
-
-
-int __efivarfs_parse_filename(const char *filename, efi_guid_t *vendor,
- s16 *name, size_t *namelen)
-{
- int len, ret;
- const char *guidstr;
- int i;
-
- len = strlen(filename);
-
- if (len < sizeof("-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"))
- return -EINVAL;
-
- guidstr = filename + len - sizeof("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx");
- if (*guidstr != '-' || guidstr == filename)
- return -EINVAL;
-
- guidstr++;
-
- ret = efi_guid_parse(guidstr, vendor);
- if (ret)
- return ret;
-
- if (guidstr - filename > *namelen)
- ret = -EFBIG;
-
- *namelen = guidstr - filename;
-
- if (ret)
- return ret;
-
- for (i = 0; i < *namelen - 1; i++)
- name[i] = filename[i];
-
- name[i] = L'\0';
-
- return 0;
-}
-
-int efivarfs_parse_filename(const char *filename, efi_guid_t *vendor,
- s16 **name)
-{
- int ret;
- s16 *varname;
- size_t namelen = 0;
- int i;
-
- if (*filename == '/')
- filename++;
-
- ret = __efivarfs_parse_filename(filename, vendor, NULL, &namelen);
- if (ret != -EFBIG)
- return ret;
-
- varname = xzalloc(namelen * sizeof(s16));
-
- for (i = 0; i < namelen - 1; i++)
- varname[i] = filename[i];
-
- varname[i] = L'\0';
-
- *name = varname;
-
- return 0;
-}
-
-
diff --git a/common/efi/errno.c b/common/efi/errno.c
deleted file mode 100644
index 3bb68e7781..0000000000
--- a/common/efi/errno.c
+++ /dev/null
@@ -1,90 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-
-#include <efi/efi-util.h>
-#include <errno.h>
-
-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;
-}
diff --git a/common/efi/guid.c b/common/efi/guid.c
deleted file mode 100644
index f16c597a20..0000000000
--- a/common/efi/guid.c
+++ /dev/null
@@ -1,95 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-
-#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, "UV System Table", "UV 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 Info");
- 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(EFI_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/payload/Makefile b/common/efi/payload/Makefile
deleted file mode 100644
index bcbdda335f..0000000000
--- a/common/efi/payload/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-
-obj-y += init.o
-obj-y += image.o
-bbenv-y += env-efi
-obj-$(CONFIG_CMD_IOMEM) += iomem.o
diff --git a/common/efi/payload/env-efi/network/eth0-discover b/common/efi/payload/env-efi/network/eth0-discover
deleted file mode 100644
index 62c31a553c..0000000000
--- a/common/efi/payload/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/efi/payload/image.c b/common/efi/payload/image.c
deleted file mode 100644
index e63da9ddf0..0000000000
--- a/common/efi/payload/image.c
+++ /dev/null
@@ -1,283 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * image.c - barebox EFI payload support
- *
- * Copyright (c) 2014 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
- */
-
-#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-payload.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:
- 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();
- }
-
- efi_pause_devices();
-
- efiret = BS->start_image(handle, NULL, NULL);
- if (EFI_ERROR(efiret))
- pr_err("failed to StartImage: %s\n", efi_strerror(efiret));
-
- efi_continue_devices();
-
- 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/payload/init.c b/common/efi/payload/init.c
deleted file mode 100644
index 6976285fb3..0000000000
--- a/common/efi/payload/init.c
+++ /dev/null
@@ -1,387 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * init.c - barebox EFI payload support
- *
- * Copyright (c) 2014 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
- */
-
-#ifdef CONFIG_DEBUG_LL
-#define DEBUG
-#endif
-
-#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/efi-payload.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);
-
-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);
-
-/**
- * efi-main - Entry point for EFI images
- */
-void 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();
-}
-
-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);
-
- ret = barebox_register_of(root);
- if (ret)
- pr_warn("Failed to register device-tree: %pe\n", ERR_PTR(ret));
-
- 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 != -ENOMEDIUM)
- 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/payload/iomem.c b/common/efi/payload/iomem.c
deleted file mode 100644
index 6b92ca993a..0000000000
--- a/common/efi/payload/iomem.c
+++ /dev/null
@@ -1,179 +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-payload.h>
-#include <memory.h>
-#include <linux/sizes.h>
-
-static int efi_parse_mmap(struct efi_memory_desc *desc, bool verbose)
-{
- 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 (verbose)
- return 0;
- name = "reserved";
- flags = IORESOURCE_MEM | IORESOURCE_DISABLED;
- break;
- case EFI_LOADER_CODE:
- name = "loader code";
- flags = IORESOURCE_MEM | IORESOURCE_READONLY;
- break;
- case EFI_LOADER_DATA:
- name = "loader data";
- flags = IORESOURCE_MEM;
- break;
- case EFI_BOOT_SERVICES_CODE:
- if (!verbose)
- return 0;
- name = "boot services code";
- flags = IORESOURCE_MEM | IORESOURCE_READONLY;
- break;
- case EFI_BOOT_SERVICES_DATA:
- if (!verbose)
- return 0;
- name = "boot services data";
- flags = IORESOURCE_MEM;
- break;
- case EFI_RUNTIME_SERVICES_CODE:
- if (!verbose)
- return 0;
- name = "runtime services code";
- flags = IORESOURCE_MEM | IORESOURCE_READONLY;
- break;
- case EFI_RUNTIME_SERVICES_DATA:
- if (!verbose)
- return 0;
- name = "runtime services data";
- flags = IORESOURCE_MEM;
- break;
- case EFI_CONVENTIONAL_MEMORY:
- if (!verbose)
- return 0;
- name = "conventional memory";
- flags = IORESOURCE_MEM | IORESOURCE_PREFETCH | IORESOURCE_CACHEABLE;
- break;
- case EFI_UNUSABLE_MEMORY:
- if (!verbose)
- return 0;
- name = "unusable";
- flags = IORESOURCE_MEM | IORESOURCE_DISABLED;
- break;
- case EFI_ACPI_RECLAIM_MEMORY:
- if (!verbose)
- return 0;
- name = "ACPI reclaim memory";
- flags = IORESOURCE_MEM | IORESOURCE_READONLY;
- break;
- case EFI_ACPI_MEMORY_NVS:
- if (!verbose)
- return 0;
- name = "ACPI NVS memory";
- flags = IORESOURCE_MEM | IORESOURCE_READONLY;
- break;
- case EFI_MEMORY_MAPPED_IO:
- if (!verbose)
- return 0;
- name = "MMIO";
- flags = IORESOURCE_MEM;
- break;
- case EFI_MEMORY_MAPPED_IO_PORT_SPACE:
- if (!verbose)
- return 0;
- name = "MMIOPORT";
- flags = IORESOURCE_IO;
- break;
- case EFI_PAL_CODE:
- if (!verbose)
- 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 (!verbose)
- 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, __is_defined(DEBUG));
-
-out:
- free(mmap_buf);
- return ret;
-}
-mem_initcall(efi_barebox_populate_mmap);
diff --git a/common/elf.c b/common/elf.c
index f10fb77953..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,7 +101,7 @@ 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 = -1;
+ int ret = 0, fd = -1;
u64 p_filesz, p_memsz, p_offset;
struct elf_section *r;
struct list_head *list = &elf->list;
@@ -109,11 +109,13 @@ static int load_elf_to_memory(struct elf_image *elf)
if (elf->filename) {
fd = open(elf->filename, O_RDONLY);
if (fd < 0) {
- pr_err("could not open: %s\n", errno_str());
+ 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);
@@ -128,15 +130,13 @@ static int load_elf_to_memory(struct elf_image *elf)
if (ret == -1) {
pr_err("lseek at offset 0x%llx failed\n",
p_offset);
- close(fd);
- return ret;
+ goto out;
}
if (read_full(fd, dst, p_filesz) < 0) {
- pr_err("could not read elf segment: %s\n",
- errno_str());
- close(fd);
- return -errno;
+ pr_err("could not read elf segment: %m\n");
+ ret = -errno;
+ goto out;
}
} else {
memcpy(dst, elf->hdr_buf + p_offset, p_filesz);
@@ -146,9 +146,12 @@ static int load_elf_to_memory(struct elf_image *elf)
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)
@@ -256,13 +259,13 @@ static struct elf_image *elf_check_init(const char *filename)
/* 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;
@@ -290,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;
diff --git a/common/env.c b/common/env.c
index 9e9988e415..c231bc8b1d 100644
--- a/common/env.c
+++ b/common/env.c
@@ -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;
@@ -336,31 +336,42 @@ const char *getenv_nonempty(const char *var)
{
const char *val = getenv(var);
- if (val && *val)
- return val;
+ if (isempty(val))
+ return NULL;
- return NULL;
+ return val;
}
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)
+ if (isempty(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);
- if (!valstr || !*valstr)
+ if (isempty(valstr))
return -EINVAL;
*val = simple_strtoul(valstr, NULL, 0);
@@ -373,7 +384,7 @@ int getenv_uint(const char *var , unsigned int *val)
{
const char *valstr = getenv(var);
- if (!valstr || !*valstr)
+ if (isempty(valstr))
return -EINVAL;
*val = simple_strtoul(valstr, NULL, 0);
diff --git a/common/envfs-core.c b/common/envfs-core.c
index 0984d53873..20b3e647d3 100644
--- a/common/envfs-core.c
+++ b/common/envfs-core.c
@@ -24,7 +24,6 @@
#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
@@ -151,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 ae7f132444..f8a01dea7a 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;
@@ -150,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;
@@ -160,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);
}
@@ -184,25 +184,24 @@ int fastboot_generic_init(struct fastboot *fb, bool export_bbu)
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);
@@ -298,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,
@@ -596,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;
}
@@ -624,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);
@@ -638,6 +666,7 @@ static void cb_flash(struct fastboot *fb, const char *cmd)
goto out;
}
+ /* Check if board-code registered a vendor-specific handler */
if (fb->cmd_flash) {
ret = fb->cmd_flash(fb, fentry, fb->tempname, fb->download_size);
if (ret != FASTBOOT_CMD_FALLTHROUGH)
@@ -912,6 +941,7 @@ void fastboot_exec_cmd(struct fastboot *fb, const char *cmdbuf)
g_fb = fb;
fb->active = true;
+ /* Check if board-code registered a vendor-specific handler */
if (fb->cmd_exec) {
ret = fb->cmd_exec(fb, cmdbuf);
if (ret != FASTBOOT_CMD_FALLTHROUGH)
@@ -927,6 +957,11 @@ 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)
@@ -936,9 +971,14 @@ struct file_list *get_fastboot_partitions(void)
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 1dc7cd8266..3867e79c09 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));
@@ -102,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;
}
@@ -111,7 +144,7 @@ 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)
@@ -161,8 +194,6 @@ struct file_list *file_list_parse(const char *str)
goto out;
}
str = endptr;
-
- files->num_entries++;
}
return files;
@@ -211,11 +242,9 @@ struct file_list *file_list_dup(struct file_list *old)
new = file_list_new();
- list_for_each_entry(old_entry, &old->list, list) {
+ list_for_each_entry(old_entry, &old->list, list)
(void)file_list_add_entry(new, old_entry->name, old_entry->filename,
old_entry->flags); /* can't fail */
- new->num_entries++;
- }
return new;
}
diff --git a/common/filetype.c b/common/filetype.c
index 8f79f48bc1..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 */
@@ -62,13 +63,16 @@ 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_fsbl_v1] = { "STM32MP FSBL image (v1)", "stm32-fsbl-v1" },
@@ -77,6 +81,7 @@ static const struct filetype_str filetype_str[] = {
[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)
@@ -248,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)
@@ -310,15 +320,17 @@ enum filetype file_detect_type(const void *_buf, size_t bufsize)
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) &&
@@ -348,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;
@@ -366,7 +380,7 @@ 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)
@@ -409,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);
@@ -431,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_by_name(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);
@@ -466,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)
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 4fd6361c2f..a83529f98f 100644
--- a/common/globalvar.c
+++ b/common/globalvar.c
@@ -16,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,
};
@@ -101,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;
@@ -130,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;
@@ -177,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;
@@ -195,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;
@@ -214,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;
@@ -375,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;
@@ -452,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;
@@ -744,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;
@@ -766,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 6a089fabf1..608c0e4937 100644
--- a/common/hush.c
+++ b/common/hush.c
@@ -617,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 == '\'') {
@@ -629,6 +630,7 @@ static void remove_quotes_in_str(char *src)
/* drop quotes */
if (*src == '"') {
+ in_double_quotes = !in_double_quotes;
src++;
continue;
}
@@ -654,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;
@@ -1828,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 3e6e7fbd6d..251fda97b3 100644
--- a/common/image-fit.c
+++ b/common/image-fit.c
@@ -264,7 +264,7 @@ static int fit_check_rsa_signature(struct device_node *sig_node,
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;
}
@@ -310,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;
}
@@ -323,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;
}
@@ -381,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;
}
@@ -413,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;
}
@@ -453,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;
}
@@ -546,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)
@@ -555,6 +555,11 @@ 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;
@@ -565,6 +570,47 @@ 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
@@ -587,8 +633,7 @@ int fit_open_image(struct fit_handle *handle, void *configuration,
unsigned long *outsize)
{
struct device_node *image;
- const char *unit = name, *type = NULL, *compression = NULL,
- *desc= "(no description)";
+ const char *unit = name, *type = NULL, *desc= "(no description)";
const void *data;
int data_len;
int ret = 0;
@@ -602,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;
}
@@ -620,28 +665,9 @@ int fit_open_image(struct fit_handle *handle, void *configuration,
if (ret < 0)
return ret;
- of_property_read_string(image, "compression", &compression);
- if (compression && strcmp(compression, "none") != 0) {
- void *uc_data;
-
- if (!IS_ENABLED(CONFIG_UNCOMPRESS)) {
- pr_err("image has compression = \"%s\", but support not compiled in\n",
- compression);
- return -ENOSYS;
- }
-
- data_len = uncompress_buf_to_buf(data, data_len, &uc_data,
- fit_uncompress_error_fn);
- if (data_len < 0) {
- pr_err("data couldn't be decompressed\n");
- return data_len;
- }
-
- data = uc_data;
-
- /* associate buffer with FIT, so it's not leaked */
- __of_new_property(image, "uncompressed-data", uc_data, data_len);
- }
+ ret = fit_handle_decompression(image, type, &data, &data_len);
+ if (ret)
+ return ret;
*outdata = data;
*outsize = data_len;
@@ -670,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, ~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;
@@ -703,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)
@@ -741,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);
@@ -827,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.
@@ -834,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;
@@ -845,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/imx-bbu-nand-fcb.c b/common/imx-bbu-nand-fcb.c
index bde0b227f8..d0261140cf 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;
};
@@ -78,7 +79,7 @@ static void encode_bch_ecc(void *buf, struct fcb_block *fcb, int eccbits)
int blocksize = 128;
int numblocks = 8;
int ecc_buf_size = (m * eccbits + 7) / 8;
- struct bch_control *bch = init_bch(m, eccbits, 0);
+ struct bch_control *bch = bch_init(m, eccbits, 0, false);
uint8_t *ecc_buf = xmalloc(ecc_buf_size);
uint8_t *tmp_buf = xzalloc(blocksize * numblocks);
uint8_t *psrc, *pdst;
@@ -108,7 +109,7 @@ static void encode_bch_ecc(void *buf, struct fcb_block *fcb, int eccbits)
for (j = 0; j < blocksize; j++)
psrc[j] = reverse_bit(psrc[j]);
- encode_bch(bch, psrc, blocksize, ecc_buf);
+ bch_encode(bch, psrc, blocksize, ecc_buf);
/* reverse ecc bit */
for (j = 0; j < ecc_buf_size; j++)
@@ -120,16 +121,16 @@ static void encode_bch_ecc(void *buf, struct fcb_block *fcb, int eccbits)
free(ecc_buf);
free(tmp_buf);
- free_bch(bch);
+ bch_free(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;
int numblocks = 8;
int ecc_buf_size = (m * eccbits + 7) / 8;
- struct bch_control *bch = init_bch(m, eccbits, 0);
+ struct bch_control *bch = bch_init(m, eccbits, 0, false);
uint8_t *fcb = xmalloc(numblocks * blocksize);
uint8_t *ecc_buf = xmalloc(ecc_buf_size);
uint8_t *data_buf = xmalloc(blocksize);
@@ -151,7 +152,7 @@ static struct fcb_block *read_fcb_bch(void *rawpage, int eccbits)
for (j = 0; j < ecc_buf_size; j++)
ecc_buf[j] = reverse_bit(psrc[j + blocksize]);
- ret = decode_bch(bch, data_buf, blocksize, ecc_buf,
+ ret = bch_decode(bch, data_buf, blocksize, ecc_buf,
NULL, NULL, errloc);
if (ret < 0) {
@@ -184,7 +185,7 @@ out:
free(data_buf);
free(ecc_buf);
free(errloc);
- free_bch(bch);
+ bch_free(bch);
return (struct fcb_block *)fcb;
}
@@ -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)
@@ -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 a9b2b93689..3c5904f8a8 100644
--- a/common/kallsyms.c
+++ b/common/kallsyms.c
@@ -165,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 8c273b9349..e670886d85 100644
--- a/common/machine_id.c
+++ b/common/machine_id.c
@@ -13,17 +13,102 @@
#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;
@@ -61,6 +146,7 @@ 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:
digest_free(digest);
diff --git a/common/meminfo.c b/common/meminfo.c
index f4994959b6..3ceb0ba4cf 100644
--- a/common/meminfo.c
+++ b/common/meminfo.c
@@ -13,8 +13,8 @@ static int display_meminfo(void)
ulong msize = mend - mstart + 1;
if (!IS_ENABLED(CONFIG_SANDBOX)) {
- 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);
+ 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));
diff --git a/common/memory.c b/common/memory.c
index 7e24ecb2bd..583843cc34 100644
--- a/common/memory.c
+++ b/common/memory.c
@@ -15,6 +15,7 @@
#include <asm/sections.h>
#include <malloc.h>
#include <of.h>
+#include <mmu.h>
/*
* Begin and End of memory area for malloc(), and current "brk"
@@ -149,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) {
@@ -210,6 +212,31 @@ struct resource *__request_sdram_region(const char *name, unsigned flags,
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 77868be26a..c0ca469703 100644
--- a/common/memory_display.c
+++ b/common/memory_display.c
@@ -123,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;
}
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/misc.c b/common/misc.c
index e0e32f47c5..530f85f6e3 100644
--- a/common/misc.c
+++ b/common/misc.c
@@ -13,6 +13,8 @@
#include <led.h>
#include <of.h>
#include <restart.h>
+#include <poweroff.h>
+#include <string.h>
#include <linux/stringify.h>
int errno;
@@ -105,16 +107,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
@@ -152,6 +148,67 @@ static char *hostname;
static char *serial_number;
static char *of_machine_compatible;
+/* Note that HOST_NAME_MAX is 64 on Linux */
+#define BAREBOX_HOST_NAME_MAX 64
+
+static bool barebox_valid_ldh_char(char c)
+{
+ /* "LDH" -> "Letters, digits, hyphens", as per RFC 5890, Section 2.3.1 */
+ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
+ (c >= '0' && c <= '9') || c == '-';
+}
+
+bool barebox_hostname_is_valid(const char *s)
+{
+ unsigned int n_dots = 0;
+ const char *p;
+ bool dot, hyphen;
+
+ /*
+ * Check if s looks like a valid hostname or FQDN. This does not do full
+ * DNS validation, but only checks if the name is composed of allowed
+ * characters and the length is not above the maximum allowed by Linux.
+ * Doesn't accept empty hostnames, hostnames with leading dots, and
+ * hostnames with multiple dots in a sequence. Doesn't allow hyphens at
+ * the beginning or end of label.
+ */
+ if (isempty(s))
+ return false;
+
+ for (p = s, dot = hyphen = true; *p; p++) {
+ if (*p == '.') {
+ if (dot || hyphen)
+ return false;
+
+ dot = true;
+ hyphen = false;
+ n_dots++;
+
+ } else if (*p == '-') {
+ if (dot)
+ return false;
+
+ dot = false;
+ hyphen = true;
+
+ } else {
+ if (!barebox_valid_ldh_char(*p))
+ return false;
+
+ dot = false;
+ hyphen = false;
+ }
+ }
+
+ if (dot || hyphen)
+ return false;
+
+ if (p - s > BAREBOX_HOST_NAME_MAX)
+ return false;
+
+ return true;
+}
+
/*
* The hostname is supposed to be the shortname of a board. It should
* contain only lowercase letters, numbers, '-', '_'. No whitespaces
@@ -162,6 +219,10 @@ void barebox_set_hostname(const char *__hostname)
globalvar_add_simple_string("hostname", &hostname);
free(hostname);
+
+ if (!barebox_hostname_is_valid(__hostname))
+ pr_warn("Hostname is not valid, please fix it\n");
+
hostname = xstrdup(__hostname);
}
@@ -222,23 +283,43 @@ device_initcall(of_kernel_init);
BAREBOX_MAGICVAR(global.of.kernel.add_machine_compatible, "Additional machine/board compatible");
-void __noreturn panic(const char *fmt, ...)
+static void __noreturn do_panic(bool stacktrace, const char *fmt, va_list ap)
{
- va_list args;
- va_start(args, fmt);
- vprintf(fmt, args);
+ 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 38752e2c19..c12b3cfb16 100644
--- a/common/oftree.c
+++ b/common/oftree.c
@@ -124,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.
@@ -140,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;
}
@@ -205,7 +200,7 @@ 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;
@@ -233,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);
@@ -308,8 +303,8 @@ int of_fixup_reserved_memory(struct device_node *root, void *_res)
of_write_number(reg, res->start, addr_n_cells);
of_write_number(reg + addr_n_cells, resource_size(res), size_n_cells);
- of_new_property(child, "reg", reg,
- (addr_n_cells + size_n_cells) * sizeof(*reg));
+ of_set_property(child, "reg", reg,
+ (addr_n_cells + size_n_cells) * sizeof(*reg), true);
return 0;
}
@@ -350,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)
{
@@ -393,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;
@@ -401,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;
}
/*
@@ -416,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;
+
+ of_fix_tree(np);
- fdt = of_flatten_dtb(node);
+ fdt = of_flatten_dtb(np);
-out:
- of_delete_node(freenp);
+ of_delete_node(np);
return fdt;
}
diff --git a/common/optee.c b/common/optee.c
index b460fbcd01..7fe93e4419 100644
--- a/common/optee.c
+++ b/common/optee.c
@@ -4,20 +4,58 @@
#include <tee/optee.h>
#include <linux/printk.h>
-#include <asm-generic/errno.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/partitions.c b/common/partitions.c
index 9cca5c4a15..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,31 +26,34 @@ 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;
- strcpy(cdev->uuid, part->partuuid);
+ 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;
- parser->parse(buf, blk, pdesc);
+ pdesc = parser->parse(buf, blk);
+ if (!pdesc)
+ goto err;
- if (!pdesc->used_entries)
- goto on_error;
+ pdesc->parser = parser;
+err:
+ free(buf);
+
+ return 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;
+}
+
+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,12 +261,31 @@ 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);
diff --git a/common/partitions/Kconfig b/common/partitions/Kconfig
index 7f12383082..3bbcceedc1 100644
--- a/common/partitions/Kconfig
+++ b/common/partitions/Kconfig
@@ -19,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/dos.c b/common/partitions/dos.c
index 566c8dd949..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,58 +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);
- if (signature)
- sprintf(blk->cdev.uuid, "%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)) {
- pd->parts[n].size = 2;
-
- 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;
@@ -240,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 0f3f790539..829360da6e 100644
--- a/common/partitions/efi.c
+++ b/common/partitions/efi.c
@@ -20,7 +20,18 @@
#include <linux/ctype.h>
#include <efi/partition.h>
-#include "parser.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;
@@ -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,23 +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);
- snprintf(blk->cdev.uuid, sizeof(blk->cdev.uuid), "%pUl", &gpt->disk_guid);
- dev_add_param_string_fixed(blk->dev, "guid", blk->cdev.uuid);
+ blk->cdev.flags |= DEVFS_IS_GPT_PARTITIONED;
nb_part = le32_to_cpu(gpt->num_partition_entries);
@@ -456,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/parser.h b/common/partitions/parser.h
deleted file mode 100644
index d67f8e1d6a..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_UUID_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/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/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 774ea5fc8c..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,11 +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)
{
unsigned int priority = RESET_SOURCE_DEFAULT_PRIORITY;
- of_property_read_u32(dev->device_node, "reset-source-priority", &priority);
+ of_property_read_u32(dev->of_node, "reset-source-priority", &priority);
__reset_source_set(dev, st, priority, -1);
}
diff --git a/common/resource.c b/common/resource.c
index 8678609229..76f19de494 100644
--- a/common/resource.c
+++ b/common/resource.c
@@ -10,6 +10,7 @@
#include <init.h>
#include <linux/ioport.h>
#include <linux/err.h>
+#include <linux/resource_ext.h>
#include <asm/io.h>
static int init_resource(struct resource *res, const char *name)
@@ -164,3 +165,18 @@ struct resource *request_ioport_region(const char *name,
return res;
}
+
+struct resource_entry *resource_list_create_entry(struct resource *res,
+ size_t extra_size)
+{
+ struct resource_entry *entry;
+
+ entry = kzalloc(sizeof(*entry) + extra_size, GFP_KERNEL);
+ if (entry) {
+ INIT_LIST_HEAD(&entry->node);
+ entry->res = res ? res : &entry->__res;
+ }
+
+ return entry;
+}
+EXPORT_SYMBOL(resource_list_create_entry);
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 1d328c6a33..5399a20627 100644
--- a/common/serdev.c
+++ b/common/serdev.c
@@ -132,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);
@@ -186,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 f53b73f81a..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);
}
@@ -173,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;
}
@@ -307,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/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 117cdfb46c..03c752d6fe 100644
--- a/common/state/backend_bucket_direct.c
+++ b/common/state/backend_bucket_direct.c
@@ -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,6 +72,8 @@ 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;
@@ -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 7835f977c9..105f7dd444 100644
--- a/common/state/backend_format_raw.c
+++ b/common/state/backend_format_raw.c
@@ -32,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;
@@ -299,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 c55d22e37f..df81902bf7 100644
--- a/common/state/backend_storage.c
+++ b/common/state/backend_storage.c
@@ -332,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 a614c849c7..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>
@@ -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;
diff --git a/common/state/state.h b/common/state/state.h
index 0545cf6ac1..f0c5b1de41 100644
--- a/common/state/state.h
+++ b/common/state/state.h
@@ -90,7 +90,7 @@ struct state_backend_storage {
struct list_head buckets;
/* For outputs */
- struct device_d *dev;
+ struct device *dev;
const char *name;
@@ -105,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;
@@ -202,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);
@@ -224,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,
diff --git a/common/state/state_variables.c b/common/state/state_variables.c
index cb85f3a926..77946206cd 100644
--- a/common/state/state_variables.c
+++ b/common/state/state_variables.c
@@ -263,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);
@@ -329,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);
}
@@ -444,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 3ca58e3abb..ba2ed367c0 100644
--- a/common/tlsf.c
+++ b/common/tlsf.c
@@ -30,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),
/*
@@ -101,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.
*/
@@ -122,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;
@@ -134,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
@@ -166,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;
@@ -253,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;
}
@@ -464,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);
@@ -730,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))
{
@@ -765,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)
@@ -836,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);
@@ -854,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;
@@ -982,7 +983,7 @@ void* tlsf_memalign(tlsf_t tlsf, size_t align, size_t size)
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)
{
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 7291fbf4d5..3713551163 100644
--- a/common/usbgadget.c
+++ b/common/usbgadget.c
@@ -12,9 +12,9 @@
#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>
@@ -35,7 +35,7 @@ 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));
diff --git a/common/version.c b/common/version.c
index 15f03c2a00..0cac5ee609 100644
--- a/common/version.c
+++ b/common/version.c
@@ -5,7 +5,7 @@
#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[] =
@@ -20,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());
}