From bb34bc0c96168857d6b5127d3487223b0ea8cfa5 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 27 Jul 2023 10:12:39 +0300 Subject: cmd: pxe_utils: add some missing tabs These lines are supposed to be indented one more tab. Otherwise it's confusing to read. Signed-off-by: Dan Carpenter Reviewed-by: Patrick Delaunay --- boot/pxe_utils.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'boot') diff --git a/boot/pxe_utils.c b/boot/pxe_utils.c index d13c47dd942..ac1414a5f26 100644 --- a/boot/pxe_utils.c +++ b/boot/pxe_utils.c @@ -702,8 +702,8 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label) } } - if (label->kaslrseed) - label_boot_kaslrseed(); + if (label->kaslrseed) + label_boot_kaslrseed(); #ifdef CONFIG_OF_LIBFDT_OVERLAY if (label->fdtoverlays) -- cgit v1.3.1 From d864bd0e21ad6ab901bc6365abc8c3dbebe3ad29 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 31 Jul 2023 17:08:29 +0300 Subject: expo: allocate correct amount of memory This should be allocating the memory for "item" instead of "menu". The item struct is 48 bytes instead of 96 (assuming a 64bit system) so this saves a little memory. Signed-off-by: Dan Carpenter Reviewed-by: Simon Glass --- boot/scene_menu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'boot') diff --git a/boot/scene_menu.c b/boot/scene_menu.c index 8a355f838cc..57ffb523ff3 100644 --- a/boot/scene_menu.c +++ b/boot/scene_menu.c @@ -416,7 +416,7 @@ int scene_menuitem(struct scene *scn, uint menu_id, const char *name, uint id, if (!scene_obj_find(scn, label_id, SCENEOBJT_TEXT)) return log_msg_ret("txt", -EINVAL); - item = calloc(1, sizeof(struct scene_obj_menu)); + item = calloc(1, sizeof(struct scene_menitem)); if (!item) return log_msg_ret("item", -ENOMEM); item->name = strdup(name); -- cgit v1.3.1 From 1a549c8961a6db72db374a4db2be598b30c9c46d Mon Sep 17 00:00:00 2001 From: Ilya Lukin <4.shket@gmail.com> Date: Fri, 14 Jul 2023 17:39:32 +0300 Subject: crc32: Drop duplicates crc header includes Fixes: 3db711085752 ("crc32: Use the crc.h header for crc functions") Signed-off-by: Ilya Lukin <4.shket@gmail.com> --- board/sunxi/board.c | 1 - boot/android_ab.c | 1 - common/hash.c | 1 - lib/crc32.c | 1 - tools/default_image.c | 1 - 5 files changed, 5 deletions(-) (limited to 'boot') diff --git a/board/sunxi/board.c b/board/sunxi/board.c index f321cd58a6e..de0f3505e52 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -33,7 +33,6 @@ #include #include #include -#include #ifndef CONFIG_ARM64 #include #endif diff --git a/boot/android_ab.c b/boot/android_ab.c index 73b55c196c4..0f20a34e511 100644 --- a/boot/android_ab.c +++ b/boot/android_ab.c @@ -12,7 +12,6 @@ #include #include #include -#include /** * Compute the CRC-32 of the bootloader control struct. diff --git a/common/hash.c b/common/hash.c index cbffdfd6db3..159179e7f21 100644 --- a/common/hash.c +++ b/common/hash.c @@ -21,7 +21,6 @@ #include #include #include -#include #else #include "mkimage.h" #include diff --git a/lib/crc32.c b/lib/crc32.c index aa94d70ef3e..f6fad8c15df 100644 --- a/lib/crc32.c +++ b/lib/crc32.c @@ -10,7 +10,6 @@ #ifdef USE_HOSTCC #include -#include #else #include #include diff --git a/tools/default_image.c b/tools/default_image.c index 0e49ab33015..04bc85bf932 100644 --- a/tools/default_image.c +++ b/tools/default_image.c @@ -15,7 +15,6 @@ #include "imagetool.h" #include "mkimage.h" -#include #include #include -- cgit v1.3.1 From a077ac13d03c8cde646ddab30b03ec0f8b753e1e Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Wed, 2 Aug 2023 11:09:43 -0400 Subject: Kconfigs: Correct default of "0" on hex type entries It is not a parse error to have a default value of "0" for a "hex" type entry, instead of "0x0". However, "0" and "0x0" are not treated the same even by the tools themselves. Correct this by changing the default value from "0" to "0x0" for all hex type questions that had the incorrect default. Fix one instance (in two configs) of a default of "0" being used on a hex question to be "0x0". Remove the cases where a defconfig had set a value of "0x0" to be used as the default had been "0". Signed-off-by: Tom Rini Reviewed-by: Simon Glass --- arch/arm/cpu/armv7/ls102xa/Kconfig | 1 - arch/arm/cpu/armv8/fsl-layerscape/Kconfig | 2 +- arch/arm/mach-imx/Kconfig | 2 +- arch/arm/mach-imx/imx8/Kconfig | 4 ++-- arch/arm/mach-rockchip/Kconfig | 2 +- arch/arm/mach-sunxi/Kconfig | 4 ++-- arch/powerpc/cpu/mpc8xx/Kconfig | 2 +- boot/Kconfig | 2 +- cmd/Kconfig | 8 ++++---- common/Kconfig | 2 +- common/spl/Kconfig | 2 +- common/spl/Kconfig.tpl | 2 +- configs/am335x_guardian_defconfig | 1 - configs/efi-x86_app32_defconfig | 2 +- configs/efi-x86_app64_defconfig | 2 +- configs/evb-rk3229_defconfig | 1 - configs/evb-rk3308_defconfig | 1 - configs/imx6q_logic_defconfig | 1 - configs/imx8mm_data_modul_edm_sbc_defconfig | 1 - configs/imx8mn_beacon_2g_defconfig | 1 - configs/imx8mn_beacon_defconfig | 1 - configs/imx8mn_beacon_fspi_defconfig | 1 - configs/imx8mp_beacon_defconfig | 1 - configs/imx8mp_data_modul_edm_sbc_defconfig | 1 - configs/imx8mp_dhcom_pdk2_defconfig | 1 - configs/imx8mp_dhcom_pdk3_defconfig | 1 - configs/kontron_sl28_defconfig | 2 -- configs/lion-rk3368_defconfig | 1 - configs/roc-cc-rk3308_defconfig | 1 - configs/rock-pi-s-rk3308_defconfig | 1 - configs/sandbox64_defconfig | 1 - configs/sandbox_defconfig | 1 - configs/sandbox_flattree_defconfig | 1 - configs/sandbox_noinst_defconfig | 1 - configs/sandbox_spl_defconfig | 1 - configs/sandbox_vpl_defconfig | 1 - configs/xilinx_versal_net_virt_defconfig | 1 - configs/xilinx_zynqmp_virt_defconfig | 1 - drivers/block/Kconfig | 2 +- drivers/fastboot/Kconfig | 2 +- drivers/i2c/Kconfig | 16 ++++++++-------- drivers/misc/Kconfig | 2 +- drivers/serial/Kconfig | 6 +++--- drivers/usb/gadget/Kconfig | 2 +- drivers/video/Kconfig | 4 ++-- env/Kconfig | 4 ++-- lib/Kconfig | 2 +- 47 files changed, 38 insertions(+), 64 deletions(-) (limited to 'boot') diff --git a/arch/arm/cpu/armv7/ls102xa/Kconfig b/arch/arm/cpu/armv7/ls102xa/Kconfig index 3e292bf70e1..46ace7e5fd6 100644 --- a/arch/arm/cpu/armv7/ls102xa/Kconfig +++ b/arch/arm/cpu/armv7/ls102xa/Kconfig @@ -98,7 +98,6 @@ config SYS_FSL_ERRATUM_A008407 config SYS_FSL_QSPI_SKIP_CLKSEL bool "Skip setting QSPI clock during SoC init" - default 0 help To improve startup times when booting from QSPI flash, the QSPI frequency can be set very early in the boot process. If this option diff --git a/arch/arm/cpu/armv8/fsl-layerscape/Kconfig b/arch/arm/cpu/armv8/fsl-layerscape/Kconfig index a8b493e2f87..d46934c2dcf 100644 --- a/arch/arm/cpu/armv8/fsl-layerscape/Kconfig +++ b/arch/arm/cpu/armv8/fsl-layerscape/Kconfig @@ -739,7 +739,7 @@ config HAS_FSL_XHCI_USB config SYS_FSL_BOOTROM_BASE hex depends on FSL_LSCH2 - default 0 + default 0x0 config SYS_FSL_BOOTROM_SIZE hex diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index d94b5828d0d..2136ab7e9eb 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -181,7 +181,7 @@ config IMX8_ROMAPI config SPL_IMX_ROMAPI_LOADADDR hex "Default load address to load image through ROM API" depends on IMX8_ROMAPI || SPL_BOOTROM_SUPPORT - default 0 + default 0x0 config IMX_DCD_ADDR hex "DCD Blocks location on the image" diff --git a/arch/arm/mach-imx/imx8/Kconfig b/arch/arm/mach-imx/imx8/Kconfig index 15f844f5030..59d11b3179e 100644 --- a/arch/arm/mach-imx/imx8/Kconfig +++ b/arch/arm/mach-imx/imx8/Kconfig @@ -34,11 +34,11 @@ config SYS_SOC config BOOTAUX_RESERVED_MEM_BASE hex "i.MX auxiliary core dram memory base" - default 0 + default 0x0 config BOOTAUX_RESERVED_MEM_SIZE hex "i.MX auxiliary core dram memory size" - default 0 + default 0x0 choice prompt "i.MX8 board select" diff --git a/arch/arm/mach-rockchip/Kconfig b/arch/arm/mach-rockchip/Kconfig index 49da93d54b4..4569a9ce283 100644 --- a/arch/arm/mach-rockchip/Kconfig +++ b/arch/arm/mach-rockchip/Kconfig @@ -469,7 +469,7 @@ config ROCKCHIP_STIMER_BASE config ROCKCHIP_SPL_RESERVE_IRAM hex "Size of IRAM reserved in SPL" - default 0 + default 0x0 help SPL may need reserve memory for firmware loaded by SPL, whose load address is in IRAM and may overlay with SPL text area if not diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index e20c3a3ee92..9d5df2c1027 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -568,7 +568,7 @@ config DRAM_EMR1 config DRAM_TPR3 hex "sunxi dram tpr3 value" - default 0 + default 0x0 ---help--- Set the dram controller tpr3 parameter. This parameter configures the delay on the command lane and also phase shifts, which are @@ -579,7 +579,7 @@ config DRAM_TPR3 config DRAM_DQS_GATING_DELAY hex "sunxi dram dqs_gating_delay value" - default 0 + default 0x0 ---help--- Set the dram controller dqs_gating_delay parmeter. Each byte encodes the DQS gating delay for each byte lane. The delay diff --git a/arch/powerpc/cpu/mpc8xx/Kconfig b/arch/powerpc/cpu/mpc8xx/Kconfig index bd2af8dc10e..1731c965ad9 100644 --- a/arch/powerpc/cpu/mpc8xx/Kconfig +++ b/arch/powerpc/cpu/mpc8xx/Kconfig @@ -94,7 +94,7 @@ config SYS_SIUMCR config SYS_SYPCR hex "SYPCR register" if !WDT_MPC8xxx - default 0 + default 0x0 help System Protection Control (11-9) diff --git a/boot/Kconfig b/boot/Kconfig index e8fb03b8016..b00d7a8d11e 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -1007,7 +1007,7 @@ config BOOTSTAGE_STASH config BOOTSTAGE_STASH_ADDR hex "Address to stash boot timing information" - default 0 + default 0x0 help Provide an address which will not be overwritten by the OS when it starts, so that it can read this information when ready. diff --git a/cmd/Kconfig b/cmd/Kconfig index 7f65e3187a6..8ab47b333c2 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -517,7 +517,7 @@ config CMD_SPL config CMD_SPL_NAND_OFS hex "Offset of OS args or dtb for Falcon-mode NAND boot" depends on CMD_SPL && (TPL_NAND_SUPPORT || SPL_NAND_SUPPORT) - default 0 + default 0x0 help This provides the offset of the command line arguments for Linux when booting from NAND in Falcon mode. See doc/README.falcon @@ -527,7 +527,7 @@ config CMD_SPL_NAND_OFS config CMD_SPL_NOR_OFS hex "Offset of OS args or dtb for Falcon-mode NOR boot" depends on CMD_SPL && SPL_NOR_SUPPORT - default 0 + default 0x0 help This provides the offset of the command line arguments or dtb for Linux when booting from NOR in Falcon mode. @@ -1514,7 +1514,7 @@ config DEFAULT_SPI_BUS config DEFAULT_SPI_MODE hex "default spi mode used by sspi command (see include/spi.h)" depends on CMD_SPI - default 0 + default 0x0 config CMD_TEMPERATURE bool "temperature - display the temperature from thermal sensors" @@ -1805,7 +1805,7 @@ config BOOTP_PXE_CLIENTARCH depends on BOOTP_PXE default 0x16 if ARM64 default 0x15 if ARM - default 0 if X86 + default 0x0 if X86 config BOOTP_VCI_STRING string diff --git a/common/Kconfig b/common/Kconfig index cdb77a6a7da..0b09bd68bd1 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -1031,7 +1031,7 @@ config BLOBLIST_SIZE config BLOBLIST_SIZE_RELOC hex "Size of bloblist after relocation" default BLOBLIST_SIZE if BLOBLIST_FIXED || BLOBLIST_ALLOC - default 0 if BLOBLIST_PASSAGE + default 0x0 if BLOBLIST_PASSAGE help Sets the size of the bloblist in bytes after relocation. Since U-Boot has a lot more memory available then, it is possible to use a larger diff --git a/common/spl/Kconfig b/common/spl/Kconfig index c5dd476db58..1c2fe78e3e0 100644 --- a/common/spl/Kconfig +++ b/common/spl/Kconfig @@ -67,7 +67,7 @@ config SPL_SIZE_LIMIT_SUBTRACT_MALLOC config SPL_SIZE_LIMIT_PROVIDE_STACK hex "SPL image size check: provide stack space before relocation" depends on SPL_SIZE_LIMIT > 0 - default 0 + default 0x0 help If set, this size is reserved in SPL_SIZE_LIMIT check to ensure such an image does not overflow SRAM if SPL_SIZE_LIMIT describes the size diff --git a/common/spl/Kconfig.tpl b/common/spl/Kconfig.tpl index 3d6cf1e59f3..cc71578f646 100644 --- a/common/spl/Kconfig.tpl +++ b/common/spl/Kconfig.tpl @@ -126,7 +126,7 @@ config TPL_POWER config TPL_TEXT_BASE hex "Base address for the .text section of the TPL stage" - default 0 + default 0x0 help The base address for the .text section of the TPL stage. diff --git a/configs/am335x_guardian_defconfig b/configs/am335x_guardian_defconfig index a485cc65eaf..7c4085d0849 100644 --- a/configs/am335x_guardian_defconfig +++ b/configs/am335x_guardian_defconfig @@ -17,7 +17,6 @@ CONFIG_SPL_SERIAL=y CONFIG_SPL_DRIVERS_MISC=y CONFIG_BOOTCOUNT_BOOTLIMIT=3 CONFIG_SPL=y -CONFIG_BOOTSTAGE_STASH_ADDR=0x0 CONFIG_ENV_OFFSET_REDUND=0x540000 CONFIG_SPL_LIBDISK_SUPPORT=y CONFIG_SYS_MEMTEST_START=0x80000000 diff --git a/configs/efi-x86_app32_defconfig b/configs/efi-x86_app32_defconfig index 50975dbfaaf..1bfc01f060d 100644 --- a/configs/efi-x86_app32_defconfig +++ b/configs/efi-x86_app32_defconfig @@ -2,7 +2,7 @@ CONFIG_X86=y CONFIG_NR_DRAM_BANKS=8 CONFIG_ENV_SIZE=0x1000 CONFIG_DEFAULT_DEVICE_TREE="efi-x86_app" -CONFIG_DEBUG_UART_BASE=0 +CONFIG_DEBUG_UART_BASE=0x0 CONFIG_DEBUG_UART_CLOCK=0 CONFIG_VENDOR_EFI=y CONFIG_TARGET_EFI_APP32=y diff --git a/configs/efi-x86_app64_defconfig b/configs/efi-x86_app64_defconfig index 0fc358ddcdf..46a1900c704 100644 --- a/configs/efi-x86_app64_defconfig +++ b/configs/efi-x86_app64_defconfig @@ -2,7 +2,7 @@ CONFIG_X86=y CONFIG_NR_DRAM_BANKS=8 CONFIG_ENV_SIZE=0x1000 CONFIG_DEFAULT_DEVICE_TREE="efi-x86_app" -CONFIG_DEBUG_UART_BASE=0 +CONFIG_DEBUG_UART_BASE=0x0 CONFIG_DEBUG_UART_CLOCK=0 CONFIG_X86_RUN_64BIT=y CONFIG_VENDOR_EFI=y diff --git a/configs/evb-rk3229_defconfig b/configs/evb-rk3229_defconfig index c1e7f390ad5..7469f3fbe0a 100644 --- a/configs/evb-rk3229_defconfig +++ b/configs/evb-rk3229_defconfig @@ -12,7 +12,6 @@ CONFIG_ENV_OFFSET=0x3F8000 CONFIG_DEFAULT_DEVICE_TREE="rk3229-evb" CONFIG_SPL_TEXT_BASE=0x60000000 CONFIG_ROCKCHIP_RK322X=y -CONFIG_ROCKCHIP_SPL_RESERVE_IRAM=0x0 CONFIG_TARGET_EVB_RK3229=y CONFIG_SPL_STACK_R_ADDR=0x60600000 CONFIG_DEBUG_UART_BASE=0x11030000 diff --git a/configs/evb-rk3308_defconfig b/configs/evb-rk3308_defconfig index a13a809c1ef..d1e78582a3a 100644 --- a/configs/evb-rk3308_defconfig +++ b/configs/evb-rk3308_defconfig @@ -11,7 +11,6 @@ CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0x800000 CONFIG_DEFAULT_DEVICE_TREE="rk3308-evb" CONFIG_DM_RESET=y CONFIG_ROCKCHIP_RK3308=y -CONFIG_ROCKCHIP_SPL_RESERVE_IRAM=0x0 CONFIG_SPL_DRIVERS_MISC=y CONFIG_TARGET_EVB_RK3308=y CONFIG_SPL_STACK_R_ADDR=0xc00000 diff --git a/configs/imx6q_logic_defconfig b/configs/imx6q_logic_defconfig index 2814e2c8147..74733c4de32 100644 --- a/configs/imx6q_logic_defconfig +++ b/configs/imx6q_logic_defconfig @@ -86,7 +86,6 @@ CONFIG_LED=y CONFIG_LED_GPIO=y CONFIG_MISC=y CONFIG_I2C_EEPROM=y -CONFIG_SYS_I2C_EEPROM_ADDR=0x0 CONFIG_FSL_USDHC=y CONFIG_MTD=y CONFIG_DM_MTD=y diff --git a/configs/imx8mm_data_modul_edm_sbc_defconfig b/configs/imx8mm_data_modul_edm_sbc_defconfig index f63eb4fd64c..e2bca406113 100644 --- a/configs/imx8mm_data_modul_edm_sbc_defconfig +++ b/configs/imx8mm_data_modul_edm_sbc_defconfig @@ -233,6 +233,5 @@ CONFIG_USB_GADGET_MANUFACTURER="Data Modul" CONFIG_USB_GADGET_VENDOR_NUM=0x0525 CONFIG_USB_GADGET_PRODUCT_NUM=0xa4a5 CONFIG_CI_UDC=y -CONFIG_SDP_LOADADDR=0x0 CONFIG_USB_FUNCTION_ACM=y CONFIG_IMX_WATCHDOG=y diff --git a/configs/imx8mn_beacon_2g_defconfig b/configs/imx8mn_beacon_2g_defconfig index fab3ab154b5..975fcc2481a 100644 --- a/configs/imx8mn_beacon_2g_defconfig +++ b/configs/imx8mn_beacon_2g_defconfig @@ -142,4 +142,3 @@ CONFIG_USB_GADGET_MANUFACTURER="FSL" CONFIG_USB_GADGET_VENDOR_NUM=0x0525 CONFIG_USB_GADGET_PRODUCT_NUM=0xa4a5 CONFIG_CI_UDC=y -CONFIG_SDP_LOADADDR=0x0 diff --git a/configs/imx8mn_beacon_defconfig b/configs/imx8mn_beacon_defconfig index f810d4be610..f4ecdc88f39 100644 --- a/configs/imx8mn_beacon_defconfig +++ b/configs/imx8mn_beacon_defconfig @@ -149,5 +149,4 @@ CONFIG_USB_GADGET_MANUFACTURER="FSL" CONFIG_USB_GADGET_VENDOR_NUM=0x0525 CONFIG_USB_GADGET_PRODUCT_NUM=0xa4a5 CONFIG_CI_UDC=y -CONFIG_SDP_LOADADDR=0x0 CONFIG_IMX_WATCHDOG=y diff --git a/configs/imx8mn_beacon_fspi_defconfig b/configs/imx8mn_beacon_fspi_defconfig index 8705d9bccc4..f5e57fb50bc 100644 --- a/configs/imx8mn_beacon_fspi_defconfig +++ b/configs/imx8mn_beacon_fspi_defconfig @@ -149,7 +149,6 @@ CONFIG_USB_GADGET_MANUFACTURER="FSL" CONFIG_USB_GADGET_VENDOR_NUM=0x0525 CONFIG_USB_GADGET_PRODUCT_NUM=0xa4a5 CONFIG_CI_UDC=y -CONFIG_SDP_LOADADDR=0x0 CONFIG_IMX_WATCHDOG=y CONFIG_FSPI_CONF_HEADER=y CONFIG_FSPI_CONF_FILE="fspi_header.bin" diff --git a/configs/imx8mp_beacon_defconfig b/configs/imx8mp_beacon_defconfig index 2570eb6a885..c6a3e35e73a 100644 --- a/configs/imx8mp_beacon_defconfig +++ b/configs/imx8mp_beacon_defconfig @@ -172,7 +172,6 @@ CONFIG_USB_GADGET=y CONFIG_USB_GADGET_MANUFACTURER="FSL" CONFIG_USB_GADGET_VENDOR_NUM=0x1fc9 CONFIG_USB_GADGET_PRODUCT_NUM=0x0152 -CONFIG_SDP_LOADADDR=0x0 CONFIG_USB_FUNCTION_ACM=y CONFIG_USB_ETHER=y CONFIG_USB_ETH_CDC=y diff --git a/configs/imx8mp_data_modul_edm_sbc_defconfig b/configs/imx8mp_data_modul_edm_sbc_defconfig index 2ff577f2d8a..d3b629caf5c 100644 --- a/configs/imx8mp_data_modul_edm_sbc_defconfig +++ b/configs/imx8mp_data_modul_edm_sbc_defconfig @@ -257,7 +257,6 @@ CONFIG_USB_GADGET=y CONFIG_USB_GADGET_MANUFACTURER="Data Modul" CONFIG_USB_GADGET_VENDOR_NUM=0x0525 CONFIG_USB_GADGET_PRODUCT_NUM=0xa4a5 -CONFIG_SDP_LOADADDR=0x0 CONFIG_USB_FUNCTION_ACM=y CONFIG_USB_ETHER=y CONFIG_USB_ETH_CDC=y diff --git a/configs/imx8mp_dhcom_pdk2_defconfig b/configs/imx8mp_dhcom_pdk2_defconfig index 14ac499e587..24c87aae781 100644 --- a/configs/imx8mp_dhcom_pdk2_defconfig +++ b/configs/imx8mp_dhcom_pdk2_defconfig @@ -255,7 +255,6 @@ CONFIG_USB_GADGET=y CONFIG_USB_GADGET_MANUFACTURER="DH electronics" CONFIG_USB_GADGET_VENDOR_NUM=0x0525 CONFIG_USB_GADGET_PRODUCT_NUM=0xa4a5 -CONFIG_SDP_LOADADDR=0x0 CONFIG_USB_FUNCTION_ACM=y CONFIG_USB_ETHER=y CONFIG_USB_ETH_CDC=y diff --git a/configs/imx8mp_dhcom_pdk3_defconfig b/configs/imx8mp_dhcom_pdk3_defconfig index 3b26f315bba..3e89e0f8293 100644 --- a/configs/imx8mp_dhcom_pdk3_defconfig +++ b/configs/imx8mp_dhcom_pdk3_defconfig @@ -258,7 +258,6 @@ CONFIG_USB_GADGET=y CONFIG_USB_GADGET_MANUFACTURER="DH electronics" CONFIG_USB_GADGET_VENDOR_NUM=0x0525 CONFIG_USB_GADGET_PRODUCT_NUM=0xa4a5 -CONFIG_SDP_LOADADDR=0x0 CONFIG_USB_FUNCTION_ACM=y CONFIG_USB_ETHER=y CONFIG_USB_ETH_CDC=y diff --git a/configs/kontron_sl28_defconfig b/configs/kontron_sl28_defconfig index 8fe2798c3cc..21a397933e7 100644 --- a/configs/kontron_sl28_defconfig +++ b/configs/kontron_sl28_defconfig @@ -20,7 +20,6 @@ CONFIG_SPL_MMC=y CONFIG_SPL_SERIAL=y CONFIG_SPL_STACK=0x18009ff0 CONFIG_SPL_SIZE_LIMIT=0x20000 -CONFIG_SPL_SIZE_LIMIT_PROVIDE_STACK=0x0 CONFIG_SPL=y CONFIG_ENV_OFFSET_REDUND=0x3f0000 CONFIG_SPL_SPI_FLASH_SUPPORT=y @@ -130,7 +129,6 @@ CONFIG_USB_GADGET_DOWNLOAD=y CONFIG_WDT=y CONFIG_WDT_SL28CPLD=y CONFIG_WDT_SP805=y -CONFIG_OF_LIBFDT_ASSUME_MASK=0x0 CONFIG_EFI_SET_TIME=y CONFIG_EFI_RUNTIME_UPDATE_CAPSULE=y CONFIG_EFI_CAPSULE_FIRMWARE_FIT=y diff --git a/configs/lion-rk3368_defconfig b/configs/lion-rk3368_defconfig index 7c55b3be0d2..9c29eb6fed3 100644 --- a/configs/lion-rk3368_defconfig +++ b/configs/lion-rk3368_defconfig @@ -10,7 +10,6 @@ CONFIG_ENV_OFFSET=0x3F8000 CONFIG_DEFAULT_DEVICE_TREE="rk3368-lion-haikou" CONFIG_SPL_TEXT_BASE=0x00000000 CONFIG_ROCKCHIP_RK3368=y -CONFIG_ROCKCHIP_SPL_RESERVE_IRAM=0x0 CONFIG_TPL_LIBCOMMON_SUPPORT=y CONFIG_TPL_LIBGENERIC_SUPPORT=y CONFIG_SPL_DRIVERS_MISC=y diff --git a/configs/roc-cc-rk3308_defconfig b/configs/roc-cc-rk3308_defconfig index 9a789b212f1..3f3c223fa1d 100644 --- a/configs/roc-cc-rk3308_defconfig +++ b/configs/roc-cc-rk3308_defconfig @@ -11,7 +11,6 @@ CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0x800000 CONFIG_DEFAULT_DEVICE_TREE="rk3308-roc-cc" CONFIG_DM_RESET=y CONFIG_ROCKCHIP_RK3308=y -CONFIG_ROCKCHIP_SPL_RESERVE_IRAM=0x0 CONFIG_SPL_DRIVERS_MISC=y CONFIG_TARGET_ROC_RK3308_CC=y CONFIG_SPL_STACK_R_ADDR=0xc00000 diff --git a/configs/rock-pi-s-rk3308_defconfig b/configs/rock-pi-s-rk3308_defconfig index cc3274a98b3..8c13f7f9c3b 100644 --- a/configs/rock-pi-s-rk3308_defconfig +++ b/configs/rock-pi-s-rk3308_defconfig @@ -11,7 +11,6 @@ CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0x800000 CONFIG_DEFAULT_DEVICE_TREE="rk3308-rock-pi-s" CONFIG_DM_RESET=y CONFIG_ROCKCHIP_RK3308=y -CONFIG_ROCKCHIP_SPL_RESERVE_IRAM=0x0 CONFIG_SPL_DRIVERS_MISC=y CONFIG_TARGET_EVB_RK3308=y CONFIG_SPL_STACK_R_ADDR=0xc00000 diff --git a/configs/sandbox64_defconfig b/configs/sandbox64_defconfig index bf3ef0c4007..0e079d7bb4d 100644 --- a/configs/sandbox64_defconfig +++ b/configs/sandbox64_defconfig @@ -4,7 +4,6 @@ CONFIG_ENV_SIZE=0x2000 CONFIG_DEFAULT_DEVICE_TREE="sandbox64" CONFIG_DM_RESET=y CONFIG_PRE_CON_BUF_ADDR=0x100000 -CONFIG_BOOTSTAGE_STASH_ADDR=0x0 CONFIG_SYS_LOAD_ADDR=0x0 CONFIG_PCI=y CONFIG_SANDBOX64=y diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index ea2b2566aa1..f031b509105 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -4,7 +4,6 @@ CONFIG_ENV_SIZE=0x2000 CONFIG_DEFAULT_DEVICE_TREE="sandbox" CONFIG_DM_RESET=y CONFIG_PRE_CON_BUF_ADDR=0xf0000 -CONFIG_BOOTSTAGE_STASH_ADDR=0x0 CONFIG_SYS_LOAD_ADDR=0x0 CONFIG_PCI=y CONFIG_DEBUG_UART=y diff --git a/configs/sandbox_flattree_defconfig b/configs/sandbox_flattree_defconfig index 8aa295686dc..c20015db47b 100644 --- a/configs/sandbox_flattree_defconfig +++ b/configs/sandbox_flattree_defconfig @@ -3,7 +3,6 @@ CONFIG_NR_DRAM_BANKS=1 CONFIG_ENV_SIZE=0x2000 CONFIG_DEFAULT_DEVICE_TREE="sandbox" CONFIG_DM_RESET=y -CONFIG_BOOTSTAGE_STASH_ADDR=0x0 CONFIG_SYS_LOAD_ADDR=0x0 CONFIG_PCI=y CONFIG_DEBUG_UART=y diff --git a/configs/sandbox_noinst_defconfig b/configs/sandbox_noinst_defconfig index 2c6aab6c859..f6e351961e9 100644 --- a/configs/sandbox_noinst_defconfig +++ b/configs/sandbox_noinst_defconfig @@ -10,7 +10,6 @@ CONFIG_SPL_SERIAL=y CONFIG_SPL_DRIVERS_MISC=y CONFIG_SPL_SYS_MALLOC_F_LEN=0x8000 CONFIG_SPL=y -CONFIG_BOOTSTAGE_STASH_ADDR=0x0 CONFIG_SYS_LOAD_ADDR=0x0 CONFIG_PCI=y CONFIG_SANDBOX_SPL=y diff --git a/configs/sandbox_spl_defconfig b/configs/sandbox_spl_defconfig index 8d50162b274..7e6ee936769 100644 --- a/configs/sandbox_spl_defconfig +++ b/configs/sandbox_spl_defconfig @@ -10,7 +10,6 @@ CONFIG_SPL_SERIAL=y CONFIG_SPL_DRIVERS_MISC=y CONFIG_SPL_SYS_MALLOC_F_LEN=0x8000 CONFIG_SPL=y -CONFIG_BOOTSTAGE_STASH_ADDR=0x0 CONFIG_SYS_LOAD_ADDR=0x0 CONFIG_PCI=y CONFIG_SANDBOX_SPL=y diff --git a/configs/sandbox_vpl_defconfig b/configs/sandbox_vpl_defconfig index f3a0fd19a96..9ac800a93c0 100644 --- a/configs/sandbox_vpl_defconfig +++ b/configs/sandbox_vpl_defconfig @@ -15,7 +15,6 @@ CONFIG_TPL_SERIAL=y CONFIG_SPL_DRIVERS_MISC=y CONFIG_SPL_SYS_MALLOC_F_LEN=0x8000 CONFIG_SPL=y -CONFIG_BOOTSTAGE_STASH_ADDR=0x0 CONFIG_SYS_LOAD_ADDR=0x0 CONFIG_PCI=y CONFIG_SANDBOX_SPL=y diff --git a/configs/xilinx_versal_net_virt_defconfig b/configs/xilinx_versal_net_virt_defconfig index 97904bdec0a..54ba0b7c4f2 100644 --- a/configs/xilinx_versal_net_virt_defconfig +++ b/configs/xilinx_versal_net_virt_defconfig @@ -77,7 +77,6 @@ CONFIG_DM_MAILBOX=y CONFIG_ZYNQMP_IPI=y CONFIG_MISC=y CONFIG_I2C_EEPROM=y -CONFIG_SYS_I2C_EEPROM_ADDR=0x0 CONFIG_SUPPORT_EMMC_BOOT=y CONFIG_MMC_IO_VOLTAGE=y CONFIG_MMC_UHS_SUPPORT=y diff --git a/configs/xilinx_zynqmp_virt_defconfig b/configs/xilinx_zynqmp_virt_defconfig index acab38fefee..26260841c59 100644 --- a/configs/xilinx_zynqmp_virt_defconfig +++ b/configs/xilinx_zynqmp_virt_defconfig @@ -11,7 +11,6 @@ CONFIG_DM_RESET=y CONFIG_SPL_STACK_R_ADDR=0x18000000 CONFIG_SPL_STACK=0xfffffffc CONFIG_SPL_SIZE_LIMIT=0x2a000 -CONFIG_SPL_SIZE_LIMIT_PROVIDE_STACK=0x0 CONFIG_SPL=y CONFIG_ENV_OFFSET_REDUND=0x1E80000 CONFIG_SPL_SPI_FLASH_SUPPORT=y diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 6baaa6f0711..1abea3f10db 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -167,7 +167,7 @@ config SYS_IDE_MAXDEVICE config SYS_ATA_BASE_ADDR hex "Base address of IDE controller" - default 0 + default 0x0 help This is the address of the IDE controller, from which other addresses are calculated. Each bus is at a fixed offset from this address, diff --git a/drivers/fastboot/Kconfig b/drivers/fastboot/Kconfig index a3df9aa3d0f..837c6f1180d 100644 --- a/drivers/fastboot/Kconfig +++ b/drivers/fastboot/Kconfig @@ -56,7 +56,7 @@ config FASTBOOT_BUF_ADDR ROCKCHIP_RK3399 default 0x280000 if ROCKCHIP_RK3368 default 0x100000 if ARCH_ZYNQMP - default 0 if SANDBOX + default 0x0 if SANDBOX help The fastboot protocol requires a large memory buffer for downloads. Define this to the starting RAM address to use for diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 4c76fd7e415..4f42200f392 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -372,7 +372,7 @@ config SYS_MXC_I2C1_SPEED config SYS_MXC_I2C1_SLAVE hex "I2C1 Slave" - default 0 + default 0x0 help MXC I2C1 Slave endif @@ -387,7 +387,7 @@ config SYS_MXC_I2C2_SPEED config SYS_MXC_I2C2_SLAVE hex "I2C2 Slave" - default 0 + default 0x0 help MXC I2C2 Slave endif @@ -401,7 +401,7 @@ config SYS_MXC_I2C3_SPEED config SYS_MXC_I2C3_SLAVE hex "I2C3 Slave" - default 0 + default 0x0 help MXC I2C3 Slave endif @@ -415,7 +415,7 @@ config SYS_MXC_I2C4_SPEED config SYS_MXC_I2C4_SLAVE hex "I2C4 Slave" - default 0 + default 0x0 help MXC I2C4 Slave endif @@ -429,7 +429,7 @@ config SYS_MXC_I2C5_SPEED config SYS_MXC_I2C5_SLAVE hex "I2C5 Slave" - default 0 + default 0x0 help MXC I2C5 Slave endif @@ -443,7 +443,7 @@ config SYS_MXC_I2C6_SPEED config SYS_MXC_I2C6_SLAVE hex "I2C6 Slave" - default 0 + default 0x0 help MXC I2C6 Slave endif @@ -457,7 +457,7 @@ config SYS_MXC_I2C7_SPEED config SYS_MXC_I2C7_SLAVE hex "I2C7 Slave" - default 0 + default 0x0 help MXC I2C7 Slave endif @@ -471,7 +471,7 @@ config SYS_MXC_I2C8_SPEED config SYS_MXC_I2C8_SLAVE hex "I2C8 Slave" - default 0 + default 0x0 help MXC I2C8 Slave endif diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index b9f5c7a37ae..a6e3f62ecb0 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -555,7 +555,7 @@ config SPL_I2C_EEPROM config SYS_I2C_EEPROM_ADDR hex "Chip address of the EEPROM device" depends on ID_EEPROM || I2C_EEPROM || SPL_I2C_EEPROM || CMD_EEPROM || ENV_IS_IN_EEPROM - default 0 + default 0x0 if I2C_EEPROM diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index a1e089962a9..7ca42df6a7e 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -482,8 +482,8 @@ endchoice config DEBUG_UART_BASE hex "Base address of UART" depends on DEBUG_UART - default 0 if DEBUG_SBI_CONSOLE - default 0 if DEBUG_UART_SANDBOX + default 0x0 if DEBUG_SBI_CONSOLE + default 0x0 if DEBUG_UART_SANDBOX default 0xff000000 if DEBUG_UART_ZYNQ && ARCH_ZYNQMP default 0xe0000000 if DEBUG_UART_ZYNQ && ARCH_ZYNQ help @@ -1139,6 +1139,6 @@ config SYS_SDSR config SYS_SDMR hex "SDMR Value" depends on MPC8XX_CONS - default 0 + default 0x0 endif diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 1cfe6022842..4eccc5e3370 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -160,7 +160,7 @@ config USB_GADGET_VBUS_DRAW config SDP_LOADADDR hex "Default load address at SDP_WRITE and SDP_JUMP" - default 0 + default 0x0 # Selected by UDC drivers that support high-speed operation. config USB_GADGET_DUALSPEED diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index e32ce13fb6b..fe43fbd7004 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -66,7 +66,7 @@ config VIDEO_PCI_DEFAULT_FB_SIZE hex "Default framebuffer size to use if no drivers request it" default 0x1000000 if X86 default 0x800000 if !X86 && VIDEO_BOCHS - default 0 if !X86 && !VIDEO_BOCHS + default 0x0 if !X86 && !VIDEO_BOCHS help Generally, video drivers request the amount of memory they need for the frame buffer when they are bound, by setting the size field in @@ -1039,7 +1039,7 @@ config SPL_VIDEO_PCI_DEFAULT_FB_SIZE hex "Default framebuffer size to use if no drivers request it at SPL" default 0x1000000 if X86 default 0x800000 if !X86 && VIDEO_BOCHS - default 0 if !X86 && !VIDEO_BOCHS + default 0x0 if !X86 && !VIDEO_BOCHS help Generally, video drivers request the amount of memory they need for the frame buffer when they are bound, by setting the size field in diff --git a/env/Kconfig b/env/Kconfig index 13e32104b4c..54203faa89e 100644 --- a/env/Kconfig +++ b/env/Kconfig @@ -571,7 +571,7 @@ config ENV_OFFSET default 0xE0000 if ARCH_ZYNQ default 0x1E00000 if ARCH_ZYNQMP default 0x7F40000 if ARCH_VERSAL || ARCH_VERSAL_NET - default 0 if ARC + default 0x0 if ARC default 0x140000 if ARCH_AT91 default 0x260000 if ARCH_OMAP2PLUS default 0x1080000 if MICROBLAZE && ENV_IS_IN_SPI_FLASH @@ -583,7 +583,7 @@ config ENV_OFFSET_REDUND depends on (ENV_IS_IN_EEPROM || ENV_IS_IN_MMC || ENV_IS_IN_NAND || \ ENV_IS_IN_SPI_FLASH) && SYS_REDUNDAND_ENVIRONMENT default 0x10C0000 if MICROBLAZE - default 0 + default 0x0 help Offset from the start of the device (or partition) of the redundant environment location. diff --git a/lib/Kconfig b/lib/Kconfig index 07e61de5b64..42e559ad0b5 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -862,7 +862,7 @@ config OF_LIBFDT config OF_LIBFDT_ASSUME_MASK hex "Mask of conditions to assume for libfdt" depends on OF_LIBFDT || FIT - default 0 + default 0x0 help Use this to change the assumptions made by libfdt about the device tree it is working with. A value of 0 means that no assumptions -- cgit v1.3.1 From defa33ad29f8d2897e78fdef6218b2eeea6acf6d Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 30 Jul 2023 11:16:47 -0600 Subject: bootstd: cros: Correct reporting of I/O errors Return -EIO when the read failed, rather than the number of blocks read. Signed-off-by: Simon Glass --- boot/bootmeth_cros.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'boot') diff --git a/boot/bootmeth_cros.c b/boot/bootmeth_cros.c index aa19ae097f5..6179a547f74 100644 --- a/boot/bootmeth_cros.c +++ b/boot/bootmeth_cros.c @@ -106,7 +106,7 @@ static int cros_read_bootflow(struct udevice *dev, struct bootflow *bflow) return log_msg_ret("hdr", -ENOMEM); ret = blk_read(bflow->blk, info.start, num_blks, hdr); if (ret != num_blks) - return log_msg_ret("inf", ret); + return log_msg_ret("inf", -EIO); if (memcmp("CHROMEOS", hdr, 8)) return -ENOENT; @@ -125,7 +125,7 @@ static int cros_read_bootflow(struct udevice *dev, struct bootflow *bflow) bflow->blk->name, (ulong)info.start, num_blks); ret = blk_read(bflow->blk, (ulong)info.start + 0x80, num_blks, buf); if (ret != num_blks) - return log_msg_ret("inf", ret); + return log_msg_ret("inf", -EIO); base = map_to_sysmem(buf); setup = base + start - OFFSET_BASE - SETUP_OFFSET; -- cgit v1.3.1 From 5a8589ebd6b20a4ba992bdf8806e574c339b12ea Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 30 Jul 2023 11:16:48 -0600 Subject: bootstd: cros: Move partition reading into a function Move the code which reads a partition into its own function. Add a constant for the number of bytes to 'probe' at the start of the partition. Signed-off-by: Simon Glass --- boot/bootmeth_cros.c | 66 +++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 50 insertions(+), 16 deletions(-) (limited to 'boot') diff --git a/boot/bootmeth_cros.c b/boot/bootmeth_cros.c index 6179a547f74..f6fb521f206 100644 --- a/boot/bootmeth_cros.c +++ b/boot/bootmeth_cros.c @@ -23,6 +23,8 @@ #include enum { + PROBE_SIZE = SZ_4K, /* initial bytes read from partition */ + /* Offsets in the kernel-partition header */ KERN_START = 0x4f0, KERN_SIZE = 0x518, @@ -77,6 +79,51 @@ static int copy_cmdline(const char *from, const char *uuid, char **bufp) return 0; } +/** + * scan_part() - Scan a kernel partition to see if has a ChromeOS header + * + * This reads the first PROBE_SIZE of a partition, loookng for CHROMEOS + * + * @blk: Block device to scan + * @partnum: Partition number to scan + * @info: Please to put partition info + * @hdrp: Return allocated keyblock header on success + */ +static int scan_part(struct udevice *blk, int partnum, + struct disk_partition *info, void **hdrp) +{ + struct blk_desc *desc = dev_get_uclass_plat(blk); + struct vb2_keyblock *hdr; + ulong num_blks; + int ret; + + ret = part_get_info(desc, partnum, info); + if (ret) + return log_msg_ret("part", ret); + + /* Make a buffer for the header information */ + num_blks = PROBE_SIZE >> desc->log2blksz; + log_debug("Reading header, blk=%s, start=%lx, blocks=%lx\n", + blk->name, (ulong)info->start, num_blks); + hdr = memalign(SZ_1K, PROBE_SIZE); + if (!hdr) + return log_msg_ret("hdr", -ENOMEM); + ret = blk_read(blk, info->start, num_blks, hdr); + if (ret != num_blks) { + free(hdr); + return log_msg_ret("inf", -EIO); + } + + if (memcmp("CHROMEOS", hdr, 8)) { + free(hdr); + return -ENOENT; + } + + *hdrp = hdr; + + return 0; +} + static int cros_read_bootflow(struct udevice *dev, struct bootflow *bflow) { struct blk_desc *desc = dev_get_uclass_plat(bflow->blk); @@ -93,23 +140,10 @@ static int cros_read_bootflow(struct udevice *dev, struct bootflow *bflow) return log_msg_ret("max", -ENOENT); /* Check partition 2 */ - ret = part_get_info(desc, 2, &info); + ret = scan_part(bflow->blk, 2, &info, &hdr); if (ret) - return log_msg_ret("part", ret); - - /* Make a buffer for the header information */ - num_blks = SZ_4K >> desc->log2blksz; - log_debug("Reading header, blk=%s, start=%lx, blocks=%lx\n", - bflow->blk->name, (ulong)info.start, num_blks); - hdr = memalign(SZ_1K, SZ_4K); - if (!hdr) - return log_msg_ret("hdr", -ENOMEM); - ret = blk_read(bflow->blk, info.start, num_blks, hdr); - if (ret != num_blks) - return log_msg_ret("inf", -EIO); - - if (memcmp("CHROMEOS", hdr, 8)) - return -ENOENT; + return log_msg_ret("scan", ret); + bflow->part = 2; log_info("Header at %lx\n", (ulong)map_to_sysmem(hdr)); start = *(u32 *)(hdr + KERN_START); -- cgit v1.3.1 From de30aa9a2f5659ecee599d61e1940b30c76d627c Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 30 Jul 2023 11:16:49 -0600 Subject: bootstd: cros: Bring in some ChromiumOS structures Add a header file with structures for booting ChromiumOS, taken from the vboot tree. Using these makes it easier to understand the code. Note that the code style has not been updated for U-Boot, with use of uint64_t, __attribute__((packed)) and one comment-style nit. This should make it easier to keep the code in sync. It was taken from commit: 5b8596ce ("2sha256_arm: Fix data abort issue") Update the CHROMEOS string to use the defined values. Signed-off-by: Simon Glass --- boot/bootmeth_cros.c | 6 +- boot/bootmeth_cros.h | 197 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 201 insertions(+), 2 deletions(-) create mode 100644 boot/bootmeth_cros.h (limited to 'boot') diff --git a/boot/bootmeth_cros.c b/boot/bootmeth_cros.c index f6fb521f206..385eca37381 100644 --- a/boot/bootmeth_cros.c +++ b/boot/bootmeth_cros.c @@ -21,6 +21,7 @@ #include #endif #include +#include "bootmeth_cros.h" enum { PROBE_SIZE = SZ_4K, /* initial bytes read from partition */ @@ -82,7 +83,8 @@ static int copy_cmdline(const char *from, const char *uuid, char **bufp) /** * scan_part() - Scan a kernel partition to see if has a ChromeOS header * - * This reads the first PROBE_SIZE of a partition, loookng for CHROMEOS + * This reads the first PROBE_SIZE of a partition, loookng for + * VB2_KEYBLOCK_MAGIC * * @blk: Block device to scan * @partnum: Partition number to scan @@ -114,7 +116,7 @@ static int scan_part(struct udevice *blk, int partnum, return log_msg_ret("inf", -EIO); } - if (memcmp("CHROMEOS", hdr, 8)) { + if (memcmp(VB2_KEYBLOCK_MAGIC, hdr->magic, VB2_KEYBLOCK_MAGIC_SIZE)) { free(hdr); return -ENOENT; } diff --git a/boot/bootmeth_cros.h b/boot/bootmeth_cros.h new file mode 100644 index 00000000000..8e3038571d1 --- /dev/null +++ b/boot/bootmeth_cros.h @@ -0,0 +1,197 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Structures used by the ChromiumOS bootmeth + * + * See docs at: + * https://www.chromium.org/chromium-os/chromiumos-design-docs/verified-boot-data-structures/ + * + * Original code at: + * https://chromium.googlesource.com/chromiumos/platform/vboot_reference/+/refs/heads/main/firmware/2lib/include/2struct.h + * + * Code taken from vboot_reference commit 5b8596ce file 2struct.h + * + * Copyright 2023 Google LLC + * Written by Simon Glass + */ + +#ifndef __BOOTMETH_CROS_H +#define __BOOTMETH_CROS_H + +/* Signature data (a secure hash, possibly signed) */ +struct vb2_signature { + /* Offset of signature data from start of this struct */ + uint32_t sig_offset; + uint32_t reserved0; + + /* Size of signature data in bytes */ + uint32_t sig_size; + uint32_t reserved1; + + /* Size of the data block which was signed in bytes */ + uint32_t data_size; + uint32_t reserved2; +} __attribute__((packed)); + +#define EXPECTED_VB2_SIGNATURE_SIZE 24 + +/* Packed public key data */ +struct vb2_packed_key { + /* Offset of key data from start of this struct */ + uint32_t key_offset; + uint32_t reserved0; + + /* Size of key data in bytes (NOT strength of key in bits) */ + uint32_t key_size; + uint32_t reserved1; + + /* Signature algorithm used by the key (enum vb2_crypto_algorithm) */ + uint32_t algorithm; + uint32_t reserved2; + + /* Key version */ + uint32_t key_version; + uint32_t reserved3; + + /* TODO: when redoing this struct, add a text description of the key */ +} __attribute__((packed)); + +#define EXPECTED_VB2_PACKED_KEY_SIZE 32 + +#define VB2_KEYBLOCK_MAGIC "CHROMEOS" +#define VB2_KEYBLOCK_MAGIC_SIZE 8 + +/* + * Keyblock, containing the public key used to sign some other chunk of data. + * + * This should be followed by: + * 1) The data_key key data, pointed to by data_key.key_offset. + * 2) The checksum data for (vb2_keyblock + data_key data), pointed to + * by keyblock_checksum.sig_offset. + * 3) The signature data for (vb2_keyblock + data_key data), pointed to + * by keyblock_signature.sig_offset. + */ +struct vb2_keyblock { + /* Magic number */ + uint8_t magic[VB2_KEYBLOCK_MAGIC_SIZE]; + + /* Version of this header format */ + uint32_t header_version_major; + uint32_t header_version_minor; + + /* + * Length of this entire keyblock, including keys, signatures, and + * padding, in bytes + */ + uint32_t keyblock_size; + uint32_t reserved0; + + /* + * Signature for this keyblock (header + data pointed to by data_key) + * For use with signed data keys + */ + struct vb2_signature keyblock_signature; + + /* + * SHA-512 hash for this keyblock (header + data pointed to by + * data_key) For use with unsigned data keys. + * + * Only supported for kernel keyblocks, not firmware keyblocks. + */ + struct vb2_signature keyblock_hash; + + /* Flags for key (VB2_KEYBLOCK_FLAG_*) */ + uint32_t keyblock_flags; + uint32_t reserved1; + + /* Key to verify the chunk of data */ + struct vb2_packed_key data_key; +} __attribute__((packed)); + +#define EXPECTED_VB2_KEYBLOCK_SIZE 112 + +/* + * Preamble block for kernel, version 2.2 + * + * This should be followed by: + * 1) The signature data for the kernel body, pointed to by + * body_signature.sig_offset. + * 2) The signature data for (vb2_kernel_preamble + body signature data), + * pointed to by preamble_signature.sig_offset. + * 3) The 16-bit vmlinuz header, which is used for reconstruction of + * vmlinuz image. + */ +struct vb2_kernel_preamble { + /* + * Size of this preamble, including keys, signatures, vmlinuz header, + * and padding, in bytes + */ + uint32_t preamble_size; + uint32_t reserved0; + + /* Signature for this preamble (header + body signature) */ + struct vb2_signature preamble_signature; + + /* Version of this header format */ + uint32_t header_version_major; + uint32_t header_version_minor; + + /* Kernel version */ + uint32_t kernel_version; + uint32_t reserved1; + + /* Load address for kernel body */ + uint64_t body_load_address; + /* TODO (vboot 2.1): we never used that */ + + /* Address of bootloader, after body is loaded at body_load_address */ + uint64_t bootloader_address; + /* TODO (vboot 2.1): should be a 32-bit offset */ + + /* Size of bootloader in bytes */ + uint32_t bootloader_size; + uint32_t reserved2; + + /* Signature for the kernel body */ + struct vb2_signature body_signature; + + /* + * TODO (vboot 2.1): fields for kernel offset and size. Right now the + * size is implicitly the same as the size of data signed by the body + * signature, and the offset is implicitly at the end of the preamble. + * But that forces us to pad the preamble to 64KB rather than just + * having a tiny preamble and an offset field. + */ + + /* + * Fields added in header version 2.1. You must verify the header + * version before reading these fields! + */ + + /* + * Address of 16-bit header for vmlinuz reassembly. Readers should + * return 0 for header version < 2.1. + */ + uint64_t vmlinuz_header_address; + + /* Size of 16-bit header for vmlinuz in bytes. Readers should return 0 + for header version < 2.1 */ + uint32_t vmlinuz_header_size; + uint32_t reserved3; + + /* + * Fields added in header version 2.2. You must verify the header + * version before reading these fields! + */ + + /* + * Flags; see VB2_KERNEL_PREAMBLE_*. Readers should return 0 for + * header version < 2.2. Flags field is currently defined as: + * [31:2] - Reserved (for future use) + * [1:0] - Kernel image type (0b00 - CrOS, + * 0b01 - bootimg, + * 0b10 - multiboot) + */ + uint32_t flags; +} __attribute__((packed)); + +#endif /* __BOOTMETH_CROS_H */ -- cgit v1.3.1 From 4cfe4510f1e6e0cf2e346f5bd9de5d5be346238d Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 30 Jul 2023 11:16:50 -0600 Subject: bootstd: cros: Support a kernel on either partition ChromiumOS allows a kernel to be on either partition 2 or 4. Add support for scanning both and using the first one we find with a suitable signature. Record the partition which is used. Signed-off-by: Simon Glass --- boot/bootmeth_cros.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) (limited to 'boot') diff --git a/boot/bootmeth_cros.c b/boot/bootmeth_cros.c index 385eca37381..7b25042bfe5 100644 --- a/boot/bootmeth_cros.c +++ b/boot/bootmeth_cros.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -133,7 +134,7 @@ static int cros_read_bootflow(struct udevice *dev, struct bootflow *bflow) struct disk_partition info; const char *uuid = NULL; void *buf, *hdr; - int ret; + int part, ret; log_debug("starting, part=%d\n", bflow->part); @@ -141,13 +142,19 @@ static int cros_read_bootflow(struct udevice *dev, struct bootflow *bflow) if (bflow->part) return log_msg_ret("max", -ENOENT); - /* Check partition 2 */ - ret = scan_part(bflow->blk, 2, &info, &hdr); - if (ret) - return log_msg_ret("scan", ret); - bflow->part = 2; + /* Check partition 2 then 4 */ + part = 2; + ret = scan_part(bflow->blk, part, &info, &hdr); + if (ret) { + part = 4; + ret = scan_part(bflow->blk, part, &info, &hdr); + if (ret) + return log_msg_ret("scan", ret); + } + bflow->part = part; - log_info("Header at %lx\n", (ulong)map_to_sysmem(hdr)); + log_info("Selected parition %d, header at %lx\n", bflow->part, + (ulong)map_to_sysmem(hdr)); start = *(u32 *)(hdr + KERN_START); size = ALIGN(*(u32 *)(hdr + KERN_SIZE), desc->blksz); log_debug("Reading start %lx size %lx\n", start, size); -- cgit v1.3.1 From 3257835e5640d92a22581d38a97b918a89cd3783 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 30 Jul 2023 11:16:51 -0600 Subject: bootstd: cros: Decode some kernel preamble fields Decode the kernel start and size using the structures provided. This accesses the same data, just in a cleaner way. Add some logging for some of the fields in the kernel preamble. Signed-off-by: Simon Glass --- boot/bootmeth_cros.c | 54 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 17 deletions(-) (limited to 'boot') diff --git a/boot/bootmeth_cros.c b/boot/bootmeth_cros.c index 7b25042bfe5..2a745621e30 100644 --- a/boot/bootmeth_cros.c +++ b/boot/bootmeth_cros.c @@ -27,10 +27,6 @@ enum { PROBE_SIZE = SZ_4K, /* initial bytes read from partition */ - /* Offsets in the kernel-partition header */ - KERN_START = 0x4f0, - KERN_SIZE = 0x518, - SETUP_OFFSET = 0x1000, /* bytes before base */ CMDLINE_OFFSET = 0x2000, /* bytes before base */ OFFSET_BASE = 0x100000, /* assumed kernel load-address */ @@ -93,7 +89,7 @@ static int copy_cmdline(const char *from, const char *uuid, char **bufp) * @hdrp: Return allocated keyblock header on success */ static int scan_part(struct udevice *blk, int partnum, - struct disk_partition *info, void **hdrp) + struct disk_partition *info, struct vb2_keyblock **hdrp) { struct blk_desc *desc = dev_get_uclass_plat(blk); struct vb2_keyblock *hdr; @@ -130,11 +126,14 @@ static int scan_part(struct udevice *blk, int partnum, static int cros_read_bootflow(struct udevice *dev, struct bootflow *bflow) { struct blk_desc *desc = dev_get_uclass_plat(bflow->blk); - ulong base, start, size, setup, cmdline, num_blks, kern_base; + ulong base, start, setup, cmdline, num_blks, kern_base; + const struct vb2_kernel_preamble *preamble; + ulong body_offset, body_size; struct disk_partition info; const char *uuid = NULL; - void *buf, *hdr; + struct vb2_keyblock *hdr; int part, ret; + void *buf; log_debug("starting, part=%d\n", bflow->part); @@ -155,18 +154,39 @@ static int cros_read_bootflow(struct udevice *dev, struct bootflow *bflow) log_info("Selected parition %d, header at %lx\n", bflow->part, (ulong)map_to_sysmem(hdr)); - start = *(u32 *)(hdr + KERN_START); - size = ALIGN(*(u32 *)(hdr + KERN_SIZE), desc->blksz); - log_debug("Reading start %lx size %lx\n", start, size); - bflow->size = size; - - buf = memalign(SZ_1K, size); + preamble = (void *)hdr + hdr->keyblock_size; + log_debug("Kernel preamble at %lx, version major %x, minor %x\n", + (ulong)map_to_sysmem(preamble), + preamble->header_version_major, + preamble->header_version_minor); + + start = (ulong)preamble->bootloader_address; + log_debug(" - load_address %lx, bl_addr %lx, bl_size %lx\n", + (ulong)preamble->body_load_address, + (ulong)preamble->bootloader_address, + (ulong)preamble->bootloader_size); + + body_offset = hdr->keyblock_size + preamble->preamble_size; + body_size = preamble->body_signature.data_size; + log_debug("Kernel body at %lx size %lx\n", body_offset, body_size); + bflow->size = body_size; + + buf = memalign(SZ_1K, body_size); if (!buf) return log_msg_ret("buf", -ENOMEM); - num_blks = size >> desc->log2blksz; - log_debug("Reading data, blk=%s, start=%lx, blocks=%lx\n", - bflow->blk->name, (ulong)info.start, num_blks); - ret = blk_read(bflow->blk, (ulong)info.start + 0x80, num_blks, buf); + + /* Check that the header is not smaller than permitted */ + if (body_offset < PROBE_SIZE) + return log_msg_ret("san", EFAULT); + + /* Read kernel body */ + num_blks = body_size >> desc->log2blksz; + log_debug("Reading body to %lx, blk=%s, size=%lx, blocks=%lx\n", + (ulong)map_to_sysmem(buf), bflow->blk->name, body_size, + num_blks); + ret = blk_read(bflow->blk, + info.start + (body_offset >> desc->log2blksz), + num_blks, buf); if (ret != num_blks) return log_msg_ret("inf", -EIO); base = map_to_sysmem(buf); -- cgit v1.3.1 From c5dca50bbb07a0040197f9a6ccf5da3493736b5d Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 30 Jul 2023 11:16:52 -0600 Subject: bootstd: cros: Simplify setup and cmdline expressions Create a common base from which the other parts are offset and make all of the offsets related to that. This makes the code a little easier to read. Use X86_ prefixes for the two values which are x86-specific. Drop OFFSET_BASE since it is available in a header field. Drop the unnecessary 'start' variable too. Signed-off-by: Simon Glass --- boot/bootmeth_cros.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'boot') diff --git a/boot/bootmeth_cros.c b/boot/bootmeth_cros.c index 2a745621e30..05284713f67 100644 --- a/boot/bootmeth_cros.c +++ b/boot/bootmeth_cros.c @@ -27,9 +27,9 @@ enum { PROBE_SIZE = SZ_4K, /* initial bytes read from partition */ - SETUP_OFFSET = 0x1000, /* bytes before base */ - CMDLINE_OFFSET = 0x2000, /* bytes before base */ - OFFSET_BASE = 0x100000, /* assumed kernel load-address */ + X86_SETUP_OFFSET = -0x1000, /* setup offset relative to base */ + CMDLINE_OFFSET = -0x2000, /* cmdline offset relative to base */ + X86_KERNEL_OFFSET = 0x4000, /* kernel offset relative to base */ }; static int cros_check(struct udevice *dev, struct bootflow_iter *iter) @@ -126,7 +126,7 @@ static int scan_part(struct udevice *blk, int partnum, static int cros_read_bootflow(struct udevice *dev, struct bootflow *bflow) { struct blk_desc *desc = dev_get_uclass_plat(bflow->blk); - ulong base, start, setup, cmdline, num_blks, kern_base; + ulong base, setup, cmdline, num_blks, kern_base; const struct vb2_kernel_preamble *preamble; ulong body_offset, body_size; struct disk_partition info; @@ -160,7 +160,6 @@ static int cros_read_bootflow(struct udevice *dev, struct bootflow *bflow) preamble->header_version_major, preamble->header_version_minor); - start = (ulong)preamble->bootloader_address; log_debug(" - load_address %lx, bl_addr %lx, bl_size %lx\n", (ulong)preamble->body_load_address, (ulong)preamble->bootloader_address, @@ -189,12 +188,13 @@ static int cros_read_bootflow(struct udevice *dev, struct bootflow *bflow) num_blks, buf); if (ret != num_blks) return log_msg_ret("inf", -EIO); - base = map_to_sysmem(buf); + base = map_to_sysmem(buf) + preamble->bootloader_address - + preamble->body_load_address; - setup = base + start - OFFSET_BASE - SETUP_OFFSET; - cmdline = base + start - OFFSET_BASE - CMDLINE_OFFSET; - kern_base = base + start - OFFSET_BASE + SZ_16K; - log_debug("base %lx setup %lx, cmdline %lx, kern_base %lx\n", base, + setup = base + X86_SETUP_OFFSET; + cmdline = base + CMDLINE_OFFSET; + kern_base = base + X86_KERNEL_OFFSET; + log_debug("base %lx setup %lx cmdline %lx kern_base %lx\n", base, setup, cmdline, kern_base); #ifdef CONFIG_X86 -- cgit v1.3.1 From 1a0810924a29311a330d717a2813d212865a5df0 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 30 Jul 2023 11:16:53 -0600 Subject: bootstd: Move common zimage functions to bootm.h We want to avoid using #ifdefs around header files and in the code. It makes sense to collect the various functions used for loading images into a single header which can be included by all architectures. The best place for this is the arch-neutral bootm.h header, so use that. Move some zimage functions into this bootm.h header. Signed-off-by: Simon Glass --- arch/x86/include/asm/zimage.h | 27 --------------------------- boot/bootmeth_cros.c | 4 +--- include/bootm.h | 28 ++++++++++++++++++++++++++++ 3 files changed, 29 insertions(+), 30 deletions(-) (limited to 'boot') diff --git a/arch/x86/include/asm/zimage.h b/arch/x86/include/asm/zimage.h index 9ad74dc0b94..000b38ea899 100644 --- a/arch/x86/include/asm/zimage.h +++ b/arch/x86/include/asm/zimage.h @@ -72,31 +72,4 @@ int setup_zimage(struct boot_params *setup_base, char *cmd_line, int auto_boot, */ void zimage_dump(struct boot_params *base_ptr); -/** - * zboot_start() - Boot a zimage - * - * Boot a zimage, given the component parts - * - * @addr: Address where the bzImage is moved before booting, either - * BZIMAGE_LOAD_ADDR or ZIMAGE_LOAD_ADDR - * @base: Pointer to the boot parameters, typically at address - * DEFAULT_SETUP_BASE - * @initrd: Address of the initial ramdisk, or 0 if none - * @initrd_size: Size of the initial ramdisk, or 0 if none - * @cmdline: Command line to use for booting - * Return: -EFAULT on error (normally it does not return) - */ -int zboot_start(ulong addr, ulong size, ulong initrd, ulong initrd_size, - ulong base, char *cmdline); - -/* - * zimage_get_kernel_version() - Get the version string from a kernel - * - * @params: boot_params pointer - * @kernel_base: base address of kernel - * Return: Kernel version as a NUL-terminated string - */ -const char *zimage_get_kernel_version(struct boot_params *params, - void *kernel_base); - #endif diff --git a/boot/bootmeth_cros.c b/boot/bootmeth_cros.c index 05284713f67..3b9e75540aa 100644 --- a/boot/bootmeth_cros.c +++ b/boot/bootmeth_cros.c @@ -12,15 +12,13 @@ #include #include #include +#include #include #include #include #include #include #include -#ifdef CONFIG_X86 -#include -#endif #include #include "bootmeth_cros.h" diff --git a/include/bootm.h b/include/bootm.h index 044a4797ed3..6fe418e0027 100644 --- a/include/bootm.h +++ b/include/bootm.h @@ -9,6 +9,7 @@ #include +struct boot_params; struct cmd_tbl; #define BOOTM_ERR_RESET (-1) @@ -124,4 +125,31 @@ int bootm_process_cmdline(char *buf, int maxlen, int flags); */ int bootm_process_cmdline_env(int flags); +/** + * zboot_start() - Boot a zimage + * + * Boot a zimage, given the component parts + * + * @addr: Address where the bzImage is moved before booting, either + * BZIMAGE_LOAD_ADDR or ZIMAGE_LOAD_ADDR + * @base: Pointer to the boot parameters, typically at address + * DEFAULT_SETUP_BASE + * @initrd: Address of the initial ramdisk, or 0 if none + * @initrd_size: Size of the initial ramdisk, or 0 if none + * @cmdline: Command line to use for booting + * Return: -EFAULT on error (normally it does not return) + */ +int zboot_start(ulong addr, ulong size, ulong initrd, ulong initrd_size, + ulong base, char *cmdline); + +/* + * zimage_get_kernel_version() - Get the version string from a kernel + * + * @params: boot_params pointer + * @kernel_base: base address of kernel + * Return: Kernel version as a NUL-terminated string + */ +const char *zimage_get_kernel_version(struct boot_params *params, + void *kernel_base); + #endif -- cgit v1.3.1 From b7ed5386a4502bf48e4b04def69afae39873b536 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 30 Jul 2023 11:16:54 -0600 Subject: bootstd: cros: Add docs for the kernel layout Provide brief documentation about the ChromiumOS kernel layout. Signed-off-by: Simon Glass --- boot/bootmeth_cros.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'boot') diff --git a/boot/bootmeth_cros.c b/boot/bootmeth_cros.c index 3b9e75540aa..a551d43701d 100644 --- a/boot/bootmeth_cros.c +++ b/boot/bootmeth_cros.c @@ -22,6 +22,35 @@ #include #include "bootmeth_cros.h" +/* + * Layout of the ChromeOS kernel + * + * Partitions 2 and 4 contain kernels + * + * Contents are: + * + * Offset Contents + * 0 struct vb2_keyblock + * m struct vb2_kernel_preamble + * m + n kernel buffer + * + * m is keyblock->keyblock_size + * n is preamble->preamble_size + * + * The kernel buffer itself consists of various parts: + * + * Offset Contents + * m + n kernel image (Flat vmlinux binary or FIT) + * b - 8KB Command line text + * b - 4KB X86 setup block (struct boot_params, extends for about 16KB) + * b X86 bootloader (continuation of setup block) + * b + 16KB X86 setup block (copy, used for hold data pointed to) + * + * b is m + n + preamble->bootloader_address - preamble->body_load_address + * + * Useful metadata extends from b - 8KB through to b + 32 KB + */ + enum { PROBE_SIZE = SZ_4K, /* initial bytes read from partition */ -- cgit v1.3.1 From 1d4bbdf3e493b173d5f73150cea51c1965e3e1df Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 30 Jul 2023 11:16:55 -0600 Subject: bootstd: cros: Add private info for ChromiumOS Create a new private structure to hold information gleaned from the disk. This will allow separation between reading of the bootflow information and (later) reading the whole kernel. Signed-off-by: Simon Glass --- boot/bootmeth_cros.c | 55 +++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 42 insertions(+), 13 deletions(-) (limited to 'boot') diff --git a/boot/bootmeth_cros.c b/boot/bootmeth_cros.c index a551d43701d..16a42ad46ae 100644 --- a/boot/bootmeth_cros.c +++ b/boot/bootmeth_cros.c @@ -59,6 +59,29 @@ enum { X86_KERNEL_OFFSET = 0x4000, /* kernel offset relative to base */ }; +/** + * struct cros_priv - Private data + * + * This is read from the disk and recorded for use when the full kernel must + * be loaded and booted + * + * @body_offset: Offset of kernel body from start of partition (in bytes) + * @body_size: Size of kernel body in bytes + * @part_start: Block offset of selected partition from the start of the disk + * @body_load_address: Nominal load address for kernel body + * @bootloader_address: Address of bootloader, after body is loaded at + * body_load_address + * @bootloader_size: Size of bootloader in bytes + */ +struct cros_priv { + ulong body_offset; + ulong body_size; + lbaint_t part_start; + ulong body_load_address; + ulong bootloader_address; + ulong bootloader_size; +}; + static int cros_check(struct udevice *dev, struct bootflow_iter *iter) { /* This only works on block and network devices */ @@ -155,7 +178,7 @@ static int cros_read_bootflow(struct udevice *dev, struct bootflow *bflow) struct blk_desc *desc = dev_get_uclass_plat(bflow->blk); ulong base, setup, cmdline, num_blks, kern_base; const struct vb2_kernel_preamble *preamble; - ulong body_offset, body_size; + struct cros_priv s_priv, *priv = &s_priv; struct disk_partition info; const char *uuid = NULL; struct vb2_keyblock *hdr; @@ -192,31 +215,37 @@ static int cros_read_bootflow(struct udevice *dev, struct bootflow *bflow) (ulong)preamble->bootloader_address, (ulong)preamble->bootloader_size); - body_offset = hdr->keyblock_size + preamble->preamble_size; - body_size = preamble->body_signature.data_size; - log_debug("Kernel body at %lx size %lx\n", body_offset, body_size); - bflow->size = body_size; - - buf = memalign(SZ_1K, body_size); + priv->body_offset = hdr->keyblock_size + preamble->preamble_size; + priv->part_start = info.start; + priv->body_size = preamble->body_signature.data_size; + priv->body_load_address = preamble->body_load_address; + priv->bootloader_address = preamble->bootloader_address; + priv->bootloader_size = preamble->bootloader_size; + log_debug("Kernel body at %lx size %lx\n", priv->body_offset, + priv->body_size); + bflow->size = priv->body_size; + + buf = memalign(SZ_1K, priv->body_size); if (!buf) return log_msg_ret("buf", -ENOMEM); /* Check that the header is not smaller than permitted */ - if (body_offset < PROBE_SIZE) + if (priv->body_offset < PROBE_SIZE) return log_msg_ret("san", EFAULT); /* Read kernel body */ - num_blks = body_size >> desc->log2blksz; + num_blks = priv->body_size >> desc->log2blksz; log_debug("Reading body to %lx, blk=%s, size=%lx, blocks=%lx\n", - (ulong)map_to_sysmem(buf), bflow->blk->name, body_size, + (ulong)map_to_sysmem(buf), bflow->blk->name, priv->body_size, num_blks); ret = blk_read(bflow->blk, - info.start + (body_offset >> desc->log2blksz), + priv->part_start + + (priv->body_offset >> desc->log2blksz), num_blks, buf); if (ret != num_blks) return log_msg_ret("inf", -EIO); - base = map_to_sysmem(buf) + preamble->bootloader_address - - preamble->body_load_address; + base = map_to_sysmem(buf) + priv->bootloader_address - + priv->body_load_address; setup = base + X86_SETUP_OFFSET; cmdline = base + CMDLINE_OFFSET; -- cgit v1.3.1 From 76bd6844dcfeb1a7d2f529c2f715b34f4e574229 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 30 Jul 2023 11:16:56 -0600 Subject: bootstd: Add private bootmeth data to the bootflow Some bootmeths need to store their own information related to the bootflow, in addition to the generic information in struct bootflow. Add a pointer for this. Signed-off-by: Simon Glass --- boot/bootflow.c | 1 + include/bootflow.h | 2 ++ 2 files changed, 3 insertions(+) (limited to 'boot') diff --git a/boot/bootflow.c b/boot/bootflow.c index 81b5829d5b3..daf862fac78 100644 --- a/boot/bootflow.c +++ b/boot/bootflow.c @@ -432,6 +432,7 @@ void bootflow_free(struct bootflow *bflow) free(bflow->buf); free(bflow->os_name); free(bflow->fdt_fname); + free(bflow->bootmeth_priv); } void bootflow_remove(struct bootflow *bflow) diff --git a/include/bootflow.h b/include/bootflow.h index 4152577afb7..ff2bddb5151 100644 --- a/include/bootflow.h +++ b/include/bootflow.h @@ -83,6 +83,7 @@ enum bootflow_flags_t { * @flags: Flags for the bootflow (see enum bootflow_flags_t) * @cmdline: OS command line, or NULL if not known (allocated) * @x86_setup: Pointer to x86 setup block inside @buf, NULL if not present + * @bootmeth_priv: Private data for the bootmeth */ struct bootflow { struct list_head bm_node; @@ -108,6 +109,7 @@ struct bootflow { int flags; char *cmdline; char *x86_setup; + void *bootmeth_priv; }; /** -- cgit v1.3.1 From f861b1ee70aafff68a9a1ecbffb0bc79b71d13eb Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 30 Jul 2023 11:16:57 -0600 Subject: bootstd: cros: Add a function to read info from partition The code to read the ChromiumOS information from the partition is currently all in one function. It reads the entire kernel, which is unnecessary unless it is to be booted. Create a new function which reads just the minimum required data from the disk, then obtains what it needs from there. For now this function is not used. Future work will plumb it in. Signed-off-by: Simon Glass --- boot/bootmeth_cros.c | 121 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) (limited to 'boot') diff --git a/boot/bootmeth_cros.c b/boot/bootmeth_cros.c index 16a42ad46ae..82cbdcf2c93 100644 --- a/boot/bootmeth_cros.c +++ b/boot/bootmeth_cros.c @@ -72,6 +72,7 @@ enum { * @bootloader_address: Address of bootloader, after body is loaded at * body_load_address * @bootloader_size: Size of bootloader in bytes + * @info_buf: Buffer containing ChromiumOS info */ struct cros_priv { ulong body_offset; @@ -80,6 +81,7 @@ struct cros_priv { ulong body_load_address; ulong bootloader_address; ulong bootloader_size; + void *info_buf; }; static int cros_check(struct udevice *dev, struct bootflow_iter *iter) @@ -173,6 +175,125 @@ static int scan_part(struct udevice *blk, int partnum, return 0; } +/** + * cros_read_buf() - Read information into a buf and parse it + * + * @bflow: Bootflow to update + * @buf: Buffer to use + * @size: Size of buffer and number of bytes to read thereinto + * @start: Start offset to read from on disk + * @before_base: Number of bytes to read before the bootloader base + * @uuid: UUID string if supported, else NULL + * Return: 0 if OK, -ENOMEM if out of memory, -EIO on read failure + */ +static int cros_read_buf(struct bootflow *bflow, void *buf, ulong size, + loff_t start, ulong before_base, const char *uuid) +{ + struct blk_desc *desc = dev_get_uclass_plat(bflow->blk); + ulong base, setup, cmdline, kern_base; + ulong num_blks; + int ret; + + num_blks = size >> desc->log2blksz; + log_debug("Reading info to %lx, blk=%s, size=%lx, blocks=%lx\n", + (ulong)map_to_sysmem(buf), bflow->blk->name, size, num_blks); + ret = blk_read(bflow->blk, start, num_blks, buf); + if (ret != num_blks) + return log_msg_ret("inf", -EIO); + base = map_to_sysmem(buf) + before_base; + + setup = base + X86_SETUP_OFFSET; + cmdline = base + CMDLINE_OFFSET; + kern_base = base + X86_KERNEL_OFFSET; + log_debug("base %lx setup %lx cmdline %lx kern_base %lx\n", base, + setup, cmdline, kern_base); + +#ifdef CONFIG_X86 + const char *version; + + version = zimage_get_kernel_version(map_sysmem(setup, 0), + map_sysmem(kern_base, 0)); + log_debug("version %s\n", version); + if (version) + bflow->name = strdup(version); +#endif + if (!bflow->name) + bflow->name = strdup("ChromeOS"); + if (!bflow->name) + return log_msg_ret("nam", -ENOMEM); + bflow->os_name = strdup("ChromeOS"); + if (!bflow->os_name) + return log_msg_ret("os", -ENOMEM); + + ret = copy_cmdline(map_sysmem(cmdline, 0), uuid, &bflow->cmdline); + if (ret) + return log_msg_ret("cmd", ret); + bflow->x86_setup = map_sysmem(setup, 0); + + return 0; +} + +/** + * cros_read_info() - Read information and fill out the bootflow + * + * @bflow: Bootflow to update + * @uuid: UUID string if supported, else NULL + * @preamble: Kernel preamble information + * Return: 0 if OK, -ENOMEM if out of memory, -EIO on read failure + */ +static int cros_read_info(struct bootflow *bflow, const char *uuid, + const struct vb2_kernel_preamble *preamble) +{ + struct cros_priv *priv = bflow->bootmeth_priv; + struct udevice *blk = bflow->blk; + struct blk_desc *desc = dev_get_uclass_plat(blk); + ulong offset, size, before_base; + void *buf; + int ret; + + log_debug("Kernel preamble at %lx, version major %x, minor %x\n", + (ulong)map_to_sysmem(preamble), + preamble->header_version_major, + preamble->header_version_minor); + + log_debug(" - load_address %lx, bl_addr %lx, bl_size %lx\n", + (ulong)preamble->body_load_address, + (ulong)preamble->bootloader_address, + (ulong)preamble->bootloader_size); + + priv->body_size = preamble->body_signature.data_size; + priv->body_load_address = preamble->body_load_address; + priv->bootloader_address = preamble->bootloader_address; + priv->bootloader_size = preamble->bootloader_size; + log_debug("Kernel body at %lx size %lx\n", priv->body_offset, + priv->body_size); + + /* Work out how many bytes to read before the bootloader base */ + before_base = -CMDLINE_OFFSET; + + /* Read the cmdline through to the end of the bootloader */ + size = priv->bootloader_size + before_base; + offset = priv->body_offset + + (priv->bootloader_address - priv->body_load_address) + + CMDLINE_OFFSET; + buf = malloc(size); + if (!buf) + return log_msg_ret("buf", -ENOMEM); + + ret = cros_read_buf(bflow, buf, size, + priv->part_start + (offset >> desc->log2blksz), + before_base, uuid); + if (ret) { + /* Clear this since the buffer is invalid */ + bflow->x86_setup = NULL; + free(buf); + return log_msg_ret("pro", ret); + } + priv->info_buf = buf; + + return 0; +} + static int cros_read_bootflow(struct udevice *dev, struct bootflow *bflow) { struct blk_desc *desc = dev_get_uclass_plat(bflow->blk); -- cgit v1.3.1 From 074503c40a14f0e35b69bb3f06bb255b6881ca4e Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 30 Jul 2023 11:16:58 -0600 Subject: bootstd: cros: Add a function to read a kernel The code to read the ChromiumOS information from the partition is currently all in one function. Create a new function which reads the kernel, assuming that the metadata has been parsed. For now this function is not used. Future work will plumb it in. Signed-off-by: Simon Glass --- boot/bootmeth_cros.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'boot') diff --git a/boot/bootmeth_cros.c b/boot/bootmeth_cros.c index 82cbdcf2c93..8728cd18e3c 100644 --- a/boot/bootmeth_cros.c +++ b/boot/bootmeth_cros.c @@ -294,6 +294,45 @@ static int cros_read_info(struct bootflow *bflow, const char *uuid, return 0; } +static int cros_read_kernel(struct bootflow *bflow) +{ + struct blk_desc *desc = dev_get_uclass_plat(bflow->blk); + struct cros_priv *priv = bflow->bootmeth_priv; + ulong base, setup; + ulong num_blks; + void *buf; + int ret; + + bflow->size = priv->body_size; + + buf = memalign(SZ_1K, priv->body_size); + if (!buf) + return log_msg_ret("buf", -ENOMEM); + + /* Check that the header is not smaller than permitted */ + if (priv->body_offset < PROBE_SIZE) + return log_msg_ret("san", EFAULT); + + /* Read kernel body */ + num_blks = priv->body_size >> desc->log2blksz; + log_debug("Reading body to %lx, blk=%s, size=%lx, blocks=%lx\n", + (ulong)map_to_sysmem(buf), bflow->blk->name, priv->body_size, + num_blks); + ret = blk_read(bflow->blk, + priv->part_start + (priv->body_offset >> desc->log2blksz), + num_blks, buf); + if (ret != num_blks) + return log_msg_ret("inf", -EIO); + base = map_to_sysmem(buf) + priv->bootloader_address - + priv->body_load_address; + setup = base + X86_SETUP_OFFSET; + + bflow->buf = buf; + bflow->x86_setup = map_sysmem(setup, 0); + + return 0; +} + static int cros_read_bootflow(struct udevice *dev, struct bootflow *bflow) { struct blk_desc *desc = dev_get_uclass_plat(bflow->blk); -- cgit v1.3.1 From 598dea978d5b7076fc5b6ed31bea0767925e8db0 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 30 Jul 2023 11:16:59 -0600 Subject: bootstd: cros: Split up reading info and kernel Use the two new functions to separate reading of the ChromiumOS info from the partition from actually reading the kernel and booting it. Signed-off-by: Simon Glass --- boot/bootmeth_cros.c | 96 +++++++++++++--------------------------------------- 1 file changed, 23 insertions(+), 73 deletions(-) (limited to 'boot') diff --git a/boot/bootmeth_cros.c b/boot/bootmeth_cros.c index 8728cd18e3c..06709dd9171 100644 --- a/boot/bootmeth_cros.c +++ b/boot/bootmeth_cros.c @@ -335,15 +335,12 @@ static int cros_read_kernel(struct bootflow *bflow) static int cros_read_bootflow(struct udevice *dev, struct bootflow *bflow) { - struct blk_desc *desc = dev_get_uclass_plat(bflow->blk); - ulong base, setup, cmdline, num_blks, kern_base; const struct vb2_kernel_preamble *preamble; - struct cros_priv s_priv, *priv = &s_priv; struct disk_partition info; - const char *uuid = NULL; struct vb2_keyblock *hdr; + const char *uuid = NULL; + struct cros_priv *priv; int part, ret; - void *buf; log_debug("starting, part=%d\n", bflow->part); @@ -362,84 +359,32 @@ static int cros_read_bootflow(struct udevice *dev, struct bootflow *bflow) } bflow->part = part; - log_info("Selected parition %d, header at %lx\n", bflow->part, - (ulong)map_to_sysmem(hdr)); - preamble = (void *)hdr + hdr->keyblock_size; - log_debug("Kernel preamble at %lx, version major %x, minor %x\n", - (ulong)map_to_sysmem(preamble), - preamble->header_version_major, - preamble->header_version_minor); + priv = malloc(sizeof(struct cros_priv)); + if (!priv) { + free(hdr); + return log_msg_ret("buf", -ENOMEM); + } + bflow->bootmeth_priv = priv; - log_debug(" - load_address %lx, bl_addr %lx, bl_size %lx\n", - (ulong)preamble->body_load_address, - (ulong)preamble->bootloader_address, - (ulong)preamble->bootloader_size); + log_info("Selected partition %d, header at %lx\n", bflow->part, + (ulong)map_to_sysmem(hdr)); + /* Grab a few things from the preamble */ + preamble = (void *)hdr + hdr->keyblock_size; priv->body_offset = hdr->keyblock_size + preamble->preamble_size; priv->part_start = info.start; - priv->body_size = preamble->body_signature.data_size; - priv->body_load_address = preamble->body_load_address; - priv->bootloader_address = preamble->bootloader_address; - priv->bootloader_size = preamble->bootloader_size; - log_debug("Kernel body at %lx size %lx\n", priv->body_offset, - priv->body_size); - bflow->size = priv->body_size; - - buf = memalign(SZ_1K, priv->body_size); - if (!buf) - return log_msg_ret("buf", -ENOMEM); - - /* Check that the header is not smaller than permitted */ - if (priv->body_offset < PROBE_SIZE) - return log_msg_ret("san", EFAULT); - - /* Read kernel body */ - num_blks = priv->body_size >> desc->log2blksz; - log_debug("Reading body to %lx, blk=%s, size=%lx, blocks=%lx\n", - (ulong)map_to_sysmem(buf), bflow->blk->name, priv->body_size, - num_blks); - ret = blk_read(bflow->blk, - priv->part_start + - (priv->body_offset >> desc->log2blksz), - num_blks, buf); - if (ret != num_blks) - return log_msg_ret("inf", -EIO); - base = map_to_sysmem(buf) + priv->bootloader_address - - priv->body_load_address; - - setup = base + X86_SETUP_OFFSET; - cmdline = base + CMDLINE_OFFSET; - kern_base = base + X86_KERNEL_OFFSET; - log_debug("base %lx setup %lx cmdline %lx kern_base %lx\n", base, - setup, cmdline, kern_base); - -#ifdef CONFIG_X86 - const char *version; - - version = zimage_get_kernel_version(map_sysmem(setup, 0), - map_sysmem(kern_base, 0)); - log_debug("version %s\n", version); - if (version) - bflow->name = strdup(version); -#endif - if (!bflow->name) - bflow->name = strdup("ChromeOS"); - if (!bflow->name) - return log_msg_ret("nam", -ENOMEM); - bflow->os_name = strdup("ChromeOS"); - if (!bflow->os_name) - return log_msg_ret("os", -ENOMEM); + /* Now read everything we can learn about kernel */ #if CONFIG_IS_ENABLED(PARTITION_UUIDS) uuid = info.uuid; #endif - ret = copy_cmdline(map_sysmem(cmdline, 0), uuid, &bflow->cmdline); + ret = cros_read_info(bflow, uuid, preamble); + preamble = NULL; + free(hdr); if (ret) - return log_msg_ret("cmd", ret); - + return log_msg_ret("inf", ret); + bflow->size = priv->body_size; bflow->state = BOOTFLOWST_READY; - bflow->buf = buf; - bflow->x86_setup = map_sysmem(setup, 0); return 0; } @@ -452,6 +397,11 @@ static int cros_read_file(struct udevice *dev, struct bootflow *bflow, static int cros_boot(struct udevice *dev, struct bootflow *bflow) { + int ret; + + ret = cros_read_kernel(bflow); + if (ret) + return log_msg_ret("rd", ret); #ifdef CONFIG_X86 zboot_start(map_to_sysmem(bflow->buf), bflow->size, 0, 0, map_to_sysmem(bflow->x86_setup), -- cgit v1.3.1 From c279224ea6686a992b258b01e07fcadb7f0c7ecb Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 10 Aug 2023 19:33:18 -0600 Subject: bootstd: Add a command to read all files for a bootflow Some bootflows (such as EFI and ChromiumOS) delay reading the kernel until it is needed to boot. This saves time when scanning and avoids needing to allocate memory for something that may never be used. To permit reading of these files, add a new 'bootflow read' command. Signed-off-by: Simon Glass --- boot/bootflow.c | 16 ++++++++++ boot/bootmeth-uclass.c | 12 +++++++ boot/bootmeth_cros.c | 22 ++++++++++++- cmd/bootflow.c | 33 ++++++++++++++++++- doc/usage/cmd/bootflow.rst | 80 +++++++++++++++++++++++++++++++++++++++++++++- include/bootflow.h | 11 +++++++ include/bootmeth.h | 25 ++++++++++++++- 7 files changed, 195 insertions(+), 4 deletions(-) (limited to 'boot') diff --git a/boot/bootflow.c b/boot/bootflow.c index daf862fac78..6ef62e1d189 100644 --- a/boot/bootflow.c +++ b/boot/bootflow.c @@ -445,6 +445,22 @@ void bootflow_remove(struct bootflow *bflow) free(bflow); } +#if CONFIG_IS_ENABLED(BOOTSTD_FULL) +int bootflow_read_all(struct bootflow *bflow) +{ + int ret; + + if (bflow->state != BOOTFLOWST_READY) + return log_msg_ret("rd", -EPROTO); + + ret = bootmeth_read_all(bflow->method, bflow); + if (ret) + return log_msg_ret("rd2", ret); + + return 0; +} +#endif /* BOOTSTD_FULL */ + int bootflow_boot(struct bootflow *bflow) { int ret; diff --git a/boot/bootmeth-uclass.c b/boot/bootmeth-uclass.c index 175eb1de5e1..1d157d54dbd 100644 --- a/boot/bootmeth-uclass.c +++ b/boot/bootmeth-uclass.c @@ -61,6 +61,18 @@ int bootmeth_set_bootflow(struct udevice *dev, struct bootflow *bflow, return ops->set_bootflow(dev, bflow, buf, size); } +#if CONFIG_IS_ENABLED(BOOTSTD_FULL) +int bootmeth_read_all(struct udevice *dev, struct bootflow *bflow) +{ + const struct bootmeth_ops *ops = bootmeth_get_ops(dev); + + if (!ops->read_all) + return -ENOSYS; + + return ops->read_all(dev, bflow); +} +#endif /* BOOTSTD_FULL */ + int bootmeth_boot(struct udevice *dev, struct bootflow *bflow) { const struct bootmeth_ops *ops = bootmeth_get_ops(dev); diff --git a/boot/bootmeth_cros.c b/boot/bootmeth_cros.c index 06709dd9171..6c28feb34fe 100644 --- a/boot/bootmeth_cros.c +++ b/boot/bootmeth_cros.c @@ -395,13 +395,30 @@ static int cros_read_file(struct udevice *dev, struct bootflow *bflow, return -ENOSYS; } -static int cros_boot(struct udevice *dev, struct bootflow *bflow) +#if CONFIG_IS_ENABLED(BOOSTD_FULL) +static int cros_read_all(struct udevice *dev, struct bootflow *bflow) { int ret; + if (bflow->buf) + return log_msg_ret("ld", -EALREADY); ret = cros_read_kernel(bflow); if (ret) return log_msg_ret("rd", ret); + + return 0; +} +#endif /* BOOSTD_FULL */ + +static int cros_boot(struct udevice *dev, struct bootflow *bflow) +{ + int ret; + + if (!bflow->buf) { + ret = cros_read_kernel(bflow); + if (ret) + return log_msg_ret("rd", ret); + } #ifdef CONFIG_X86 zboot_start(map_to_sysmem(bflow->buf), bflow->size, 0, 0, map_to_sysmem(bflow->x86_setup), @@ -425,6 +442,9 @@ static struct bootmeth_ops cros_bootmeth_ops = { .read_bootflow = cros_read_bootflow, .read_file = cros_read_file, .boot = cros_boot, +#if CONFIG_IS_ENABLED(BOOSTD_FULL) + .read_all = cros_read_all, +#endif /* BOOSTD_FULL */ }; static const struct udevice_id cros_bootmeth_ids[] = { diff --git a/cmd/bootflow.c b/cmd/bootflow.c index 9562832ce43..3c3abaf8a3b 100644 --- a/cmd/bootflow.c +++ b/cmd/bootflow.c @@ -379,6 +379,35 @@ static int do_bootflow_info(struct cmd_tbl *cmdtp, int flag, int argc, return 0; } +static int do_bootflow_read(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct bootstd_priv *std; + struct bootflow *bflow; + int ret; + + ret = bootstd_get_priv(&std); + if (ret) + return CMD_RET_FAILURE; + + /* + * Require a current bootflow. Users can use 'bootflow scan -b' to + * automatically scan and boot, if needed. + */ + if (!std->cur_bootflow) { + printf("No bootflow selected\n"); + return CMD_RET_FAILURE; + } + bflow = std->cur_bootflow; + ret = bootflow_read_all(bflow); + if (ret) { + printf("Failed: err=%dE\n", ret); + return CMD_RET_FAILURE; + } + + return 0; +} + static int do_bootflow_boot(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { @@ -519,7 +548,8 @@ static char bootflow_help_text[] = "bootflow list [-e] - list scanned bootflows (-e errors)\n" "bootflow select [|] - select a bootflow\n" "bootflow info [-ds] - show info on current bootflow (-d dump bootflow)\n" - "bootflow boot - boot current bootflow (or first available if none selected)\n" + "bootflow read - read all current-bootflow files\n" + "bootflow boot - boot current bootflow\n" "bootflow menu [-t] - show a menu of available bootflows\n" "bootflow cmdline [set|get|clear|delete|auto] [] - update cmdline"; #else @@ -533,6 +563,7 @@ U_BOOT_CMD_WITH_SUBCMDS(bootflow, "Boot flows", bootflow_help_text, U_BOOT_SUBCMD_MKENT(list, 2, 1, do_bootflow_list), U_BOOT_SUBCMD_MKENT(select, 2, 1, do_bootflow_select), U_BOOT_SUBCMD_MKENT(info, 2, 1, do_bootflow_info), + U_BOOT_SUBCMD_MKENT(read, 1, 1, do_bootflow_read), U_BOOT_SUBCMD_MKENT(boot, 1, 1, do_bootflow_boot), U_BOOT_SUBCMD_MKENT(menu, 2, 1, do_bootflow_menu), U_BOOT_SUBCMD_MKENT(cmdline, 4, 1, do_bootflow_cmdline), diff --git a/doc/usage/cmd/bootflow.rst b/doc/usage/cmd/bootflow.rst index d53f8373eff..ead493d0aaf 100644 --- a/doc/usage/cmd/bootflow.rst +++ b/doc/usage/cmd/bootflow.rst @@ -12,6 +12,7 @@ Synopis bootflow list [-e] bootflow select [] bootflow info [-ds] + bootflow read bootflow boot bootflow cmdline [set|get|clear|delete|auto] [] @@ -194,10 +195,26 @@ Use the `-d` flag to dump out the contents of the bootfile file. The `-s` flag shows any x86 setup block, instead of the above. +bootflow read +~~~~~~~~~~~~~ + +This reads any files related to the bootflow. Some bootflows with large files +avoid doing this when the bootflow is scanned, since it uses a lot of memory +and takes extra time. The files are then automatically read when `bootflow boot` +is used. + +This command reads these files immediately. Typically this fills in the bootflow +`buf` property, which can be used to examine the bootflow. + +Note that reading the files does not result in any extra parsing, nor loading of +images in the files. This is purely used to read in the data ready for +booting, or examination. + + bootflow boot ~~~~~~~~~~~~~ -This boots the current bootflow. +This boots the current bootflow, reading any required files first. bootflow cmdline @@ -580,6 +597,67 @@ This shows looking at x86 setup information:: Init size : 1383000 Handover offset : 0 +This shows reading a bootflow to examine the kernel:: + + => bootfl i 0 + Name: + Device: emmc@1c,0.bootdev + Block dev: emmc@1c,0.blk + Method: cros + State: ready + Partition: 2 + Subdir: (none) + Filename: + Buffer: 0 + Size: 63ee00 (6548992 bytes) + OS: ChromeOS + Cmdline: console= loglevel=7 init=/sbin/init cros_secure oops=panic panic=-1 root=PARTUUID=35c775e7-3735-d745-93e5-d9e0238f7ed0/PARTNROFF=1 rootwait rw dm_verity.error_behavior=3 dm_verity.max_bios=-1 dm_verity.dev_wait=0 dm="1 vroot none rw 1,0 3788800 verity payload=ROOT_DEV hashtree=HASH_DEV hashstart=3788800 alg=sha1 root_hexdigest=55052b629d3ac889f25a9583ea12cdcd3ea15ff8 salt=a2d4d9e574069f4fed5e3961b99054b7a4905414b60a25d89974a7334021165c" noinitrd vt.global_cursor_default=0 kern_guid=35c775e7-3735-d745-93e5-d9e0238f7ed0 add_efi_memmap boot=local noresume noswap i915.modeset=1 tpm_tis.force=1 tpm_tis.interrupts=0 nmi_watchdog=panic,lapic disablevmx=off + X86 setup: 77b56010 + Logo: (none) + FDT: + Error: 0 + +Note that `Buffer` is 0 so it has not be read yet. Using `bootflow read`:: + + => bootfl read + => bootfl info + Name: + Device: emmc@1c,0.bootdev + Block dev: emmc@1c,0.blk + Method: cros + State: ready + Partition: 2 + Subdir: (none) + Filename: + Buffer: 77b7e400 + Size: 63ee00 (6548992 bytes) + OS: ChromeOS + Cmdline: console= loglevel=7 init=/sbin/init cros_secure oops=panic panic=-1 root=PARTUUID=35c775e7-3735-d745-93e5-d9e0238f7ed0/PARTNROFF=1 rootwait rw dm_verity.error_behavior=3 dm_verity.max_bios=-1 dm_verity.dev_wait=0 dm="1 vroot none rw 1,0 3788800 verity payload=ROOT_DEV hashtree=HASH_DEV hashstart=3788800 alg=sha1 root_hexdigest=55052b629d3ac889f25a9583ea12cdcd3ea15ff8 salt=a2d4d9e574069f4fed5e3961b99054b7a4905414b60a25d89974a7334021165c" noinitrd vt.global_cursor_default=0 kern_guid=35c775e7-3735-d745-93e5-d9e0238f7ed0 add_efi_memmap boot=local noresume noswap i915.modeset=1 tpm_tis.force=1 tpm_tis.interrupts=0 nmi_watchdog=panic,lapic disablevmx=off + X86 setup: 781b4400 + Logo: (none) + FDT: + Error: 0 + +Now the buffer can be accessed:: + + => md 77b7e400 + 77b7e400: 1186f6fc 40000002 b8fa0c75 00000018 .......@u....... + 77b7e410: c08ed88e a68dd08e 000001e8 000000e8 ................ + 77b7e420: ed815d00 00000021 62c280b8 89e80100 .]..!......b.... + 77b7e430: 22f7e8c4 c0850061 22ec850f eb890061 ..."a......"a... + 77b7e440: 0230868b 01480000 21d0f7c3 00fb81c3 ..0...H....!.... + 77b7e450: 7d010000 0000bb05 c3810100 00d4f000 ...}............ + 77b7e460: 8130858d 85890061 00618132 3095010f ..0.a...2.a....0 + 77b7e470: 0f006181 c883e020 e0220f20 e000bb8d .a.. ... ."..... + 77b7e480: c0310062 001800b9 8dabf300 62e000bb b.1............b + 77b7e490: 07878d00 89000010 00bb8d07 8d0062f0 .............b.. + 77b7e4a0: 00100787 0004b900 07890000 00100005 ................ + 77b7e4b0: 08c78300 8df37549 630000bb 0183b800 ....Iu.....c.... + 77b7e4c0: 00b90000 89000008 00000507 c7830020 ............ ... + 77b7e4d0: f3754908 e000838d 220f0062 0080b9d8 .Iu.....b..".... + 77b7e4e0: 320fc000 08e8ba0f c031300f b8d0000f ...2.....01..... + 77b7e4f0: 00000020 6ad8000f 00858d10 50000002 ......j.......P + Return value ------------ diff --git a/include/bootflow.h b/include/bootflow.h index fdcfeddc1a6..44d3741eaca 100644 --- a/include/bootflow.h +++ b/include/bootflow.h @@ -352,6 +352,17 @@ void bootflow_free(struct bootflow *bflow); */ int bootflow_boot(struct bootflow *bflow); +/** + * bootflow_read_all() - Read all bootflow files + * + * Some bootmeths delay reading of large files until booting is requested. This + * causes those files to be read. + * + * @bflow: Bootflow to read + * Return: result of trying to read + */ +int bootflow_read_all(struct bootflow *bflow); + /** * bootflow_run_boot() - Try to boot a bootflow * diff --git a/include/bootmeth.h b/include/bootmeth.h index 7cb7da33dea..d3d8d608cd7 100644 --- a/include/bootmeth.h +++ b/include/bootmeth.h @@ -119,7 +119,16 @@ struct bootmeth_ops { */ int (*read_file)(struct udevice *dev, struct bootflow *bflow, const char *file_path, ulong addr, ulong *sizep); - +#if CONFIG_IS_ENABLED(BOOTSTD_FULL) + /** + * readall() - read all files for a bootflow + * + * @dev: Bootmethod device to boot + * @bflow: Bootflow to read + * Return: 0 if OK, -EIO on I/O error, other -ve on other error + */ + int (*read_all)(struct udevice *dev, struct bootflow *bflow); +#endif /* BOOTSTD_FULL */ /** * boot() - boot a bootflow * @@ -223,6 +232,20 @@ int bootmeth_set_bootflow(struct udevice *dev, struct bootflow *bflow, int bootmeth_read_file(struct udevice *dev, struct bootflow *bflow, const char *file_path, ulong addr, ulong *sizep); +/** + * bootmeth_read_all() - read all bootflow files + * + * Some bootmeths delay reading of large files until booting is requested. This + * causes those files to be read. + * + * @dev: Bootmethod device to use + * @bflow: Bootflow to read + * Return: does not return on success, since it should boot the + * Operating Systemn. Returns -EFAULT if that fails, other -ve on + * other error + */ +int bootmeth_read_all(struct udevice *dev, struct bootflow *bflow); + /** * bootmeth_boot() - boot a bootflow * -- cgit v1.3.1 From daffb0be2c839f3abe431cd68c772fae0e7e49ca Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 30 Jul 2023 11:17:02 -0600 Subject: bootstd: cros: Add ARM support Support booting ChromiumOS on ARM devices using FIT. Add an entry into the boot implementation which does not require a command line. This can be expanded over time as the bootm code is refactored. Signed-off-by: Simon Glass --- boot/Kconfig | 4 ++-- boot/bootm.c | 37 +++++++++++++++++++++++++++++++++++++ boot/bootmeth_cros.c | 16 ++++++++++------ include/bootm.h | 8 ++++++++ 4 files changed, 57 insertions(+), 8 deletions(-) (limited to 'boot') diff --git a/boot/Kconfig b/boot/Kconfig index b00d7a8d11e..5e2d4286aea 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -464,8 +464,8 @@ config BOOTMETH_GLOBAL config BOOTMETH_CROS bool "Bootdev support for Chromium OS" - depends on X86 || SANDBOX - default y + depends on X86 || ARM || SANDBOX + default y if !ARM help Enables support for booting Chromium OS using bootdevs. This uses the kernel A slot and obtains the kernel command line from the parameters diff --git a/boot/bootm.c b/boot/bootm.c index 75f0b4a9af8..b1c3afe0a3a 100644 --- a/boot/bootm.c +++ b/boot/bootm.c @@ -823,6 +823,43 @@ err: return ret; } +int bootm_boot_start(ulong addr, const char *cmdline) +{ + static struct cmd_tbl cmd = {"bootm"}; + char addr_str[30]; + char *argv[] = {addr_str, NULL}; + int states; + int ret; + + /* + * TODO(sjg@chromium.org): This uses the command-line interface, but + * should not. To clean this up, the various bootm states need to be + * passed an info structure instead of cmdline flags. Then this can + * set up the required info and move through the states without needing + * the command line. + */ + states = BOOTM_STATE_START | BOOTM_STATE_FINDOS | BOOTM_STATE_PRE_LOAD | + BOOTM_STATE_FINDOTHER | BOOTM_STATE_LOADOS | + BOOTM_STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO | + BOOTM_STATE_OS_GO; + if (IS_ENABLED(CONFIG_SYS_BOOT_RAMDISK_HIGH)) + states |= BOOTM_STATE_RAMDISK; + if (IS_ENABLED(CONFIG_PPC) || IS_ENABLED(CONFIG_MIPS)) + states |= BOOTM_STATE_OS_CMDLINE; + images.state |= states; + + snprintf(addr_str, sizeof(addr_str), "%lx", addr); + + ret = env_set("bootargs", cmdline); + if (ret) { + printf("Failed to set cmdline\n"); + return ret; + } + ret = do_bootm_states(&cmd, 0, 1, argv, states, &images, 1); + + return ret; +} + #if CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT) /** * image_get_kernel - verify legacy format kernel image diff --git a/boot/bootmeth_cros.c b/boot/bootmeth_cros.c index 6c28feb34fe..1776fb1838c 100644 --- a/boot/bootmeth_cros.c +++ b/boot/bootmeth_cros.c @@ -419,13 +419,17 @@ static int cros_boot(struct udevice *dev, struct bootflow *bflow) if (ret) return log_msg_ret("rd", ret); } -#ifdef CONFIG_X86 - zboot_start(map_to_sysmem(bflow->buf), bflow->size, 0, 0, - map_to_sysmem(bflow->x86_setup), - bflow->cmdline); -#endif - return log_msg_ret("go", -EFAULT); + if (IS_ENABLED(CONFIG_X86)) { + ret = zboot_start(map_to_sysmem(bflow->buf), bflow->size, 0, 0, + map_to_sysmem(bflow->x86_setup), + bflow->cmdline); + } else { + ret = bootm_boot_start(map_to_sysmem(bflow->buf), + bflow->cmdline); + } + + return log_msg_ret("go", ret); } static int cros_bootmeth_bind(struct udevice *dev) diff --git a/include/bootm.h b/include/bootm.h index 92870ff1a20..c3c7336207b 100644 --- a/include/bootm.h +++ b/include/bootm.h @@ -163,4 +163,12 @@ const char *zimage_get_kernel_version(struct boot_params *params, */ void zimage_dump(struct boot_params *base_ptr, bool show_cmdline); +/* + * bootm_boot_start() - Boot an image at the given address + * + * @addr: Image address + * @cmdline: Command line to set + */ +int bootm_boot_start(ulong addr, const char *cmdline); + #endif -- cgit v1.3.1 From 633b3dc75536a7a878126c41babc248c095b66fe Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 14 Aug 2023 16:40:21 -0600 Subject: expo: Make scene_obj_find() take a const scene This does not change the scene, so mark the pointer const. Signed-off-by: Simon Glass --- boot/scene.c | 2 +- boot/scene_internal.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'boot') diff --git a/boot/scene.c b/boot/scene.c index e52333371f9..b4c36c41702 100644 --- a/boot/scene.c +++ b/boot/scene.c @@ -79,7 +79,7 @@ int scene_obj_count(struct scene *scn) return count; } -void *scene_obj_find(struct scene *scn, uint id, enum scene_obj_t type) +void *scene_obj_find(const struct scene *scn, uint id, enum scene_obj_t type) { struct scene_obj *obj; diff --git a/boot/scene_internal.h b/boot/scene_internal.h index fb1ea5533b9..1620d10a777 100644 --- a/boot/scene_internal.h +++ b/boot/scene_internal.h @@ -38,7 +38,7 @@ uint resolve_id(struct expo *exp, uint id); * @type: Type of the object, or SCENEOBJT_NONE to match any type * Returns: Object found, or NULL if not found */ -void *scene_obj_find(struct scene *scn, uint id, enum scene_obj_t type); +void *scene_obj_find(const struct scene *scn, uint id, enum scene_obj_t type); /** * scene_obj_find_by_name() - Find an object in a scene by name -- cgit v1.3.1 From f2eb6ad50a3e610897d6386bb3192c049dc6fd12 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 14 Aug 2023 16:40:23 -0600 Subject: expo: Provide a way to iterate through all scene objects For some operations it is necessary to process all objects in an expo. Provide an iterator to handle this. Signed-off-by: Simon Glass --- boot/expo.c | 15 +++++++++++++++ boot/scene.c | 16 ++++++++++++++++ boot/scene_internal.h | 24 ++++++++++++++++++++++++ test/boot/expo.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 100 insertions(+) (limited to 'boot') diff --git a/boot/expo.c b/boot/expo.c index db837f7b492..139d684f8e6 100644 --- a/boot/expo.c +++ b/boot/expo.c @@ -266,3 +266,18 @@ int expo_apply_theme(struct expo *exp, ofnode node) return 0; } + +int expo_iter_scene_objs(struct expo *exp, expo_scene_obj_iterator iter, + void *priv) +{ + struct scene *scn; + int ret; + + list_for_each_entry(scn, &exp->scene_head, sibling) { + ret = scene_iter_objs(scn, iter, priv); + if (ret) + return log_msg_ret("wr", ret); + } + + return 0; +} diff --git a/boot/scene.c b/boot/scene.c index b4c36c41702..6c52948eb69 100644 --- a/boot/scene.c +++ b/boot/scene.c @@ -681,3 +681,19 @@ int scene_set_open(struct scene *scn, uint id, bool open) return 0; } + +int scene_iter_objs(struct scene *scn, expo_scene_obj_iterator iter, + void *priv) +{ + struct scene_obj *obj; + + list_for_each_entry(obj, &scn->obj_head, sibling) { + int ret; + + ret = iter(obj, priv); + if (ret) + return log_msg_ret("itr", ret); + } + + return 0; +} diff --git a/boot/scene_internal.h b/boot/scene_internal.h index 1620d10a777..60b14344078 100644 --- a/boot/scene_internal.h +++ b/boot/scene_internal.h @@ -9,6 +9,8 @@ #ifndef __SCENE_INTERNAL_H #define __SCENE_INTERNAL_H +typedef int (*expo_scene_obj_iterator)(struct scene_obj *obj, void *priv); + /** * expo_lookup_scene_id() - Look up a scene ID * @@ -198,4 +200,26 @@ int scene_menu_render_deps(struct scene *scn, struct scene_obj_menu *menu); */ int scene_menu_calc_dims(struct scene_obj_menu *menu); +/** + * scene_iter_objs() - Iterate through all scene objects + * + * @scn: Scene to process + * @iter: Iterator to call on each object + * @priv: Private data to pass to the iterator, in addition to the object + * Return: 0 if OK, -ve on error + */ +int scene_iter_objs(struct scene *scn, expo_scene_obj_iterator iter, + void *priv); + +/** + * expo_iter_scene_objects() - Iterate through all scene objects + * + * @exp: Expo to process + * @iter: Iterator to call on each object + * @priv: Private data to pass to the iterator, in addition to the object + * Return: 0 if OK, -ve on error + */ +int expo_iter_scene_objs(struct expo *exp, expo_scene_obj_iterator iter, + void *priv); + #endif /* __SCENE_INTERNAL_H */ diff --git a/test/boot/expo.c b/test/boot/expo.c index 3898f853a75..458e332440c 100644 --- a/test/boot/expo.c +++ b/test/boot/expo.c @@ -289,6 +289,33 @@ static int expo_object_attr(struct unit_test_state *uts) } BOOTSTD_TEST(expo_object_attr, UT_TESTF_DM | UT_TESTF_SCAN_FDT); +/** + * struct test_iter_priv - private data for expo-iterator test + * + * @count: number of scene objects + * @menu_count: number of menus + * @fail_at: item ID at which to return an error + */ +struct test_iter_priv { + int count; + int menu_count; + int fail_at; +}; + +int h_test_iter(struct scene_obj *obj, void *vpriv) +{ + struct test_iter_priv *priv = vpriv; + + if (priv->fail_at == obj->id) + return -EINVAL; + + priv->count++; + if (obj->type == SCENEOBJT_MENU) + priv->menu_count++; + + return 0; +} + /* Check creating a scene with a menu */ static int expo_object_menu(struct unit_test_state *uts) { @@ -296,6 +323,7 @@ static int expo_object_menu(struct unit_test_state *uts) struct scene_menitem *item; int id, label_id, desc_id, key_id, pointer_id, preview_id; struct scene_obj_txt *ptr, *name1, *desc1, *key1, *tit, *prev1; + struct test_iter_priv priv; struct scene *scn; struct expo *exp; ulong start_mem; @@ -382,6 +410,23 @@ static int expo_object_menu(struct unit_test_state *uts) ut_asserteq(menu->obj.dim.y + 32, prev1->obj.dim.y); ut_asserteq(true, prev1->obj.flags & SCENEOF_HIDE); + /* check iterating through scene items */ + memset(&priv, '\0', sizeof(priv)); + ut_assertok(expo_iter_scene_objs(exp, h_test_iter, &priv)); + ut_asserteq(7, priv.count); + ut_asserteq(1, priv.menu_count); + + /* check the iterator failing part way through iteration */ + memset(&priv, '\0', sizeof(priv)); + priv.fail_at = key_id; + ut_asserteq(-EINVAL, expo_iter_scene_objs(exp, h_test_iter, &priv)); + + /* 2 items (preview_id and the menuitem) are after key_id, 7 - 2 = 5 */ + ut_asserteq(5, priv.count); + + /* menu is first, so is still processed */ + ut_asserteq(1, priv.menu_count); + expo_destroy(exp); ut_assertok(ut_check_delta(start_mem)); -- cgit v1.3.1 From 431b21fd407f4a76cdc182ee40184311562e5505 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 14 Aug 2023 16:40:24 -0600 Subject: expo: Refactor menu_build() to return the object created The caller reads the ID but menu_build() does this again. Add the ID as a parameter to avoid this. Return the object created so that the caller can adjust it. Signed-off-by: Simon Glass --- boot/expo_build.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'boot') diff --git a/boot/expo_build.c b/boot/expo_build.c index 22f62eb54bc..e8c4a40d3f0 100644 --- a/boot/expo_build.c +++ b/boot/expo_build.c @@ -214,22 +214,21 @@ static void list_strings(struct build_info *info) * @info: Build information * @node: Node containing the menu description * @scn: Scene to add the menu to + * @id: ID for the menu + * @objp: Returns the object pointer * Returns: 0 if OK, -ENOMEM if out of memory, -EINVAL if there is a format * error, -ENOENT if there is a references to a non-existent string */ -static int menu_build(struct build_info *info, ofnode node, struct scene *scn) +static int menu_build(struct build_info *info, ofnode node, struct scene *scn, + uint id, struct scene_obj **objp) { struct scene_obj_menu *menu; uint title_id, menu_id; const u32 *item_ids; int ret, size, i; const char *name; - u32 id; name = ofnode_get_name(node); - ret = ofnode_read_u32(node, "id", &id); - if (ret) - return log_msg_ret("id", -EINVAL); ret = scene_menu(scn, name, id, &menu); if (ret < 0) @@ -275,12 +274,13 @@ static int menu_build(struct build_info *info, ofnode node, struct scene *scn) if (ret < 0) return log_msg_ret("mi", ret); } + *objp = &menu->obj; return 0; } /** - * menu_build() - Build an expo object and add it to a scene + * obj_build() - Build an expo object and add it to a scene * * See doc/developer/expo.rst for a description of the format * @@ -292,6 +292,7 @@ static int menu_build(struct build_info *info, ofnode node, struct scene *scn) */ static int obj_build(struct build_info *info, ofnode node, struct scene *scn) { + struct scene_obj *obj; const char *type; u32 id; int ret; @@ -306,7 +307,7 @@ static int obj_build(struct build_info *info, ofnode node, struct scene *scn) return log_msg_ret("typ", -EINVAL); if (!strcmp("menu", type)) - ret = menu_build(info, node, scn); + ret = menu_build(info, node, scn, id, &obj); else ret = -EINVAL; if (ret) -- cgit v1.3.1 From 040b04685ea4c47a5148c2fcc2ff6dfdd83bc714 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 14 Aug 2023 16:40:25 -0600 Subject: expo: Split out cedit into its own header Before adding more functions to this interface, create a new header for the configuration editor. Fix up the expo header guard while we are here. Signed-off-by: Simon Glass --- boot/cedit.c | 1 + cmd/cedit.c | 1 + include/cedit.h | 33 +++++++++++++++++++++++++++++++++ include/expo.h | 27 +++------------------------ 4 files changed, 38 insertions(+), 24 deletions(-) create mode 100644 include/cedit.h (limited to 'boot') diff --git a/boot/cedit.c b/boot/cedit.c index ee24658917b..2d16086bad6 100644 --- a/boot/cedit.c +++ b/boot/cedit.c @@ -7,6 +7,7 @@ */ #include +#include #include #include #include diff --git a/cmd/cedit.c b/cmd/cedit.c index 0cae304c4ad..5f0e84403f5 100644 --- a/cmd/cedit.c +++ b/cmd/cedit.c @@ -7,6 +7,7 @@ */ #include +#include #include #include #include diff --git a/include/cedit.h b/include/cedit.h new file mode 100644 index 00000000000..21de12dfe7a --- /dev/null +++ b/include/cedit.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright 2023 Google LLC + * Written by Simon Glass + */ + +#ifndef __CEDIT_H +#define __CEDIT_H + +struct expo; +struct video_priv; + +/** + * cedit_arange() - Arrange objects in a configuration-editor scene + * + * @exp: Expo to update + * @vid_priv: Private info of the video device + * @scene_id: scene ID to arrange + * Returns: 0 if OK, -ve on error + */ +int cedit_arange(struct expo *exp, struct video_priv *vid_priv, uint scene_id); + +/** + * cedit_run() - Run a configuration editor + * + * This accepts input until the user quits with Escape + * + * @exp: Expo to use + * Returns: 0 if OK, -ve on error + */ +int cedit_run(struct expo *exp); + +#endif /* __CEDIT_H */ diff --git a/include/expo.h b/include/expo.h index 0b1d944a169..da151074d20 100644 --- a/include/expo.h +++ b/include/expo.h @@ -4,14 +4,13 @@ * Written by Simon Glass */ -#ifndef __SCENE_H -#define __SCENE_H +#ifndef __EXPO_H +#define __EXPO_H #include #include struct udevice; -struct video_priv; /** * enum expoact_type - types of actions reported by the expo @@ -676,24 +675,4 @@ int expo_apply_theme(struct expo *exp, ofnode node); */ int expo_build(ofnode root, struct expo **expp); -/** - * cedit_arange() - Arrange objects in a configuration-editor scene - * - * @exp: Expo to update - * @vid_priv: Private info of the video device - * @scene_id: scene ID to arrange - * Returns: 0 if OK, -ve on error - */ -int cedit_arange(struct expo *exp, struct video_priv *vid_priv, uint scene_id); - -/** - * cedit_run() - Run a configuration editor - * - * This accepts input until the user quits with Escape - * - * @exp: Expo to use - * Returns: 0 if OK, -ve on error - */ -int cedit_run(struct expo *exp); - -#endif /*__SCENE_H */ +#endif /*__EXPO_H */ -- cgit v1.3.1 From 8d0f890a0b9b0f7bf0b529f18f81a45ec6f64eb1 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 14 Aug 2023 16:40:27 -0600 Subject: expo: Add a function to prepare a cedit Split out the code which prepares the cedit for use, so we can call it from a test. Add a log category while we are here. Signed-off-by: Simon Glass --- boot/cedit.c | 32 ++++++++++++++++++++++++++------ include/cedit.h | 15 +++++++++++++++ 2 files changed, 41 insertions(+), 6 deletions(-) (limited to 'boot') diff --git a/boot/cedit.c b/boot/cedit.c index 2d16086bad6..6c10b211454 100644 --- a/boot/cedit.c +++ b/boot/cedit.c @@ -6,6 +6,8 @@ * Written by Simon Glass */ +#define LOG_CATEGORY LOGC_EXPO + #include #include #include @@ -47,18 +49,15 @@ int cedit_arange(struct expo *exp, struct video_priv *vpriv, uint scene_id) return 0; } -int cedit_run(struct expo *exp) +int cedit_prepare(struct expo *exp, struct video_priv **vid_privp, + struct scene **scnp) { - struct cli_ch_state s_cch, *cch = &s_cch; struct video_priv *vid_priv; - uint scene_id; struct udevice *dev; struct scene *scn; - bool done; + uint scene_id; int ret; - cli_ch_init(cch); - /* For now we only support a video console */ ret = uclass_first_device_err(UCLASS_VIDEO, &dev); if (ret) @@ -93,6 +92,27 @@ int cedit_run(struct expo *exp) if (ret) return log_msg_ret("dim", ret); + *vid_privp = vid_priv; + *scnp = scn; + + return scene_id; +} + +int cedit_run(struct expo *exp) +{ + struct cli_ch_state s_cch, *cch = &s_cch; + struct video_priv *vid_priv; + uint scene_id; + struct scene *scn; + bool done; + int ret; + + cli_ch_init(cch); + ret = cedit_prepare(exp, &vid_priv, &scn); + if (ret < 0) + return log_msg_ret("prep", ret); + scene_id = ret; + done = false; do { struct expo_action act; diff --git a/include/cedit.h b/include/cedit.h index 21de12dfe7a..851d8e83564 100644 --- a/include/cedit.h +++ b/include/cedit.h @@ -8,6 +8,7 @@ #define __CEDIT_H struct expo; +struct scene; struct video_priv; /** @@ -30,4 +31,18 @@ int cedit_arange(struct expo *exp, struct video_priv *vid_priv, uint scene_id); */ int cedit_run(struct expo *exp); +/** + * cedit_prepare() - Prepare to run a cedit + * + * Set up the video device, select the first scene and highlight the first item. + * This ensures that all menus have a selected item. + * + * @exp: Expo to use + * @vid_privp: Set to private data for the video device + * @scnp: Set to the first scene + * Return: scene ID of first scene if OK, -ve on error + */ +int cedit_prepare(struct expo *exp, struct video_priv **vid_privp, + struct scene **scnp); + #endif /* __CEDIT_H */ -- cgit v1.3.1 From 6e648fa781eea9ae0c5e130217ffeabbd45d9385 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 14 Aug 2023 16:40:32 -0600 Subject: expo: Export scene_menuitem_find() for use in internal code Make this function available to other expo code so we can use it to look up a menu item. Signed-off-by: Simon Glass --- boot/scene_internal.h | 12 ++++++++++++ boot/scene_menu.c | 4 ++-- 2 files changed, 14 insertions(+), 2 deletions(-) (limited to 'boot') diff --git a/boot/scene_internal.h b/boot/scene_internal.h index 60b14344078..23e29cb349b 100644 --- a/boot/scene_internal.h +++ b/boot/scene_internal.h @@ -222,4 +222,16 @@ int scene_iter_objs(struct scene *scn, expo_scene_obj_iterator iter, int expo_iter_scene_objs(struct expo *exp, expo_scene_obj_iterator iter, void *priv); +/** + * scene_menuitem_find() - Find the menu item for an ID + * + * Looks up the menu to find the item with the given ID + * + * @menu: Menu to check + * @id: ID to look for + * Return: Menu item, or NULL if not found + */ +struct scene_menitem *scene_menuitem_find(const struct scene_obj_menu *menu, + int id); + #endif /* __SCENE_INTERNAL_H */ diff --git a/boot/scene_menu.c b/boot/scene_menu.c index 57ffb523ff3..602fe24580a 100644 --- a/boot/scene_menu.c +++ b/boot/scene_menu.c @@ -33,8 +33,8 @@ void scene_menu_destroy(struct scene_obj_menu *menu) scene_menuitem_destroy(item); } -static struct scene_menitem *scene_menuitem_find(struct scene_obj_menu *menu, - int id) +struct scene_menitem *scene_menuitem_find(const struct scene_obj_menu *menu, + int id) { struct scene_menitem *item; -- cgit v1.3.1 From 2dee81fe5f4a6427ba48fe17ff017930ddf3b4e4 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 14 Aug 2023 16:40:33 -0600 Subject: expo: cedit: Support writing settings to a file Support writing settings from an expo into a file in FDT format. It consists of a single node with a two properties for each sceneitem, one with tag ID chosen by the user and another for its text value. Signed-off-by: Simon Glass --- boot/cedit.c | 136 ++++++++++++++++++++++++++++++++++++++++++++++++ cmd/cedit.c | 51 ++++++++++++++++-- doc/usage/cmd/cedit.rst | 19 +++++++ include/cedit.h | 22 ++++++++ test/boot/cedit.c | 45 ++++++++++++++++ 5 files changed, 270 insertions(+), 3 deletions(-) (limited to 'boot') diff --git a/boot/cedit.c b/boot/cedit.c index 6c10b211454..4dd79a2263d 100644 --- a/boot/cedit.c +++ b/boot/cedit.c @@ -9,6 +9,7 @@ #define LOG_CATEGORY LOGC_EXPO #include +#include #include #include #include @@ -18,6 +19,15 @@ #include #include "scene_internal.h" +/** + * struct cedit_iter_priv - private data for cedit operations + * + * @buf: Buffer to use when writing settings to the devicetree + */ +struct cedit_iter_priv { + struct abuf *buf; +}; + int cedit_arange(struct expo *exp, struct video_priv *vpriv, uint scene_id) { struct scene_obj_txt *txt; @@ -182,3 +192,129 @@ int cedit_run(struct expo *exp) return 0; } + +static int check_space(int ret, struct abuf *buf) +{ + if (ret == -FDT_ERR_NOSPACE) { + if (!abuf_realloc_inc(buf, CEDIT_SIZE_INC)) + return log_msg_ret("spc", -ENOMEM); + ret = fdt_resize(abuf_data(buf), abuf_data(buf), + abuf_size(buf)); + if (ret) + return log_msg_ret("res", -EFAULT); + } + + return 0; +} + +static int h_write_settings(struct scene_obj *obj, void *vpriv) +{ + struct cedit_iter_priv *priv = vpriv; + struct abuf *buf = priv->buf; + + switch (obj->type) { + case SCENEOBJT_NONE: + case SCENEOBJT_IMAGE: + case SCENEOBJT_TEXT: + break; + case SCENEOBJT_MENU: { + const struct scene_obj_menu *menu; + const struct scene_obj_txt *txt; + struct scene *scn = obj->scene; + const struct scene_menitem *mi; + const char *str; + char name[80]; + int ret, i; + + menu = (struct scene_obj_menu *)obj; + ret = -EAGAIN; + for (i = 0; ret && i < 2; i++) { + ret = fdt_property_u32(abuf_data(buf), obj->name, + menu->cur_item_id); + if (!i) { + ret = check_space(ret, buf); + if (ret) + return log_msg_ret("res", -ENOMEM); + } + } + /* this should not happen */ + if (ret) + return log_msg_ret("wrt", -EFAULT); + + mi = scene_menuitem_find(menu, menu->cur_item_id); + if (!mi) + return log_msg_ret("mi", -ENOENT); + + txt = scene_obj_find(scn, mi->label_id, SCENEOBJT_TEXT); + if (!txt) + return log_msg_ret("txt", -ENOENT); + + str = expo_get_str(scn->expo, txt->str_id); + if (!str) + return log_msg_ret("str", -ENOENT); + + snprintf(name, sizeof(name), "%s-str", obj->name); + ret = -EAGAIN; + for (i = 0; ret && i < 2; i++) { + ret = fdt_property_string(abuf_data(buf), name, str); + if (!i) { + ret = check_space(ret, buf); + if (ret) + return log_msg_ret("rs2", -ENOMEM); + } + } + + /* this should not happen */ + if (ret) + return log_msg_ret("wr2", -EFAULT); + + break; + } + } + + return 0; +} + +int cedit_write_settings(struct expo *exp, struct abuf *buf) +{ + struct cedit_iter_priv priv; + void *fdt; + int ret; + + abuf_init(buf); + if (!abuf_realloc(buf, CEDIT_SIZE_INC)) + return log_msg_ret("buf", -ENOMEM); + + fdt = abuf_data(buf); + ret = fdt_create(fdt, abuf_size(buf)); + if (!ret) + ret = fdt_finish_reservemap(fdt); + if (!ret) + ret = fdt_begin_node(fdt, ""); + if (!ret) + ret = fdt_begin_node(fdt, CEDIT_NODE_NAME); + if (ret) { + log_debug("Failed to start FDT (err=%d)\n", ret); + return log_msg_ret("sta", -EINVAL); + } + + /* write out the items */ + priv.buf = buf; + ret = expo_iter_scene_objs(exp, h_write_settings, &priv); + if (ret) { + log_debug("Failed to write settings (err=%d)\n", ret); + return log_msg_ret("set", ret); + } + + ret = fdt_end_node(fdt); + if (!ret) + ret = fdt_end_node(fdt); + if (!ret) + ret = fdt_finish(fdt); + if (ret) { + log_debug("Failed to finish FDT (err=%d)\n", ret); + return log_msg_ret("fin", -EINVAL); + } + + return 0; +} diff --git a/cmd/cedit.c b/cmd/cedit.c index e98121b067b..18cc8ba191b 100644 --- a/cmd/cedit.c +++ b/cmd/cedit.c @@ -7,15 +7,28 @@ */ #include +#include #include #include #include #include +#include +#include #include #include struct expo *cur_exp; +static int check_cur_expo(void) +{ + if (!cur_exp) { + printf("No expo loaded\n"); + return -ENOENT; + } + + return 0; +} + static int do_cedit_load(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { @@ -54,16 +67,46 @@ static int do_cedit_load(struct cmd_tbl *cmdtp, int flag, int argc, return 0; } +static int do_cedit_write_fdt(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + const char *fname; + struct abuf buf; + loff_t bytes; + int ret; + + if (argc < 4) + return CMD_RET_USAGE; + fname = argv[3]; + + if (check_cur_expo()) + return CMD_RET_FAILURE; + + ret = cedit_write_settings(cur_exp, &buf); + if (ret) { + printf("Failed to write settings: %dE\n", ret); + return CMD_RET_FAILURE; + } + + if (fs_set_blk_dev(argv[1], argv[2], FS_TYPE_ANY)) + return CMD_RET_FAILURE; + + ret = fs_write(fname, map_to_sysmem(abuf_data(&buf)), 0, + abuf_size(&buf), &bytes); + if (ret) + return CMD_RET_FAILURE; + + return 0; +} + static int do_cedit_run(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { ofnode node; int ret; - if (!cur_exp) { - printf("No expo loaded\n"); + if (check_cur_expo()) return CMD_RET_FAILURE; - } node = ofnode_path("/bootstd/cedit-theme"); if (ofnode_valid(node)) { @@ -85,10 +128,12 @@ static int do_cedit_run(struct cmd_tbl *cmdtp, int flag, int argc, #ifdef CONFIG_SYS_LONGHELP static char cedit_help_text[] = "load - load config editor\n" + "cedit write_fdt - write settings\n" "cedit run - run config editor"; #endif /* CONFIG_SYS_LONGHELP */ U_BOOT_CMD_WITH_SUBCMDS(cedit, "Configuration editor", cedit_help_text, U_BOOT_SUBCMD_MKENT(load, 5, 1, do_cedit_load), + U_BOOT_SUBCMD_MKENT(write_fdt, 5, 1, do_cedit_write_fdt), U_BOOT_SUBCMD_MKENT(run, 1, 1, do_cedit_run), ); diff --git a/doc/usage/cmd/cedit.rst b/doc/usage/cmd/cedit.rst index d34a220797e..0581594831f 100644 --- a/doc/usage/cmd/cedit.rst +++ b/doc/usage/cmd/cedit.rst @@ -10,6 +10,7 @@ Synopis cedit load cedit run + cedit write_fdt Description ----------- @@ -38,6 +39,12 @@ Runs the default configuration-editor event loop. This is very simple, just accepting character input and moving through the objects under user control. The implementation is at `cedit_run()`. +cedit write_fdt +~~~~~~~~~~~~~~~ + +Writes the current user settings to a devicetree file. For each menu item the +selected ID and its text string are written. + Example ------- @@ -46,3 +53,15 @@ Example => cedit load hostfs - fred.dtb => cedit run + => cedit write_fdt hostfs - settings.dtb + +That results in:: + + / { + cedit-values { + cpu-speed = <0x00000006>; + cpu-speed-str = "2 GHz"; + power-loss = <0x0000000a>; + power-loss-str = "Always Off"; + }; + } diff --git a/include/cedit.h b/include/cedit.h index 851d8e83564..6086e302006 100644 --- a/include/cedit.h +++ b/include/cedit.h @@ -7,10 +7,21 @@ #ifndef __CEDIT_H #define __CEDIT_H +struct abuf; struct expo; struct scene; struct video_priv; +enum { + /* size increment for writing FDT */ + CEDIT_SIZE_INC = 1024, +}; + +/* Name of the cedit node in the devicetree */ +#define CEDIT_NODE_NAME "cedit-values" + +extern struct expo *cur_exp; + /** * cedit_arange() - Arrange objects in a configuration-editor scene * @@ -45,4 +56,15 @@ int cedit_run(struct expo *exp); int cedit_prepare(struct expo *exp, struct video_priv **vid_privp, struct scene **scnp); +/** + * cedit_write_settings() - Write settings in FDT format + * + * Sets up an FDT with the settings + * + * @exp: Expo to write settings from + * @buf: Returns abuf containing the settings FDT (inited by this function) + * Return: 0 if OK, -ve on error + */ +int cedit_write_settings(struct expo *exp, struct abuf *buf); + #endif /* __CEDIT_H */ diff --git a/test/boot/cedit.c b/test/boot/cedit.c index f3411f734fa..1dd78c64158 100644 --- a/test/boot/cedit.c +++ b/test/boot/cedit.c @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include #include "bootstd_common.h" #include @@ -51,3 +53,46 @@ static int cedit_base(struct unit_test_state *uts) return 0; } BOOTSTD_TEST(cedit_base, 0); + +/* Check the cedit write_fdt commands */ +static int cedit_fdt(struct unit_test_state *uts) +{ + struct video_priv *vid_priv; + extern struct expo *cur_exp; + ulong addr = 0x1000; + struct ofprop prop; + struct scene *scn; + oftree tree; + ofnode node; + void *fdt; + int i; + + console_record_reset_enable(); + ut_assertok(run_command("cedit load hostfs - cedit.dtb", 0)); + + ut_asserteq(ID_SCENE1, cedit_prepare(cur_exp, &vid_priv, &scn)); + + ut_assertok(run_command("cedit write_fdt hostfs - settings.dtb", 0)); + ut_assertok(run_commandf("load hostfs - %lx settings.dtb", addr)); + ut_assert_nextlinen("1024 bytes read"); + + fdt = map_sysmem(addr, 1024); + tree = oftree_from_fdt(fdt); + node = ofnode_find_subnode(oftree_root(tree), CEDIT_NODE_NAME); + + ut_asserteq(ID_CPU_SPEED_1, + ofnode_read_u32_default(node, "cpu-speed", 0)); + ut_asserteq_str("2 GHz", ofnode_read_string(node, "cpu-speed-str")); + ut_assert(ofnode_valid(node)); + + /* There should only be 4 properties */ + for (i = 0, ofnode_first_property(node, &prop); ofprop_valid(&prop); + i++, ofnode_next_property(&prop)) + ; + ut_asserteq(4, i); + + ut_assert_console_end(); + + return 0; +} +BOOTSTD_TEST(cedit_fdt, 0); -- cgit v1.3.1 From 472317cb12e534f56b631365987934960dfb0a3f Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 14 Aug 2023 16:40:34 -0600 Subject: expo: cedit: Support reading settings from a file Add a command to read cedit settings from a devicetree file. Signed-off-by: Simon Glass --- boot/cedit.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++ cmd/cedit.c | 39 +++++++++++++++++++++++++++++++++++++ doc/usage/cmd/cedit.rst | 8 ++++++++ include/cedit.h | 13 +++++++++++++ test/boot/cedit.c | 22 ++++++++++++++++++--- 5 files changed, 131 insertions(+), 3 deletions(-) (limited to 'boot') diff --git a/boot/cedit.c b/boot/cedit.c index 4dd79a2263d..6a74a380989 100644 --- a/boot/cedit.c +++ b/boot/cedit.c @@ -23,9 +23,11 @@ * struct cedit_iter_priv - private data for cedit operations * * @buf: Buffer to use when writing settings to the devicetree + * @node: Node to read from when reading settings from devicetree */ struct cedit_iter_priv { struct abuf *buf; + ofnode node; }; int cedit_arange(struct expo *exp, struct video_priv *vpriv, uint scene_id) @@ -318,3 +320,53 @@ int cedit_write_settings(struct expo *exp, struct abuf *buf) return 0; } + +static int h_read_settings(struct scene_obj *obj, void *vpriv) +{ + struct cedit_iter_priv *priv = vpriv; + ofnode node = priv->node; + + switch (obj->type) { + case SCENEOBJT_NONE: + case SCENEOBJT_IMAGE: + case SCENEOBJT_TEXT: + break; + case SCENEOBJT_MENU: { + struct scene_obj_menu *menu; + uint val; + + if (ofnode_read_u32(node, obj->name, &val)) + return log_msg_ret("rd", -ENOENT); + menu = (struct scene_obj_menu *)obj; + menu->cur_item_id = val; + + break; + } + } + + return 0; +} + +int cedit_read_settings(struct expo *exp, oftree tree) +{ + struct cedit_iter_priv priv; + ofnode root, node; + int ret; + + root = oftree_root(tree); + if (!ofnode_valid(root)) + return log_msg_ret("roo", -ENOENT); + node = ofnode_find_subnode(root, CEDIT_NODE_NAME); + if (!ofnode_valid(node)) + return log_msg_ret("pat", -ENOENT); + + /* read in the items */ + priv.node = node; + ret = expo_iter_scene_objs(exp, h_read_settings, &priv); + if (ret) { + log_debug("Failed to read settings (err=%d)\n", ret); + return log_msg_ret("set", ret); + } + + return 0; +} diff --git a/cmd/cedit.c b/cmd/cedit.c index 18cc8ba191b..a155e080b1f 100644 --- a/cmd/cedit.c +++ b/cmd/cedit.c @@ -99,6 +99,43 @@ static int do_cedit_write_fdt(struct cmd_tbl *cmdtp, int flag, int argc, return 0; } +static int do_cedit_read_fdt(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + const char *fname; + void *buf; + oftree tree; + ulong size; + int ret; + + if (argc < 4) + return CMD_RET_USAGE; + fname = argv[3]; + + ret = fs_load_alloc(argv[1], argv[2], argv[3], SZ_1M, 0, &buf, &size); + if (ret) { + printf("File not found\n"); + return CMD_RET_FAILURE; + } + + tree = oftree_from_fdt(buf); + if (!oftree_valid(tree)) { + free(buf); + printf("Cannot create oftree\n"); + return CMD_RET_FAILURE; + } + + ret = cedit_read_settings(cur_exp, tree); + oftree_dispose(tree); + free(buf); + if (ret) { + printf("Failed to read settings: %dE\n", ret); + return CMD_RET_FAILURE; + } + + return 0; +} + static int do_cedit_run(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { @@ -128,12 +165,14 @@ static int do_cedit_run(struct cmd_tbl *cmdtp, int flag, int argc, #ifdef CONFIG_SYS_LONGHELP static char cedit_help_text[] = "load - load config editor\n" + "cedit read_fdt - read settings\n" "cedit write_fdt - write settings\n" "cedit run - run config editor"; #endif /* CONFIG_SYS_LONGHELP */ U_BOOT_CMD_WITH_SUBCMDS(cedit, "Configuration editor", cedit_help_text, U_BOOT_SUBCMD_MKENT(load, 5, 1, do_cedit_load), + U_BOOT_SUBCMD_MKENT(read_fdt, 5, 1, do_cedit_read_fdt), U_BOOT_SUBCMD_MKENT(write_fdt, 5, 1, do_cedit_write_fdt), U_BOOT_SUBCMD_MKENT(run, 1, 1, do_cedit_run), ); diff --git a/doc/usage/cmd/cedit.rst b/doc/usage/cmd/cedit.rst index 0581594831f..0a9f620b59b 100644 --- a/doc/usage/cmd/cedit.rst +++ b/doc/usage/cmd/cedit.rst @@ -11,6 +11,7 @@ Synopis cedit load cedit run cedit write_fdt + cedit read_fdt Description ----------- @@ -45,6 +46,11 @@ cedit write_fdt Writes the current user settings to a devicetree file. For each menu item the selected ID and its text string are written. +cedit read_fdt +~~~~~~~~~~~~~~ + +Reads the user settings from a devicetree file and updates the cedit with those +settings. Example ------- @@ -65,3 +71,5 @@ That results in:: power-loss-str = "Always Off"; }; } + + => cedit read_fdt hostfs - settings.dtb diff --git a/include/cedit.h b/include/cedit.h index 6086e302006..bb6e87d4af7 100644 --- a/include/cedit.h +++ b/include/cedit.h @@ -7,6 +7,8 @@ #ifndef __CEDIT_H #define __CEDIT_H +#include + struct abuf; struct expo; struct scene; @@ -67,4 +69,15 @@ int cedit_prepare(struct expo *exp, struct video_priv **vid_privp, */ int cedit_write_settings(struct expo *exp, struct abuf *buf); +/** + * cedit_read_settings() - Read settings in FDT format + * + * Read an FDT with the settings + * + * @exp: Expo to read settings into + * @tree: Tree to read from + * Return: 0 if OK, -ve on error + */ +int cedit_read_settings(struct expo *exp, oftree tree); + #endif /* __CEDIT_H */ diff --git a/test/boot/cedit.c b/test/boot/cedit.c index 1dd78c64158..659c47ed35f 100644 --- a/test/boot/cedit.c +++ b/test/boot/cedit.c @@ -54,11 +54,12 @@ static int cedit_base(struct unit_test_state *uts) } BOOTSTD_TEST(cedit_base, 0); -/* Check the cedit write_fdt commands */ +/* Check the cedit write_fdt and read_fdt commands */ static int cedit_fdt(struct unit_test_state *uts) { struct video_priv *vid_priv; extern struct expo *cur_exp; + struct scene_obj_menu *menu; ulong addr = 0x1000; struct ofprop prop; struct scene *scn; @@ -72,6 +73,11 @@ static int cedit_fdt(struct unit_test_state *uts) ut_asserteq(ID_SCENE1, cedit_prepare(cur_exp, &vid_priv, &scn)); + /* get a menu to fiddle with */ + menu = scene_obj_find(scn, ID_CPU_SPEED, SCENEOBJT_MENU); + ut_assertnonnull(menu); + menu->cur_item_id = ID_CPU_SPEED_2; + ut_assertok(run_command("cedit write_fdt hostfs - settings.dtb", 0)); ut_assertok(run_commandf("load hostfs - %lx settings.dtb", addr)); ut_assert_nextlinen("1024 bytes read"); @@ -80,9 +86,9 @@ static int cedit_fdt(struct unit_test_state *uts) tree = oftree_from_fdt(fdt); node = ofnode_find_subnode(oftree_root(tree), CEDIT_NODE_NAME); - ut_asserteq(ID_CPU_SPEED_1, + ut_asserteq(ID_CPU_SPEED_2, ofnode_read_u32_default(node, "cpu-speed", 0)); - ut_asserteq_str("2 GHz", ofnode_read_string(node, "cpu-speed-str")); + ut_asserteq_str("2.5 GHz", ofnode_read_string(node, "cpu-speed-str")); ut_assert(ofnode_valid(node)); /* There should only be 4 properties */ @@ -93,6 +99,16 @@ static int cedit_fdt(struct unit_test_state *uts) ut_assert_console_end(); + /* reset the expo */ + menu->cur_item_id = ID_CPU_SPEED_1; + + /* load in the settings and make sure they update */ + ut_assertok(run_command("cedit read_fdt hostfs - settings.dtb", 0)); + ut_asserteq(ID_CPU_SPEED_2, menu->cur_item_id); + + ut_assertnonnull(menu); + ut_assert_console_end(); + return 0; } BOOTSTD_TEST(cedit_fdt, 0); -- cgit v1.3.1 From fc9c0e0771cad76b24f73bb64c105b6ea39721ca Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 14 Aug 2023 16:40:35 -0600 Subject: expo: cedit: Support writing settings to environment vars Add a command to write cedit settings to environment variables so that they can be stored with 'saveenv'. Signed-off-by: Simon Glass --- boot/cedit.c | 97 ++++++++++++++++++++++++++++++++++++++++++------- cmd/cedit.c | 22 +++++++++++ doc/usage/cmd/cedit.rst | 25 +++++++++++++ include/cedit.h | 9 +++++ test/boot/cedit.c | 33 +++++++++++++++++ 5 files changed, 172 insertions(+), 14 deletions(-) (limited to 'boot') diff --git a/boot/cedit.c b/boot/cedit.c index 6a74a380989..9399c01cda9 100644 --- a/boot/cedit.c +++ b/boot/cedit.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -24,10 +25,12 @@ * * @buf: Buffer to use when writing settings to the devicetree * @node: Node to read from when reading settings from devicetree + * @verbose: true to show writing to environment variables */ struct cedit_iter_priv { struct abuf *buf; ofnode node; + bool verbose; }; int cedit_arange(struct expo *exp, struct video_priv *vpriv, uint scene_id) @@ -209,6 +212,30 @@ static int check_space(int ret, struct abuf *buf) return 0; } +static int get_cur_menuitem_text(const struct scene_obj_menu *menu, + const char **strp) +{ + struct scene *scn = menu->obj.scene; + const struct scene_menitem *mi; + const struct scene_obj_txt *txt; + const char *str; + + mi = scene_menuitem_find(menu, menu->cur_item_id); + if (!mi) + return log_msg_ret("mi", -ENOENT); + + txt = scene_obj_find(scn, mi->label_id, SCENEOBJT_TEXT); + if (!txt) + return log_msg_ret("txt", -ENOENT); + + str = expo_get_str(scn->expo, txt->str_id); + if (!str) + return log_msg_ret("str", -ENOENT); + *strp = str; + + return 0; +} + static int h_write_settings(struct scene_obj *obj, void *vpriv) { struct cedit_iter_priv *priv = vpriv; @@ -221,9 +248,6 @@ static int h_write_settings(struct scene_obj *obj, void *vpriv) break; case SCENEOBJT_MENU: { const struct scene_obj_menu *menu; - const struct scene_obj_txt *txt; - struct scene *scn = obj->scene; - const struct scene_menitem *mi; const char *str; char name[80]; int ret, i; @@ -243,17 +267,9 @@ static int h_write_settings(struct scene_obj *obj, void *vpriv) if (ret) return log_msg_ret("wrt", -EFAULT); - mi = scene_menuitem_find(menu, menu->cur_item_id); - if (!mi) - return log_msg_ret("mi", -ENOENT); - - txt = scene_obj_find(scn, mi->label_id, SCENEOBJT_TEXT); - if (!txt) - return log_msg_ret("txt", -ENOENT); - - str = expo_get_str(scn->expo, txt->str_id); - if (!str) - return log_msg_ret("str", -ENOENT); + ret = get_cur_menuitem_text(menu, &str); + if (ret) + return log_msg_ret("mis", ret); snprintf(name, sizeof(name), "%s-str", obj->name); ret = -EAGAIN; @@ -370,3 +386,56 @@ int cedit_read_settings(struct expo *exp, oftree tree) return 0; } + +static int h_write_settings_env(struct scene_obj *obj, void *vpriv) +{ + const struct scene_obj_menu *menu; + struct cedit_iter_priv *priv = vpriv; + char name[80], var[60]; + const char *str; + int val, ret; + + if (obj->type != SCENEOBJT_MENU) + return 0; + + menu = (struct scene_obj_menu *)obj; + val = menu->cur_item_id; + snprintf(var, sizeof(var), "c.%s", obj->name); + + if (priv->verbose) + printf("%s=%d\n", var, val); + + ret = env_set_ulong(var, val); + if (ret) + return log_msg_ret("set", ret); + + ret = get_cur_menuitem_text(menu, &str); + if (ret) + return log_msg_ret("mis", ret); + + snprintf(name, sizeof(name), "c.%s-str", obj->name); + if (priv->verbose) + printf("%s=%s\n", name, str); + + ret = env_set(name, str); + if (ret) + return log_msg_ret("st2", ret); + + return 0; +} + +int cedit_write_settings_env(struct expo *exp, bool verbose) +{ + struct cedit_iter_priv priv; + int ret; + + /* write out the items */ + priv.verbose = verbose; + ret = expo_iter_scene_objs(exp, h_write_settings_env, &priv); + if (ret) { + log_debug("Failed to write settings to env (err=%d)\n", ret); + return log_msg_ret("set", ret); + } + + return 0; +} diff --git a/cmd/cedit.c b/cmd/cedit.c index a155e080b1f..85629f7b83c 100644 --- a/cmd/cedit.c +++ b/cmd/cedit.c @@ -136,6 +136,26 @@ static int do_cedit_read_fdt(struct cmd_tbl *cmdtp, int flag, int argc, return 0; } +static int do_cedit_write_env(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + bool verbose; + int ret; + + if (check_cur_expo()) + return CMD_RET_FAILURE; + + verbose = argc > 1 && !strcmp(argv[1], "-v"); + + ret = cedit_write_settings_env(cur_exp, verbose); + if (ret) { + printf("Failed to write settings to environment: %dE\n", ret); + return CMD_RET_FAILURE; + } + + return 0; +} + static int do_cedit_run(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { @@ -167,6 +187,7 @@ static char cedit_help_text[] = "load - load config editor\n" "cedit read_fdt - read settings\n" "cedit write_fdt - write settings\n" + "cedit write_env [-v] - write settings to env vars\n" "cedit run - run config editor"; #endif /* CONFIG_SYS_LONGHELP */ @@ -174,5 +195,6 @@ U_BOOT_CMD_WITH_SUBCMDS(cedit, "Configuration editor", cedit_help_text, U_BOOT_SUBCMD_MKENT(load, 5, 1, do_cedit_load), U_BOOT_SUBCMD_MKENT(read_fdt, 5, 1, do_cedit_read_fdt), U_BOOT_SUBCMD_MKENT(write_fdt, 5, 1, do_cedit_write_fdt), + U_BOOT_SUBCMD_MKENT(write_env, 2, 1, do_cedit_write_env), U_BOOT_SUBCMD_MKENT(run, 1, 1, do_cedit_run), ); diff --git a/doc/usage/cmd/cedit.rst b/doc/usage/cmd/cedit.rst index 0a9f620b59b..426470a82ac 100644 --- a/doc/usage/cmd/cedit.rst +++ b/doc/usage/cmd/cedit.rst @@ -12,6 +12,7 @@ Synopis cedit run cedit write_fdt cedit read_fdt + cedit write_env [-v] Description ----------- @@ -52,6 +53,19 @@ cedit read_fdt Reads the user settings from a devicetree file and updates the cedit with those settings. +cedit write_env +~~~~~~~~~~~~~~~ + +Writes the settings to environment variables. For each menu item the selected +ID and its text string are written, similar to: + + setenv c. + setenv c.-str + +The `-v` flag enables verbose mode, where each variable is printed before it is +set. + + Example ------- @@ -73,3 +87,14 @@ That results in:: } => cedit read_fdt hostfs - settings.dtb + +This shows settings being stored in the environment:: + + => cedit write_env -v + => print + ... + c.cpu-speed=6 + c.cpu-speed-str=2 GHz + c.power-loss=10 + c.power-loss-str=Always Off + ... diff --git a/include/cedit.h b/include/cedit.h index bb6e87d4af7..f261207e209 100644 --- a/include/cedit.h +++ b/include/cedit.h @@ -80,4 +80,13 @@ int cedit_write_settings(struct expo *exp, struct abuf *buf); */ int cedit_read_settings(struct expo *exp, oftree tree); +/** + * cedit_write_settings_env() - Write settings to envrionment variables + * + * @exp: Expo to write settings from + * @verbose: true to print each var as it is set + * Return: 0 if OK, -ve on error + */ +int cedit_write_settings_env(struct expo *exp, bool verbose); + #endif /* __CEDIT_H */ diff --git a/test/boot/cedit.c b/test/boot/cedit.c index 659c47ed35f..26a69f0323f 100644 --- a/test/boot/cedit.c +++ b/test/boot/cedit.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -112,3 +113,35 @@ static int cedit_fdt(struct unit_test_state *uts) return 0; } BOOTSTD_TEST(cedit_fdt, 0); + +/* Check the cedit write_env command */ +static int cedit_env(struct unit_test_state *uts) +{ + struct video_priv *vid_priv; + extern struct expo *cur_exp; + struct scene_obj_menu *menu; + struct scene *scn; + + console_record_reset_enable(); + ut_assertok(run_command("cedit load hostfs - cedit.dtb", 0)); + + ut_asserteq(ID_SCENE1, cedit_prepare(cur_exp, &vid_priv, &scn)); + + /* get a menu to fiddle with */ + menu = scene_obj_find(scn, ID_CPU_SPEED, SCENEOBJT_MENU); + ut_assertnonnull(menu); + menu->cur_item_id = ID_CPU_SPEED_2; + + ut_assertok(run_command("cedit write_env -v", 0)); + ut_assert_nextlinen("c.cpu-speed=7"); + ut_assert_nextlinen("c.cpu-speed-str=2.5 GHz"); + ut_assert_nextlinen("c.power-loss=10"); + ut_assert_nextlinen("c.power-loss-str=Always Off"); + ut_assert_console_end(); + + ut_asserteq(7, env_get_ulong("c.cpu-speed", 10, 0)); + ut_asserteq_str("2.5 GHz", env_get("c.cpu-speed-str")); + + return 0; +} +BOOTSTD_TEST(cedit_env, 0); -- cgit v1.3.1 From bcf2b7202e960e7fb3df8d5e8ed0d6fa00a5a9fa Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 14 Aug 2023 16:40:36 -0600 Subject: expo: cedit: Support reading settings from environment vars Add a command to read cedit settings from environment variables so that they can be restored as part of the environment. Signed-off-by: Simon Glass --- boot/cedit.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ cmd/cedit.c | 22 ++++++++++++++++++++++ doc/usage/cmd/cedit.rst | 19 +++++++++++++++++++ include/cedit.h | 8 ++++++++ test/boot/cedit.c | 12 +++++++++++- 5 files changed, 105 insertions(+), 1 deletion(-) (limited to 'boot') diff --git a/boot/cedit.c b/boot/cedit.c index 9399c01cda9..e3f6dc00399 100644 --- a/boot/cedit.c +++ b/boot/cedit.c @@ -439,3 +439,48 @@ int cedit_write_settings_env(struct expo *exp, bool verbose) return 0; } + +static int h_read_settings_env(struct scene_obj *obj, void *vpriv) +{ + struct cedit_iter_priv *priv = vpriv; + struct scene_obj_menu *menu; + char var[60]; + int val, ret; + + if (obj->type != SCENEOBJT_MENU) + return 0; + + menu = (struct scene_obj_menu *)obj; + val = menu->cur_item_id; + snprintf(var, sizeof(var), "c.%s", obj->name); + + val = env_get_ulong(var, 10, 0); + if (priv->verbose) + printf("%s=%d\n", var, val); + if (!val) + return log_msg_ret("get", -ENOENT); + + /* + * note that no validation is done here, to make sure the ID is valid + * and actually points to a menu item + */ + menu->cur_item_id = val; + + return 0; +} + +int cedit_read_settings_env(struct expo *exp, bool verbose) +{ + struct cedit_iter_priv priv; + int ret; + + /* write out the items */ + priv.verbose = verbose; + ret = expo_iter_scene_objs(exp, h_read_settings_env, &priv); + if (ret) { + log_debug("Failed to read settings from env (err=%d)\n", ret); + return log_msg_ret("set", ret); + } + + return 0; +} diff --git a/cmd/cedit.c b/cmd/cedit.c index 85629f7b83c..b2548f44b57 100644 --- a/cmd/cedit.c +++ b/cmd/cedit.c @@ -156,6 +156,26 @@ static int do_cedit_write_env(struct cmd_tbl *cmdtp, int flag, int argc, return 0; } +static int do_cedit_read_env(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + bool verbose; + int ret; + + if (check_cur_expo()) + return CMD_RET_FAILURE; + + verbose = argc > 1 && !strcmp(argv[1], "-v"); + + ret = cedit_read_settings_env(cur_exp, verbose); + if (ret) { + printf("Failed to read settings from environment: %dE\n", ret); + return CMD_RET_FAILURE; + } + + return 0; +} + static int do_cedit_run(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { @@ -187,6 +207,7 @@ static char cedit_help_text[] = "load - load config editor\n" "cedit read_fdt - read settings\n" "cedit write_fdt - write settings\n" + "cedit read_env [-v] - read settings from env vars\n" "cedit write_env [-v] - write settings to env vars\n" "cedit run - run config editor"; #endif /* CONFIG_SYS_LONGHELP */ @@ -195,6 +216,7 @@ U_BOOT_CMD_WITH_SUBCMDS(cedit, "Configuration editor", cedit_help_text, U_BOOT_SUBCMD_MKENT(load, 5, 1, do_cedit_load), U_BOOT_SUBCMD_MKENT(read_fdt, 5, 1, do_cedit_read_fdt), U_BOOT_SUBCMD_MKENT(write_fdt, 5, 1, do_cedit_write_fdt), + U_BOOT_SUBCMD_MKENT(read_env, 2, 1, do_cedit_read_env), U_BOOT_SUBCMD_MKENT(write_env, 2, 1, do_cedit_write_env), U_BOOT_SUBCMD_MKENT(run, 1, 1, do_cedit_run), ); diff --git a/doc/usage/cmd/cedit.rst b/doc/usage/cmd/cedit.rst index 426470a82ac..1f92b7306a7 100644 --- a/doc/usage/cmd/cedit.rst +++ b/doc/usage/cmd/cedit.rst @@ -13,6 +13,7 @@ Synopis cedit write_fdt cedit read_fdt cedit write_env [-v] + cedit read_env [-v] Description ----------- @@ -53,6 +54,16 @@ cedit read_fdt Reads the user settings from a devicetree file and updates the cedit with those settings. +cedit read_env +~~~~~~~~~~~~~~ + +Reads the settings from the environment variables. For each menu item ``, +cedit looks for a variable called `c.` with the ID of the selected menu +item. + +The `-v` flag enables verbose mode, where each variable is printed after it is +read. + cedit write_env ~~~~~~~~~~~~~~~ @@ -91,6 +102,10 @@ That results in:: This shows settings being stored in the environment:: => cedit write_env -v + c.cpu-speed=7 + c.cpu-speed-str=2.5 GHz + c.power-loss=12 + c.power-loss-str=Memory => print ... c.cpu-speed=6 @@ -98,3 +113,7 @@ This shows settings being stored in the environment:: c.power-loss=10 c.power-loss-str=Always Off ... + + => cedit read_env -v + c.cpu-speed=7 + c.power-loss=12 diff --git a/include/cedit.h b/include/cedit.h index f261207e209..fe10e6c829c 100644 --- a/include/cedit.h +++ b/include/cedit.h @@ -89,4 +89,12 @@ int cedit_read_settings(struct expo *exp, oftree tree); */ int cedit_write_settings_env(struct expo *exp, bool verbose); +/* + * cedit_read_settings_env() - Read settings from the environment + * + * @exp: Expo to read settings into + * @verbose: true to print each var before it is read + */ +int cedit_read_settings_env(struct expo *exp, bool verbose); + #endif /* __CEDIT_H */ diff --git a/test/boot/cedit.c b/test/boot/cedit.c index 26a69f0323f..7cf0c3e4e93 100644 --- a/test/boot/cedit.c +++ b/test/boot/cedit.c @@ -114,7 +114,7 @@ static int cedit_fdt(struct unit_test_state *uts) } BOOTSTD_TEST(cedit_fdt, 0); -/* Check the cedit write_env command */ +/* Check the cedit write_env and read_env commands */ static int cedit_env(struct unit_test_state *uts) { struct video_priv *vid_priv; @@ -142,6 +142,16 @@ static int cedit_env(struct unit_test_state *uts) ut_asserteq(7, env_get_ulong("c.cpu-speed", 10, 0)); ut_asserteq_str("2.5 GHz", env_get("c.cpu-speed-str")); + /* reset the expo */ + menu->cur_item_id = ID_CPU_SPEED_1; + + ut_assertok(run_command("cedit read_env -v", 0)); + ut_assert_nextlinen("c.cpu-speed=7"); + ut_assert_nextlinen("c.power-loss=10"); + ut_assert_console_end(); + + ut_asserteq(ID_CPU_SPEED_2, menu->cur_item_id); + return 0; } BOOTSTD_TEST(cedit_env, 0); -- cgit v1.3.1 From eb6c71b56282d3054dbffb83793e7d2c6745578e Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 14 Aug 2023 16:40:37 -0600 Subject: expo: cedit: Support writing settings to CMOS RAM Add a command to write cedit settings to CMOS RAM so that it can be preserved across a reboot. This uses a simple bit-encoding, where each field has a 'bit position' and a 'bit length' in the schema. Signed-off-by: Simon Glass --- boot/cedit.c | 137 +++++++++++++++++++++++++++++++++++++++- boot/expo_build.c | 7 +- cmd/cedit.c | 36 +++++++++++ doc/develop/expo.rst | 13 ++++ doc/usage/cmd/cedit.rst | 22 +++++++ include/cedit.h | 13 ++++ include/expo.h | 6 +- test/boot/cedit.c | 30 +++++++++ test/boot/files/expo_layout.dts | 5 ++ 9 files changed, 266 insertions(+), 3 deletions(-) (limited to 'boot') diff --git a/boot/cedit.c b/boot/cedit.c index e3f6dc00399..725745aba55 100644 --- a/boot/cedit.c +++ b/boot/cedit.c @@ -15,22 +15,37 @@ #include #include #include +#include #include +#include #include #include #include "scene_internal.h" +enum { + CMOS_MAX_BITS = 2048, + CMOS_MAX_BYTES = CMOS_MAX_BITS / 8, +}; + +#define CMOS_BYTE(bit) ((bit) / 8) +#define CMOS_BIT(bit) ((bit) % 8) + /** * struct cedit_iter_priv - private data for cedit operations * * @buf: Buffer to use when writing settings to the devicetree * @node: Node to read from when reading settings from devicetree * @verbose: true to show writing to environment variables + * @mask: Mask bits for the CMOS RAM. If a bit is set the byte containing it + * will be written + * @value: Value bits for CMOS RAM. This is the actual value written */ struct cedit_iter_priv { struct abuf *buf; ofnode node; bool verbose; + u8 *mask; + u8 *value; }; int cedit_arange(struct expo *exp, struct video_priv *vpriv, uint scene_id) @@ -445,7 +460,7 @@ static int h_read_settings_env(struct scene_obj *obj, void *vpriv) struct cedit_iter_priv *priv = vpriv; struct scene_obj_menu *menu; char var[60]; - int val, ret; + int val; if (obj->type != SCENEOBJT_MENU) return 0; @@ -484,3 +499,123 @@ int cedit_read_settings_env(struct expo *exp, bool verbose) return 0; } + +/** + * get_cur_menuitem_seq() - Get the sequence number of a menu's current item + * + * Enumerates the items of a menu (0, 1, 2) and returns the sequence number of + * the currently selected item. If the first item is selected, this returns 0; + * if the second, 1; etc. + * + * @menu: Menu to check + * Return: Sequence number on success, else -ve error value + */ +static int get_cur_menuitem_seq(const struct scene_obj_menu *menu) +{ + const struct scene_menitem *mi; + int seq, found; + + seq = 0; + found = -1; + list_for_each_entry(mi, &menu->item_head, sibling) { + if (mi->id == menu->cur_item_id) { + found = seq; + break; + } + seq++; + } + + if (found == -1) + return log_msg_ret("nf", -ENOENT); + + return found; +} + +static int h_write_settings_cmos(struct scene_obj *obj, void *vpriv) +{ + const struct scene_obj_menu *menu; + struct cedit_iter_priv *priv = vpriv; + int val, ret; + uint i, seq; + + if (obj->type != SCENEOBJT_MENU) + return 0; + + menu = (struct scene_obj_menu *)obj; + val = menu->cur_item_id; + + ret = get_cur_menuitem_seq(menu); + if (ret < 0) + return log_msg_ret("cur", ret); + seq = ret; + log_debug("%s: seq=%d\n", menu->obj.name, seq); + + /* figure out where to place this item */ + if (!obj->bit_length) + return log_msg_ret("len", -EINVAL); + if (obj->start_bit + obj->bit_length > CMOS_MAX_BITS) + return log_msg_ret("bit", -E2BIG); + + for (i = 0; i < obj->bit_length; i++, seq >>= 1) { + uint bitnum = obj->start_bit + i; + + priv->mask[CMOS_BYTE(bitnum)] |= 1 << CMOS_BIT(bitnum); + if (seq & 1) + priv->value[CMOS_BYTE(bitnum)] |= BIT(CMOS_BIT(bitnum)); + log_debug("bit %x %x %x\n", bitnum, + priv->mask[CMOS_BYTE(bitnum)], + priv->value[CMOS_BYTE(bitnum)]); + } + + return 0; +} + +int cedit_write_settings_cmos(struct expo *exp, struct udevice *dev, + bool verbose) +{ + struct cedit_iter_priv priv; + int ret, i, count, first, last; + + /* write out the items */ + priv.mask = calloc(1, CMOS_MAX_BYTES); + if (!priv.mask) + return log_msg_ret("mas", -ENOMEM); + priv.value = calloc(1, CMOS_MAX_BYTES); + if (!priv.value) { + free(priv.mask); + return log_msg_ret("val", -ENOMEM); + } + + ret = expo_iter_scene_objs(exp, h_write_settings_cmos, &priv); + if (ret) { + log_debug("Failed to write CMOS (err=%d)\n", ret); + ret = log_msg_ret("set", ret); + goto done; + } + + /* write the data to the RTC */ + first = CMOS_MAX_BYTES; + last = -1; + for (i = 0, count = 0; i < CMOS_MAX_BYTES; i++) { + if (priv.mask[i]) { + log_debug("Write byte %x: %x\n", i, priv.value[i]); + ret = rtc_write8(dev, i, priv.value[i]); + if (ret) { + ret = log_msg_ret("wri", ret); + goto done; + } + count++; + first = min(first, i); + last = max(last, i); + } + } + if (verbose) { + printf("Write %d bytes from offset %x to %x\n", count, first, + last); + } + +done: + free(priv.mask); + free(priv.value); + return ret; +} diff --git a/boot/expo_build.c b/boot/expo_build.c index e8c4a40d3f0..bb33cc2a33f 100644 --- a/boot/expo_build.c +++ b/boot/expo_build.c @@ -294,7 +294,7 @@ static int obj_build(struct build_info *info, ofnode node, struct scene *scn) { struct scene_obj *obj; const char *type; - u32 id; + u32 id, val; int ret; log_debug("- object %s\n", ofnode_get_name(node)); @@ -313,6 +313,11 @@ static int obj_build(struct build_info *info, ofnode node, struct scene *scn) if (ret) return log_msg_ret("bld", ret); + if (!ofnode_read_u32(node, "start-bit", &val)) + obj->start_bit = val; + if (!ofnode_read_u32(node, "bit-length", &val)) + obj->bit_length = val; + return 0; } diff --git a/cmd/cedit.c b/cmd/cedit.c index b2548f44b57..95d5c22c2f7 100644 --- a/cmd/cedit.c +++ b/cmd/cedit.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -176,6 +177,39 @@ static int do_cedit_read_env(struct cmd_tbl *cmdtp, int flag, int argc, return 0; } +static int do_cedit_write_cmos(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct udevice *dev; + bool verbose = false; + int ret; + + if (check_cur_expo()) + return CMD_RET_FAILURE; + + if (argc > 1 && !strcmp(argv[1], "-v")) { + verbose = true; + argc--; + argv++; + } + + if (argc > 1) + ret = uclass_get_device_by_name(UCLASS_RTC, argv[1], &dev); + else + ret = uclass_first_device_err(UCLASS_RTC, &dev); + if (ret) { + printf("Failed to get RTC device: %dE\n", ret); + return CMD_RET_FAILURE; + } + + if (cedit_write_settings_cmos(cur_exp, dev, verbose)) { + printf("Failed to write settings to CMOS\n"); + return CMD_RET_FAILURE; + } + + return 0; +} + static int do_cedit_run(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { @@ -209,6 +243,7 @@ static char cedit_help_text[] = "cedit write_fdt - write settings\n" "cedit read_env [-v] - read settings from env vars\n" "cedit write_env [-v] - write settings to env vars\n" + "cedit write_cmos [-v] [dev] - write settings to CMOS RAM\n" "cedit run - run config editor"; #endif /* CONFIG_SYS_LONGHELP */ @@ -218,5 +253,6 @@ U_BOOT_CMD_WITH_SUBCMDS(cedit, "Configuration editor", cedit_help_text, U_BOOT_SUBCMD_MKENT(write_fdt, 5, 1, do_cedit_write_fdt), U_BOOT_SUBCMD_MKENT(read_env, 2, 1, do_cedit_read_env), U_BOOT_SUBCMD_MKENT(write_env, 2, 1, do_cedit_write_env), + U_BOOT_SUBCMD_MKENT(write_cmos, 2, 1, do_cedit_write_cmos), U_BOOT_SUBCMD_MKENT(run, 1, 1, do_cedit_run), ); diff --git a/doc/develop/expo.rst b/doc/develop/expo.rst index fde91494799..61b6855c72f 100644 --- a/doc/develop/expo.rst +++ b/doc/develop/expo.rst @@ -317,6 +317,18 @@ id Specifies the ID of the object. This is used when referring to the object. +Where CMOS RAM is used for reading and writing settings, the following +additional properties are required: + +start-bit + Specifies the first bit in the CMOS RAM to use for this setting. For a RAM + with 0x100 bytes, there are 0x800 bit locations. For example, register 0x80 + holds bits 0x400 to 0x407. + +bit-length + Specifies the number of CMOS RAM bits to use for this setting. The bits + extend from `start-bit` to `start-bit + bit-length - 1`. Note that the bits + must be contiguous. Menu nodes have the following additional properties: @@ -474,6 +486,7 @@ Some ideas for future work: - Support curses for proper serial-terminal menus - Add support for large menus which need to scroll - Add support for reading and writing configuration settings with cedit +- Update expo.py tool to check for overlapping names and CMOS locations .. Simon Glass .. 7-Oct-22 diff --git a/doc/usage/cmd/cedit.rst b/doc/usage/cmd/cedit.rst index 1f92b7306a7..3d6f26e631d 100644 --- a/doc/usage/cmd/cedit.rst +++ b/doc/usage/cmd/cedit.rst @@ -14,6 +14,7 @@ Synopis cedit read_fdt cedit write_env [-v] cedit read_env [-v] + cedit write_cmos [-v] [dev] Description ----------- @@ -76,6 +77,18 @@ ID and its text string are written, similar to: The `-v` flag enables verbose mode, where each variable is printed before it is set. +cedit write_cmos +~~~~~~~~~~~~~~~~ + +Writes the settings to locations in the CMOS RAM. The locations used are +specified by the schema. See `expo_format_`. + +The `-v` flag enables verbose mode, which shows which CMOS locations were +updated. + +Normally the first RTC device is used to hold the data. You can specify a +different device by name using the `dev` parameter. + Example ------- @@ -117,3 +130,12 @@ This shows settings being stored in the environment:: => cedit read_env -v c.cpu-speed=7 c.power-loss=12 + +This shows writing to CMOS RAM. Notice that the bytes at 80 and 84 change:: + + => rtc read 80 8 + 00000080: 00 00 00 00 00 2f 2a 08 ...../*. + => cedit write_cmos + Write 2 bytes from offset 80 to 84 + => rtc read 80 8 + 00000080: 01 00 00 00 08 2f 2a 08 ...../*. diff --git a/include/cedit.h b/include/cedit.h index fe10e6c829c..2970965b5f6 100644 --- a/include/cedit.h +++ b/include/cedit.h @@ -97,4 +97,17 @@ int cedit_write_settings_env(struct expo *exp, bool verbose); */ int cedit_read_settings_env(struct expo *exp, bool verbose); +/** + * cedit_write_settings_cmos() - Write settings to CMOS RAM + * + * Write settings to the defined places in CMOS RAM + * + * @exp: Expo to write settings from + * @dev: UCLASS_RTC device containing space for this information + * Returns 0 if OK, -ve on error + * @verbose: true to print a summary at the end + */ +int cedit_write_settings_cmos(struct expo *exp, struct udevice *dev, + bool verbose); + #endif /* __CEDIT_H */ diff --git a/include/expo.h b/include/expo.h index da151074d20..a2b3a71c159 100644 --- a/include/expo.h +++ b/include/expo.h @@ -187,6 +187,8 @@ enum scene_obj_flags_t { * @type: Type of this object * @dim: Dimensions for this object * @flags: Flags for this object + * @bit_length: Number of bits used for this object in CMOS RAM + * @start_bit: Start bit to use for this object in CMOS RAM * @sibling: Node to link this object to its siblings */ struct scene_obj { @@ -195,7 +197,9 @@ struct scene_obj { uint id; enum scene_obj_t type; struct scene_dim dim; - int flags; + u8 flags; + u8 bit_length; + u16 start_bit; struct list_head sibling; }; diff --git a/test/boot/cedit.c b/test/boot/cedit.c index 7cf0c3e4e93..010aae615b9 100644 --- a/test/boot/cedit.c +++ b/test/boot/cedit.c @@ -155,3 +155,33 @@ static int cedit_env(struct unit_test_state *uts) return 0; } BOOTSTD_TEST(cedit_env, 0); + +/* Check the cedit write_cmos and read_cmos commands */ +static int cedit_cmos(struct unit_test_state *uts) +{ + struct scene_obj_menu *menu, *menu2; + struct video_priv *vid_priv; + extern struct expo *cur_exp; + struct scene *scn; + + console_record_reset_enable(); + ut_assertok(run_command("cedit load hostfs - cedit.dtb", 0)); + + ut_asserteq(ID_SCENE1, cedit_prepare(cur_exp, &vid_priv, &scn)); + + /* get the menus to fiddle with */ + menu = scene_obj_find(scn, ID_CPU_SPEED, SCENEOBJT_MENU); + ut_assertnonnull(menu); + menu->cur_item_id = ID_CPU_SPEED_2; + + menu2 = scene_obj_find(scn, ID_POWER_LOSS, SCENEOBJT_MENU); + ut_assertnonnull(menu2); + menu2->cur_item_id = ID_AC_MEMORY; + + ut_assertok(run_command("cedit write_cmos -v", 0)); + ut_assert_nextlinen("Write 2 bytes from offset 80 to 84"); + ut_assert_console_end(); + + return 0; +} +BOOTSTD_TEST(cedit_cmos, 0); diff --git a/test/boot/files/expo_layout.dts b/test/boot/files/expo_layout.dts index 913140bace9..cb2a674d9d5 100644 --- a/test/boot/files/expo_layout.dts +++ b/test/boot/files/expo_layout.dts @@ -38,6 +38,9 @@ /* IDs for the menu items */ item-id = ; + + start-bit = <0x400>; + bit-length = <2>; }; power-loss { @@ -49,6 +52,8 @@ "Memory"; item-id = ; + start-bit = <0x422>; + bit-length = <2>; }; }; }; -- cgit v1.3.1 From cfc402db3954d7c852c322b232ad6d8842af6bf1 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 14 Aug 2023 16:40:38 -0600 Subject: expo: cedit: Support reading settings from CMOS RAM Add a command to read edit settings from CMOS RAM, using the cedit definition to indicate which registers and bits are used. Signed-off-by: Simon Glass --- boot/cedit.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++ boot/scene_internal.h | 12 ++++++ boot/scene_menu.c | 16 ++++++++ cmd/cedit.c | 36 ++++++++++++++++++ doc/usage/cmd/cedit.rst | 9 ++++- include/cedit.h | 12 ++++++ test/boot/cedit.c | 11 ++++++ 7 files changed, 194 insertions(+), 1 deletion(-) (limited to 'boot') diff --git a/boot/cedit.c b/boot/cedit.c index 725745aba55..73645f70b6c 100644 --- a/boot/cedit.c +++ b/boot/cedit.c @@ -39,6 +39,7 @@ enum { * @mask: Mask bits for the CMOS RAM. If a bit is set the byte containing it * will be written * @value: Value bits for CMOS RAM. This is the actual value written + * @dev: RTC device to write to */ struct cedit_iter_priv { struct abuf *buf; @@ -46,6 +47,7 @@ struct cedit_iter_priv { bool verbose; u8 *mask; u8 *value; + struct udevice *dev; }; int cedit_arange(struct expo *exp, struct video_priv *vpriv, uint scene_id) @@ -619,3 +621,100 @@ done: free(priv.value); return ret; } + +static int h_read_settings_cmos(struct scene_obj *obj, void *vpriv) +{ + struct cedit_iter_priv *priv = vpriv; + const struct scene_menitem *mi; + struct scene_obj_menu *menu; + int val, ret; + uint i; + + if (obj->type != SCENEOBJT_MENU) + return 0; + + menu = (struct scene_obj_menu *)obj; + + /* figure out where to place this item */ + if (!obj->bit_length) + return log_msg_ret("len", -EINVAL); + if (obj->start_bit + obj->bit_length > CMOS_MAX_BITS) + return log_msg_ret("bit", -E2BIG); + + val = 0; + for (i = 0; i < obj->bit_length; i++) { + uint bitnum = obj->start_bit + i; + uint offset = CMOS_BYTE(bitnum); + + /* read the byte if not already read */ + if (!priv->mask[offset]) { + ret = rtc_read8(priv->dev, offset); + if (ret < 0) + return log_msg_ret("rea", ret); + priv->value[offset] = ret; + + /* mark it as read */ + priv->mask[offset] = 0xff; + } + + if (priv->value[offset] & BIT(CMOS_BIT(bitnum))) + val |= BIT(i); + log_debug("bit %x %x\n", bitnum, val); + } + + /* update the current item */ + mi = scene_menuitem_find_seq(menu, val); + if (!mi) + return log_msg_ret("seq", -ENOENT); + + menu->cur_item_id = mi->id; + log_debug("Update menu %d cur_item_id %d\n", menu->obj.id, mi->id); + + return 0; +} + +int cedit_read_settings_cmos(struct expo *exp, struct udevice *dev, + bool verbose) +{ + struct cedit_iter_priv priv; + int ret, i, count, first, last; + + /* read in the items */ + priv.mask = calloc(1, CMOS_MAX_BYTES); + if (!priv.mask) + return log_msg_ret("mas", -ENOMEM); + priv.value = calloc(1, CMOS_MAX_BYTES); + if (!priv.value) { + free(priv.mask); + return log_msg_ret("val", -ENOMEM); + } + priv.dev = dev; + + ret = expo_iter_scene_objs(exp, h_read_settings_cmos, &priv); + if (ret) { + log_debug("Failed to read CMOS (err=%d)\n", ret); + ret = log_msg_ret("set", ret); + goto done; + } + + /* read the data to the RTC */ + first = CMOS_MAX_BYTES; + last = -1; + for (i = 0, count = 0; i < CMOS_MAX_BYTES; i++) { + if (priv.mask[i]) { + log_debug("Read byte %x: %x\n", i, priv.value[i]); + count++; + first = min(first, i); + last = max(last, i); + } + } + if (verbose) { + printf("Read %d bytes from offset %x to %x\n", count, first, + last); + } + +done: + free(priv.mask); + free(priv.value); + return ret; +} diff --git a/boot/scene_internal.h b/boot/scene_internal.h index 23e29cb349b..695a907dc6a 100644 --- a/boot/scene_internal.h +++ b/boot/scene_internal.h @@ -234,4 +234,16 @@ int expo_iter_scene_objs(struct expo *exp, expo_scene_obj_iterator iter, struct scene_menitem *scene_menuitem_find(const struct scene_obj_menu *menu, int id); +/** + * scene_menuitem_find_seq() - Find the menu item at a sequential position + * + * This numbers the items from 0 and returns the seq'th one + * + * @menu: Menu to check + * @seq: Sequence number to look for + * Return: menu item if found, else NULL + */ +struct scene_menitem *scene_menuitem_find_seq(const struct scene_obj_menu *menu, + uint seq); + #endif /* __SCENE_INTERNAL_H */ diff --git a/boot/scene_menu.c b/boot/scene_menu.c index 602fe24580a..e0dcd0a4e04 100644 --- a/boot/scene_menu.c +++ b/boot/scene_menu.c @@ -46,6 +46,22 @@ struct scene_menitem *scene_menuitem_find(const struct scene_obj_menu *menu, return NULL; } +struct scene_menitem *scene_menuitem_find_seq(const struct scene_obj_menu *menu, + uint seq) +{ + struct scene_menitem *item; + uint i; + + i = 0; + list_for_each_entry(item, &menu->item_head, sibling) { + if (i == seq) + return item; + i++; + } + + return NULL; +} + /** * update_pointers() - Update the pointer object and handle highlights * diff --git a/cmd/cedit.c b/cmd/cedit.c index 95d5c22c2f7..2ff284f4cde 100644 --- a/cmd/cedit.c +++ b/cmd/cedit.c @@ -210,6 +210,40 @@ static int do_cedit_write_cmos(struct cmd_tbl *cmdtp, int flag, int argc, return 0; } +static int do_cedit_read_cmos(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct udevice *dev; + bool verbose = false; + int ret; + + if (check_cur_expo()) + return CMD_RET_FAILURE; + + if (argc > 1 && !strcmp(argv[1], "-v")) { + verbose = true; + argc--; + argv++; + } + + if (argc > 1) + ret = uclass_get_device_by_name(UCLASS_RTC, argv[1], &dev); + else + ret = uclass_first_device_err(UCLASS_RTC, &dev); + if (ret) { + printf("Failed to get RTC device: %dE\n", ret); + return CMD_RET_FAILURE; + } + + ret = cedit_read_settings_cmos(cur_exp, dev, verbose); + if (ret) { + printf("Failed to read settings from CMOS: %dE\n", ret); + return CMD_RET_FAILURE; + } + + return 0; +} + static int do_cedit_run(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { @@ -243,6 +277,7 @@ static char cedit_help_text[] = "cedit write_fdt - write settings\n" "cedit read_env [-v] - read settings from env vars\n" "cedit write_env [-v] - write settings to env vars\n" + "cedit read_cmos [-v] [dev] - read settings from CMOS RAM\n" "cedit write_cmos [-v] [dev] - write settings to CMOS RAM\n" "cedit run - run config editor"; #endif /* CONFIG_SYS_LONGHELP */ @@ -253,6 +288,7 @@ U_BOOT_CMD_WITH_SUBCMDS(cedit, "Configuration editor", cedit_help_text, U_BOOT_SUBCMD_MKENT(write_fdt, 5, 1, do_cedit_write_fdt), U_BOOT_SUBCMD_MKENT(read_env, 2, 1, do_cedit_read_env), U_BOOT_SUBCMD_MKENT(write_env, 2, 1, do_cedit_write_env), + U_BOOT_SUBCMD_MKENT(read_cmos, 2, 1, do_cedit_read_cmos), U_BOOT_SUBCMD_MKENT(write_cmos, 2, 1, do_cedit_write_cmos), U_BOOT_SUBCMD_MKENT(run, 1, 1, do_cedit_run), ); diff --git a/doc/usage/cmd/cedit.rst b/doc/usage/cmd/cedit.rst index 3d6f26e631d..f415b48699e 100644 --- a/doc/usage/cmd/cedit.rst +++ b/doc/usage/cmd/cedit.rst @@ -135,7 +135,14 @@ This shows writing to CMOS RAM. Notice that the bytes at 80 and 84 change:: => rtc read 80 8 00000080: 00 00 00 00 00 2f 2a 08 ...../*. - => cedit write_cmos + => cedit write_cmos -v Write 2 bytes from offset 80 to 84 => rtc read 80 8 00000080: 01 00 00 00 08 2f 2a 08 ...../*. + => cedit read_cmos -v + Read 2 bytes from offset 80 to 84 + +Here is an example with the device specified:: + + => cedit write_cmos rtc@43 + => diff --git a/include/cedit.h b/include/cedit.h index 2970965b5f6..f43cafa5aa2 100644 --- a/include/cedit.h +++ b/include/cedit.h @@ -110,4 +110,16 @@ int cedit_read_settings_env(struct expo *exp, bool verbose); int cedit_write_settings_cmos(struct expo *exp, struct udevice *dev, bool verbose); +/** + * cedit_read_settings_cmos() - Read settings from CMOS RAM + * + * Read settings from the defined places in CMO RAM + * + * @exp: Expo to read settings into + * @dev: RTC device to read settings from + * @verbose: true to print a summary at the end + */ +int cedit_read_settings_cmos(struct expo *exp, struct udevice *dev, + bool verbose); + #endif /* __CEDIT_H */ diff --git a/test/boot/cedit.c b/test/boot/cedit.c index 010aae615b9..ab2b8a1f9ff 100644 --- a/test/boot/cedit.c +++ b/test/boot/cedit.c @@ -182,6 +182,17 @@ static int cedit_cmos(struct unit_test_state *uts) ut_assert_nextlinen("Write 2 bytes from offset 80 to 84"); ut_assert_console_end(); + /* reset the expo */ + menu->cur_item_id = ID_CPU_SPEED_1; + menu2->cur_item_id = ID_AC_OFF; + + ut_assertok(run_command("cedit read_cmos -v", 0)); + ut_assert_nextlinen("Read 2 bytes from offset 80 to 84"); + ut_assert_console_end(); + + ut_asserteq(ID_CPU_SPEED_2, menu->cur_item_id); + ut_asserteq(ID_AC_MEMORY, menu2->cur_item_id); + return 0; } BOOTSTD_TEST(cedit_cmos, 0); -- cgit v1.3.1 From b2b7e6c1812d2b6bea517ea8f7df5c23ae04ce84 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 24 Aug 2023 13:55:33 -0600 Subject: part: Add an accessor for struct disk_partition sys_ind This field is only present when a CONFIG is set. To avoid annoying #ifdefs in the source code, add an accessor. Update the only usage. Note that the accessor is optional. It can be omitted if it is known that the option is enabled. Signed-off-by: Simon Glass --- boot/bootdev-uclass.c | 7 +++---- include/part.h | 12 ++++++++++++ 2 files changed, 15 insertions(+), 4 deletions(-) (limited to 'boot') diff --git a/boot/bootdev-uclass.c b/boot/bootdev-uclass.c index fa52bc3a9c4..c4044d87dc3 100644 --- a/boot/bootdev-uclass.c +++ b/boot/bootdev-uclass.c @@ -184,12 +184,11 @@ int bootdev_find_in_blk(struct udevice *dev, struct udevice *blk, if (ret) return log_msg_ret("fs", ret); - /* Use an #ifdef due to info.sys_ind */ -#ifdef CONFIG_DOS_PARTITION log_debug("%s: Found partition %x type %x fstype %d\n", - blk->name, bflow->part, info.sys_ind, + blk->name, bflow->part, + IS_ENABLED(CONFIG_DOS_PARTITION) ? + disk_partition_sys_ind(&info) : 0, ret ? -1 : fs_get_type()); -#endif bflow->blk = blk; bflow->state = BOOTFLOWST_FS; } diff --git a/include/part.h b/include/part.h index 5cf1c5ec96f..16ba8c10253 100644 --- a/include/part.h +++ b/include/part.h @@ -135,6 +135,18 @@ static inline void disk_partition_clr_type_guid(struct disk_partition *info) #endif } +/* Accessors for struct disk_partition field ->sys_ind */ +extern int __invalid_use_of_disk_partition_sys_ind; + +static inline uint disk_partition_sys_ind(const struct disk_partition *info) +{ +#ifdef CONFIG_DOS_PARTITION + return info->sys_ind; +#else + return __invalid_use_of_disk_partition_sys_ind; +#endif +} + struct disk_part { int partnum; struct disk_partition gpt_part_info; -- cgit v1.3.1 From 831405f41de122c2a3a0908f07c632c87266709a Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 24 Aug 2023 13:55:43 -0600 Subject: bootstd: Support bootmeths which can scan any partition Some bootmeths support scanning a partition without a filesystem on it. Add a flag to support this. This will allow the ChromiumOS bootmeth to find kernel partition, which are stored in a special format, without a filesystem. Signed-off-by: Simon Glass --- boot/bootdev-uclass.c | 17 ++++++++++++++--- doc/develop/bootstd.rst | 11 ++++++----- include/bootmeth.h | 3 +++ 3 files changed, 23 insertions(+), 8 deletions(-) (limited to 'boot') diff --git a/boot/bootdev-uclass.c b/boot/bootdev-uclass.c index c4044d87dc3..69506e3865f 100644 --- a/boot/bootdev-uclass.c +++ b/boot/bootdev-uclass.c @@ -111,6 +111,8 @@ int bootdev_bind(struct udevice *parent, const char *drv_name, const char *name, int bootdev_find_in_blk(struct udevice *dev, struct udevice *blk, struct bootflow_iter *iter, struct bootflow *bflow) { + struct bootmeth_uc_plat *plat = dev_get_uclass_plat(bflow->method); + bool allow_any_part = plat->flags & BOOTMETHF_ANY_PART; struct blk_desc *desc = dev_get_uclass_plat(blk); struct disk_partition info; char partstr[20]; @@ -142,6 +144,7 @@ int bootdev_find_in_blk(struct udevice *dev, struct udevice *blk, * us whether there is valid media there */ ret = part_get_info(desc, iter->part, &info); + log_debug("part_get_info() returned %d\n", ret); if (!iter->part && ret == -ENOENT) ret = 0; @@ -154,7 +157,7 @@ int bootdev_find_in_blk(struct udevice *dev, struct udevice *blk, ret = -ESHUTDOWN; else bflow->state = BOOTFLOWST_MEDIA; - if (ret) { + if (ret && !allow_any_part) { /* allow partition 1 to be missing */ if (iter->part == 1) { iter->max_part = 3; @@ -174,9 +177,15 @@ int bootdev_find_in_blk(struct udevice *dev, struct udevice *blk, if (!iter->part) { iter->first_bootable = part_get_bootable(desc); log_debug("checking bootable=%d\n", iter->first_bootable); + } else if (allow_any_part) { + /* + * allow any partition to be scanned, by skipping any checks + * for filesystems or partition contents on this disk + */ /* if there are bootable partitions, scan only those */ - } else if (iter->first_bootable ? !info.bootable : iter->part != 1) { + } else if (iter->first_bootable >= 0 && + (iter->first_bootable ? !info.bootable : iter->part != 1)) { return log_msg_ret("boot", -EINVAL); } else { ret = fs_set_blk_dev_with_part(desc, bflow->part); @@ -193,6 +202,7 @@ int bootdev_find_in_blk(struct udevice *dev, struct udevice *blk, bflow->state = BOOTFLOWST_FS; } + log_debug("method %s\n", bflow->method->name); ret = bootmeth_read_bootflow(bflow->method, bflow); if (ret) return log_msg_ret("method", ret); @@ -559,7 +569,8 @@ int bootdev_get_bootflow(struct udevice *dev, struct bootflow_iter *iter, { const struct bootdev_ops *ops = bootdev_get_ops(dev); - log_debug("->get_bootflow %s=%p\n", dev->name, ops->get_bootflow); + log_debug("->get_bootflow %s,%x=%p\n", dev->name, iter->part, + ops->get_bootflow); bootflow_init(bflow, dev, iter->method); if (!ops->get_bootflow) return default_get_bootflow(dev, iter, bflow); diff --git a/doc/develop/bootstd.rst b/doc/develop/bootstd.rst index ec313653578..c01e0971dc8 100644 --- a/doc/develop/bootstd.rst +++ b/doc/develop/bootstd.rst @@ -677,11 +677,12 @@ Assuming the bootmeth is happy, or at least indicates that it is willing to try partition. If that works it tries to detect a file system. If that works then it calls the bootmeth device once more, this time to read the bootflow. -Note: At present a filesystem is needed for the bootmeth to be called on block -devices, simply because we don't have any examples where this is not the case. -This feature can be added as needed. Note that sandbox is a special case, since -in that case the host filesystem can be accessed even though the block device -is NULL. +Note: Normally a filesystem is needed for the bootmeth to be called on block +devices, but bootmeths which don't need that can set the BOOTMETHF_ANY_PART +flag to indicate that they can scan any partition. An example is the ChromiumOS +bootmeth which can store a kernel in a raw partition. Note also that sandbox is +a special case, since in that case the host filesystem can be accessed even +though the block device is NULL. If we take the example of the `bootmeth_extlinux` driver, this call ends up at `extlinux_read_bootflow()`. It has the filesystem ready, so tries various diff --git a/include/bootmeth.h b/include/bootmeth.h index d3d8d608cd7..0fc36104ece 100644 --- a/include/bootmeth.h +++ b/include/bootmeth.h @@ -16,9 +16,12 @@ struct udevice; * enum bootmeth_flags - Flags for bootmeths * * @BOOTMETHF_GLOBAL: bootmeth handles bootdev selection automatically + * @BOOTMETHF_ANY_PART: bootmeth is willing to check any partition, even if it + * has no filesystem */ enum bootmeth_flags { BOOTMETHF_GLOBAL = BIT(0), + BOOTMETHF_ANY_PART = BIT(1), }; /** -- cgit v1.3.1 From 71f634b822ae6613c43fc960d5afbe5b5d728fb4 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 24 Aug 2023 13:55:45 -0600 Subject: bootstd: cros: Allow detection of any kernel partition The existing ChromiumOS bootmeth only supports reading a single kernel partition, either 2 or 4. In fact there are normally two options available. Use the GUID to detect kernel partitions, with the BOOTMETHF_ANY_PART flag, so that bootstd does not require a valid filesystem before calling the bootmeth. Tidy up and improve the logging while we are here. Signed-off-by: Simon Glass Suggested-by: Alper Nebi Yasak [trini: Add missing select of PARTITION_TYPE_GUID] Signed-off-by: Tom Rini --- boot/Kconfig | 3 +++ boot/bootmeth_cros.c | 48 ++++++++++++++++++++++++++++++------------------ test/boot/bootflow.c | 5 +++-- 3 files changed, 36 insertions(+), 20 deletions(-) (limited to 'boot') diff --git a/boot/Kconfig b/boot/Kconfig index 5e2d4286aea..86ccfd78031 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -466,6 +466,9 @@ config BOOTMETH_CROS bool "Bootdev support for Chromium OS" depends on X86 || ARM || SANDBOX default y if !ARM + select EFI_PARTITION + select PARTITION_TYPE_GUID + select PARTITION_UUIDS help Enables support for booting Chromium OS using bootdevs. This uses the kernel A slot and obtains the kernel command line from the parameters diff --git a/boot/bootmeth_cros.c b/boot/bootmeth_cros.c index 1776fb1838c..20e0b1e89c3 100644 --- a/boot/bootmeth_cros.c +++ b/boot/bootmeth_cros.c @@ -16,16 +16,19 @@ #include #include #include +#include #include #include #include #include #include "bootmeth_cros.h" +static const efi_guid_t cros_kern_type = PARTITION_CROS_KERNEL; + /* * Layout of the ChromeOS kernel * - * Partitions 2 and 4 contain kernels + * Partitions 2 and 4 contain kernels with type GUID_CROS_KERNEL * * Contents are: * @@ -145,13 +148,25 @@ static int scan_part(struct udevice *blk, int partnum, { struct blk_desc *desc = dev_get_uclass_plat(blk); struct vb2_keyblock *hdr; + struct uuid type; ulong num_blks; int ret; + if (!partnum) + return log_msg_ret("efi", -ENOENT); + ret = part_get_info(desc, partnum, info); if (ret) return log_msg_ret("part", ret); + /* Check for kernel partition type */ + log_debug("part %x: type=%s\n", partnum, info->type_guid); + if (uuid_str_to_bin(info->type_guid, (u8 *)&type, UUID_STR_FORMAT_GUID)) + return log_msg_ret("typ", -EINVAL); + + if (memcmp(&cros_kern_type, &type, sizeof(type))) + return log_msg_ret("typ", -ENOEXEC); + /* Make a buffer for the header information */ num_blks = PROBE_SIZE >> desc->log2blksz; log_debug("Reading header, blk=%s, start=%lx, blocks=%lx\n", @@ -167,6 +182,7 @@ static int scan_part(struct udevice *blk, int partnum, if (memcmp(VB2_KEYBLOCK_MAGIC, hdr->magic, VB2_KEYBLOCK_MAGIC_SIZE)) { free(hdr); + log_debug("no magic\n"); return -ENOENT; } @@ -340,24 +356,16 @@ static int cros_read_bootflow(struct udevice *dev, struct bootflow *bflow) struct vb2_keyblock *hdr; const char *uuid = NULL; struct cros_priv *priv; - int part, ret; - - log_debug("starting, part=%d\n", bflow->part); + int ret; - /* We consider the whole disk, not any one partition */ - if (bflow->part) - return log_msg_ret("max", -ENOENT); + log_debug("starting, part=%x\n", bflow->part); - /* Check partition 2 then 4 */ - part = 2; - ret = scan_part(bflow->blk, part, &info, &hdr); + /* Check for kernel partitions */ + ret = scan_part(bflow->blk, bflow->part, &info, &hdr); if (ret) { - part = 4; - ret = scan_part(bflow->blk, part, &info, &hdr); - if (ret) - return log_msg_ret("scan", ret); + log_debug("- scan failed: err=%d\n", ret); + return log_msg_ret("scan", ret); } - bflow->part = part; priv = malloc(sizeof(struct cros_priv)); if (!priv) { @@ -366,8 +374,8 @@ static int cros_read_bootflow(struct udevice *dev, struct bootflow *bflow) } bflow->bootmeth_priv = priv; - log_info("Selected partition %d, header at %lx\n", bflow->part, - (ulong)map_to_sysmem(hdr)); + log_debug("Selected partition %d, header at %lx\n", bflow->part, + (ulong)map_to_sysmem(hdr)); /* Grab a few things from the preamble */ preamble = (void *)hdr + hdr->keyblock_size; @@ -381,8 +389,11 @@ static int cros_read_bootflow(struct udevice *dev, struct bootflow *bflow) ret = cros_read_info(bflow, uuid, preamble); preamble = NULL; free(hdr); - if (ret) + if (ret) { + free(priv->info_buf); + free(priv); return log_msg_ret("inf", ret); + } bflow->size = priv->body_size; bflow->state = BOOTFLOWST_READY; @@ -437,6 +448,7 @@ static int cros_bootmeth_bind(struct udevice *dev) struct bootmeth_uc_plat *plat = dev_get_uclass_plat(dev); plat->desc = "ChromiumOS boot"; + plat->flags = BOOTMETHF_ANY_PART; return 0; } diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c index ae34370981c..1ff2320c036 100644 --- a/test/boot/bootflow.c +++ b/test/boot/bootflow.c @@ -983,9 +983,10 @@ static int bootflow_cros(struct unit_test_state *uts) ut_assert_nextlinen("Seq"); ut_assert_nextlinen("---"); ut_assert_nextlinen(" 0 extlinux"); - ut_assert_nextlinen(" 1 cros ready mmc 2 mmc5.bootdev.whole "); + ut_assert_nextlinen(" 1 cros ready mmc 2 mmc5.bootdev.part_2 "); + ut_assert_nextlinen(" 2 cros ready mmc 4 mmc5.bootdev.part_4 "); ut_assert_nextlinen("---"); - ut_assert_skip_to_line("(2 bootflows, 2 valid)"); + ut_assert_skip_to_line("(3 bootflows, 3 valid)"); ut_assert_console_end(); -- cgit v1.3.1 From 6c4cad74382aed5d6bd08b4a62b8747c98310dea Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 21 Aug 2023 21:16:57 -0600 Subject: event: Rename EVENT_SPY to EVENT_SPY_FULL The new name makes it clearer that this is for a full spy, with access to the context and the event data. Signed-off-by: Simon Glass --- boot/vbe_request.c | 2 +- boot/vbe_simple_os.c | 2 +- include/event.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'boot') diff --git a/boot/vbe_request.c b/boot/vbe_request.c index 312edfa2bdb..2f218d4bf97 100644 --- a/boot/vbe_request.c +++ b/boot/vbe_request.c @@ -230,4 +230,4 @@ static int bootmeth_vbe_ft_fixup(void *ctx, struct event *event) return 0; } -EVENT_SPY(EVT_FT_FIXUP, bootmeth_vbe_ft_fixup); +EVENT_SPY_FULL(EVT_FT_FIXUP, bootmeth_vbe_ft_fixup); diff --git a/boot/vbe_simple_os.c b/boot/vbe_simple_os.c index 8c641ec07e2..3285e438a56 100644 --- a/boot/vbe_simple_os.c +++ b/boot/vbe_simple_os.c @@ -109,4 +109,4 @@ static int bootmeth_vbe_simple_ft_fixup(void *ctx, struct event *event) return 0; } -EVENT_SPY(EVT_FT_FIXUP, bootmeth_vbe_simple_ft_fixup); +EVENT_SPY_FULL(EVT_FT_FIXUP, bootmeth_vbe_simple_ft_fixup); diff --git a/include/event.h b/include/event.h index 062b5847897..b2cfd65c9f8 100644 --- a/include/event.h +++ b/include/event.h @@ -195,7 +195,7 @@ static inline const char *event_spy_id(struct evspy_info *spy) * away the linker-list entry sometimes, e.g. with the EVT_FT_FIXUP entry in * vbe_simple.c - so for now, make it global. */ -#define EVENT_SPY(_type, _func) \ +#define EVENT_SPY_FULL(_type, _func) \ __used ll_entry_declare(struct evspy_info, _type ## _3_ ## _func, \ evspy_info) = _ESPY_REC(_type, _func) -- cgit v1.3.1 From 446d6643033edffd4b832de71ef190533398bd91 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 6 Sep 2023 23:29:41 +0200 Subject: boot: Remove unused NEEDS_MANUAL_RELOC code bits The last user of the NEEDS_MANUAL_RELOC has been removed in commit 26af162ac8f8 ("arch: m68k: Implement relocation") Remove now unused NEEDS_MANUAL_RELOC code. Signed-off-by: Marek Vasut --- boot/bootm_os.c | 14 -------------- boot/image-sig.c | 28 ---------------------------- cmd/bootm.c | 14 -------------- 3 files changed, 56 deletions(-) (limited to 'boot') diff --git a/boot/bootm_os.c b/boot/bootm_os.c index 99ff0e6c02d..9c035b5be88 100644 --- a/boot/bootm_os.c +++ b/boot/bootm_os.c @@ -609,19 +609,5 @@ int boot_selected_os(int argc, char *const argv[], int state, boot_os_fn *bootm_os_get_boot_func(int os) { -#ifdef CONFIG_NEEDS_MANUAL_RELOC - static bool relocated; - - if (!relocated) { - int i; - - /* relocate boot function table */ - for (i = 0; i < ARRAY_SIZE(boot_os); i++) - if (boot_os[i] != NULL) - boot_os[i] += gd->reloc_off; - - relocated = true; - } -#endif return boot_os[os]; } diff --git a/boot/image-sig.c b/boot/image-sig.c index 1aa0b586450..b5692d58b24 100644 --- a/boot/image-sig.c +++ b/boot/image-sig.c @@ -57,20 +57,6 @@ struct checksum_algo *image_get_checksum_algo(const char *full_name) int i; const char *name; - if (IS_ENABLED(CONFIG_NEEDS_MANUAL_RELOC)) { - static bool done; - - if (!done) { - done = true; - for (i = 0; i < ARRAY_SIZE(checksum_algos); i++) { - struct checksum_algo *algo = &checksum_algos[i]; - - MANUAL_RELOC(algo->name); - MANUAL_RELOC(algo->calculate); - } - } - } - for (i = 0; i < ARRAY_SIZE(checksum_algos); i++) { name = checksum_algos[i].name; /* Make sure names match and next char is a comma */ @@ -87,20 +73,6 @@ struct crypto_algo *image_get_crypto_algo(const char *full_name) struct crypto_algo *crypto, *end; const char *name; - if (IS_ENABLED(CONFIG_NEEDS_MANUAL_RELOC)) { - static bool done; - - if (!done) { - done = true; - crypto = ll_entry_start(struct crypto_algo, cryptos); - end = ll_entry_end(struct crypto_algo, cryptos); - for (; crypto < end; crypto++) { - MANUAL_RELOC(crypto->name); - MANUAL_RELOC(crypto->verify); - } - } - } - /* Move name to after the comma */ name = strchr(full_name, ','); if (!name) diff --git a/cmd/bootm.c b/cmd/bootm.c index 37c2af96e08..7968415b6d1 100644 --- a/cmd/bootm.c +++ b/cmd/bootm.c @@ -123,20 +123,6 @@ int do_bootm(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) int states; int ret; -#ifdef CONFIG_NEEDS_MANUAL_RELOC - static int relocated = 0; - - if (!relocated) { - int i; - - /* relocate names of sub-command table */ - for (i = 0; i < ARRAY_SIZE(cmd_bootm_sub); i++) - cmd_bootm_sub[i].name += gd->reloc_off; - - relocated = 1; - } -#endif - /* determine if we have a sub command */ argc--; argv++; if (argc > 0) { -- cgit v1.3.1 From ba377a6c2c4e9907a198837366bd80c032432bc7 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 6 Sep 2023 23:29:59 +0200 Subject: image: Remove unused NEEDS_MANUAL_RELOC code bits The last user of the NEEDS_MANUAL_RELOC has been removed in commit 26af162ac8f8 ("arch: m68k: Implement relocation") Remove now unused NEEDS_MANUAL_RELOC code. Signed-off-by: Marek Vasut --- boot/image.c | 10 +++++----- include/relocate.h | 14 -------------- 2 files changed, 5 insertions(+), 19 deletions(-) (limited to 'boot') diff --git a/boot/image.c b/boot/image.c index 5c4f9b807d6..26f68d4c407 100644 --- a/boot/image.c +++ b/boot/image.c @@ -571,7 +571,7 @@ const char *genimg_get_cat_name(enum ih_category category, uint id) entry = get_table_entry(table_info[category].table, id); if (!entry) return unknown_msg(category); - return manual_reloc(entry->lname); + return entry->lname; } /** @@ -591,7 +591,7 @@ const char *genimg_get_cat_short_name(enum ih_category category, uint id) entry = get_table_entry(table_info[category].table, id); if (!entry) return unknown_msg(category); - return manual_reloc(entry->sname); + return entry->sname; } int genimg_get_cat_count(enum ih_category category) @@ -641,7 +641,7 @@ char *get_table_entry_name(const table_entry_t *table, char *msg, int id) table = get_table_entry(table, id); if (!table) return msg; - return manual_reloc(table->lname); + return table->lname; } const char *genimg_get_os_name(uint8_t os) @@ -676,7 +676,7 @@ static const char *genimg_get_short_name(const table_entry_t *table, int val) table = get_table_entry(table, val); if (!table) return "unknown"; - return manual_reloc(table->sname); + return table->sname; } const char *genimg_get_type_short_name(uint8_t type) @@ -719,7 +719,7 @@ int get_table_entry_id(const table_entry_t *table, const table_entry_t *t; for (t = table; t->id >= 0; ++t) { - if (t->sname && !strcasecmp(manual_reloc(t->sname), name)) + if (t->sname && !strcasecmp(t->sname, name)) return t->id; } debug("Invalid %s Type: %s\n", table_name, name); diff --git a/include/relocate.h b/include/relocate.h index 5ae1a2ed555..8ca25e1105e 100644 --- a/include/relocate.h +++ b/include/relocate.h @@ -39,18 +39,4 @@ int clear_bss(void); */ int do_elf_reloc_fixups(void); -/** - * manual_reloc() - Manually relocate a pointer if needed - * - * This is a nop in almost all cases, except for the systems with a broken gcc - * which need to manually relocate some things. - * - * @ptr: Pointer to relocate - * Return: new pointer value - */ -static inline void *manual_reloc(void *ptr) -{ - return ptr; -} - #endif /* _RELOCATE_H_ */ -- cgit v1.3.1 From b1a4b46734af68d734978cd5220b1af33d124814 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 14 Sep 2023 10:55:45 -0600 Subject: boot: Move fdt_support to boot/ This relates to booting since it fixes up the devicetree for the OS. Move it into the boot/ directory. Signed-off-by: Simon Glass Reviewed-by: Tom Rini --- boot/Makefile | 3 + boot/fdt_support.c | 2150 ++++++++++++++++++++++++++++++++++++++++++++++++++ common/Makefile | 2 - common/fdt_support.c | 2150 -------------------------------------------------- 4 files changed, 2153 insertions(+), 2152 deletions(-) create mode 100644 boot/fdt_support.c delete mode 100644 common/fdt_support.c (limited to 'boot') diff --git a/boot/Makefile b/boot/Makefile index 10f01572237..f15a161614f 100644 --- a/boot/Makefile +++ b/boot/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_QFW) += bootmeth_qfw.o endif obj-y += image.o image-board.o + obj-$(CONFIG_ANDROID_AB) += android_ab.o obj-$(CONFIG_ANDROID_BOOT_IMAGE) += image-android.o image-android-dt.o @@ -37,6 +38,8 @@ obj-$(CONFIG_$(SPL_TPL_)BOOTSTD) += bootflow_menu.o obj-$(CONFIG_$(SPL_TPL_)CEDIT) += cedit.o endif +obj-$(CONFIG_$(SPL_TPL_)OF_LIBFDT) += fdt_support.o + obj-$(CONFIG_$(SPL_TPL_)OF_LIBFDT) += image-fdt.o obj-$(CONFIG_$(SPL_TPL_)FIT_SIGNATURE) += fdt_region.o obj-$(CONFIG_$(SPL_TPL_)FIT) += image-fit.o diff --git a/boot/fdt_support.c b/boot/fdt_support.c new file mode 100644 index 00000000000..5e49078f8c3 --- /dev/null +++ b/boot/fdt_support.c @@ -0,0 +1,2150 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2007 + * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com + * + * Copyright 2010-2011 Freescale Semiconductor, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * fdt_getprop_u32_default_node - Return a node's property or a default + * + * @fdt: ptr to device tree + * @off: offset of node + * @cell: cell offset in property + * @prop: property name + * @dflt: default value if the property isn't found + * + * Convenience function to return a node's property or a default value if + * the property doesn't exist. + */ +u32 fdt_getprop_u32_default_node(const void *fdt, int off, int cell, + const char *prop, const u32 dflt) +{ + const fdt32_t *val; + int len; + + val = fdt_getprop(fdt, off, prop, &len); + + /* Check if property exists */ + if (!val) + return dflt; + + /* Check if property is long enough */ + if (len < ((cell + 1) * sizeof(uint32_t))) + return dflt; + + return fdt32_to_cpu(*val); +} + +/** + * fdt_getprop_u32_default - Find a node and return it's property or a default + * + * @fdt: ptr to device tree + * @path: path of node + * @prop: property name + * @dflt: default value if the property isn't found + * + * Convenience function to find a node and return it's property or a + * default value if it doesn't exist. + */ +u32 fdt_getprop_u32_default(const void *fdt, const char *path, + const char *prop, const u32 dflt) +{ + int off; + + off = fdt_path_offset(fdt, path); + if (off < 0) + return dflt; + + return fdt_getprop_u32_default_node(fdt, off, 0, prop, dflt); +} + +/** + * fdt_find_and_setprop: Find a node and set it's property + * + * @fdt: ptr to device tree + * @node: path of node + * @prop: property name + * @val: ptr to new value + * @len: length of new property value + * @create: flag to create the property if it doesn't exist + * + * Convenience function to directly set a property given the path to the node. + */ +int fdt_find_and_setprop(void *fdt, const char *node, const char *prop, + const void *val, int len, int create) +{ + int nodeoff = fdt_path_offset(fdt, node); + + if (nodeoff < 0) + return nodeoff; + + if ((!create) && (fdt_get_property(fdt, nodeoff, prop, NULL) == NULL)) + return 0; /* create flag not set; so exit quietly */ + + return fdt_setprop(fdt, nodeoff, prop, val, len); +} + +/** + * fdt_find_or_add_subnode() - find or possibly add a subnode of a given node + * + * @fdt: pointer to the device tree blob + * @parentoffset: structure block offset of a node + * @name: name of the subnode to locate + * + * fdt_subnode_offset() finds a subnode of the node with a given name. + * If the subnode does not exist, it will be created. + */ +int fdt_find_or_add_subnode(void *fdt, int parentoffset, const char *name) +{ + int offset; + + offset = fdt_subnode_offset(fdt, parentoffset, name); + + if (offset == -FDT_ERR_NOTFOUND) + offset = fdt_add_subnode(fdt, parentoffset, name); + + if (offset < 0) + printf("%s: %s: %s\n", __func__, name, fdt_strerror(offset)); + + return offset; +} + +#if defined(CONFIG_OF_STDOUT_VIA_ALIAS) && defined(CONFIG_CONS_INDEX) +static int fdt_fixup_stdout(void *fdt, int chosenoff) +{ + int err; + int aliasoff; + char sername[9] = { 0 }; + const void *path; + int len; + char tmp[256]; /* long enough */ + + sprintf(sername, "serial%d", CONFIG_CONS_INDEX - 1); + + aliasoff = fdt_path_offset(fdt, "/aliases"); + if (aliasoff < 0) { + err = aliasoff; + goto noalias; + } + + path = fdt_getprop(fdt, aliasoff, sername, &len); + if (!path) { + err = len; + goto noalias; + } + + /* fdt_setprop may break "path" so we copy it to tmp buffer */ + memcpy(tmp, path, len); + + err = fdt_setprop(fdt, chosenoff, "linux,stdout-path", tmp, len); + if (err < 0) + printf("WARNING: could not set linux,stdout-path %s.\n", + fdt_strerror(err)); + + return err; + +noalias: + printf("WARNING: %s: could not read %s alias: %s\n", + __func__, sername, fdt_strerror(err)); + + return 0; +} +#else +static int fdt_fixup_stdout(void *fdt, int chosenoff) +{ + return 0; +} +#endif + +static inline int fdt_setprop_uxx(void *fdt, int nodeoffset, const char *name, + uint64_t val, int is_u64) +{ + if (is_u64) + return fdt_setprop_u64(fdt, nodeoffset, name, val); + else + return fdt_setprop_u32(fdt, nodeoffset, name, (uint32_t)val); +} + +int fdt_root(void *fdt) +{ + char *serial; + int err; + + err = fdt_check_header(fdt); + if (err < 0) { + printf("fdt_root: %s\n", fdt_strerror(err)); + return err; + } + + serial = env_get("serial#"); + if (serial) { + err = fdt_setprop(fdt, 0, "serial-number", serial, + strlen(serial) + 1); + + if (err < 0) { + printf("WARNING: could not set serial-number %s.\n", + fdt_strerror(err)); + return err; + } + } + + return 0; +} + +int fdt_initrd(void *fdt, ulong initrd_start, ulong initrd_end) +{ + int nodeoffset; + int err, j, total; + int is_u64; + uint64_t addr, size; + + /* just return if the size of initrd is zero */ + if (initrd_start == initrd_end) + return 0; + + /* find or create "/chosen" node. */ + nodeoffset = fdt_find_or_add_subnode(fdt, 0, "chosen"); + if (nodeoffset < 0) + return nodeoffset; + + total = fdt_num_mem_rsv(fdt); + + /* + * Look for an existing entry and update it. If we don't find + * the entry, we will j be the next available slot. + */ + for (j = 0; j < total; j++) { + err = fdt_get_mem_rsv(fdt, j, &addr, &size); + if (addr == initrd_start) { + fdt_del_mem_rsv(fdt, j); + break; + } + } + + err = fdt_add_mem_rsv(fdt, initrd_start, initrd_end - initrd_start); + if (err < 0) { + printf("fdt_initrd: %s\n", fdt_strerror(err)); + return err; + } + + is_u64 = (fdt_address_cells(fdt, 0) == 2); + + err = fdt_setprop_uxx(fdt, nodeoffset, "linux,initrd-start", + (uint64_t)initrd_start, is_u64); + + if (err < 0) { + printf("WARNING: could not set linux,initrd-start %s.\n", + fdt_strerror(err)); + return err; + } + + err = fdt_setprop_uxx(fdt, nodeoffset, "linux,initrd-end", + (uint64_t)initrd_end, is_u64); + + if (err < 0) { + printf("WARNING: could not set linux,initrd-end %s.\n", + fdt_strerror(err)); + + return err; + } + + return 0; +} + +/** + * board_fdt_chosen_bootargs - boards may override this function to use + * alternative kernel command line arguments + */ +__weak char *board_fdt_chosen_bootargs(void) +{ + return env_get("bootargs"); +} + +int fdt_chosen(void *fdt) +{ + struct abuf buf = {}; + int nodeoffset; + int err; + char *str; /* used to set string properties */ + + err = fdt_check_header(fdt); + if (err < 0) { + printf("fdt_chosen: %s\n", fdt_strerror(err)); + return err; + } + + /* find or create "/chosen" node. */ + nodeoffset = fdt_find_or_add_subnode(fdt, 0, "chosen"); + if (nodeoffset < 0) + return nodeoffset; + + if (IS_ENABLED(CONFIG_BOARD_RNG_SEED) && !board_rng_seed(&buf)) { + err = fdt_setprop(fdt, nodeoffset, "rng-seed", + abuf_data(&buf), abuf_size(&buf)); + abuf_uninit(&buf); + if (err < 0) { + printf("WARNING: could not set rng-seed %s.\n", + fdt_strerror(err)); + return err; + } + } + + str = board_fdt_chosen_bootargs(); + + if (str) { + err = fdt_setprop(fdt, nodeoffset, "bootargs", str, + strlen(str) + 1); + if (err < 0) { + printf("WARNING: could not set bootargs %s.\n", + fdt_strerror(err)); + return err; + } + } + + /* add u-boot version */ + err = fdt_setprop(fdt, nodeoffset, "u-boot,version", PLAIN_VERSION, + strlen(PLAIN_VERSION) + 1); + if (err < 0) { + printf("WARNING: could not set u-boot,version %s.\n", + fdt_strerror(err)); + return err; + } + + return fdt_fixup_stdout(fdt, nodeoffset); +} + +void do_fixup_by_path(void *fdt, const char *path, const char *prop, + const void *val, int len, int create) +{ +#if defined(DEBUG) + int i; + debug("Updating property '%s/%s' = ", path, prop); + for (i = 0; i < len; i++) + debug(" %.2x", *(u8*)(val+i)); + debug("\n"); +#endif + int rc = fdt_find_and_setprop(fdt, path, prop, val, len, create); + if (rc) + printf("Unable to update property %s:%s, err=%s\n", + path, prop, fdt_strerror(rc)); +} + +void do_fixup_by_path_u32(void *fdt, const char *path, const char *prop, + u32 val, int create) +{ + fdt32_t tmp = cpu_to_fdt32(val); + do_fixup_by_path(fdt, path, prop, &tmp, sizeof(tmp), create); +} + +void do_fixup_by_prop(void *fdt, + const char *pname, const void *pval, int plen, + const char *prop, const void *val, int len, + int create) +{ + int off; +#if defined(DEBUG) + int i; + debug("Updating property '%s' = ", prop); + for (i = 0; i < len; i++) + debug(" %.2x", *(u8*)(val+i)); + debug("\n"); +#endif + off = fdt_node_offset_by_prop_value(fdt, -1, pname, pval, plen); + while (off != -FDT_ERR_NOTFOUND) { + if (create || (fdt_get_property(fdt, off, prop, NULL) != NULL)) + fdt_setprop(fdt, off, prop, val, len); + off = fdt_node_offset_by_prop_value(fdt, off, pname, pval, plen); + } +} + +void do_fixup_by_prop_u32(void *fdt, + const char *pname, const void *pval, int plen, + const char *prop, u32 val, int create) +{ + fdt32_t tmp = cpu_to_fdt32(val); + do_fixup_by_prop(fdt, pname, pval, plen, prop, &tmp, 4, create); +} + +void do_fixup_by_compat(void *fdt, const char *compat, + const char *prop, const void *val, int len, int create) +{ + int off = -1; +#if defined(DEBUG) + int i; + debug("Updating property '%s' = ", prop); + for (i = 0; i < len; i++) + debug(" %.2x", *(u8*)(val+i)); + debug("\n"); +#endif + fdt_for_each_node_by_compatible(off, fdt, -1, compat) + if (create || (fdt_get_property(fdt, off, prop, NULL) != NULL)) + fdt_setprop(fdt, off, prop, val, len); +} + +void do_fixup_by_compat_u32(void *fdt, const char *compat, + const char *prop, u32 val, int create) +{ + fdt32_t tmp = cpu_to_fdt32(val); + do_fixup_by_compat(fdt, compat, prop, &tmp, 4, create); +} + +#ifdef CONFIG_ARCH_FIXUP_FDT_MEMORY +/* + * fdt_pack_reg - pack address and size array into the "reg"-suitable stream + */ +static int fdt_pack_reg(const void *fdt, void *buf, u64 *address, u64 *size, + int n) +{ + int i; + int address_cells = fdt_address_cells(fdt, 0); + int size_cells = fdt_size_cells(fdt, 0); + char *p = buf; + + for (i = 0; i < n; i++) { + if (address_cells == 2) + *(fdt64_t *)p = cpu_to_fdt64(address[i]); + else + *(fdt32_t *)p = cpu_to_fdt32(address[i]); + p += 4 * address_cells; + + if (size_cells == 2) + *(fdt64_t *)p = cpu_to_fdt64(size[i]); + else + *(fdt32_t *)p = cpu_to_fdt32(size[i]); + p += 4 * size_cells; + } + + return p - (char *)buf; +} + +#if CONFIG_NR_DRAM_BANKS > 4 +#define MEMORY_BANKS_MAX CONFIG_NR_DRAM_BANKS +#else +#define MEMORY_BANKS_MAX 4 +#endif + +/** + * fdt_fixup_memory_banks - Update DT memory node + * @blob: Pointer to DT blob + * @start: Pointer to memory start addresses array + * @size: Pointer to memory sizes array + * @banks: Number of memory banks + * + * Return: 0 on success, negative value on failure + * + * Based on the passed number of banks and arrays, the function is able to + * update existing DT memory nodes to match run time detected/changed memory + * configuration. Implementation is handling one specific case with only one + * memory node where multiple tuples could be added/updated. + * The case where multiple memory nodes with a single tuple (base, size) are + * used, this function is only updating the first memory node without removing + * others. + */ +int fdt_fixup_memory_banks(void *blob, u64 start[], u64 size[], int banks) +{ + int err, nodeoffset; + int len, i; + u8 tmp[MEMORY_BANKS_MAX * 16]; /* Up to 64-bit address + 64-bit size */ + + if (banks > MEMORY_BANKS_MAX) { + printf("%s: num banks %d exceeds hardcoded limit %d." + " Recompile with higher MEMORY_BANKS_MAX?\n", + __FUNCTION__, banks, MEMORY_BANKS_MAX); + return -1; + } + + err = fdt_check_header(blob); + if (err < 0) { + printf("%s: %s\n", __FUNCTION__, fdt_strerror(err)); + return err; + } + + /* find or create "/memory" node. */ + nodeoffset = fdt_find_or_add_subnode(blob, 0, "memory"); + if (nodeoffset < 0) + return nodeoffset; + + err = fdt_setprop(blob, nodeoffset, "device_type", "memory", + sizeof("memory")); + if (err < 0) { + printf("WARNING: could not set %s %s.\n", "device_type", + fdt_strerror(err)); + return err; + } + + for (i = 0; i < banks; i++) { + if (start[i] == 0 && size[i] == 0) + break; + } + + banks = i; + + if (!banks) + return 0; + + len = fdt_pack_reg(blob, tmp, start, size, banks); + + err = fdt_setprop(blob, nodeoffset, "reg", tmp, len); + if (err < 0) { + printf("WARNING: could not set %s %s.\n", + "reg", fdt_strerror(err)); + return err; + } + return 0; +} + +int fdt_set_usable_memory(void *blob, u64 start[], u64 size[], int areas) +{ + int err, nodeoffset; + int len; + u8 tmp[8 * 16]; /* Up to 64-bit address + 64-bit size */ + + if (areas > 8) { + printf("%s: num areas %d exceeds hardcoded limit %d\n", + __func__, areas, 8); + return -1; + } + + err = fdt_check_header(blob); + if (err < 0) { + printf("%s: %s\n", __func__, fdt_strerror(err)); + return err; + } + + /* find or create "/memory" node. */ + nodeoffset = fdt_find_or_add_subnode(blob, 0, "memory"); + if (nodeoffset < 0) + return nodeoffset; + + len = fdt_pack_reg(blob, tmp, start, size, areas); + + err = fdt_setprop(blob, nodeoffset, "linux,usable-memory", tmp, len); + if (err < 0) { + printf("WARNING: could not set %s %s.\n", + "reg", fdt_strerror(err)); + return err; + } + + return 0; +} +#endif + +int fdt_fixup_memory(void *blob, u64 start, u64 size) +{ + return fdt_fixup_memory_banks(blob, &start, &size, 1); +} + +void fdt_fixup_ethernet(void *fdt) +{ + int i = 0, j, prop; + char *tmp, *end; + char mac[16]; + const char *path; + unsigned char mac_addr[ARP_HLEN]; + int offset; +#ifdef FDT_SEQ_MACADDR_FROM_ENV + int nodeoff; + const struct fdt_property *fdt_prop; +#endif + + if (fdt_path_offset(fdt, "/aliases") < 0) + return; + + /* Cycle through all aliases */ + for (prop = 0; ; prop++) { + const char *name; + + /* FDT might have been edited, recompute the offset */ + offset = fdt_first_property_offset(fdt, + fdt_path_offset(fdt, "/aliases")); + /* Select property number 'prop' */ + for (j = 0; j < prop; j++) + offset = fdt_next_property_offset(fdt, offset); + + if (offset < 0) + break; + + path = fdt_getprop_by_offset(fdt, offset, &name, NULL); + if (!strncmp(name, "ethernet", 8)) { + /* Treat plain "ethernet" same as "ethernet0". */ + if (!strcmp(name, "ethernet") +#ifdef FDT_SEQ_MACADDR_FROM_ENV + || !strcmp(name, "ethernet0") +#endif + ) + i = 0; +#ifndef FDT_SEQ_MACADDR_FROM_ENV + else + i = trailing_strtol(name); +#endif + if (i != -1) { + if (i == 0) + strcpy(mac, "ethaddr"); + else + sprintf(mac, "eth%daddr", i); + } else { + continue; + } +#ifdef FDT_SEQ_MACADDR_FROM_ENV + nodeoff = fdt_path_offset(fdt, path); + fdt_prop = fdt_get_property(fdt, nodeoff, "status", + NULL); + if (fdt_prop && !strcmp(fdt_prop->data, "disabled")) + continue; + i++; +#endif + tmp = env_get(mac); + if (!tmp) + continue; + + for (j = 0; j < 6; j++) { + mac_addr[j] = tmp ? + hextoul(tmp, &end) : 0; + if (tmp) + tmp = (*end) ? end + 1 : end; + } + + do_fixup_by_path(fdt, path, "mac-address", + &mac_addr, 6, 0); + do_fixup_by_path(fdt, path, "local-mac-address", + &mac_addr, 6, 1); + } + } +} + +int fdt_record_loadable(void *blob, u32 index, const char *name, + uintptr_t load_addr, u32 size, uintptr_t entry_point, + const char *type, const char *os, const char *arch) +{ + int err, node; + + err = fdt_check_header(blob); + if (err < 0) { + printf("%s: %s\n", __func__, fdt_strerror(err)); + return err; + } + + /* find or create "/fit-images" node */ + node = fdt_find_or_add_subnode(blob, 0, "fit-images"); + if (node < 0) + return node; + + /* find or create "/fit-images/" node */ + node = fdt_find_or_add_subnode(blob, node, name); + if (node < 0) + return node; + + fdt_setprop_u64(blob, node, "load", load_addr); + if (entry_point != -1) + fdt_setprop_u64(blob, node, "entry", entry_point); + fdt_setprop_u32(blob, node, "size", size); + if (type) + fdt_setprop_string(blob, node, "type", type); + if (os) + fdt_setprop_string(blob, node, "os", os); + if (arch) + fdt_setprop_string(blob, node, "arch", arch); + + return node; +} + +/* Resize the fdt to its actual size + a bit of padding */ +int fdt_shrink_to_minimum(void *blob, uint extrasize) +{ + int i; + uint64_t addr, size; + int total, ret; + uint actualsize; + int fdt_memrsv = 0; + + if (!blob) + return 0; + + total = fdt_num_mem_rsv(blob); + for (i = 0; i < total; i++) { + fdt_get_mem_rsv(blob, i, &addr, &size); + if (addr == (uintptr_t)blob) { + fdt_del_mem_rsv(blob, i); + fdt_memrsv = 1; + break; + } + } + + /* + * Calculate the actual size of the fdt + * plus the size needed for 5 fdt_add_mem_rsv, one + * for the fdt itself and 4 for a possible initrd + * ((initrd-start + initrd-end) * 2 (name & value)) + */ + actualsize = fdt_off_dt_strings(blob) + + fdt_size_dt_strings(blob) + 5 * sizeof(struct fdt_reserve_entry); + + actualsize += extrasize; + /* Make it so the fdt ends on a page boundary */ + actualsize = ALIGN(actualsize + ((uintptr_t)blob & 0xfff), 0x1000); + actualsize = actualsize - ((uintptr_t)blob & 0xfff); + + /* Change the fdt header to reflect the correct size */ + fdt_set_totalsize(blob, actualsize); + + if (fdt_memrsv) { + /* Add the new reservation */ + ret = fdt_add_mem_rsv(blob, map_to_sysmem(blob), actualsize); + if (ret < 0) + return ret; + } + + return actualsize; +} + +/** + * fdt_delete_disabled_nodes: Delete all nodes with status == "disabled" + * + * @blob: ptr to device tree + */ +int fdt_delete_disabled_nodes(void *blob) +{ + while (1) { + int ret, offset; + + offset = fdt_node_offset_by_prop_value(blob, -1, "status", + "disabled", 9); + if (offset < 0) + break; + + ret = fdt_del_node(blob, offset); + if (ret < 0) + return ret; + } + + return 0; +} + +#ifdef CONFIG_PCI +#define CFG_SYS_PCI_NR_INBOUND_WIN 4 + +#define FDT_PCI_PREFETCH (0x40000000) +#define FDT_PCI_MEM32 (0x02000000) +#define FDT_PCI_IO (0x01000000) +#define FDT_PCI_MEM64 (0x03000000) + +int fdt_pci_dma_ranges(void *blob, int phb_off, struct pci_controller *hose) { + + int addrcell, sizecell, len, r; + u32 *dma_range; + /* sized based on pci addr cells, size-cells, & address-cells */ + u32 dma_ranges[(3 + 2 + 2) * CFG_SYS_PCI_NR_INBOUND_WIN]; + + addrcell = fdt_getprop_u32_default(blob, "/", "#address-cells", 1); + sizecell = fdt_getprop_u32_default(blob, "/", "#size-cells", 1); + + dma_range = &dma_ranges[0]; + for (r = 0; r < hose->region_count; r++) { + u64 bus_start, phys_start, size; + + /* skip if !PCI_REGION_SYS_MEMORY */ + if (!(hose->regions[r].flags & PCI_REGION_SYS_MEMORY)) + continue; + + bus_start = (u64)hose->regions[r].bus_start; + phys_start = (u64)hose->regions[r].phys_start; + size = (u64)hose->regions[r].size; + + dma_range[0] = 0; + if (size >= 0x100000000ull) + dma_range[0] |= cpu_to_fdt32(FDT_PCI_MEM64); + else + dma_range[0] |= cpu_to_fdt32(FDT_PCI_MEM32); + if (hose->regions[r].flags & PCI_REGION_PREFETCH) + dma_range[0] |= cpu_to_fdt32(FDT_PCI_PREFETCH); +#ifdef CONFIG_SYS_PCI_64BIT + dma_range[1] = cpu_to_fdt32(bus_start >> 32); +#else + dma_range[1] = 0; +#endif + dma_range[2] = cpu_to_fdt32(bus_start & 0xffffffff); + + if (addrcell == 2) { + dma_range[3] = cpu_to_fdt32(phys_start >> 32); + dma_range[4] = cpu_to_fdt32(phys_start & 0xffffffff); + } else { + dma_range[3] = cpu_to_fdt32(phys_start & 0xffffffff); + } + + if (sizecell == 2) { + dma_range[3 + addrcell + 0] = + cpu_to_fdt32(size >> 32); + dma_range[3 + addrcell + 1] = + cpu_to_fdt32(size & 0xffffffff); + } else { + dma_range[3 + addrcell + 0] = + cpu_to_fdt32(size & 0xffffffff); + } + + dma_range += (3 + addrcell + sizecell); + } + + len = dma_range - &dma_ranges[0]; + if (len) + fdt_setprop(blob, phb_off, "dma-ranges", &dma_ranges[0], len*4); + + return 0; +} +#endif + +int fdt_increase_size(void *fdt, int add_len) +{ + int newlen; + + newlen = fdt_totalsize(fdt) + add_len; + + /* Open in place with a new len */ + return fdt_open_into(fdt, fdt, newlen); +} + +#ifdef CONFIG_FDT_FIXUP_PARTITIONS +#include +#include + +static int fdt_del_subnodes(const void *blob, int parent_offset) +{ + int off, ndepth; + int ret; + + for (ndepth = 0, off = fdt_next_node(blob, parent_offset, &ndepth); + (off >= 0) && (ndepth > 0); + off = fdt_next_node(blob, off, &ndepth)) { + if (ndepth == 1) { + debug("delete %s: offset: %x\n", + fdt_get_name(blob, off, 0), off); + ret = fdt_del_node((void *)blob, off); + if (ret < 0) { + printf("Can't delete node: %s\n", + fdt_strerror(ret)); + return ret; + } else { + ndepth = 0; + off = parent_offset; + } + } + } + return 0; +} + +static int fdt_del_partitions(void *blob, int parent_offset) +{ + const void *prop; + int ndepth = 0; + int off; + int ret; + + off = fdt_next_node(blob, parent_offset, &ndepth); + if (off > 0 && ndepth == 1) { + prop = fdt_getprop(blob, off, "label", NULL); + if (prop == NULL) { + /* + * Could not find label property, nand {}; node? + * Check subnode, delete partitions there if any. + */ + return fdt_del_partitions(blob, off); + } else { + ret = fdt_del_subnodes(blob, parent_offset); + if (ret < 0) { + printf("Can't remove subnodes: %s\n", + fdt_strerror(ret)); + return ret; + } + } + } + return 0; +} + +static int fdt_node_set_part_info(void *blob, int parent_offset, + struct mtd_device *dev) +{ + struct list_head *pentry; + struct part_info *part; + int off, ndepth = 0; + int part_num, ret; + int sizecell; + char buf[64]; + + ret = fdt_del_partitions(blob, parent_offset); + if (ret < 0) + return ret; + + /* + * Check if size/address is 1 or 2 cells. + * We assume #address-cells and #size-cells have same value. + */ + sizecell = fdt_getprop_u32_default_node(blob, parent_offset, + 0, "#size-cells", 1); + + /* + * Check if it is nand {}; subnode, adjust + * the offset in this case + */ + off = fdt_next_node(blob, parent_offset, &ndepth); + if (off > 0 && ndepth == 1) + parent_offset = off; + + part_num = 0; + list_for_each_prev(pentry, &dev->parts) { + int newoff; + + part = list_entry(pentry, struct part_info, link); + + debug("%2d: %-20s0x%08llx\t0x%08llx\t%d\n", + part_num, part->name, part->size, + part->offset, part->mask_flags); + + sprintf(buf, "partition@%llx", part->offset); +add_sub: + ret = fdt_add_subnode(blob, parent_offset, buf); + if (ret == -FDT_ERR_NOSPACE) { + ret = fdt_increase_size(blob, 512); + if (!ret) + goto add_sub; + else + goto err_size; + } else if (ret < 0) { + printf("Can't add partition node: %s\n", + fdt_strerror(ret)); + return ret; + } + newoff = ret; + + /* Check MTD_WRITEABLE_CMD flag */ + if (part->mask_flags & 1) { +add_ro: + ret = fdt_setprop(blob, newoff, "read_only", NULL, 0); + if (ret == -FDT_ERR_NOSPACE) { + ret = fdt_increase_size(blob, 512); + if (!ret) + goto add_ro; + else + goto err_size; + } else if (ret < 0) + goto err_prop; + } + +add_reg: + if (sizecell == 2) { + ret = fdt_setprop_u64(blob, newoff, + "reg", part->offset); + if (!ret) + ret = fdt_appendprop_u64(blob, newoff, + "reg", part->size); + } else { + ret = fdt_setprop_u32(blob, newoff, + "reg", part->offset); + if (!ret) + ret = fdt_appendprop_u32(blob, newoff, + "reg", part->size); + } + + if (ret == -FDT_ERR_NOSPACE) { + ret = fdt_increase_size(blob, 512); + if (!ret) + goto add_reg; + else + goto err_size; + } else if (ret < 0) + goto err_prop; + +add_label: + ret = fdt_setprop_string(blob, newoff, "label", part->name); + if (ret == -FDT_ERR_NOSPACE) { + ret = fdt_increase_size(blob, 512); + if (!ret) + goto add_label; + else + goto err_size; + } else if (ret < 0) + goto err_prop; + + part_num++; + } + return 0; +err_size: + printf("Can't increase blob size: %s\n", fdt_strerror(ret)); + return ret; +err_prop: + printf("Can't add property: %s\n", fdt_strerror(ret)); + return ret; +} + +/* + * Update partitions in nor/nand nodes using info from + * mtdparts environment variable. The nodes to update are + * specified by node_info structure which contains mtd device + * type and compatible string: E. g. the board code in + * ft_board_setup() could use: + * + * struct node_info nodes[] = { + * { "fsl,mpc5121-nfc", MTD_DEV_TYPE_NAND, }, + * { "cfi-flash", MTD_DEV_TYPE_NOR, }, + * }; + * + * fdt_fixup_mtdparts(blob, nodes, ARRAY_SIZE(nodes)); + */ +void fdt_fixup_mtdparts(void *blob, const struct node_info *node_info, + int node_info_size) +{ + struct mtd_device *dev; + int i, idx; + int noff, parts; + bool inited = false; + + for (i = 0; i < node_info_size; i++) { + idx = 0; + + fdt_for_each_node_by_compatible(noff, blob, -1, + node_info[i].compat) { + const char *prop; + + prop = fdt_getprop(blob, noff, "status", NULL); + if (prop && !strcmp(prop, "disabled")) + continue; + + debug("%s: %s, mtd dev type %d\n", + fdt_get_name(blob, noff, 0), + node_info[i].compat, node_info[i].type); + + if (!inited) { + if (mtdparts_init() != 0) + return; + inited = true; + } + + dev = device_find(node_info[i].type, idx++); + if (dev) { + parts = fdt_subnode_offset(blob, noff, + "partitions"); + if (parts < 0) + parts = noff; + + if (fdt_node_set_part_info(blob, parts, dev)) + return; /* return on error */ + } + } + } +} +#endif + +int fdt_copy_fixed_partitions(void *blob) +{ + ofnode node, subnode; + int off, suboff, res; + char path[256]; + int address_cells, size_cells; + u8 i, j, child_count; + + node = ofnode_by_compatible(ofnode_null(), "fixed-partitions"); + while (ofnode_valid(node)) { + /* copy the U-Boot fixed partition */ + address_cells = ofnode_read_simple_addr_cells(node); + size_cells = ofnode_read_simple_size_cells(node); + + res = ofnode_get_path(ofnode_get_parent(node), path, sizeof(path)); + if (res) + return res; + + off = fdt_path_offset(blob, path); + if (off < 0) + return -ENODEV; + + off = fdt_find_or_add_subnode(blob, off, "partitions"); + res = fdt_setprop_string(blob, off, "compatible", "fixed-partitions"); + if (res) + return res; + + res = fdt_setprop_u32(blob, off, "#address-cells", address_cells); + if (res) + return res; + + res = fdt_setprop_u32(blob, off, "#size-cells", size_cells); + if (res) + return res; + + /* + * parse partition in reverse order as fdt_find_or_add_subnode() only + * insert the new node after the parent's properties + */ + child_count = ofnode_get_child_count(node); + for (i = child_count; i > 0 ; i--) { + subnode = ofnode_first_subnode(node); + if (!ofnode_valid(subnode)) + break; + + for (j = 0; (j < i - 1); j++) + subnode = ofnode_next_subnode(subnode); + + if (!ofnode_valid(subnode)) + break; + + const u32 *reg; + int len; + + suboff = fdt_find_or_add_subnode(blob, off, ofnode_get_name(subnode)); + res = fdt_setprop_string(blob, suboff, "label", + ofnode_read_string(subnode, "label")); + if (res) + return res; + + reg = ofnode_get_property(subnode, "reg", &len); + res = fdt_setprop(blob, suboff, "reg", reg, len); + if (res) + return res; + } + + /* go to next fixed-partitions node */ + node = ofnode_by_compatible(node, "fixed-partitions"); + } + + return 0; +} + +void fdt_del_node_and_alias(void *blob, const char *alias) +{ + int off = fdt_path_offset(blob, alias); + + if (off < 0) + return; + + fdt_del_node(blob, off); + + off = fdt_path_offset(blob, "/aliases"); + fdt_delprop(blob, off, alias); +} + +/* Max address size we deal with */ +#define OF_MAX_ADDR_CELLS 4 +#define OF_CHECK_COUNTS(na, ns) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \ + (ns) > 0) + +/* Debug utility */ +#ifdef DEBUG +static void of_dump_addr(const char *s, const fdt32_t *addr, int na) +{ + printf("%s", s); + while(na--) + printf(" %08x", *(addr++)); + printf("\n"); +} +#else +static void of_dump_addr(const char *s, const fdt32_t *addr, int na) { } +#endif + +/** + * struct of_bus - Callbacks for bus specific translators + * @name: A string used to identify this bus in debug output. + * @addresses: The name of the DT property from which addresses are + * to be read, typically "reg". + * @match: Return non-zero if the node whose parent is at + * parentoffset in the FDT blob corresponds to a bus + * of this type, otherwise return zero. If NULL a match + * is assumed. + * @count_cells:Count how many cells (be32 values) a node whose parent + * is at parentoffset in the FDT blob will require to + * represent its address (written to *addrc) & size + * (written to *sizec). + * @map: Map the address addr from the address space of this + * bus to that of its parent, making use of the ranges + * read from DT to an array at range. na and ns are the + * number of cells (be32 values) used to hold and address + * or size, respectively, for this bus. pna is the number + * of cells used to hold an address for the parent bus. + * Returns the address in the address space of the parent + * bus. + * @translate: Update the value of the address cells at addr within an + * FDT by adding offset to it. na specifies the number of + * cells used to hold the address being translated. Returns + * zero on success, non-zero on error. + * + * Each bus type will include a struct of_bus in the of_busses array, + * providing implementations of some or all of the functions used to + * match the bus & handle address translation for its children. + */ +struct of_bus { + const char *name; + const char *addresses; + int (*match)(const void *blob, int parentoffset); + void (*count_cells)(const void *blob, int parentoffset, + int *addrc, int *sizec); + u64 (*map)(fdt32_t *addr, const fdt32_t *range, + int na, int ns, int pna); + int (*translate)(fdt32_t *addr, u64 offset, int na); +}; + +/* Default translator (generic bus) */ +void fdt_support_default_count_cells(const void *blob, int parentoffset, + int *addrc, int *sizec) +{ + const fdt32_t *prop; + + if (addrc) + *addrc = fdt_address_cells(blob, parentoffset); + + if (sizec) { + prop = fdt_getprop(blob, parentoffset, "#size-cells", NULL); + if (prop) + *sizec = be32_to_cpup(prop); + else + *sizec = 1; + } +} + +static u64 of_bus_default_map(fdt32_t *addr, const fdt32_t *range, + int na, int ns, int pna) +{ + u64 cp, s, da; + + cp = fdt_read_number(range, na); + s = fdt_read_number(range + na + pna, ns); + da = fdt_read_number(addr, na); + + debug("OF: default map, cp=%llx, s=%llx, da=%llx\n", cp, s, da); + + if (da < cp || da >= (cp + s)) + return OF_BAD_ADDR; + return da - cp; +} + +static int of_bus_default_translate(fdt32_t *addr, u64 offset, int na) +{ + u64 a = fdt_read_number(addr, na); + memset(addr, 0, na * 4); + a += offset; + if (na > 1) + addr[na - 2] = cpu_to_fdt32(a >> 32); + addr[na - 1] = cpu_to_fdt32(a & 0xffffffffu); + + return 0; +} + +#ifdef CONFIG_OF_ISA_BUS + +/* ISA bus translator */ +static int of_bus_isa_match(const void *blob, int parentoffset) +{ + const char *name; + + name = fdt_get_name(blob, parentoffset, NULL); + if (!name) + return 0; + + return !strcmp(name, "isa"); +} + +static void of_bus_isa_count_cells(const void *blob, int parentoffset, + int *addrc, int *sizec) +{ + if (addrc) + *addrc = 2; + if (sizec) + *sizec = 1; +} + +static u64 of_bus_isa_map(fdt32_t *addr, const fdt32_t *range, + int na, int ns, int pna) +{ + u64 cp, s, da; + + /* Check address type match */ + if ((addr[0] ^ range[0]) & cpu_to_be32(1)) + return OF_BAD_ADDR; + + cp = fdt_read_number(range + 1, na - 1); + s = fdt_read_number(range + na + pna, ns); + da = fdt_read_number(addr + 1, na - 1); + + debug("OF: ISA map, cp=%llx, s=%llx, da=%llx\n", cp, s, da); + + if (da < cp || da >= (cp + s)) + return OF_BAD_ADDR; + return da - cp; +} + +static int of_bus_isa_translate(fdt32_t *addr, u64 offset, int na) +{ + return of_bus_default_translate(addr + 1, offset, na - 1); +} + +#endif /* CONFIG_OF_ISA_BUS */ + +/* Array of bus specific translators */ +static struct of_bus of_busses[] = { +#ifdef CONFIG_OF_ISA_BUS + /* ISA */ + { + .name = "isa", + .addresses = "reg", + .match = of_bus_isa_match, + .count_cells = of_bus_isa_count_cells, + .map = of_bus_isa_map, + .translate = of_bus_isa_translate, + }, +#endif /* CONFIG_OF_ISA_BUS */ + /* Default */ + { + .name = "default", + .addresses = "reg", + .count_cells = fdt_support_default_count_cells, + .map = of_bus_default_map, + .translate = of_bus_default_translate, + }, +}; + +static struct of_bus *of_match_bus(const void *blob, int parentoffset) +{ + struct of_bus *bus; + + if (ARRAY_SIZE(of_busses) == 1) + return of_busses; + + for (bus = of_busses; bus; bus++) { + if (!bus->match || bus->match(blob, parentoffset)) + return bus; + } + + /* + * We should always have matched the default bus at least, since + * it has a NULL match field. If we didn't then it somehow isn't + * in the of_busses array or something equally catastrophic has + * gone wrong. + */ + assert(0); + return NULL; +} + +static int of_translate_one(const void *blob, int parent, struct of_bus *bus, + struct of_bus *pbus, fdt32_t *addr, + int na, int ns, int pna, const char *rprop) +{ + const fdt32_t *ranges; + int rlen; + int rone; + u64 offset = OF_BAD_ADDR; + + /* Normally, an absence of a "ranges" property means we are + * crossing a non-translatable boundary, and thus the addresses + * below the current not cannot be converted to CPU physical ones. + * Unfortunately, while this is very clear in the spec, it's not + * what Apple understood, and they do have things like /uni-n or + * /ht nodes with no "ranges" property and a lot of perfectly + * useable mapped devices below them. Thus we treat the absence of + * "ranges" as equivalent to an empty "ranges" property which means + * a 1:1 translation at that level. It's up to the caller not to try + * to translate addresses that aren't supposed to be translated in + * the first place. --BenH. + */ + ranges = fdt_getprop(blob, parent, rprop, &rlen); + if (ranges == NULL || rlen == 0) { + offset = fdt_read_number(addr, na); + memset(addr, 0, pna * 4); + debug("OF: no ranges, 1:1 translation\n"); + goto finish; + } + + debug("OF: walking ranges...\n"); + + /* Now walk through the ranges */ + rlen /= 4; + rone = na + pna + ns; + for (; rlen >= rone; rlen -= rone, ranges += rone) { + offset = bus->map(addr, ranges, na, ns, pna); + if (offset != OF_BAD_ADDR) + break; + } + if (offset == OF_BAD_ADDR) { + debug("OF: not found !\n"); + return 1; + } + memcpy(addr, ranges + na, 4 * pna); + + finish: + of_dump_addr("OF: parent translation for:", addr, pna); + debug("OF: with offset: %llu\n", offset); + + /* Translate it into parent bus space */ + return pbus->translate(addr, offset, pna); +} + +/* + * Translate an address from the device-tree into a CPU physical address, + * this walks up the tree and applies the various bus mappings on the + * way. + * + * Note: We consider that crossing any level with #size-cells == 0 to mean + * that translation is impossible (that is we are not dealing with a value + * that can be mapped to a cpu physical address). This is not really specified + * that way, but this is traditionally the way IBM at least do things + */ +static u64 __of_translate_address(const void *blob, int node_offset, + const fdt32_t *in_addr, const char *rprop) +{ + int parent; + struct of_bus *bus, *pbus; + fdt32_t addr[OF_MAX_ADDR_CELLS]; + int na, ns, pna, pns; + u64 result = OF_BAD_ADDR; + + debug("OF: ** translation for device %s **\n", + fdt_get_name(blob, node_offset, NULL)); + + /* Get parent & match bus type */ + parent = fdt_parent_offset(blob, node_offset); + if (parent < 0) + goto bail; + bus = of_match_bus(blob, parent); + + /* Cound address cells & copy address locally */ + bus->count_cells(blob, parent, &na, &ns); + if (!OF_CHECK_COUNTS(na, ns)) { + printf("%s: Bad cell count for %s\n", __FUNCTION__, + fdt_get_name(blob, node_offset, NULL)); + goto bail; + } + memcpy(addr, in_addr, na * 4); + + debug("OF: bus is %s (na=%d, ns=%d) on %s\n", + bus->name, na, ns, fdt_get_name(blob, parent, NULL)); + of_dump_addr("OF: translating address:", addr, na); + + /* Translate */ + for (;;) { + /* Switch to parent bus */ + node_offset = parent; + parent = fdt_parent_offset(blob, node_offset); + + /* If root, we have finished */ + if (parent < 0) { + debug("OF: reached root node\n"); + result = fdt_read_number(addr, na); + break; + } + + /* Get new parent bus and counts */ + pbus = of_match_bus(blob, parent); + pbus->count_cells(blob, parent, &pna, &pns); + if (!OF_CHECK_COUNTS(pna, pns)) { + printf("%s: Bad cell count for %s\n", __FUNCTION__, + fdt_get_name(blob, node_offset, NULL)); + break; + } + + debug("OF: parent bus is %s (na=%d, ns=%d) on %s\n", + pbus->name, pna, pns, fdt_get_name(blob, parent, NULL)); + + /* Apply bus translation */ + if (of_translate_one(blob, node_offset, bus, pbus, + addr, na, ns, pna, rprop)) + break; + + /* Complete the move up one level */ + na = pna; + ns = pns; + bus = pbus; + + of_dump_addr("OF: one level translation:", addr, na); + } + bail: + + return result; +} + +u64 fdt_translate_address(const void *blob, int node_offset, + const fdt32_t *in_addr) +{ + return __of_translate_address(blob, node_offset, in_addr, "ranges"); +} + +u64 fdt_translate_dma_address(const void *blob, int node_offset, + const fdt32_t *in_addr) +{ + return __of_translate_address(blob, node_offset, in_addr, "dma-ranges"); +} + +int fdt_get_dma_range(const void *blob, int node, phys_addr_t *cpu, + dma_addr_t *bus, u64 *size) +{ + bool found_dma_ranges = false; + struct of_bus *bus_node; + const fdt32_t *ranges; + int na, ns, pna, pns; + int parent = node; + int ret = 0; + int len; + + /* Find the closest dma-ranges property */ + while (parent >= 0) { + ranges = fdt_getprop(blob, parent, "dma-ranges", &len); + + /* Ignore empty ranges, they imply no translation required */ + if (ranges && len > 0) + break; + + /* Once we find 'dma-ranges', then a missing one is an error */ + if (found_dma_ranges && !ranges) { + ret = -EINVAL; + goto out; + } + + if (ranges) + found_dma_ranges = true; + + parent = fdt_parent_offset(blob, parent); + } + + if (!ranges || parent < 0) { + debug("no dma-ranges found for node %s\n", + fdt_get_name(blob, node, NULL)); + ret = -ENOENT; + goto out; + } + + /* switch to that node */ + node = parent; + parent = fdt_parent_offset(blob, node); + if (parent < 0) { + printf("Found dma-ranges in root node, shouldn't happen\n"); + ret = -EINVAL; + goto out; + } + + /* Get the address sizes both for the bus and its parent */ + bus_node = of_match_bus(blob, node); + bus_node->count_cells(blob, node, &na, &ns); + if (!OF_CHECK_COUNTS(na, ns)) { + printf("%s: Bad cell count for %s\n", __FUNCTION__, + fdt_get_name(blob, node, NULL)); + return -EINVAL; + goto out; + } + + bus_node = of_match_bus(blob, parent); + bus_node->count_cells(blob, parent, &pna, &pns); + if (!OF_CHECK_COUNTS(pna, pns)) { + printf("%s: Bad cell count for %s\n", __FUNCTION__, + fdt_get_name(blob, parent, NULL)); + return -EINVAL; + goto out; + } + + *bus = fdt_read_number(ranges, na); + *cpu = fdt_translate_dma_address(blob, node, ranges + na); + *size = fdt_read_number(ranges + na + pna, ns); +out: + return ret; +} + +/** + * fdt_node_offset_by_compat_reg: Find a node that matches compatible and + * who's reg property matches a physical cpu address + * + * @blob: ptr to device tree + * @compat: compatible string to match + * @compat_off: property name + * + */ +int fdt_node_offset_by_compat_reg(void *blob, const char *compat, + phys_addr_t compat_off) +{ + int len, off; + + fdt_for_each_node_by_compatible(off, blob, -1, compat) { + const fdt32_t *reg = fdt_getprop(blob, off, "reg", &len); + if (reg && compat_off == fdt_translate_address(blob, off, reg)) + return off; + } + + return -FDT_ERR_NOTFOUND; +} + +static int vnode_offset_by_pathf(void *blob, const char *fmt, va_list ap) +{ + char path[512]; + int len; + + len = vsnprintf(path, sizeof(path), fmt, ap); + if (len < 0 || len + 1 > sizeof(path)) + return -FDT_ERR_NOSPACE; + + return fdt_path_offset(blob, path); +} + +/** + * fdt_node_offset_by_pathf: Find node offset by sprintf formatted path + * + * @blob: ptr to device tree + * @fmt: path format + * @ap: vsnprintf arguments + */ +int fdt_node_offset_by_pathf(void *blob, const char *fmt, ...) +{ + va_list ap; + int res; + + va_start(ap, fmt); + res = vnode_offset_by_pathf(blob, fmt, ap); + va_end(ap); + + return res; +} + +/* + * fdt_set_phandle: Create a phandle property for the given node + * + * @fdt: ptr to device tree + * @nodeoffset: node to update + * @phandle: phandle value to set (must be unique) + */ +int fdt_set_phandle(void *fdt, int nodeoffset, uint32_t phandle) +{ + int ret; + +#ifdef DEBUG + int off = fdt_node_offset_by_phandle(fdt, phandle); + + if ((off >= 0) && (off != nodeoffset)) { + char buf[64]; + + fdt_get_path(fdt, nodeoffset, buf, sizeof(buf)); + printf("Trying to update node %s with phandle %u ", + buf, phandle); + + fdt_get_path(fdt, off, buf, sizeof(buf)); + printf("that already exists in node %s.\n", buf); + return -FDT_ERR_BADPHANDLE; + } +#endif + + ret = fdt_setprop_cell(fdt, nodeoffset, "phandle", phandle); + + return ret; +} + +/* + * fdt_create_phandle: Get or create a phandle property for the given node + * + * @fdt: ptr to device tree + * @nodeoffset: node to update + */ +unsigned int fdt_create_phandle(void *fdt, int nodeoffset) +{ + /* see if there is a phandle already */ + uint32_t phandle = fdt_get_phandle(fdt, nodeoffset); + + /* if we got 0, means no phandle so create one */ + if (phandle == 0) { + int ret; + + ret = fdt_generate_phandle(fdt, &phandle); + if (ret < 0) { + printf("Can't generate phandle: %s\n", + fdt_strerror(ret)); + return 0; + } + + ret = fdt_set_phandle(fdt, nodeoffset, phandle); + if (ret < 0) { + printf("Can't set phandle %u: %s\n", phandle, + fdt_strerror(ret)); + return 0; + } + } + + return phandle; +} + +/** + * fdt_create_phandle_by_compatible: Get or create a phandle for first node with + * given compatible + * + * @fdt: ptr to device tree + * @compat: node's compatible string + */ +unsigned int fdt_create_phandle_by_compatible(void *fdt, const char *compat) +{ + int offset = fdt_node_offset_by_compatible(fdt, -1, compat); + + if (offset < 0) { + printf("Can't find node with compatible \"%s\": %s\n", compat, + fdt_strerror(offset)); + return 0; + } + + return fdt_create_phandle(fdt, offset); +} + +/** + * fdt_create_phandle_by_pathf: Get or create a phandle for node given by + * sprintf-formatted path + * + * @fdt: ptr to device tree + * @fmt, ...: path format string and arguments to pass to sprintf + */ +unsigned int fdt_create_phandle_by_pathf(void *fdt, const char *fmt, ...) +{ + va_list ap; + int offset; + + va_start(ap, fmt); + offset = vnode_offset_by_pathf(fdt, fmt, ap); + va_end(ap); + + if (offset < 0) { + printf("Can't find node by given path: %s\n", + fdt_strerror(offset)); + return 0; + } + + return fdt_create_phandle(fdt, offset); +} + +/* + * fdt_set_node_status: Set status for the given node + * + * @fdt: ptr to device tree + * @nodeoffset: node to update + * @status: FDT_STATUS_OKAY, FDT_STATUS_DISABLED, FDT_STATUS_FAIL + */ +int fdt_set_node_status(void *fdt, int nodeoffset, enum fdt_status status) +{ + int ret = 0; + + if (nodeoffset < 0) + return nodeoffset; + + switch (status) { + case FDT_STATUS_OKAY: + ret = fdt_setprop_string(fdt, nodeoffset, "status", "okay"); + break; + case FDT_STATUS_DISABLED: + ret = fdt_setprop_string(fdt, nodeoffset, "status", "disabled"); + break; + case FDT_STATUS_FAIL: + ret = fdt_setprop_string(fdt, nodeoffset, "status", "fail"); + break; + default: + printf("Invalid fdt status: %x\n", status); + ret = -1; + break; + } + + return ret; +} + +/* + * fdt_set_status_by_alias: Set status for the given node given an alias + * + * @fdt: ptr to device tree + * @alias: alias of node to update + * @status: FDT_STATUS_OKAY, FDT_STATUS_DISABLED, FDT_STATUS_FAIL + */ +int fdt_set_status_by_alias(void *fdt, const char* alias, + enum fdt_status status) +{ + int offset = fdt_path_offset(fdt, alias); + + return fdt_set_node_status(fdt, offset, status); +} + +/** + * fdt_set_status_by_compatible: Set node status for first node with given + * compatible + * + * @fdt: ptr to device tree + * @compat: node's compatible string + * @status: FDT_STATUS_OKAY, FDT_STATUS_DISABLED, FDT_STATUS_FAIL + */ +int fdt_set_status_by_compatible(void *fdt, const char *compat, + enum fdt_status status) +{ + int offset = fdt_node_offset_by_compatible(fdt, -1, compat); + + if (offset < 0) + return offset; + + return fdt_set_node_status(fdt, offset, status); +} + +/** + * fdt_set_status_by_pathf: Set node status for node given by sprintf-formatted + * path + * + * @fdt: ptr to device tree + * @status: FDT_STATUS_OKAY, FDT_STATUS_DISABLED, FDT_STATUS_FAIL + * @fmt, ...: path format string and arguments to pass to sprintf + */ +int fdt_set_status_by_pathf(void *fdt, enum fdt_status status, const char *fmt, + ...) +{ + va_list ap; + int offset; + + va_start(ap, fmt); + offset = vnode_offset_by_pathf(fdt, fmt, ap); + va_end(ap); + + if (offset < 0) + return offset; + + return fdt_set_node_status(fdt, offset, status); +} + +/* + * Verify the physical address of device tree node for a given alias + * + * This function locates the device tree node of a given alias, and then + * verifies that the physical address of that device matches the given + * parameter. It displays a message if there is a mismatch. + * + * Returns 1 on success, 0 on failure + */ +int fdt_verify_alias_address(void *fdt, int anode, const char *alias, u64 addr) +{ + const char *path; + const fdt32_t *reg; + int node, len; + u64 dt_addr; + + path = fdt_getprop(fdt, anode, alias, NULL); + if (!path) { + /* If there's no such alias, then it's not a failure */ + return 1; + } + + node = fdt_path_offset(fdt, path); + if (node < 0) { + printf("Warning: device tree alias '%s' points to invalid " + "node %s.\n", alias, path); + return 0; + } + + reg = fdt_getprop(fdt, node, "reg", &len); + if (!reg) { + printf("Warning: device tree node '%s' has no address.\n", + path); + return 0; + } + + dt_addr = fdt_translate_address(fdt, node, reg); + if (addr != dt_addr) { + printf("Warning: U-Boot configured device %s at address %llu,\n" + "but the device tree has it address %llx.\n", + alias, addr, dt_addr); + return 0; + } + + return 1; +} + +/* + * Returns the base address of an SOC or PCI node + */ +u64 fdt_get_base_address(const void *fdt, int node) +{ + int size; + const fdt32_t *prop; + + prop = fdt_getprop(fdt, node, "reg", &size); + + return prop ? fdt_translate_address(fdt, node, prop) : OF_BAD_ADDR; +} + +/* + * Read a property of size . Currently only supports 1 or 2 cells, + * or 3 cells specially for a PCI address. + */ +static int fdt_read_prop(const fdt32_t *prop, int prop_len, int cell_off, + uint64_t *val, int cells) +{ + const fdt32_t *prop32; + const unaligned_fdt64_t *prop64; + + if ((cell_off + cells) > prop_len) + return -FDT_ERR_NOSPACE; + + prop32 = &prop[cell_off]; + + /* + * Special handling for PCI address in PCI bus + * + * PCI child address is made up of 3 cells. Advance the cell offset + * by 1 so that the PCI child address can be correctly read. + */ + if (cells == 3) + cell_off += 1; + prop64 = (const fdt64_t *)&prop[cell_off]; + + switch (cells) { + case 1: + *val = fdt32_to_cpu(*prop32); + break; + case 2: + case 3: + *val = fdt64_to_cpu(*prop64); + break; + default: + return -FDT_ERR_NOSPACE; + } + + return 0; +} + +/** + * fdt_read_range - Read a node's n'th range property + * + * @fdt: ptr to device tree + * @node: offset of node + * @n: range index + * @child_addr: pointer to storage for the "child address" field + * @addr: pointer to storage for the CPU view translated physical start + * @len: pointer to storage for the range length + * + * Convenience function that reads and interprets a specific range out of + * a number of the "ranges" property array. + */ +int fdt_read_range(void *fdt, int node, int n, uint64_t *child_addr, + uint64_t *addr, uint64_t *len) +{ + int pnode = fdt_parent_offset(fdt, node); + const fdt32_t *ranges; + int pacells; + int acells; + int scells; + int ranges_len; + int cell = 0; + int r = 0; + + /* + * The "ranges" property is an array of + * { } + * + * All 3 elements can span a diffent number of cells. Fetch their size. + */ + pacells = fdt_getprop_u32_default_node(fdt, pnode, 0, "#address-cells", 1); + acells = fdt_getprop_u32_default_node(fdt, node, 0, "#address-cells", 1); + scells = fdt_getprop_u32_default_node(fdt, node, 0, "#size-cells", 1); + + /* Now try to get the ranges property */ + ranges = fdt_getprop(fdt, node, "ranges", &ranges_len); + if (!ranges) + return -FDT_ERR_NOTFOUND; + ranges_len /= sizeof(uint32_t); + + /* Jump to the n'th entry */ + cell = n * (pacells + acells + scells); + + /* Read */ + if (child_addr) { + r = fdt_read_prop(ranges, ranges_len, cell, child_addr, + acells); + if (r) + return r; + } + cell += acells; + + /* Read */ + if (addr) + *addr = fdt_translate_address(fdt, node, ranges + cell); + cell += pacells; + + /* Read */ + if (len) { + r = fdt_read_prop(ranges, ranges_len, cell, len, scells); + if (r) + return r; + } + + return 0; +} + +/** + * fdt_setup_simplefb_node - Fill and enable a simplefb node + * + * @fdt: ptr to device tree + * @node: offset of the simplefb node + * @base_address: framebuffer base address + * @width: width in pixels + * @height: height in pixels + * @stride: bytes per line + * @format: pixel format string + * + * Convenience function to fill and enable a simplefb node. + */ +int fdt_setup_simplefb_node(void *fdt, int node, u64 base_address, u32 width, + u32 height, u32 stride, const char *format) +{ + char name[32]; + fdt32_t cells[4]; + int i, addrc, sizec, ret; + + fdt_support_default_count_cells(fdt, fdt_parent_offset(fdt, node), + &addrc, &sizec); + i = 0; + if (addrc == 2) + cells[i++] = cpu_to_fdt32(base_address >> 32); + cells[i++] = cpu_to_fdt32(base_address); + if (sizec == 2) + cells[i++] = 0; + cells[i++] = cpu_to_fdt32(height * stride); + + ret = fdt_setprop(fdt, node, "reg", cells, sizeof(cells[0]) * i); + if (ret < 0) + return ret; + + snprintf(name, sizeof(name), "framebuffer@%llx", base_address); + ret = fdt_set_name(fdt, node, name); + if (ret < 0) + return ret; + + ret = fdt_setprop_u32(fdt, node, "width", width); + if (ret < 0) + return ret; + + ret = fdt_setprop_u32(fdt, node, "height", height); + if (ret < 0) + return ret; + + ret = fdt_setprop_u32(fdt, node, "stride", stride); + if (ret < 0) + return ret; + + ret = fdt_setprop_string(fdt, node, "format", format); + if (ret < 0) + return ret; + + ret = fdt_setprop_string(fdt, node, "status", "okay"); + if (ret < 0) + return ret; + + return 0; +} + +/* + * Update native-mode in display-timings from display environment variable. + * The node to update are specified by path. + */ +int fdt_fixup_display(void *blob, const char *path, const char *display) +{ + int off, toff; + + if (!display || !path) + return -FDT_ERR_NOTFOUND; + + toff = fdt_path_offset(blob, path); + if (toff >= 0) + toff = fdt_subnode_offset(blob, toff, "display-timings"); + if (toff < 0) + return toff; + + for (off = fdt_first_subnode(blob, toff); + off >= 0; + off = fdt_next_subnode(blob, off)) { + uint32_t h = fdt_get_phandle(blob, off); + debug("%s:0x%x\n", fdt_get_name(blob, off, NULL), + fdt32_to_cpu(h)); + if (strcasecmp(fdt_get_name(blob, off, NULL), display) == 0) + return fdt_setprop_u32(blob, toff, "native-mode", h); + } + return toff; +} + +#ifdef CONFIG_OF_LIBFDT_OVERLAY +/** + * fdt_overlay_apply_verbose - Apply an overlay with verbose error reporting + * + * @fdt: ptr to device tree + * @fdto: ptr to device tree overlay + * + * Convenience function to apply an overlay and display helpful messages + * in the case of an error + */ +int fdt_overlay_apply_verbose(void *fdt, void *fdto) +{ + int err; + bool has_symbols; + + err = fdt_path_offset(fdt, "/__symbols__"); + has_symbols = err >= 0; + + err = fdt_overlay_apply(fdt, fdto); + if (err < 0) { + printf("failed on fdt_overlay_apply(): %s\n", + fdt_strerror(err)); + if (!has_symbols) { + printf("base fdt does did not have a /__symbols__ node\n"); + printf("make sure you've compiled with -@\n"); + } + } + return err; +} +#endif + +/** + * fdt_valid() - Check if an FDT is valid. If not, change it to NULL + * + * @blobp: Pointer to FDT pointer + * Return: 1 if OK, 0 if bad (in which case *blobp is set to NULL) + */ +int fdt_valid(struct fdt_header **blobp) +{ + const void *blob = *blobp; + int err; + + if (!blob) { + printf("The address of the fdt is invalid (NULL).\n"); + return 0; + } + + err = fdt_check_header(blob); + if (err == 0) + return 1; /* valid */ + + if (err < 0) { + printf("libfdt fdt_check_header(): %s", fdt_strerror(err)); + /* + * Be more informative on bad version. + */ + if (err == -FDT_ERR_BADVERSION) { + if (fdt_version(blob) < + FDT_FIRST_SUPPORTED_VERSION) { + printf(" - too old, fdt %d < %d", + fdt_version(blob), + FDT_FIRST_SUPPORTED_VERSION); + } + if (fdt_last_comp_version(blob) > + FDT_LAST_SUPPORTED_VERSION) { + printf(" - too new, fdt %d > %d", + fdt_version(blob), + FDT_LAST_SUPPORTED_VERSION); + } + } + printf("\n"); + *blobp = NULL; + return 0; + } + return 1; +} diff --git a/common/Makefile b/common/Makefile index 0a3f75f2f1c..0948721d0b4 100644 --- a/common/Makefile +++ b/common/Makefile @@ -18,7 +18,6 @@ obj-$(CONFIG_DISPLAY_BOARDINFO) += board_info.o obj-$(CONFIG_DISPLAY_BOARDINFO_LATE) += board_info.o obj-$(CONFIG_FDT_SIMPLEFB) += fdt_simplefb.o -obj-$(CONFIG_$(SPL_TPL_)OF_LIBFDT) += fdt_support.o obj-$(CONFIG_MII) += miiphyutil.o obj-$(CONFIG_CMD_MII) += miiphyutil.o obj-$(CONFIG_PHYLIB) += miiphyutil.o @@ -51,7 +50,6 @@ ifdef CONFIG_SPL_DFU obj-$(CONFIG_DFU_OVER_USB) += dfu.o endif obj-$(CONFIG_SPL_NET) += miiphyutil.o -obj-$(CONFIG_$(SPL_TPL_)OF_LIBFDT) += fdt_support.o obj-$(CONFIG_SPL_USB_HOST) += usb.o usb_hub.o obj-$(CONFIG_SPL_USB_STORAGE) += usb_storage.o diff --git a/common/fdt_support.c b/common/fdt_support.c deleted file mode 100644 index 5e49078f8c3..00000000000 --- a/common/fdt_support.c +++ /dev/null @@ -1,2150 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * (C) Copyright 2007 - * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com - * - * Copyright 2010-2011 Freescale Semiconductor, Inc. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/** - * fdt_getprop_u32_default_node - Return a node's property or a default - * - * @fdt: ptr to device tree - * @off: offset of node - * @cell: cell offset in property - * @prop: property name - * @dflt: default value if the property isn't found - * - * Convenience function to return a node's property or a default value if - * the property doesn't exist. - */ -u32 fdt_getprop_u32_default_node(const void *fdt, int off, int cell, - const char *prop, const u32 dflt) -{ - const fdt32_t *val; - int len; - - val = fdt_getprop(fdt, off, prop, &len); - - /* Check if property exists */ - if (!val) - return dflt; - - /* Check if property is long enough */ - if (len < ((cell + 1) * sizeof(uint32_t))) - return dflt; - - return fdt32_to_cpu(*val); -} - -/** - * fdt_getprop_u32_default - Find a node and return it's property or a default - * - * @fdt: ptr to device tree - * @path: path of node - * @prop: property name - * @dflt: default value if the property isn't found - * - * Convenience function to find a node and return it's property or a - * default value if it doesn't exist. - */ -u32 fdt_getprop_u32_default(const void *fdt, const char *path, - const char *prop, const u32 dflt) -{ - int off; - - off = fdt_path_offset(fdt, path); - if (off < 0) - return dflt; - - return fdt_getprop_u32_default_node(fdt, off, 0, prop, dflt); -} - -/** - * fdt_find_and_setprop: Find a node and set it's property - * - * @fdt: ptr to device tree - * @node: path of node - * @prop: property name - * @val: ptr to new value - * @len: length of new property value - * @create: flag to create the property if it doesn't exist - * - * Convenience function to directly set a property given the path to the node. - */ -int fdt_find_and_setprop(void *fdt, const char *node, const char *prop, - const void *val, int len, int create) -{ - int nodeoff = fdt_path_offset(fdt, node); - - if (nodeoff < 0) - return nodeoff; - - if ((!create) && (fdt_get_property(fdt, nodeoff, prop, NULL) == NULL)) - return 0; /* create flag not set; so exit quietly */ - - return fdt_setprop(fdt, nodeoff, prop, val, len); -} - -/** - * fdt_find_or_add_subnode() - find or possibly add a subnode of a given node - * - * @fdt: pointer to the device tree blob - * @parentoffset: structure block offset of a node - * @name: name of the subnode to locate - * - * fdt_subnode_offset() finds a subnode of the node with a given name. - * If the subnode does not exist, it will be created. - */ -int fdt_find_or_add_subnode(void *fdt, int parentoffset, const char *name) -{ - int offset; - - offset = fdt_subnode_offset(fdt, parentoffset, name); - - if (offset == -FDT_ERR_NOTFOUND) - offset = fdt_add_subnode(fdt, parentoffset, name); - - if (offset < 0) - printf("%s: %s: %s\n", __func__, name, fdt_strerror(offset)); - - return offset; -} - -#if defined(CONFIG_OF_STDOUT_VIA_ALIAS) && defined(CONFIG_CONS_INDEX) -static int fdt_fixup_stdout(void *fdt, int chosenoff) -{ - int err; - int aliasoff; - char sername[9] = { 0 }; - const void *path; - int len; - char tmp[256]; /* long enough */ - - sprintf(sername, "serial%d", CONFIG_CONS_INDEX - 1); - - aliasoff = fdt_path_offset(fdt, "/aliases"); - if (aliasoff < 0) { - err = aliasoff; - goto noalias; - } - - path = fdt_getprop(fdt, aliasoff, sername, &len); - if (!path) { - err = len; - goto noalias; - } - - /* fdt_setprop may break "path" so we copy it to tmp buffer */ - memcpy(tmp, path, len); - - err = fdt_setprop(fdt, chosenoff, "linux,stdout-path", tmp, len); - if (err < 0) - printf("WARNING: could not set linux,stdout-path %s.\n", - fdt_strerror(err)); - - return err; - -noalias: - printf("WARNING: %s: could not read %s alias: %s\n", - __func__, sername, fdt_strerror(err)); - - return 0; -} -#else -static int fdt_fixup_stdout(void *fdt, int chosenoff) -{ - return 0; -} -#endif - -static inline int fdt_setprop_uxx(void *fdt, int nodeoffset, const char *name, - uint64_t val, int is_u64) -{ - if (is_u64) - return fdt_setprop_u64(fdt, nodeoffset, name, val); - else - return fdt_setprop_u32(fdt, nodeoffset, name, (uint32_t)val); -} - -int fdt_root(void *fdt) -{ - char *serial; - int err; - - err = fdt_check_header(fdt); - if (err < 0) { - printf("fdt_root: %s\n", fdt_strerror(err)); - return err; - } - - serial = env_get("serial#"); - if (serial) { - err = fdt_setprop(fdt, 0, "serial-number", serial, - strlen(serial) + 1); - - if (err < 0) { - printf("WARNING: could not set serial-number %s.\n", - fdt_strerror(err)); - return err; - } - } - - return 0; -} - -int fdt_initrd(void *fdt, ulong initrd_start, ulong initrd_end) -{ - int nodeoffset; - int err, j, total; - int is_u64; - uint64_t addr, size; - - /* just return if the size of initrd is zero */ - if (initrd_start == initrd_end) - return 0; - - /* find or create "/chosen" node. */ - nodeoffset = fdt_find_or_add_subnode(fdt, 0, "chosen"); - if (nodeoffset < 0) - return nodeoffset; - - total = fdt_num_mem_rsv(fdt); - - /* - * Look for an existing entry and update it. If we don't find - * the entry, we will j be the next available slot. - */ - for (j = 0; j < total; j++) { - err = fdt_get_mem_rsv(fdt, j, &addr, &size); - if (addr == initrd_start) { - fdt_del_mem_rsv(fdt, j); - break; - } - } - - err = fdt_add_mem_rsv(fdt, initrd_start, initrd_end - initrd_start); - if (err < 0) { - printf("fdt_initrd: %s\n", fdt_strerror(err)); - return err; - } - - is_u64 = (fdt_address_cells(fdt, 0) == 2); - - err = fdt_setprop_uxx(fdt, nodeoffset, "linux,initrd-start", - (uint64_t)initrd_start, is_u64); - - if (err < 0) { - printf("WARNING: could not set linux,initrd-start %s.\n", - fdt_strerror(err)); - return err; - } - - err = fdt_setprop_uxx(fdt, nodeoffset, "linux,initrd-end", - (uint64_t)initrd_end, is_u64); - - if (err < 0) { - printf("WARNING: could not set linux,initrd-end %s.\n", - fdt_strerror(err)); - - return err; - } - - return 0; -} - -/** - * board_fdt_chosen_bootargs - boards may override this function to use - * alternative kernel command line arguments - */ -__weak char *board_fdt_chosen_bootargs(void) -{ - return env_get("bootargs"); -} - -int fdt_chosen(void *fdt) -{ - struct abuf buf = {}; - int nodeoffset; - int err; - char *str; /* used to set string properties */ - - err = fdt_check_header(fdt); - if (err < 0) { - printf("fdt_chosen: %s\n", fdt_strerror(err)); - return err; - } - - /* find or create "/chosen" node. */ - nodeoffset = fdt_find_or_add_subnode(fdt, 0, "chosen"); - if (nodeoffset < 0) - return nodeoffset; - - if (IS_ENABLED(CONFIG_BOARD_RNG_SEED) && !board_rng_seed(&buf)) { - err = fdt_setprop(fdt, nodeoffset, "rng-seed", - abuf_data(&buf), abuf_size(&buf)); - abuf_uninit(&buf); - if (err < 0) { - printf("WARNING: could not set rng-seed %s.\n", - fdt_strerror(err)); - return err; - } - } - - str = board_fdt_chosen_bootargs(); - - if (str) { - err = fdt_setprop(fdt, nodeoffset, "bootargs", str, - strlen(str) + 1); - if (err < 0) { - printf("WARNING: could not set bootargs %s.\n", - fdt_strerror(err)); - return err; - } - } - - /* add u-boot version */ - err = fdt_setprop(fdt, nodeoffset, "u-boot,version", PLAIN_VERSION, - strlen(PLAIN_VERSION) + 1); - if (err < 0) { - printf("WARNING: could not set u-boot,version %s.\n", - fdt_strerror(err)); - return err; - } - - return fdt_fixup_stdout(fdt, nodeoffset); -} - -void do_fixup_by_path(void *fdt, const char *path, const char *prop, - const void *val, int len, int create) -{ -#if defined(DEBUG) - int i; - debug("Updating property '%s/%s' = ", path, prop); - for (i = 0; i < len; i++) - debug(" %.2x", *(u8*)(val+i)); - debug("\n"); -#endif - int rc = fdt_find_and_setprop(fdt, path, prop, val, len, create); - if (rc) - printf("Unable to update property %s:%s, err=%s\n", - path, prop, fdt_strerror(rc)); -} - -void do_fixup_by_path_u32(void *fdt, const char *path, const char *prop, - u32 val, int create) -{ - fdt32_t tmp = cpu_to_fdt32(val); - do_fixup_by_path(fdt, path, prop, &tmp, sizeof(tmp), create); -} - -void do_fixup_by_prop(void *fdt, - const char *pname, const void *pval, int plen, - const char *prop, const void *val, int len, - int create) -{ - int off; -#if defined(DEBUG) - int i; - debug("Updating property '%s' = ", prop); - for (i = 0; i < len; i++) - debug(" %.2x", *(u8*)(val+i)); - debug("\n"); -#endif - off = fdt_node_offset_by_prop_value(fdt, -1, pname, pval, plen); - while (off != -FDT_ERR_NOTFOUND) { - if (create || (fdt_get_property(fdt, off, prop, NULL) != NULL)) - fdt_setprop(fdt, off, prop, val, len); - off = fdt_node_offset_by_prop_value(fdt, off, pname, pval, plen); - } -} - -void do_fixup_by_prop_u32(void *fdt, - const char *pname, const void *pval, int plen, - const char *prop, u32 val, int create) -{ - fdt32_t tmp = cpu_to_fdt32(val); - do_fixup_by_prop(fdt, pname, pval, plen, prop, &tmp, 4, create); -} - -void do_fixup_by_compat(void *fdt, const char *compat, - const char *prop, const void *val, int len, int create) -{ - int off = -1; -#if defined(DEBUG) - int i; - debug("Updating property '%s' = ", prop); - for (i = 0; i < len; i++) - debug(" %.2x", *(u8*)(val+i)); - debug("\n"); -#endif - fdt_for_each_node_by_compatible(off, fdt, -1, compat) - if (create || (fdt_get_property(fdt, off, prop, NULL) != NULL)) - fdt_setprop(fdt, off, prop, val, len); -} - -void do_fixup_by_compat_u32(void *fdt, const char *compat, - const char *prop, u32 val, int create) -{ - fdt32_t tmp = cpu_to_fdt32(val); - do_fixup_by_compat(fdt, compat, prop, &tmp, 4, create); -} - -#ifdef CONFIG_ARCH_FIXUP_FDT_MEMORY -/* - * fdt_pack_reg - pack address and size array into the "reg"-suitable stream - */ -static int fdt_pack_reg(const void *fdt, void *buf, u64 *address, u64 *size, - int n) -{ - int i; - int address_cells = fdt_address_cells(fdt, 0); - int size_cells = fdt_size_cells(fdt, 0); - char *p = buf; - - for (i = 0; i < n; i++) { - if (address_cells == 2) - *(fdt64_t *)p = cpu_to_fdt64(address[i]); - else - *(fdt32_t *)p = cpu_to_fdt32(address[i]); - p += 4 * address_cells; - - if (size_cells == 2) - *(fdt64_t *)p = cpu_to_fdt64(size[i]); - else - *(fdt32_t *)p = cpu_to_fdt32(size[i]); - p += 4 * size_cells; - } - - return p - (char *)buf; -} - -#if CONFIG_NR_DRAM_BANKS > 4 -#define MEMORY_BANKS_MAX CONFIG_NR_DRAM_BANKS -#else -#define MEMORY_BANKS_MAX 4 -#endif - -/** - * fdt_fixup_memory_banks - Update DT memory node - * @blob: Pointer to DT blob - * @start: Pointer to memory start addresses array - * @size: Pointer to memory sizes array - * @banks: Number of memory banks - * - * Return: 0 on success, negative value on failure - * - * Based on the passed number of banks and arrays, the function is able to - * update existing DT memory nodes to match run time detected/changed memory - * configuration. Implementation is handling one specific case with only one - * memory node where multiple tuples could be added/updated. - * The case where multiple memory nodes with a single tuple (base, size) are - * used, this function is only updating the first memory node without removing - * others. - */ -int fdt_fixup_memory_banks(void *blob, u64 start[], u64 size[], int banks) -{ - int err, nodeoffset; - int len, i; - u8 tmp[MEMORY_BANKS_MAX * 16]; /* Up to 64-bit address + 64-bit size */ - - if (banks > MEMORY_BANKS_MAX) { - printf("%s: num banks %d exceeds hardcoded limit %d." - " Recompile with higher MEMORY_BANKS_MAX?\n", - __FUNCTION__, banks, MEMORY_BANKS_MAX); - return -1; - } - - err = fdt_check_header(blob); - if (err < 0) { - printf("%s: %s\n", __FUNCTION__, fdt_strerror(err)); - return err; - } - - /* find or create "/memory" node. */ - nodeoffset = fdt_find_or_add_subnode(blob, 0, "memory"); - if (nodeoffset < 0) - return nodeoffset; - - err = fdt_setprop(blob, nodeoffset, "device_type", "memory", - sizeof("memory")); - if (err < 0) { - printf("WARNING: could not set %s %s.\n", "device_type", - fdt_strerror(err)); - return err; - } - - for (i = 0; i < banks; i++) { - if (start[i] == 0 && size[i] == 0) - break; - } - - banks = i; - - if (!banks) - return 0; - - len = fdt_pack_reg(blob, tmp, start, size, banks); - - err = fdt_setprop(blob, nodeoffset, "reg", tmp, len); - if (err < 0) { - printf("WARNING: could not set %s %s.\n", - "reg", fdt_strerror(err)); - return err; - } - return 0; -} - -int fdt_set_usable_memory(void *blob, u64 start[], u64 size[], int areas) -{ - int err, nodeoffset; - int len; - u8 tmp[8 * 16]; /* Up to 64-bit address + 64-bit size */ - - if (areas > 8) { - printf("%s: num areas %d exceeds hardcoded limit %d\n", - __func__, areas, 8); - return -1; - } - - err = fdt_check_header(blob); - if (err < 0) { - printf("%s: %s\n", __func__, fdt_strerror(err)); - return err; - } - - /* find or create "/memory" node. */ - nodeoffset = fdt_find_or_add_subnode(blob, 0, "memory"); - if (nodeoffset < 0) - return nodeoffset; - - len = fdt_pack_reg(blob, tmp, start, size, areas); - - err = fdt_setprop(blob, nodeoffset, "linux,usable-memory", tmp, len); - if (err < 0) { - printf("WARNING: could not set %s %s.\n", - "reg", fdt_strerror(err)); - return err; - } - - return 0; -} -#endif - -int fdt_fixup_memory(void *blob, u64 start, u64 size) -{ - return fdt_fixup_memory_banks(blob, &start, &size, 1); -} - -void fdt_fixup_ethernet(void *fdt) -{ - int i = 0, j, prop; - char *tmp, *end; - char mac[16]; - const char *path; - unsigned char mac_addr[ARP_HLEN]; - int offset; -#ifdef FDT_SEQ_MACADDR_FROM_ENV - int nodeoff; - const struct fdt_property *fdt_prop; -#endif - - if (fdt_path_offset(fdt, "/aliases") < 0) - return; - - /* Cycle through all aliases */ - for (prop = 0; ; prop++) { - const char *name; - - /* FDT might have been edited, recompute the offset */ - offset = fdt_first_property_offset(fdt, - fdt_path_offset(fdt, "/aliases")); - /* Select property number 'prop' */ - for (j = 0; j < prop; j++) - offset = fdt_next_property_offset(fdt, offset); - - if (offset < 0) - break; - - path = fdt_getprop_by_offset(fdt, offset, &name, NULL); - if (!strncmp(name, "ethernet", 8)) { - /* Treat plain "ethernet" same as "ethernet0". */ - if (!strcmp(name, "ethernet") -#ifdef FDT_SEQ_MACADDR_FROM_ENV - || !strcmp(name, "ethernet0") -#endif - ) - i = 0; -#ifndef FDT_SEQ_MACADDR_FROM_ENV - else - i = trailing_strtol(name); -#endif - if (i != -1) { - if (i == 0) - strcpy(mac, "ethaddr"); - else - sprintf(mac, "eth%daddr", i); - } else { - continue; - } -#ifdef FDT_SEQ_MACADDR_FROM_ENV - nodeoff = fdt_path_offset(fdt, path); - fdt_prop = fdt_get_property(fdt, nodeoff, "status", - NULL); - if (fdt_prop && !strcmp(fdt_prop->data, "disabled")) - continue; - i++; -#endif - tmp = env_get(mac); - if (!tmp) - continue; - - for (j = 0; j < 6; j++) { - mac_addr[j] = tmp ? - hextoul(tmp, &end) : 0; - if (tmp) - tmp = (*end) ? end + 1 : end; - } - - do_fixup_by_path(fdt, path, "mac-address", - &mac_addr, 6, 0); - do_fixup_by_path(fdt, path, "local-mac-address", - &mac_addr, 6, 1); - } - } -} - -int fdt_record_loadable(void *blob, u32 index, const char *name, - uintptr_t load_addr, u32 size, uintptr_t entry_point, - const char *type, const char *os, const char *arch) -{ - int err, node; - - err = fdt_check_header(blob); - if (err < 0) { - printf("%s: %s\n", __func__, fdt_strerror(err)); - return err; - } - - /* find or create "/fit-images" node */ - node = fdt_find_or_add_subnode(blob, 0, "fit-images"); - if (node < 0) - return node; - - /* find or create "/fit-images/" node */ - node = fdt_find_or_add_subnode(blob, node, name); - if (node < 0) - return node; - - fdt_setprop_u64(blob, node, "load", load_addr); - if (entry_point != -1) - fdt_setprop_u64(blob, node, "entry", entry_point); - fdt_setprop_u32(blob, node, "size", size); - if (type) - fdt_setprop_string(blob, node, "type", type); - if (os) - fdt_setprop_string(blob, node, "os", os); - if (arch) - fdt_setprop_string(blob, node, "arch", arch); - - return node; -} - -/* Resize the fdt to its actual size + a bit of padding */ -int fdt_shrink_to_minimum(void *blob, uint extrasize) -{ - int i; - uint64_t addr, size; - int total, ret; - uint actualsize; - int fdt_memrsv = 0; - - if (!blob) - return 0; - - total = fdt_num_mem_rsv(blob); - for (i = 0; i < total; i++) { - fdt_get_mem_rsv(blob, i, &addr, &size); - if (addr == (uintptr_t)blob) { - fdt_del_mem_rsv(blob, i); - fdt_memrsv = 1; - break; - } - } - - /* - * Calculate the actual size of the fdt - * plus the size needed for 5 fdt_add_mem_rsv, one - * for the fdt itself and 4 for a possible initrd - * ((initrd-start + initrd-end) * 2 (name & value)) - */ - actualsize = fdt_off_dt_strings(blob) + - fdt_size_dt_strings(blob) + 5 * sizeof(struct fdt_reserve_entry); - - actualsize += extrasize; - /* Make it so the fdt ends on a page boundary */ - actualsize = ALIGN(actualsize + ((uintptr_t)blob & 0xfff), 0x1000); - actualsize = actualsize - ((uintptr_t)blob & 0xfff); - - /* Change the fdt header to reflect the correct size */ - fdt_set_totalsize(blob, actualsize); - - if (fdt_memrsv) { - /* Add the new reservation */ - ret = fdt_add_mem_rsv(blob, map_to_sysmem(blob), actualsize); - if (ret < 0) - return ret; - } - - return actualsize; -} - -/** - * fdt_delete_disabled_nodes: Delete all nodes with status == "disabled" - * - * @blob: ptr to device tree - */ -int fdt_delete_disabled_nodes(void *blob) -{ - while (1) { - int ret, offset; - - offset = fdt_node_offset_by_prop_value(blob, -1, "status", - "disabled", 9); - if (offset < 0) - break; - - ret = fdt_del_node(blob, offset); - if (ret < 0) - return ret; - } - - return 0; -} - -#ifdef CONFIG_PCI -#define CFG_SYS_PCI_NR_INBOUND_WIN 4 - -#define FDT_PCI_PREFETCH (0x40000000) -#define FDT_PCI_MEM32 (0x02000000) -#define FDT_PCI_IO (0x01000000) -#define FDT_PCI_MEM64 (0x03000000) - -int fdt_pci_dma_ranges(void *blob, int phb_off, struct pci_controller *hose) { - - int addrcell, sizecell, len, r; - u32 *dma_range; - /* sized based on pci addr cells, size-cells, & address-cells */ - u32 dma_ranges[(3 + 2 + 2) * CFG_SYS_PCI_NR_INBOUND_WIN]; - - addrcell = fdt_getprop_u32_default(blob, "/", "#address-cells", 1); - sizecell = fdt_getprop_u32_default(blob, "/", "#size-cells", 1); - - dma_range = &dma_ranges[0]; - for (r = 0; r < hose->region_count; r++) { - u64 bus_start, phys_start, size; - - /* skip if !PCI_REGION_SYS_MEMORY */ - if (!(hose->regions[r].flags & PCI_REGION_SYS_MEMORY)) - continue; - - bus_start = (u64)hose->regions[r].bus_start; - phys_start = (u64)hose->regions[r].phys_start; - size = (u64)hose->regions[r].size; - - dma_range[0] = 0; - if (size >= 0x100000000ull) - dma_range[0] |= cpu_to_fdt32(FDT_PCI_MEM64); - else - dma_range[0] |= cpu_to_fdt32(FDT_PCI_MEM32); - if (hose->regions[r].flags & PCI_REGION_PREFETCH) - dma_range[0] |= cpu_to_fdt32(FDT_PCI_PREFETCH); -#ifdef CONFIG_SYS_PCI_64BIT - dma_range[1] = cpu_to_fdt32(bus_start >> 32); -#else - dma_range[1] = 0; -#endif - dma_range[2] = cpu_to_fdt32(bus_start & 0xffffffff); - - if (addrcell == 2) { - dma_range[3] = cpu_to_fdt32(phys_start >> 32); - dma_range[4] = cpu_to_fdt32(phys_start & 0xffffffff); - } else { - dma_range[3] = cpu_to_fdt32(phys_start & 0xffffffff); - } - - if (sizecell == 2) { - dma_range[3 + addrcell + 0] = - cpu_to_fdt32(size >> 32); - dma_range[3 + addrcell + 1] = - cpu_to_fdt32(size & 0xffffffff); - } else { - dma_range[3 + addrcell + 0] = - cpu_to_fdt32(size & 0xffffffff); - } - - dma_range += (3 + addrcell + sizecell); - } - - len = dma_range - &dma_ranges[0]; - if (len) - fdt_setprop(blob, phb_off, "dma-ranges", &dma_ranges[0], len*4); - - return 0; -} -#endif - -int fdt_increase_size(void *fdt, int add_len) -{ - int newlen; - - newlen = fdt_totalsize(fdt) + add_len; - - /* Open in place with a new len */ - return fdt_open_into(fdt, fdt, newlen); -} - -#ifdef CONFIG_FDT_FIXUP_PARTITIONS -#include -#include - -static int fdt_del_subnodes(const void *blob, int parent_offset) -{ - int off, ndepth; - int ret; - - for (ndepth = 0, off = fdt_next_node(blob, parent_offset, &ndepth); - (off >= 0) && (ndepth > 0); - off = fdt_next_node(blob, off, &ndepth)) { - if (ndepth == 1) { - debug("delete %s: offset: %x\n", - fdt_get_name(blob, off, 0), off); - ret = fdt_del_node((void *)blob, off); - if (ret < 0) { - printf("Can't delete node: %s\n", - fdt_strerror(ret)); - return ret; - } else { - ndepth = 0; - off = parent_offset; - } - } - } - return 0; -} - -static int fdt_del_partitions(void *blob, int parent_offset) -{ - const void *prop; - int ndepth = 0; - int off; - int ret; - - off = fdt_next_node(blob, parent_offset, &ndepth); - if (off > 0 && ndepth == 1) { - prop = fdt_getprop(blob, off, "label", NULL); - if (prop == NULL) { - /* - * Could not find label property, nand {}; node? - * Check subnode, delete partitions there if any. - */ - return fdt_del_partitions(blob, off); - } else { - ret = fdt_del_subnodes(blob, parent_offset); - if (ret < 0) { - printf("Can't remove subnodes: %s\n", - fdt_strerror(ret)); - return ret; - } - } - } - return 0; -} - -static int fdt_node_set_part_info(void *blob, int parent_offset, - struct mtd_device *dev) -{ - struct list_head *pentry; - struct part_info *part; - int off, ndepth = 0; - int part_num, ret; - int sizecell; - char buf[64]; - - ret = fdt_del_partitions(blob, parent_offset); - if (ret < 0) - return ret; - - /* - * Check if size/address is 1 or 2 cells. - * We assume #address-cells and #size-cells have same value. - */ - sizecell = fdt_getprop_u32_default_node(blob, parent_offset, - 0, "#size-cells", 1); - - /* - * Check if it is nand {}; subnode, adjust - * the offset in this case - */ - off = fdt_next_node(blob, parent_offset, &ndepth); - if (off > 0 && ndepth == 1) - parent_offset = off; - - part_num = 0; - list_for_each_prev(pentry, &dev->parts) { - int newoff; - - part = list_entry(pentry, struct part_info, link); - - debug("%2d: %-20s0x%08llx\t0x%08llx\t%d\n", - part_num, part->name, part->size, - part->offset, part->mask_flags); - - sprintf(buf, "partition@%llx", part->offset); -add_sub: - ret = fdt_add_subnode(blob, parent_offset, buf); - if (ret == -FDT_ERR_NOSPACE) { - ret = fdt_increase_size(blob, 512); - if (!ret) - goto add_sub; - else - goto err_size; - } else if (ret < 0) { - printf("Can't add partition node: %s\n", - fdt_strerror(ret)); - return ret; - } - newoff = ret; - - /* Check MTD_WRITEABLE_CMD flag */ - if (part->mask_flags & 1) { -add_ro: - ret = fdt_setprop(blob, newoff, "read_only", NULL, 0); - if (ret == -FDT_ERR_NOSPACE) { - ret = fdt_increase_size(blob, 512); - if (!ret) - goto add_ro; - else - goto err_size; - } else if (ret < 0) - goto err_prop; - } - -add_reg: - if (sizecell == 2) { - ret = fdt_setprop_u64(blob, newoff, - "reg", part->offset); - if (!ret) - ret = fdt_appendprop_u64(blob, newoff, - "reg", part->size); - } else { - ret = fdt_setprop_u32(blob, newoff, - "reg", part->offset); - if (!ret) - ret = fdt_appendprop_u32(blob, newoff, - "reg", part->size); - } - - if (ret == -FDT_ERR_NOSPACE) { - ret = fdt_increase_size(blob, 512); - if (!ret) - goto add_reg; - else - goto err_size; - } else if (ret < 0) - goto err_prop; - -add_label: - ret = fdt_setprop_string(blob, newoff, "label", part->name); - if (ret == -FDT_ERR_NOSPACE) { - ret = fdt_increase_size(blob, 512); - if (!ret) - goto add_label; - else - goto err_size; - } else if (ret < 0) - goto err_prop; - - part_num++; - } - return 0; -err_size: - printf("Can't increase blob size: %s\n", fdt_strerror(ret)); - return ret; -err_prop: - printf("Can't add property: %s\n", fdt_strerror(ret)); - return ret; -} - -/* - * Update partitions in nor/nand nodes using info from - * mtdparts environment variable. The nodes to update are - * specified by node_info structure which contains mtd device - * type and compatible string: E. g. the board code in - * ft_board_setup() could use: - * - * struct node_info nodes[] = { - * { "fsl,mpc5121-nfc", MTD_DEV_TYPE_NAND, }, - * { "cfi-flash", MTD_DEV_TYPE_NOR, }, - * }; - * - * fdt_fixup_mtdparts(blob, nodes, ARRAY_SIZE(nodes)); - */ -void fdt_fixup_mtdparts(void *blob, const struct node_info *node_info, - int node_info_size) -{ - struct mtd_device *dev; - int i, idx; - int noff, parts; - bool inited = false; - - for (i = 0; i < node_info_size; i++) { - idx = 0; - - fdt_for_each_node_by_compatible(noff, blob, -1, - node_info[i].compat) { - const char *prop; - - prop = fdt_getprop(blob, noff, "status", NULL); - if (prop && !strcmp(prop, "disabled")) - continue; - - debug("%s: %s, mtd dev type %d\n", - fdt_get_name(blob, noff, 0), - node_info[i].compat, node_info[i].type); - - if (!inited) { - if (mtdparts_init() != 0) - return; - inited = true; - } - - dev = device_find(node_info[i].type, idx++); - if (dev) { - parts = fdt_subnode_offset(blob, noff, - "partitions"); - if (parts < 0) - parts = noff; - - if (fdt_node_set_part_info(blob, parts, dev)) - return; /* return on error */ - } - } - } -} -#endif - -int fdt_copy_fixed_partitions(void *blob) -{ - ofnode node, subnode; - int off, suboff, res; - char path[256]; - int address_cells, size_cells; - u8 i, j, child_count; - - node = ofnode_by_compatible(ofnode_null(), "fixed-partitions"); - while (ofnode_valid(node)) { - /* copy the U-Boot fixed partition */ - address_cells = ofnode_read_simple_addr_cells(node); - size_cells = ofnode_read_simple_size_cells(node); - - res = ofnode_get_path(ofnode_get_parent(node), path, sizeof(path)); - if (res) - return res; - - off = fdt_path_offset(blob, path); - if (off < 0) - return -ENODEV; - - off = fdt_find_or_add_subnode(blob, off, "partitions"); - res = fdt_setprop_string(blob, off, "compatible", "fixed-partitions"); - if (res) - return res; - - res = fdt_setprop_u32(blob, off, "#address-cells", address_cells); - if (res) - return res; - - res = fdt_setprop_u32(blob, off, "#size-cells", size_cells); - if (res) - return res; - - /* - * parse partition in reverse order as fdt_find_or_add_subnode() only - * insert the new node after the parent's properties - */ - child_count = ofnode_get_child_count(node); - for (i = child_count; i > 0 ; i--) { - subnode = ofnode_first_subnode(node); - if (!ofnode_valid(subnode)) - break; - - for (j = 0; (j < i - 1); j++) - subnode = ofnode_next_subnode(subnode); - - if (!ofnode_valid(subnode)) - break; - - const u32 *reg; - int len; - - suboff = fdt_find_or_add_subnode(blob, off, ofnode_get_name(subnode)); - res = fdt_setprop_string(blob, suboff, "label", - ofnode_read_string(subnode, "label")); - if (res) - return res; - - reg = ofnode_get_property(subnode, "reg", &len); - res = fdt_setprop(blob, suboff, "reg", reg, len); - if (res) - return res; - } - - /* go to next fixed-partitions node */ - node = ofnode_by_compatible(node, "fixed-partitions"); - } - - return 0; -} - -void fdt_del_node_and_alias(void *blob, const char *alias) -{ - int off = fdt_path_offset(blob, alias); - - if (off < 0) - return; - - fdt_del_node(blob, off); - - off = fdt_path_offset(blob, "/aliases"); - fdt_delprop(blob, off, alias); -} - -/* Max address size we deal with */ -#define OF_MAX_ADDR_CELLS 4 -#define OF_CHECK_COUNTS(na, ns) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \ - (ns) > 0) - -/* Debug utility */ -#ifdef DEBUG -static void of_dump_addr(const char *s, const fdt32_t *addr, int na) -{ - printf("%s", s); - while(na--) - printf(" %08x", *(addr++)); - printf("\n"); -} -#else -static void of_dump_addr(const char *s, const fdt32_t *addr, int na) { } -#endif - -/** - * struct of_bus - Callbacks for bus specific translators - * @name: A string used to identify this bus in debug output. - * @addresses: The name of the DT property from which addresses are - * to be read, typically "reg". - * @match: Return non-zero if the node whose parent is at - * parentoffset in the FDT blob corresponds to a bus - * of this type, otherwise return zero. If NULL a match - * is assumed. - * @count_cells:Count how many cells (be32 values) a node whose parent - * is at parentoffset in the FDT blob will require to - * represent its address (written to *addrc) & size - * (written to *sizec). - * @map: Map the address addr from the address space of this - * bus to that of its parent, making use of the ranges - * read from DT to an array at range. na and ns are the - * number of cells (be32 values) used to hold and address - * or size, respectively, for this bus. pna is the number - * of cells used to hold an address for the parent bus. - * Returns the address in the address space of the parent - * bus. - * @translate: Update the value of the address cells at addr within an - * FDT by adding offset to it. na specifies the number of - * cells used to hold the address being translated. Returns - * zero on success, non-zero on error. - * - * Each bus type will include a struct of_bus in the of_busses array, - * providing implementations of some or all of the functions used to - * match the bus & handle address translation for its children. - */ -struct of_bus { - const char *name; - const char *addresses; - int (*match)(const void *blob, int parentoffset); - void (*count_cells)(const void *blob, int parentoffset, - int *addrc, int *sizec); - u64 (*map)(fdt32_t *addr, const fdt32_t *range, - int na, int ns, int pna); - int (*translate)(fdt32_t *addr, u64 offset, int na); -}; - -/* Default translator (generic bus) */ -void fdt_support_default_count_cells(const void *blob, int parentoffset, - int *addrc, int *sizec) -{ - const fdt32_t *prop; - - if (addrc) - *addrc = fdt_address_cells(blob, parentoffset); - - if (sizec) { - prop = fdt_getprop(blob, parentoffset, "#size-cells", NULL); - if (prop) - *sizec = be32_to_cpup(prop); - else - *sizec = 1; - } -} - -static u64 of_bus_default_map(fdt32_t *addr, const fdt32_t *range, - int na, int ns, int pna) -{ - u64 cp, s, da; - - cp = fdt_read_number(range, na); - s = fdt_read_number(range + na + pna, ns); - da = fdt_read_number(addr, na); - - debug("OF: default map, cp=%llx, s=%llx, da=%llx\n", cp, s, da); - - if (da < cp || da >= (cp + s)) - return OF_BAD_ADDR; - return da - cp; -} - -static int of_bus_default_translate(fdt32_t *addr, u64 offset, int na) -{ - u64 a = fdt_read_number(addr, na); - memset(addr, 0, na * 4); - a += offset; - if (na > 1) - addr[na - 2] = cpu_to_fdt32(a >> 32); - addr[na - 1] = cpu_to_fdt32(a & 0xffffffffu); - - return 0; -} - -#ifdef CONFIG_OF_ISA_BUS - -/* ISA bus translator */ -static int of_bus_isa_match(const void *blob, int parentoffset) -{ - const char *name; - - name = fdt_get_name(blob, parentoffset, NULL); - if (!name) - return 0; - - return !strcmp(name, "isa"); -} - -static void of_bus_isa_count_cells(const void *blob, int parentoffset, - int *addrc, int *sizec) -{ - if (addrc) - *addrc = 2; - if (sizec) - *sizec = 1; -} - -static u64 of_bus_isa_map(fdt32_t *addr, const fdt32_t *range, - int na, int ns, int pna) -{ - u64 cp, s, da; - - /* Check address type match */ - if ((addr[0] ^ range[0]) & cpu_to_be32(1)) - return OF_BAD_ADDR; - - cp = fdt_read_number(range + 1, na - 1); - s = fdt_read_number(range + na + pna, ns); - da = fdt_read_number(addr + 1, na - 1); - - debug("OF: ISA map, cp=%llx, s=%llx, da=%llx\n", cp, s, da); - - if (da < cp || da >= (cp + s)) - return OF_BAD_ADDR; - return da - cp; -} - -static int of_bus_isa_translate(fdt32_t *addr, u64 offset, int na) -{ - return of_bus_default_translate(addr + 1, offset, na - 1); -} - -#endif /* CONFIG_OF_ISA_BUS */ - -/* Array of bus specific translators */ -static struct of_bus of_busses[] = { -#ifdef CONFIG_OF_ISA_BUS - /* ISA */ - { - .name = "isa", - .addresses = "reg", - .match = of_bus_isa_match, - .count_cells = of_bus_isa_count_cells, - .map = of_bus_isa_map, - .translate = of_bus_isa_translate, - }, -#endif /* CONFIG_OF_ISA_BUS */ - /* Default */ - { - .name = "default", - .addresses = "reg", - .count_cells = fdt_support_default_count_cells, - .map = of_bus_default_map, - .translate = of_bus_default_translate, - }, -}; - -static struct of_bus *of_match_bus(const void *blob, int parentoffset) -{ - struct of_bus *bus; - - if (ARRAY_SIZE(of_busses) == 1) - return of_busses; - - for (bus = of_busses; bus; bus++) { - if (!bus->match || bus->match(blob, parentoffset)) - return bus; - } - - /* - * We should always have matched the default bus at least, since - * it has a NULL match field. If we didn't then it somehow isn't - * in the of_busses array or something equally catastrophic has - * gone wrong. - */ - assert(0); - return NULL; -} - -static int of_translate_one(const void *blob, int parent, struct of_bus *bus, - struct of_bus *pbus, fdt32_t *addr, - int na, int ns, int pna, const char *rprop) -{ - const fdt32_t *ranges; - int rlen; - int rone; - u64 offset = OF_BAD_ADDR; - - /* Normally, an absence of a "ranges" property means we are - * crossing a non-translatable boundary, and thus the addresses - * below the current not cannot be converted to CPU physical ones. - * Unfortunately, while this is very clear in the spec, it's not - * what Apple understood, and they do have things like /uni-n or - * /ht nodes with no "ranges" property and a lot of perfectly - * useable mapped devices below them. Thus we treat the absence of - * "ranges" as equivalent to an empty "ranges" property which means - * a 1:1 translation at that level. It's up to the caller not to try - * to translate addresses that aren't supposed to be translated in - * the first place. --BenH. - */ - ranges = fdt_getprop(blob, parent, rprop, &rlen); - if (ranges == NULL || rlen == 0) { - offset = fdt_read_number(addr, na); - memset(addr, 0, pna * 4); - debug("OF: no ranges, 1:1 translation\n"); - goto finish; - } - - debug("OF: walking ranges...\n"); - - /* Now walk through the ranges */ - rlen /= 4; - rone = na + pna + ns; - for (; rlen >= rone; rlen -= rone, ranges += rone) { - offset = bus->map(addr, ranges, na, ns, pna); - if (offset != OF_BAD_ADDR) - break; - } - if (offset == OF_BAD_ADDR) { - debug("OF: not found !\n"); - return 1; - } - memcpy(addr, ranges + na, 4 * pna); - - finish: - of_dump_addr("OF: parent translation for:", addr, pna); - debug("OF: with offset: %llu\n", offset); - - /* Translate it into parent bus space */ - return pbus->translate(addr, offset, pna); -} - -/* - * Translate an address from the device-tree into a CPU physical address, - * this walks up the tree and applies the various bus mappings on the - * way. - * - * Note: We consider that crossing any level with #size-cells == 0 to mean - * that translation is impossible (that is we are not dealing with a value - * that can be mapped to a cpu physical address). This is not really specified - * that way, but this is traditionally the way IBM at least do things - */ -static u64 __of_translate_address(const void *blob, int node_offset, - const fdt32_t *in_addr, const char *rprop) -{ - int parent; - struct of_bus *bus, *pbus; - fdt32_t addr[OF_MAX_ADDR_CELLS]; - int na, ns, pna, pns; - u64 result = OF_BAD_ADDR; - - debug("OF: ** translation for device %s **\n", - fdt_get_name(blob, node_offset, NULL)); - - /* Get parent & match bus type */ - parent = fdt_parent_offset(blob, node_offset); - if (parent < 0) - goto bail; - bus = of_match_bus(blob, parent); - - /* Cound address cells & copy address locally */ - bus->count_cells(blob, parent, &na, &ns); - if (!OF_CHECK_COUNTS(na, ns)) { - printf("%s: Bad cell count for %s\n", __FUNCTION__, - fdt_get_name(blob, node_offset, NULL)); - goto bail; - } - memcpy(addr, in_addr, na * 4); - - debug("OF: bus is %s (na=%d, ns=%d) on %s\n", - bus->name, na, ns, fdt_get_name(blob, parent, NULL)); - of_dump_addr("OF: translating address:", addr, na); - - /* Translate */ - for (;;) { - /* Switch to parent bus */ - node_offset = parent; - parent = fdt_parent_offset(blob, node_offset); - - /* If root, we have finished */ - if (parent < 0) { - debug("OF: reached root node\n"); - result = fdt_read_number(addr, na); - break; - } - - /* Get new parent bus and counts */ - pbus = of_match_bus(blob, parent); - pbus->count_cells(blob, parent, &pna, &pns); - if (!OF_CHECK_COUNTS(pna, pns)) { - printf("%s: Bad cell count for %s\n", __FUNCTION__, - fdt_get_name(blob, node_offset, NULL)); - break; - } - - debug("OF: parent bus is %s (na=%d, ns=%d) on %s\n", - pbus->name, pna, pns, fdt_get_name(blob, parent, NULL)); - - /* Apply bus translation */ - if (of_translate_one(blob, node_offset, bus, pbus, - addr, na, ns, pna, rprop)) - break; - - /* Complete the move up one level */ - na = pna; - ns = pns; - bus = pbus; - - of_dump_addr("OF: one level translation:", addr, na); - } - bail: - - return result; -} - -u64 fdt_translate_address(const void *blob, int node_offset, - const fdt32_t *in_addr) -{ - return __of_translate_address(blob, node_offset, in_addr, "ranges"); -} - -u64 fdt_translate_dma_address(const void *blob, int node_offset, - const fdt32_t *in_addr) -{ - return __of_translate_address(blob, node_offset, in_addr, "dma-ranges"); -} - -int fdt_get_dma_range(const void *blob, int node, phys_addr_t *cpu, - dma_addr_t *bus, u64 *size) -{ - bool found_dma_ranges = false; - struct of_bus *bus_node; - const fdt32_t *ranges; - int na, ns, pna, pns; - int parent = node; - int ret = 0; - int len; - - /* Find the closest dma-ranges property */ - while (parent >= 0) { - ranges = fdt_getprop(blob, parent, "dma-ranges", &len); - - /* Ignore empty ranges, they imply no translation required */ - if (ranges && len > 0) - break; - - /* Once we find 'dma-ranges', then a missing one is an error */ - if (found_dma_ranges && !ranges) { - ret = -EINVAL; - goto out; - } - - if (ranges) - found_dma_ranges = true; - - parent = fdt_parent_offset(blob, parent); - } - - if (!ranges || parent < 0) { - debug("no dma-ranges found for node %s\n", - fdt_get_name(blob, node, NULL)); - ret = -ENOENT; - goto out; - } - - /* switch to that node */ - node = parent; - parent = fdt_parent_offset(blob, node); - if (parent < 0) { - printf("Found dma-ranges in root node, shouldn't happen\n"); - ret = -EINVAL; - goto out; - } - - /* Get the address sizes both for the bus and its parent */ - bus_node = of_match_bus(blob, node); - bus_node->count_cells(blob, node, &na, &ns); - if (!OF_CHECK_COUNTS(na, ns)) { - printf("%s: Bad cell count for %s\n", __FUNCTION__, - fdt_get_name(blob, node, NULL)); - return -EINVAL; - goto out; - } - - bus_node = of_match_bus(blob, parent); - bus_node->count_cells(blob, parent, &pna, &pns); - if (!OF_CHECK_COUNTS(pna, pns)) { - printf("%s: Bad cell count for %s\n", __FUNCTION__, - fdt_get_name(blob, parent, NULL)); - return -EINVAL; - goto out; - } - - *bus = fdt_read_number(ranges, na); - *cpu = fdt_translate_dma_address(blob, node, ranges + na); - *size = fdt_read_number(ranges + na + pna, ns); -out: - return ret; -} - -/** - * fdt_node_offset_by_compat_reg: Find a node that matches compatible and - * who's reg property matches a physical cpu address - * - * @blob: ptr to device tree - * @compat: compatible string to match - * @compat_off: property name - * - */ -int fdt_node_offset_by_compat_reg(void *blob, const char *compat, - phys_addr_t compat_off) -{ - int len, off; - - fdt_for_each_node_by_compatible(off, blob, -1, compat) { - const fdt32_t *reg = fdt_getprop(blob, off, "reg", &len); - if (reg && compat_off == fdt_translate_address(blob, off, reg)) - return off; - } - - return -FDT_ERR_NOTFOUND; -} - -static int vnode_offset_by_pathf(void *blob, const char *fmt, va_list ap) -{ - char path[512]; - int len; - - len = vsnprintf(path, sizeof(path), fmt, ap); - if (len < 0 || len + 1 > sizeof(path)) - return -FDT_ERR_NOSPACE; - - return fdt_path_offset(blob, path); -} - -/** - * fdt_node_offset_by_pathf: Find node offset by sprintf formatted path - * - * @blob: ptr to device tree - * @fmt: path format - * @ap: vsnprintf arguments - */ -int fdt_node_offset_by_pathf(void *blob, const char *fmt, ...) -{ - va_list ap; - int res; - - va_start(ap, fmt); - res = vnode_offset_by_pathf(blob, fmt, ap); - va_end(ap); - - return res; -} - -/* - * fdt_set_phandle: Create a phandle property for the given node - * - * @fdt: ptr to device tree - * @nodeoffset: node to update - * @phandle: phandle value to set (must be unique) - */ -int fdt_set_phandle(void *fdt, int nodeoffset, uint32_t phandle) -{ - int ret; - -#ifdef DEBUG - int off = fdt_node_offset_by_phandle(fdt, phandle); - - if ((off >= 0) && (off != nodeoffset)) { - char buf[64]; - - fdt_get_path(fdt, nodeoffset, buf, sizeof(buf)); - printf("Trying to update node %s with phandle %u ", - buf, phandle); - - fdt_get_path(fdt, off, buf, sizeof(buf)); - printf("that already exists in node %s.\n", buf); - return -FDT_ERR_BADPHANDLE; - } -#endif - - ret = fdt_setprop_cell(fdt, nodeoffset, "phandle", phandle); - - return ret; -} - -/* - * fdt_create_phandle: Get or create a phandle property for the given node - * - * @fdt: ptr to device tree - * @nodeoffset: node to update - */ -unsigned int fdt_create_phandle(void *fdt, int nodeoffset) -{ - /* see if there is a phandle already */ - uint32_t phandle = fdt_get_phandle(fdt, nodeoffset); - - /* if we got 0, means no phandle so create one */ - if (phandle == 0) { - int ret; - - ret = fdt_generate_phandle(fdt, &phandle); - if (ret < 0) { - printf("Can't generate phandle: %s\n", - fdt_strerror(ret)); - return 0; - } - - ret = fdt_set_phandle(fdt, nodeoffset, phandle); - if (ret < 0) { - printf("Can't set phandle %u: %s\n", phandle, - fdt_strerror(ret)); - return 0; - } - } - - return phandle; -} - -/** - * fdt_create_phandle_by_compatible: Get or create a phandle for first node with - * given compatible - * - * @fdt: ptr to device tree - * @compat: node's compatible string - */ -unsigned int fdt_create_phandle_by_compatible(void *fdt, const char *compat) -{ - int offset = fdt_node_offset_by_compatible(fdt, -1, compat); - - if (offset < 0) { - printf("Can't find node with compatible \"%s\": %s\n", compat, - fdt_strerror(offset)); - return 0; - } - - return fdt_create_phandle(fdt, offset); -} - -/** - * fdt_create_phandle_by_pathf: Get or create a phandle for node given by - * sprintf-formatted path - * - * @fdt: ptr to device tree - * @fmt, ...: path format string and arguments to pass to sprintf - */ -unsigned int fdt_create_phandle_by_pathf(void *fdt, const char *fmt, ...) -{ - va_list ap; - int offset; - - va_start(ap, fmt); - offset = vnode_offset_by_pathf(fdt, fmt, ap); - va_end(ap); - - if (offset < 0) { - printf("Can't find node by given path: %s\n", - fdt_strerror(offset)); - return 0; - } - - return fdt_create_phandle(fdt, offset); -} - -/* - * fdt_set_node_status: Set status for the given node - * - * @fdt: ptr to device tree - * @nodeoffset: node to update - * @status: FDT_STATUS_OKAY, FDT_STATUS_DISABLED, FDT_STATUS_FAIL - */ -int fdt_set_node_status(void *fdt, int nodeoffset, enum fdt_status status) -{ - int ret = 0; - - if (nodeoffset < 0) - return nodeoffset; - - switch (status) { - case FDT_STATUS_OKAY: - ret = fdt_setprop_string(fdt, nodeoffset, "status", "okay"); - break; - case FDT_STATUS_DISABLED: - ret = fdt_setprop_string(fdt, nodeoffset, "status", "disabled"); - break; - case FDT_STATUS_FAIL: - ret = fdt_setprop_string(fdt, nodeoffset, "status", "fail"); - break; - default: - printf("Invalid fdt status: %x\n", status); - ret = -1; - break; - } - - return ret; -} - -/* - * fdt_set_status_by_alias: Set status for the given node given an alias - * - * @fdt: ptr to device tree - * @alias: alias of node to update - * @status: FDT_STATUS_OKAY, FDT_STATUS_DISABLED, FDT_STATUS_FAIL - */ -int fdt_set_status_by_alias(void *fdt, const char* alias, - enum fdt_status status) -{ - int offset = fdt_path_offset(fdt, alias); - - return fdt_set_node_status(fdt, offset, status); -} - -/** - * fdt_set_status_by_compatible: Set node status for first node with given - * compatible - * - * @fdt: ptr to device tree - * @compat: node's compatible string - * @status: FDT_STATUS_OKAY, FDT_STATUS_DISABLED, FDT_STATUS_FAIL - */ -int fdt_set_status_by_compatible(void *fdt, const char *compat, - enum fdt_status status) -{ - int offset = fdt_node_offset_by_compatible(fdt, -1, compat); - - if (offset < 0) - return offset; - - return fdt_set_node_status(fdt, offset, status); -} - -/** - * fdt_set_status_by_pathf: Set node status for node given by sprintf-formatted - * path - * - * @fdt: ptr to device tree - * @status: FDT_STATUS_OKAY, FDT_STATUS_DISABLED, FDT_STATUS_FAIL - * @fmt, ...: path format string and arguments to pass to sprintf - */ -int fdt_set_status_by_pathf(void *fdt, enum fdt_status status, const char *fmt, - ...) -{ - va_list ap; - int offset; - - va_start(ap, fmt); - offset = vnode_offset_by_pathf(fdt, fmt, ap); - va_end(ap); - - if (offset < 0) - return offset; - - return fdt_set_node_status(fdt, offset, status); -} - -/* - * Verify the physical address of device tree node for a given alias - * - * This function locates the device tree node of a given alias, and then - * verifies that the physical address of that device matches the given - * parameter. It displays a message if there is a mismatch. - * - * Returns 1 on success, 0 on failure - */ -int fdt_verify_alias_address(void *fdt, int anode, const char *alias, u64 addr) -{ - const char *path; - const fdt32_t *reg; - int node, len; - u64 dt_addr; - - path = fdt_getprop(fdt, anode, alias, NULL); - if (!path) { - /* If there's no such alias, then it's not a failure */ - return 1; - } - - node = fdt_path_offset(fdt, path); - if (node < 0) { - printf("Warning: device tree alias '%s' points to invalid " - "node %s.\n", alias, path); - return 0; - } - - reg = fdt_getprop(fdt, node, "reg", &len); - if (!reg) { - printf("Warning: device tree node '%s' has no address.\n", - path); - return 0; - } - - dt_addr = fdt_translate_address(fdt, node, reg); - if (addr != dt_addr) { - printf("Warning: U-Boot configured device %s at address %llu,\n" - "but the device tree has it address %llx.\n", - alias, addr, dt_addr); - return 0; - } - - return 1; -} - -/* - * Returns the base address of an SOC or PCI node - */ -u64 fdt_get_base_address(const void *fdt, int node) -{ - int size; - const fdt32_t *prop; - - prop = fdt_getprop(fdt, node, "reg", &size); - - return prop ? fdt_translate_address(fdt, node, prop) : OF_BAD_ADDR; -} - -/* - * Read a property of size . Currently only supports 1 or 2 cells, - * or 3 cells specially for a PCI address. - */ -static int fdt_read_prop(const fdt32_t *prop, int prop_len, int cell_off, - uint64_t *val, int cells) -{ - const fdt32_t *prop32; - const unaligned_fdt64_t *prop64; - - if ((cell_off + cells) > prop_len) - return -FDT_ERR_NOSPACE; - - prop32 = &prop[cell_off]; - - /* - * Special handling for PCI address in PCI bus - * - * PCI child address is made up of 3 cells. Advance the cell offset - * by 1 so that the PCI child address can be correctly read. - */ - if (cells == 3) - cell_off += 1; - prop64 = (const fdt64_t *)&prop[cell_off]; - - switch (cells) { - case 1: - *val = fdt32_to_cpu(*prop32); - break; - case 2: - case 3: - *val = fdt64_to_cpu(*prop64); - break; - default: - return -FDT_ERR_NOSPACE; - } - - return 0; -} - -/** - * fdt_read_range - Read a node's n'th range property - * - * @fdt: ptr to device tree - * @node: offset of node - * @n: range index - * @child_addr: pointer to storage for the "child address" field - * @addr: pointer to storage for the CPU view translated physical start - * @len: pointer to storage for the range length - * - * Convenience function that reads and interprets a specific range out of - * a number of the "ranges" property array. - */ -int fdt_read_range(void *fdt, int node, int n, uint64_t *child_addr, - uint64_t *addr, uint64_t *len) -{ - int pnode = fdt_parent_offset(fdt, node); - const fdt32_t *ranges; - int pacells; - int acells; - int scells; - int ranges_len; - int cell = 0; - int r = 0; - - /* - * The "ranges" property is an array of - * { } - * - * All 3 elements can span a diffent number of cells. Fetch their size. - */ - pacells = fdt_getprop_u32_default_node(fdt, pnode, 0, "#address-cells", 1); - acells = fdt_getprop_u32_default_node(fdt, node, 0, "#address-cells", 1); - scells = fdt_getprop_u32_default_node(fdt, node, 0, "#size-cells", 1); - - /* Now try to get the ranges property */ - ranges = fdt_getprop(fdt, node, "ranges", &ranges_len); - if (!ranges) - return -FDT_ERR_NOTFOUND; - ranges_len /= sizeof(uint32_t); - - /* Jump to the n'th entry */ - cell = n * (pacells + acells + scells); - - /* Read */ - if (child_addr) { - r = fdt_read_prop(ranges, ranges_len, cell, child_addr, - acells); - if (r) - return r; - } - cell += acells; - - /* Read */ - if (addr) - *addr = fdt_translate_address(fdt, node, ranges + cell); - cell += pacells; - - /* Read */ - if (len) { - r = fdt_read_prop(ranges, ranges_len, cell, len, scells); - if (r) - return r; - } - - return 0; -} - -/** - * fdt_setup_simplefb_node - Fill and enable a simplefb node - * - * @fdt: ptr to device tree - * @node: offset of the simplefb node - * @base_address: framebuffer base address - * @width: width in pixels - * @height: height in pixels - * @stride: bytes per line - * @format: pixel format string - * - * Convenience function to fill and enable a simplefb node. - */ -int fdt_setup_simplefb_node(void *fdt, int node, u64 base_address, u32 width, - u32 height, u32 stride, const char *format) -{ - char name[32]; - fdt32_t cells[4]; - int i, addrc, sizec, ret; - - fdt_support_default_count_cells(fdt, fdt_parent_offset(fdt, node), - &addrc, &sizec); - i = 0; - if (addrc == 2) - cells[i++] = cpu_to_fdt32(base_address >> 32); - cells[i++] = cpu_to_fdt32(base_address); - if (sizec == 2) - cells[i++] = 0; - cells[i++] = cpu_to_fdt32(height * stride); - - ret = fdt_setprop(fdt, node, "reg", cells, sizeof(cells[0]) * i); - if (ret < 0) - return ret; - - snprintf(name, sizeof(name), "framebuffer@%llx", base_address); - ret = fdt_set_name(fdt, node, name); - if (ret < 0) - return ret; - - ret = fdt_setprop_u32(fdt, node, "width", width); - if (ret < 0) - return ret; - - ret = fdt_setprop_u32(fdt, node, "height", height); - if (ret < 0) - return ret; - - ret = fdt_setprop_u32(fdt, node, "stride", stride); - if (ret < 0) - return ret; - - ret = fdt_setprop_string(fdt, node, "format", format); - if (ret < 0) - return ret; - - ret = fdt_setprop_string(fdt, node, "status", "okay"); - if (ret < 0) - return ret; - - return 0; -} - -/* - * Update native-mode in display-timings from display environment variable. - * The node to update are specified by path. - */ -int fdt_fixup_display(void *blob, const char *path, const char *display) -{ - int off, toff; - - if (!display || !path) - return -FDT_ERR_NOTFOUND; - - toff = fdt_path_offset(blob, path); - if (toff >= 0) - toff = fdt_subnode_offset(blob, toff, "display-timings"); - if (toff < 0) - return toff; - - for (off = fdt_first_subnode(blob, toff); - off >= 0; - off = fdt_next_subnode(blob, off)) { - uint32_t h = fdt_get_phandle(blob, off); - debug("%s:0x%x\n", fdt_get_name(blob, off, NULL), - fdt32_to_cpu(h)); - if (strcasecmp(fdt_get_name(blob, off, NULL), display) == 0) - return fdt_setprop_u32(blob, toff, "native-mode", h); - } - return toff; -} - -#ifdef CONFIG_OF_LIBFDT_OVERLAY -/** - * fdt_overlay_apply_verbose - Apply an overlay with verbose error reporting - * - * @fdt: ptr to device tree - * @fdto: ptr to device tree overlay - * - * Convenience function to apply an overlay and display helpful messages - * in the case of an error - */ -int fdt_overlay_apply_verbose(void *fdt, void *fdto) -{ - int err; - bool has_symbols; - - err = fdt_path_offset(fdt, "/__symbols__"); - has_symbols = err >= 0; - - err = fdt_overlay_apply(fdt, fdto); - if (err < 0) { - printf("failed on fdt_overlay_apply(): %s\n", - fdt_strerror(err)); - if (!has_symbols) { - printf("base fdt does did not have a /__symbols__ node\n"); - printf("make sure you've compiled with -@\n"); - } - } - return err; -} -#endif - -/** - * fdt_valid() - Check if an FDT is valid. If not, change it to NULL - * - * @blobp: Pointer to FDT pointer - * Return: 1 if OK, 0 if bad (in which case *blobp is set to NULL) - */ -int fdt_valid(struct fdt_header **blobp) -{ - const void *blob = *blobp; - int err; - - if (!blob) { - printf("The address of the fdt is invalid (NULL).\n"); - return 0; - } - - err = fdt_check_header(blob); - if (err == 0) - return 1; /* valid */ - - if (err < 0) { - printf("libfdt fdt_check_header(): %s", fdt_strerror(err)); - /* - * Be more informative on bad version. - */ - if (err == -FDT_ERR_BADVERSION) { - if (fdt_version(blob) < - FDT_FIRST_SUPPORTED_VERSION) { - printf(" - too old, fdt %d < %d", - fdt_version(blob), - FDT_FIRST_SUPPORTED_VERSION); - } - if (fdt_last_comp_version(blob) > - FDT_LAST_SUPPORTED_VERSION) { - printf(" - too new, fdt %d > %d", - fdt_version(blob), - FDT_LAST_SUPPORTED_VERSION); - } - } - printf("\n"); - *blobp = NULL; - return 0; - } - return 1; -} -- cgit v1.3.1 From ddc5f9b13ec6665e480e3415a3cd2a3e5668cb4d Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 14 Sep 2023 10:55:46 -0600 Subject: Move fdt_simplefb to boot/ This relates to booting, so move it there. Create a new Kconfig menu for things related to devicetree fixup. Signed-off-by: Simon Glass Reviewed-by: Tom Rini --- boot/Kconfig | 16 +++++++ boot/Makefile | 1 + boot/fdt_simplefb.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++ common/Kconfig | 9 ---- common/Makefile | 1 - common/fdt_simplefb.c | 116 -------------------------------------------------- 6 files changed, 133 insertions(+), 126 deletions(-) create mode 100644 boot/fdt_simplefb.c delete mode 100644 common/fdt_simplefb.c (limited to 'boot') diff --git a/boot/Kconfig b/boot/Kconfig index 0a98f1e2220..39c51e9e2fe 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -1538,6 +1538,22 @@ config SPL_IMAGE_PRE_LOAD_SIG endmenu +if OF_LIBFDT + +menu "Devicetree fixup" + +config FDT_SIMPLEFB + bool "FDT tools for simplefb support" + help + Enable the fdt tools to manage the simple fb nodes in device tree. + These functions can be used by board to indicate to the OS + the presence of the simple frame buffer with associated reserved + memory + +endmenu + +endif # OF_LIBFDT + config USE_BOOTARGS bool "Enable boot arguments" help diff --git a/boot/Makefile b/boot/Makefile index f15a161614f..6ce983b83fa 100644 --- a/boot/Makefile +++ b/boot/Makefile @@ -39,6 +39,7 @@ obj-$(CONFIG_$(SPL_TPL_)CEDIT) += cedit.o endif obj-$(CONFIG_$(SPL_TPL_)OF_LIBFDT) += fdt_support.o +obj-$(CONFIG_$(SPL_TPL_)FDT_SIMPLEFB) += fdt_simplefb.o obj-$(CONFIG_$(SPL_TPL_)OF_LIBFDT) += image-fdt.o obj-$(CONFIG_$(SPL_TPL_)FIT_SIGNATURE) += fdt_region.o diff --git a/boot/fdt_simplefb.c b/boot/fdt_simplefb.c new file mode 100644 index 00000000000..069ced75a7f --- /dev/null +++ b/boot/fdt_simplefb.c @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Simplefb device tree support + * + * (C) Copyright 2015 + * Stephen Warren + */ + +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +static int fdt_simplefb_configure_node(void *blob, int off) +{ + int xsize, ysize; + int bpix; /* log2 of bits per pixel */ + const char *name; + ulong fb_base; + struct video_uc_plat *plat; + struct video_priv *uc_priv; + struct udevice *dev; + int ret; + + ret = uclass_first_device_err(UCLASS_VIDEO, &dev); + if (ret) + return ret; + uc_priv = dev_get_uclass_priv(dev); + plat = dev_get_uclass_plat(dev); + xsize = uc_priv->xsize; + ysize = uc_priv->ysize; + bpix = uc_priv->bpix; + fb_base = plat->base; + switch (bpix) { + case 4: /* VIDEO_BPP16 */ + name = "r5g6b5"; + break; + case 5: /* VIDEO_BPP32 */ + name = "a8r8g8b8"; + break; + default: + return -EINVAL; + } + + return fdt_setup_simplefb_node(blob, off, fb_base, xsize, ysize, + xsize * (1 << bpix) / 8, name); +} + +int fdt_simplefb_add_node(void *blob) +{ + static const char compat[] = "simple-framebuffer"; + static const char disabled[] = "disabled"; + int off, ret; + + off = fdt_add_subnode(blob, 0, "framebuffer"); + if (off < 0) + return -1; + + ret = fdt_setprop(blob, off, "status", disabled, sizeof(disabled)); + if (ret < 0) + return -1; + + ret = fdt_setprop(blob, off, "compatible", compat, sizeof(compat)); + if (ret < 0) + return -1; + + return fdt_simplefb_configure_node(blob, off); +} + +/** + * fdt_simplefb_enable_existing_node() - enable simple-framebuffer DT node + * + * @blob: device-tree + * Return: 0 on success, non-zero otherwise + */ +static int fdt_simplefb_enable_existing_node(void *blob) +{ + int off; + + off = fdt_node_offset_by_compatible(blob, -1, "simple-framebuffer"); + if (off < 0) + return -1; + + return fdt_simplefb_configure_node(blob, off); +} + +#if IS_ENABLED(CONFIG_VIDEO) +int fdt_simplefb_enable_and_mem_rsv(void *blob) +{ + struct fdt_memory mem; + int ret; + + /* nothing to do when video is not active */ + if (!video_is_active()) + return 0; + + ret = fdt_simplefb_enable_existing_node(blob); + if (ret) + return ret; + + /* nothing to do when the frame buffer is not defined */ + if (gd->video_bottom == gd->video_top) + return 0; + + /* reserved with no-map tag the video buffer */ + mem.start = gd->video_bottom; + mem.end = gd->video_top - 1; + + return fdtdec_add_reserved_memory(blob, "framebuffer", &mem, NULL, 0, NULL, + FDTDEC_RESERVED_MEMORY_NO_MAP); +} +#endif diff --git a/common/Kconfig b/common/Kconfig index d11292f52c2..21eaa5e815f 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -1157,14 +1157,5 @@ config VPL_IMAGE_SIGN_INFO endif -config FDT_SIMPLEFB - bool "FDT tools for simplefb support" - depends on OF_LIBFDT - help - Enable the fdt tools to manage the simple fb nodes in device tree. - These functions can be used by board to indicate to the OS - the presence of the simple frame buffer with associated reserved - memory - config IO_TRACE bool diff --git a/common/Makefile b/common/Makefile index 0948721d0b4..5c1617206f0 100644 --- a/common/Makefile +++ b/common/Makefile @@ -17,7 +17,6 @@ obj-y += board_r.o obj-$(CONFIG_DISPLAY_BOARDINFO) += board_info.o obj-$(CONFIG_DISPLAY_BOARDINFO_LATE) += board_info.o -obj-$(CONFIG_FDT_SIMPLEFB) += fdt_simplefb.o obj-$(CONFIG_MII) += miiphyutil.o obj-$(CONFIG_CMD_MII) += miiphyutil.o obj-$(CONFIG_PHYLIB) += miiphyutil.o diff --git a/common/fdt_simplefb.c b/common/fdt_simplefb.c deleted file mode 100644 index 069ced75a7f..00000000000 --- a/common/fdt_simplefb.c +++ /dev/null @@ -1,116 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Simplefb device tree support - * - * (C) Copyright 2015 - * Stephen Warren - */ - -#include -#include -#include -#include -#include -#include - -DECLARE_GLOBAL_DATA_PTR; - -static int fdt_simplefb_configure_node(void *blob, int off) -{ - int xsize, ysize; - int bpix; /* log2 of bits per pixel */ - const char *name; - ulong fb_base; - struct video_uc_plat *plat; - struct video_priv *uc_priv; - struct udevice *dev; - int ret; - - ret = uclass_first_device_err(UCLASS_VIDEO, &dev); - if (ret) - return ret; - uc_priv = dev_get_uclass_priv(dev); - plat = dev_get_uclass_plat(dev); - xsize = uc_priv->xsize; - ysize = uc_priv->ysize; - bpix = uc_priv->bpix; - fb_base = plat->base; - switch (bpix) { - case 4: /* VIDEO_BPP16 */ - name = "r5g6b5"; - break; - case 5: /* VIDEO_BPP32 */ - name = "a8r8g8b8"; - break; - default: - return -EINVAL; - } - - return fdt_setup_simplefb_node(blob, off, fb_base, xsize, ysize, - xsize * (1 << bpix) / 8, name); -} - -int fdt_simplefb_add_node(void *blob) -{ - static const char compat[] = "simple-framebuffer"; - static const char disabled[] = "disabled"; - int off, ret; - - off = fdt_add_subnode(blob, 0, "framebuffer"); - if (off < 0) - return -1; - - ret = fdt_setprop(blob, off, "status", disabled, sizeof(disabled)); - if (ret < 0) - return -1; - - ret = fdt_setprop(blob, off, "compatible", compat, sizeof(compat)); - if (ret < 0) - return -1; - - return fdt_simplefb_configure_node(blob, off); -} - -/** - * fdt_simplefb_enable_existing_node() - enable simple-framebuffer DT node - * - * @blob: device-tree - * Return: 0 on success, non-zero otherwise - */ -static int fdt_simplefb_enable_existing_node(void *blob) -{ - int off; - - off = fdt_node_offset_by_compatible(blob, -1, "simple-framebuffer"); - if (off < 0) - return -1; - - return fdt_simplefb_configure_node(blob, off); -} - -#if IS_ENABLED(CONFIG_VIDEO) -int fdt_simplefb_enable_and_mem_rsv(void *blob) -{ - struct fdt_memory mem; - int ret; - - /* nothing to do when video is not active */ - if (!video_is_active()) - return 0; - - ret = fdt_simplefb_enable_existing_node(blob); - if (ret) - return ret; - - /* nothing to do when the frame buffer is not defined */ - if (gd->video_bottom == gd->video_top) - return 0; - - /* reserved with no-map tag the video buffer */ - mem.start = gd->video_bottom; - mem.end = gd->video_top - 1; - - return fdtdec_add_reserved_memory(blob, "framebuffer", &mem, NULL, 0, NULL, - FDTDEC_RESERVED_MEMORY_NO_MAP); -} -#endif -- cgit v1.3.1 From 96095e131ccaebc4aee2e4fac92602a619f1aa57 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 14 Sep 2023 10:55:47 -0600 Subject: boot: Move some other fdt-fixup options to the same menu Move more options relating to fixing up a device tree into the new devicetree-fixup menu. Signed-off-by: Simon Glass Reviewed-by: Tom Rini --- boot/Kconfig | 55 ++++++++++++++++++++++++++----------------------------- 1 file changed, 26 insertions(+), 29 deletions(-) (limited to 'boot') diff --git a/boot/Kconfig b/boot/Kconfig index 39c51e9e2fe..f8b8d608951 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -696,35 +696,6 @@ config SUPPORT_RAW_INITRD address of the initrd must be augmented by it's size, in the following format: ":". -config OF_BOARD_SETUP - bool "Set up board-specific details in device tree before boot" - depends on OF_LIBFDT - help - This causes U-Boot to call ft_board_setup() before booting into - the Operating System. This function can set up various - board-specific information in the device tree for use by the OS. - The device tree is then passed to the OS. - -config OF_SYSTEM_SETUP - bool "Set up system-specific details in device tree before boot" - depends on OF_LIBFDT - help - This causes U-Boot to call ft_system_setup() before booting into - the Operating System. This function can set up various - system-specific information in the device tree for use by the OS. - The device tree is then passed to the OS. - -config OF_STDOUT_VIA_ALIAS - bool "Update the device-tree stdout alias from U-Boot" - depends on OF_LIBFDT - help - This uses U-Boot's serial alias from the aliases node to update - the device tree passed to the OS. The "linux,stdout-path" property - in the chosen node is set to point to the correct serial node. - This option currently references CONFIG_CONS_INDEX, which is - incorrect when used with device tree as this option does not - exist / should not be used. - config HAVE_TEXT_BASE bool depends on !NIOS2 && !XTENSA @@ -1542,6 +1513,32 @@ if OF_LIBFDT menu "Devicetree fixup" +config OF_BOARD_SETUP + bool "Set up board-specific details in device tree before boot" + help + This causes U-Boot to call ft_board_setup() before booting into + the Operating System. This function can set up various + board-specific information in the device tree for use by the OS. + The device tree is then passed to the OS. + +config OF_SYSTEM_SETUP + bool "Set up system-specific details in device tree before boot" + help + This causes U-Boot to call ft_system_setup() before booting into + the Operating System. This function can set up various + system-specific information in the device tree for use by the OS. + The device tree is then passed to the OS. + +config OF_STDOUT_VIA_ALIAS + bool "Update the device-tree stdout alias from U-Boot" + help + This uses U-Boot's serial alias from the aliases node to update + the device tree passed to the OS. The "linux,stdout-path" property + in the chosen node is set to point to the correct serial node. + This option currently references CONFIG_CONS_INDEX, which is + incorrect when used with device tree as this option does not + exist / should not be used. + config FDT_SIMPLEFB bool "FDT tools for simplefb support" help -- cgit v1.3.1 From 47b18c0e33ea58d83e76d5e4bb4a25bb3e55657e Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 14 Sep 2023 10:55:48 -0600 Subject: boot: Rename Android-boot text Phrases like 'Enable support for' are pointless since this is an option which enables things. Drop that part so it is easier to follow. Signed-off-by: Simon Glass Reviewed-by: Mattijs Korpershoek Reviewed-by: Tom Rini --- boot/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'boot') diff --git a/boot/Kconfig b/boot/Kconfig index f8b8d608951..017f7117d57 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -3,7 +3,7 @@ menu "Boot options" menu "Boot images" config ANDROID_BOOT_IMAGE - bool "Enable support for Android Boot Images" + bool "Android Boot Images" default y if FASTBOOT help This enables support for booting images which use the Android -- cgit v1.3.1 From 12a7ea005957b3439fd10654da2bc6bac8c53f4e Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 14 Sep 2023 10:55:49 -0600 Subject: Kconfig: Create a menu for FIT This is a major feature with a lot of options. Give it its own menu to tidy up the 'make menuconfig' display. Drop the 'depends on FIT' pieces which are now unnecessary, since they are now bracketed by an 'if FIT'. Leave CONFIG_TIMESTAMP out since it affects legacy images too. Signed-off-by: Simon Glass Reviewed-by: Tom Rini --- boot/Kconfig | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) (limited to 'boot') diff --git a/boot/Kconfig b/boot/Kconfig index 017f7117d57..99a2ffca2fc 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -9,8 +9,19 @@ config ANDROID_BOOT_IMAGE This enables support for booting images which use the Android image format header. -config FIT - bool "Support Flattened Image Tree" +config TIMESTAMP + bool "Show image date and time when displaying image information" + default y if CMD_DATE + help + When CONFIG_TIMESTAMP is selected, the timestamp (date and time) of + an image is printed by image commands like bootm or iminfo. This + is shown as 'Timestamp: xxx' and 'Created: xxx'. If this option is + enabled, then U-Boot requires FITs to have a timestamp. If a FIT is + loaded that does not, the message 'Wrong FIT format: no timestamp' + is shown. + +menuconfig FIT + bool "Flattened Image Tree (FIT)" select HASH select MD5 select SHA1 @@ -25,20 +36,10 @@ config FIT multiple configurations, verification through hashing and also verified boot (secure boot using RSA). -config TIMESTAMP - bool "Show image date and time when displaying image information" - default y if CMD_DATE - help - When CONFIG_TIMESTAMP is selected, the timestamp (date and time) of - an image is printed by image commands like bootm or iminfo. This - is shown as 'Timestamp: xxx' and 'Created: xxx'. If this option is - enabled, then U-Boot requires FITs to have a timestamp. If a FIT is - loaded that does not, the message 'Wrong FIT format: no timestamp' - is shown. +if FIT config FIT_EXTERNAL_OFFSET hex "FIT external data offset" - depends on FIT default 0x0 help This specifies a data offset in fit image. @@ -49,7 +50,6 @@ config FIT_EXTERNAL_OFFSET config FIT_FULL_CHECK bool "Do a full check of the FIT before using it" - depends on FIT default y help Enable this do a full check of the FIT to make sure it is valid. This @@ -59,7 +59,7 @@ config FIT_FULL_CHECK config FIT_SIGNATURE bool "Enable signature verification of FIT uImages" - depends on DM && FIT + depends on DM select HASH imply RSA imply RSA_VERIFY @@ -97,7 +97,7 @@ config FIT_RSASSA_PSS config FIT_CIPHER bool "Enable ciphering data in a FIT uImages" - depends on DM && FIT + depends on DM select AES help Enable the feature of data ciphering/unciphering in the tool mkimage @@ -105,7 +105,6 @@ config FIT_CIPHER config FIT_VERBOSE bool "Show verbose messages when FIT images fail" - depends on FIT help Generally a system will have valid FIT images so debug messages are a waste of code space. If you are debugging your images then @@ -114,7 +113,6 @@ config FIT_VERBOSE config FIT_BEST_MATCH bool "Select the best match for the kernel device tree" - depends on FIT help When no configuration is explicitly selected, default to the one whose fdt's compatibility field best matches that of @@ -124,7 +122,6 @@ config FIT_BEST_MATCH config FIT_IMAGE_POST_PROCESS bool "Enable post-processing of FIT artifacts after loading by U-Boot" - depends on FIT depends on SOCFPGA_SECURE_VAB_AUTH help Allows doing any sort of manipulation to blobs after they got extracted @@ -139,11 +136,12 @@ config FIT_IMAGE_POST_PROCESS config FIT_PRINT bool "Support FIT printing" - depends on FIT default y help Support printing the content of the fitImage in a verbose manner. +endif # FIT + config SPL_FIT bool "Support Flattened Image Tree within SPL" depends on SPL && FIT -- cgit v1.3.1 From 815f8d3f86dcabea7b82d302aefa86c6cc09a210 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 14 Sep 2023 10:55:51 -0600 Subject: spl: Drop SPL/TPL_RAM_SUPPORT option for SPL_LOAD_FIT_ADDRESS All boards which actually define this address enable SPL_LOAD_FIT, or at least just rely on the default value of 0. So drop the dependency. Signed-off-by: Simon Glass Reviewed-by: Tom Rini --- boot/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'boot') diff --git a/boot/Kconfig b/boot/Kconfig index 99a2ffca2fc..f564cb8dd84 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -217,7 +217,7 @@ config SPL_LOAD_FIT config SPL_LOAD_FIT_ADDRESS hex "load address of fit image" - depends on SPL_LOAD_FIT || SPL_RAM_SUPPORT || TPL_RAM_SUPPORT + depends on SPL_LOAD_FIT default 0x0 help Specify the load address of the fit image that will be loaded -- cgit v1.3.1 From 4d8ea26f99062c92e93d25a1cb7613600b30b3c7 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 14 Sep 2023 10:55:52 -0600 Subject: Kconfig: Move SPL_FIT under FIT This option already depends on FIT, so put it under the same umbrella, so that it appears in the FIT menu. Signed-off-by: Simon Glass Reviewed-by: Tom Rini --- boot/Kconfig | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'boot') diff --git a/boot/Kconfig b/boot/Kconfig index f564cb8dd84..9b09d636d05 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -140,11 +140,9 @@ config FIT_PRINT help Support printing the content of the fitImage in a verbose manner. -endif # FIT - config SPL_FIT bool "Support Flattened Image Tree within SPL" - depends on SPL && FIT + depends on SPL select SPL_HASH select SPL_OF_LIBFDT @@ -195,7 +193,7 @@ config SPL_FIT_RSASSA_PSS config SPL_LOAD_FIT bool "Enable SPL loading U-Boot as a FIT (basic fitImage features)" - depends on SPL && FIT + depends on SPL select SPL_FIT help Normally with the SPL framework a legacy image is generated as part @@ -243,7 +241,6 @@ config SPL_LOAD_FIT_APPLY_OVERLAY_BUF_SZ config SPL_LOAD_FIT_FULL bool "Enable SPL loading U-Boot as a FIT (full fitImage features)" - depends on FIT select SPL_FIT help Normally with the SPL framework a legacy image is generated as part @@ -341,6 +338,8 @@ config VPL_FIT_SIGNATURE_MAX_SIZE endif # VPL +endif # FIT + config PXE_UTILS bool select MENU -- cgit v1.3.1 From 4a8fcb6e0b384c42906e411f051e3c54d168516d Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 14 Sep 2023 10:55:53 -0600 Subject: boot: Make standard boot a menu Collect these options into a menu for easier viewing. Signed-off-by: Simon Glass Reviewed-by: Tom Rini --- boot/Kconfig | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'boot') diff --git a/boot/Kconfig b/boot/Kconfig index 9b09d636d05..a885fea692f 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -372,8 +372,8 @@ config BOOT_DEFAULTS of U-Boot to boot various images. Currently much functionality is tied to enabling the command that exercises it. -config BOOTSTD - bool "Standard boot support" +menuconfig BOOTSTD + bool "Standard boot" default y depends on DM && OF_CONTROL && BLK help @@ -393,6 +393,8 @@ config BOOTSTD U-Boot) - bootflow - a description of how to boot (owned by the distro) +if BOOTSTD + config SPL_BOOTSTD bool "Standard boot support in SPL" depends on SPL && SPL_DM && SPL_OF_CONTROL && SPL_BLK @@ -413,8 +415,6 @@ config VPL_BOOTSTD boot. It is enabled by default since the main purpose of VPL is to handle the firmware part of VBE. -if BOOTSTD - config BOOTSTD_FULL bool "Enhanced features for standard boot" default y if SANDBOX @@ -673,7 +673,7 @@ config BOOTMETH_SCRIPT This provides a way to try out standard boot on an existing boot flow. It is not enabled by default to save space. -endif +endif # BOOTSTD config LEGACY_IMAGE_FORMAT bool "Enable support for the legacy image format" -- cgit v1.3.1 From 064a57d019781906e32ccaa16ce122e254dc6533 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 14 Sep 2023 10:55:54 -0600 Subject: Kconfig: Move TEXT_BASE et al under general setup These don't relate to booting. Move them out of there and into the same place as the other related settings. Signed-off-by: Simon Glass Reviewed-by: Tom Rini --- Kconfig | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ boot/Kconfig | 65 ------------------------------------------------------------ 2 files changed, 65 insertions(+), 65 deletions(-) (limited to 'boot') diff --git a/Kconfig b/Kconfig index 0a2e97578df..2d4b8214986 100644 --- a/Kconfig +++ b/Kconfig @@ -585,6 +585,71 @@ config MP This provides an option to bringup different processors in multiprocessor cases. +config HAVE_TEXT_BASE + bool + depends on !NIOS2 && !XTENSA + depends on !EFI_APP + default y + +config TEXT_BASE + depends on HAVE_TEXT_BASE + default 0x0 if POSITION_INDEPENDENT + default 0x80800000 if ARCH_OMAP2PLUS || ARCH_K3 + default 0x81700000 if MACH_SUNIV + default 0x2a000000 if MACH_SUN9I + default 0x4a000000 if SUNXI_MINIMUM_DRAM_MB >= 256 + default 0x42e00000 if SUNXI_MINIMUM_DRAM_MB >= 64 + hex "Text Base" + help + The address in memory that U-Boot will be running from, initially. + +config HAVE_SYS_MONITOR_BASE + bool + depends on ARC || MIPS || M68K || NIOS2 || PPC || XTENSA || X86 \ + || ENV_IS_IN_FLASH || MTD_NOR_FLASH + depends on !EFI_APP + default y + +config SYS_MONITOR_BASE + depends on HAVE_SYS_MONITOR_BASE + hex "Physical start address of boot monitor code" + default TEXT_BASE + help + The physical start address of boot monitor code (which is the same as + CONFIG_TEXT_BASE when linking) and the same as CFG_SYS_FLASH_BASE + when booting from flash. + +config SPL_SYS_MONITOR_BASE + depends on MPC85xx && SPL && HAVE_SYS_MONITOR_BASE + hex "Physical start address of SPL monitor code" + default SPL_TEXT_BASE + +config TPL_SYS_MONITOR_BASE + depends on MPC85xx && TPL && HAVE_SYS_MONITOR_BASE + hex "Physical start address of TPL monitor code" + +config DYNAMIC_SYS_CLK_FREQ + bool "Determine CPU clock frequency at run-time" + help + Implement a get_board_sys_clk function that will determine the CPU + clock frequency at run time, rather than define it statically. + +config SYS_CLK_FREQ + depends on !DYNAMIC_SYS_CLK_FREQ + int "CPU clock frequency" + default 125000000 if ARCH_LS1012A + default 100000000 if ARCH_P2020 || ARCH_T1024 || ARCH_T1042 || \ + ARCH_LS1021A || FSL_LSCH2 || FSL_LSCH3 + default 66666666 if ARCH_P1010 || ARCH_P1020 || ARCH_T4240 + default 66660000 if ARCH_T2080 + default 33333333 if RCAR_GEN3 + default 24000000 if ARCH_EXYNOS + default 20000000 if RCAR_GEN2 + default 0 + help + A static value for the CPU frequency. Note that if not required + for a given SoC, this can be left at 0. + source "api/Kconfig" endmenu # General setup diff --git a/boot/Kconfig b/boot/Kconfig index a885fea692f..4ebcf310911 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -693,71 +693,6 @@ config SUPPORT_RAW_INITRD address of the initrd must be augmented by it's size, in the following format: ":". -config HAVE_TEXT_BASE - bool - depends on !NIOS2 && !XTENSA - depends on !EFI_APP - default y - -config TEXT_BASE - depends on HAVE_TEXT_BASE - default 0x0 if POSITION_INDEPENDENT - default 0x80800000 if ARCH_OMAP2PLUS || ARCH_K3 - default 0x81700000 if MACH_SUNIV - default 0x2a000000 if MACH_SUN9I - default 0x4a000000 if SUNXI_MINIMUM_DRAM_MB >= 256 - default 0x42e00000 if SUNXI_MINIMUM_DRAM_MB >= 64 - hex "Text Base" - help - The address in memory that U-Boot will be running from, initially. - -config HAVE_SYS_MONITOR_BASE - bool - depends on ARC || MIPS || M68K || NIOS2 || PPC || XTENSA || X86 \ - || ENV_IS_IN_FLASH || MTD_NOR_FLASH - depends on !EFI_APP - default y - -config SYS_MONITOR_BASE - depends on HAVE_SYS_MONITOR_BASE - hex "Physical start address of boot monitor code" - default TEXT_BASE - help - The physical start address of boot monitor code (which is the same as - CONFIG_TEXT_BASE when linking) and the same as CFG_SYS_FLASH_BASE - when booting from flash. - -config SPL_SYS_MONITOR_BASE - depends on MPC85xx && SPL && HAVE_SYS_MONITOR_BASE - hex "Physical start address of SPL monitor code" - default SPL_TEXT_BASE - -config TPL_SYS_MONITOR_BASE - depends on MPC85xx && TPL && HAVE_SYS_MONITOR_BASE - hex "Physical start address of TPL monitor code" - -config DYNAMIC_SYS_CLK_FREQ - bool "Determine CPU clock frequency at run-time" - help - Implement a get_board_sys_clk function that will determine the CPU - clock frequency at run time, rather than define it statically. - -config SYS_CLK_FREQ - depends on !DYNAMIC_SYS_CLK_FREQ - int "CPU clock frequency" - default 125000000 if ARCH_LS1012A - default 100000000 if ARCH_P2020 || ARCH_T1024 || ARCH_T1042 || \ - ARCH_LS1021A || FSL_LSCH2 || FSL_LSCH3 - default 66666666 if ARCH_P1010 || ARCH_P1020 || ARCH_T4240 - default 66660000 if ARCH_T2080 - default 33333333 if RCAR_GEN3 - default 24000000 if ARCH_EXYNOS - default 20000000 if RCAR_GEN2 - default 0 - help - A static value for the CPU frequency. Note that if not required - for a given SoC, this can be left at 0. - config ARCH_FIXUP_FDT_MEMORY bool "Enable arch_fixup_memory_banks() call" default y -- cgit v1.3.1 From 3b58de4d0b6bde8f8dab0fa0c0dc417e57b6c804 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 14 Sep 2023 10:55:55 -0600 Subject: Mark DISTRO_DEFAULTS as deprecated Standard boot has been in place for a while now. Quite a few problems have been found and fixed. It seems like a good time to mark the script-based approach as deprecated and encourage people to use standard boot. Update the DISTRO_DEFAULTS Kconfig to encourage people to move to standard boot, which is able to boot Linux distributions automatically. Add a short migration guide to make this easier. Signed-off-by: Simon Glass Reviewed-by: Tom Rini --- boot/Kconfig | 6 +++++- doc/develop/bootstd.rst | 23 +++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) (limited to 'boot') diff --git a/boot/Kconfig b/boot/Kconfig index 4ebcf310911..7ef44a26fb9 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -784,7 +784,7 @@ config SYS_BOOT_RAMDISK_HIGH endmenu # Boot images config DISTRO_DEFAULTS - bool "Select defaults suitable for booting general purpose Linux distributions" + bool "(deprecated) Script-based booting of Linux distributions" select BOOT_DEFAULTS select AUTO_COMPLETE select CMDLINE_EDITING @@ -792,6 +792,10 @@ config DISTRO_DEFAULTS select HUSH_PARSER select SYS_LONGHELP help + Note: These scripts have been replaced by Standard Boot. Do not use + them on new boards. See 'Migrating from distro_boot' at + doc/develop/bootstd.rst + Select this to enable various options and commands which are suitable for building u-boot for booting general purpose Linux distributions. diff --git a/doc/develop/bootstd.rst b/doc/develop/bootstd.rst index e8b90752f08..6172dc906bd 100644 --- a/doc/develop/bootstd.rst +++ b/doc/develop/bootstd.rst @@ -464,6 +464,28 @@ ready File was loaded and is ready for use. In this state the bootflow is ======= ======================================================================= +Migrating from distro_boot +-------------------------- + +To migrate from distro_boot: + +#. Update your board header files to remove the BOOTENV and BOOT_TARGET_xxx + defines. Standard boot finds available boot devices automatically. + +#. Remove the "boot_targets" variable unless you need it. Standard boot uses a + default order from fastest to slowest, which generally matches the order used + by boards. + +#. Make sure that CONFIG_BOOTSTD_DEFAULTS is enabled by your board, so it can + boot common Linux distributions. + +An example patch is at migrate_patch_. + +If you are using custom boot scripts for your board, consider creating your +own bootmeth to hold the logic. There are various examples at +`boot/bootmeth_...`. + + Theory of operation ------------------- @@ -775,3 +797,4 @@ Other ideas: .. _BootLoaderSpec: http://www.freedesktop.org/wiki/Specifications/BootLoaderSpec/ .. _distro_boot: https://github.com/u-boot/u-boot/blob/master/boot/distro.c .. _bootflow_h: https://github.com/u-boot/u-boot/blob/master/include/bootflow.h +.. _migrate_patch: https://patchwork.ozlabs.org/project/uboot/patch/20230727215433.578830-2-sjg@chromium.org/ -- cgit v1.3.1 From 4483184127f8ac36869d014ebe116d4822b30ca7 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 14 Sep 2023 10:55:56 -0600 Subject: Make ARCH_FIXUP_FDT_MEMORY depend on OF_LIBFDT We need CONFIG_OF_LIBFDT to be able to do fdt fixups, so add that condition. Signed-off-by: Simon Glass Reviewed-by: Tom Rini --- boot/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'boot') diff --git a/boot/Kconfig b/boot/Kconfig index 7ef44a26fb9..2dd05e2e166 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -695,7 +695,7 @@ config SUPPORT_RAW_INITRD config ARCH_FIXUP_FDT_MEMORY bool "Enable arch_fixup_memory_banks() call" - default y + default y if OF_LIBFDT help Enable FDT memory map syncup before OS boot. This feature can be used for booting OS with different memory setup where the part of -- cgit v1.3.1 From 040a604880c6eb86779ef564c055deb7b1bcb828 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 14 Sep 2023 10:55:57 -0600 Subject: boot: Join FDT_FIXUP_PARTITIONS with related options Move this to be with the other devicetree-fixup options. Signed-off-by: Simon Glass Reviewed-by: Tom Rini --- boot/Kconfig | 8 ++++++++ lib/Kconfig | 9 --------- 2 files changed, 8 insertions(+), 9 deletions(-) (limited to 'boot') diff --git a/boot/Kconfig b/boot/Kconfig index 2dd05e2e166..a1592a74e62 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -1475,6 +1475,14 @@ config OF_STDOUT_VIA_ALIAS incorrect when used with device tree as this option does not exist / should not be used. +config FDT_FIXUP_PARTITIONS + bool "overwrite MTD partitions in DTS through defined in 'mtdparts'" + depends on CMD_MTDPARTS + help + Allow overwriting defined partitions in the device tree blob + using partition info defined in the 'mtdparts' environment + variable. + config FDT_SIMPLEFB bool "FDT tools for simplefb support" help diff --git a/lib/Kconfig b/lib/Kconfig index bfab2f3165a..eb2b1016182 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -953,15 +953,6 @@ config VPL_OF_LIBFDT_ASSUME_MASK 0xff means all assumptions are made and any invalid data may cause unsafe execution. See FDT_ASSUME_PERFECT, etc. in libfdt_internal.h -config FDT_FIXUP_PARTITIONS - bool "overwrite MTD partitions in DTS through defined in 'mtdparts'" - depends on OF_LIBFDT - depends on CMD_MTDPARTS - help - Allow overwriting defined partitions in the device tree blob - using partition info defined in the 'mtdparts' environment - variable. - menu "System tables" depends on (!EFI && !SYS_COREBOOT) || (ARM && EFI_LOADER) -- cgit v1.3.1 From 400a6a3a1be8c7a058253e326ec20cd935d124fb Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 14 Sep 2023 10:55:58 -0600 Subject: boot: Drop CMD_MTDPARTS condition for FDT_FIXUP_PARTITIONS This is not needed, so drop it. Also use a capital 'O' for the option, while we are here. Signed-off-by: Simon Glass Suggested-by: Tom Rini Reviewed-by: Tom Rini --- boot/Kconfig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'boot') diff --git a/boot/Kconfig b/boot/Kconfig index a1592a74e62..235c5a7a993 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -1476,8 +1476,7 @@ config OF_STDOUT_VIA_ALIAS exist / should not be used. config FDT_FIXUP_PARTITIONS - bool "overwrite MTD partitions in DTS through defined in 'mtdparts'" - depends on CMD_MTDPARTS + bool "Overwrite MTD partitions in DTS through defined in 'mtdparts'" help Allow overwriting defined partitions in the device tree blob using partition info defined in the 'mtdparts' environment -- cgit v1.3.1 From c0e5b0ebab6ae8f04cf42bd4ac10c19af58af3a2 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 14 Sep 2023 10:55:59 -0600 Subject: boot: Join ARCH_FIXUP_FDT_MEMORY with related options Move this to be with the other devicetree-fixup options. Signed-off-by: Simon Glass Reviewed-by: Tom Rini --- boot/Kconfig | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'boot') diff --git a/boot/Kconfig b/boot/Kconfig index 235c5a7a993..a01e6cb8aaf 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -693,14 +693,6 @@ config SUPPORT_RAW_INITRD address of the initrd must be augmented by it's size, in the following format: ":". -config ARCH_FIXUP_FDT_MEMORY - bool "Enable arch_fixup_memory_banks() call" - default y if OF_LIBFDT - help - Enable FDT memory map syncup before OS boot. This feature can be - used for booting OS with different memory setup where the part of - the memory location should be used for different purpose. - config CHROMEOS bool "Support booting Chrome OS" help @@ -1490,6 +1482,14 @@ config FDT_SIMPLEFB the presence of the simple frame buffer with associated reserved memory +config ARCH_FIXUP_FDT_MEMORY + bool "Enable arch_fixup_memory_banks() call" + default y + help + Enable FDT memory map syncup before OS boot. This feature can be + used for booting OS with different memory setup where the part of + the memory location should be used for different purpose. + endmenu endif # OF_LIBFDT -- cgit v1.3.1 From 64fd30d367a1d5e33dbcbc2d017ca0431242155c Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 17 Sep 2023 13:47:30 +0200 Subject: tools: mkimage: Add StarFive SPL image support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The StarFive JH7110 base boards require a header to be prefixed to the SPL binary image. This has previously done with a vendor tool 'spl_tool' published under a GPL-2-or-later license. Integrate this capability into mkimage. Signed-off-by: Heinrich Schuchardt Tested-by: Chanho Park Tested-by: Milan P. Stanić --- boot/image.c | 1 + include/image.h | 1 + tools/Makefile | 1 + tools/sfspl.c | 174 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 177 insertions(+) create mode 100644 tools/sfspl.c (limited to 'boot') diff --git a/boot/image.c b/boot/image.c index 26f68d4c407..88b67bc3a19 100644 --- a/boot/image.c +++ b/boot/image.c @@ -182,6 +182,7 @@ static const table_entry_t uimage_type[] = { { IH_TYPE_SUNXI_TOC0, "sunxi_toc0", "Allwinner TOC0 Boot Image" }, { IH_TYPE_FDT_LEGACY, "fdt_legacy", "legacy Image with Flat Device Tree ", }, { IH_TYPE_RENESAS_SPKG, "spkgimage", "Renesas SPKG Image" }, + { IH_TYPE_STARFIVE_SPL, "sfspl", "StarFive SPL Image" }, { -1, "", "", }, }; diff --git a/include/image.h b/include/image.h index 01a6787d211..5f85bf84a2d 100644 --- a/include/image.h +++ b/include/image.h @@ -231,6 +231,7 @@ enum image_type_t { IH_TYPE_SUNXI_TOC0, /* Allwinner TOC0 Boot Image */ IH_TYPE_FDT_LEGACY, /* Binary Flat Device Tree Blob in a Legacy Image */ IH_TYPE_RENESAS_SPKG, /* Renesas SPKG image */ + IH_TYPE_STARFIVE_SPL, /* StarFive SPL image */ IH_TYPE_COUNT, /* Number of image types */ }; diff --git a/tools/Makefile b/tools/Makefile index 3d0c4b0dd6a..1aa1e36137b 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -123,6 +123,7 @@ dumpimage-mkimage-objs := aisimage.o \ pblimage.o \ pbl_crc32.o \ renesas_spkgimage.o \ + sfspl.o \ vybridimage.o \ stm32image.o \ $(ROCKCHIP_OBS) \ diff --git a/tools/sfspl.c b/tools/sfspl.c new file mode 100644 index 00000000000..ec18a0a77e7 --- /dev/null +++ b/tools/sfspl.c @@ -0,0 +1,174 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright Heinrich Schuchardt + * + * The StarFive JH7110 requires to prepend a header to u-boot-spl.bin describing + * the payload length and CRC32. + * + * This module implements support in mkimage and dumpimage for this file format. + * + * StarFive's spl_tool available under GPL-2.0-and-later at + * https://github.com/starfive-tech/Tools implements writing the same file + * format and served as a reference. + */ + +#include +#include +#include +#include +#include "imagetool.h" + +#define DEFAULT_VERSION 0x01010101 +#define DEFAULT_BACKUP 0x200000U +#define DEFAULT_OFFSET 0x240 + +/** + * struct spl_hdr - header for SPL on JH7110 + * + * All fields are low-endian. + */ +struct spl_hdr { + /** @offset: offset to SPL header (0x240) */ + unsigned int offset; + /** @bkp_offs: address of backup SPL, defaults to DEFAULT_BACKUP */ + unsigned int bkp_offs; + /** @zero1: set to zero */ + unsigned int zero1[159]; + /** @version: header version, defaults to DEFAULT_VERSION */ + unsigned int version; + /** @file_size: file size */ + unsigned int file_size; + /** @hdr_size: size of the file header (0x400) */ + unsigned int hdr_size; + /** @crc32: CRC32 */ + unsigned int crc32; + /** @zero2: set to zero */ + unsigned int zero2[91]; +}; + +static int sfspl_check_params(struct image_tool_params *params) +{ + /* Only the RISC-V architecture is supported */ + if (params->Aflag && params->arch != IH_ARCH_RISCV) + return EXIT_FAILURE; + + return EXIT_SUCCESS; +} + +static int sfspl_verify_header(unsigned char *buf, int size, + struct image_tool_params *params) +{ + struct spl_hdr *hdr = (void *)buf; + unsigned int hdr_size = le32_to_cpu(hdr->hdr_size); + unsigned int file_size = le32_to_cpu(hdr->file_size); + unsigned int crc = le32_to_cpu(hdr->crc32); + unsigned int crc_check; + + if (size < 0 || + (size_t)size < sizeof(struct spl_hdr) || + (size_t)size < hdr_size + file_size) { + printf("Truncated file\n"); + return EXIT_FAILURE; + } + if (hdr->version != DEFAULT_VERSION) { + printf("Unknown file format version\n"); + return EXIT_FAILURE; + } + crc_check = crc32(0, &buf[hdr_size], size - hdr_size); + if (crc_check != crc) { + printf("Incorrect CRC32\n"); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + +static void sfspl_print_header(const void *buf, + struct image_tool_params *params) +{ + struct spl_hdr *hdr = (void *)buf; + unsigned int hdr_size = le32_to_cpu(hdr->hdr_size); + unsigned int file_size = le32_to_cpu(hdr->file_size); + + printf("Header size: %u\n", hdr_size); + printf("Payload size: %u\n", file_size); +} + +static int sfspl_image_extract_subimage(void *ptr, + struct image_tool_params *params) +{ + struct spl_hdr *hdr = (void *)ptr; + unsigned char *buf = ptr; + int fd; + unsigned int hdr_size = le32_to_cpu(hdr->hdr_size); + unsigned int file_size = le32_to_cpu(hdr->file_size); + + if (params->pflag) { + printf("Invalid image index %d\n", params->pflag); + return EXIT_FAILURE; + } + + fd = open(params->outfile, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd == -1) { + perror("Can write file"); + return EXIT_FAILURE; + } + if (write(fd, &buf[hdr_size], file_size) != file_size) { + perror("Cannot write file"); + return EXIT_FAILURE; + } + close(fd); + + return EXIT_SUCCESS; +} + +static int sfspl_check_image_type(uint8_t type) +{ + if (type == IH_TYPE_STARFIVE_SPL) + return EXIT_SUCCESS; + + return EXIT_FAILURE; +} + +static void sfspl_set_header(void *buf, struct stat *sbuf, int infd, + struct image_tool_params *params) +{ + struct spl_hdr *hdr = buf; + unsigned int file_size; + unsigned int crc; + + file_size = params->file_size - sizeof(struct spl_hdr); + crc = crc32(0, &((unsigned char *)buf)[sizeof(struct spl_hdr)], + file_size); + + hdr->offset = cpu_to_le32(DEFAULT_OFFSET); + hdr->bkp_offs = cpu_to_le32(DEFAULT_BACKUP); + hdr->version = cpu_to_le32(DEFAULT_VERSION); + hdr->file_size = cpu_to_le32(file_size); + hdr->hdr_size = cpu_to_le32(sizeof(struct spl_hdr)); + hdr->crc32 = cpu_to_le32(crc); +} + +static int sfspl_vrec_header(struct image_tool_params *params, + struct image_type_params *tparams) +{ + tparams->hdr = calloc(sizeof(struct spl_hdr), 1); + + /* No padding */ + return 0; +} + +U_BOOT_IMAGE_TYPE( + sfspl, /* id */ + "StarFive SPL Image", /* name */ + sizeof(struct spl_hdr), /* header_size */ + NULL, /* header */ + sfspl_check_params, /* check_params */ + sfspl_verify_header, /* verify header */ + sfspl_print_header, /* print header */ + sfspl_set_header, /* set header */ + sfspl_image_extract_subimage, /* extract_subimage */ + sfspl_check_image_type, /* check_image_type */ + NULL, /* fflag_handle */ + sfspl_vrec_header /* vrec_header */ +); -- cgit v1.3.1 From 1a075d4e0de797ac2b25adcc27ea537fa01f89cb Mon Sep 17 00:00:00 2001 From: Thomas Mittelstaedt Date: Thu, 4 May 2023 13:42:55 +0000 Subject: x86: pxeboot: bugfix: Set variable for size of initrd The problem was, that zboot() didn't work because of missing ramdisc size. Signed-off-by: Thomas Mittelstaedt Reviewed-by: Simon Glass --- boot/pxe_utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'boot') diff --git a/boot/pxe_utils.c b/boot/pxe_utils.c index ac1414a5f26..a92bb896c63 100644 --- a/boot/pxe_utils.c +++ b/boot/pxe_utils.c @@ -554,7 +554,7 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label) label->name); goto cleanup; } - + strcpy(initrd_filesize, simple_xtoa(size)); initrd_addr_str = env_get("ramdisk_addr_r"); size = snprintf(initrd_str, sizeof(initrd_str), "%s:%lx", initrd_addr_str, size); -- cgit v1.3.1 From 1b1d36ec58f43585081b387ee44053278e480171 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 20 Sep 2023 07:29:49 -0600 Subject: bootstd: Keep track of use of usb stop When 'usb stop' is run, doing 'bootflow scan' does not run the USB hunter again so does not see any devices. Fix this by telling bootstd about the state of USB. Signed-off-by: Simon Glass --- boot/bootdev-uclass.c | 27 +++++++++++++++++++++++++++ drivers/usb/host/usb-uclass.c | 8 ++++++++ include/bootdev.h | 9 +++++++++ 3 files changed, 44 insertions(+) (limited to 'boot') diff --git a/boot/bootdev-uclass.c b/boot/bootdev-uclass.c index 69506e3865f..974ddee5d2f 100644 --- a/boot/bootdev-uclass.c +++ b/boot/bootdev-uclass.c @@ -830,6 +830,33 @@ int bootdev_hunt(const char *spec, bool show) return result; } +int bootdev_unhunt(enum uclass_id id) +{ + struct bootdev_hunter *start; + int n_ent, i; + + start = ll_entry_start(struct bootdev_hunter, bootdev_hunter); + n_ent = ll_entry_count(struct bootdev_hunter, bootdev_hunter); + for (i = 0; i < n_ent; i++) { + struct bootdev_hunter *info = start + i; + + if (info->uclass == id) { + struct bootstd_priv *std; + int ret; + + ret = bootstd_get_priv(&std); + if (ret) + return log_msg_ret("std", ret); + if (!(std->hunters_used & BIT(i))) + return -EALREADY; + std->hunters_used &= ~BIT(i); + return 0; + } + } + + return -ENOENT; +} + int bootdev_hunt_prio(enum bootdev_prio_t prio, bool show) { struct bootdev_hunter *start; diff --git a/drivers/usb/host/usb-uclass.c b/drivers/usb/host/usb-uclass.c index e5fe949f254..a1cd0ad2d66 100644 --- a/drivers/usb/host/usb-uclass.c +++ b/drivers/usb/host/usb-uclass.c @@ -9,6 +9,7 @@ #define LOG_CATEGORY UCLASS_USB #include +#include #include #include #include @@ -208,6 +209,13 @@ int usb_stop(void) #ifdef CONFIG_USB_STORAGE usb_stor_reset(); #endif + if (CONFIG_IS_ENABLED(BOOTSTD)) { + int ret; + + ret = bootdev_unhunt(UCLASS_USB); + if (IS_ENABLED(CONFIG_BOOTSTD_FULL) && ret && ret != -EALREADY) + printf("failed to unhunt USB (err=%dE)\n", ret); + } uc_priv->companion_device_count = 0; usb_started = 0; diff --git a/include/bootdev.h b/include/bootdev.h index 848233187f8..b079a91b5b7 100644 --- a/include/bootdev.h +++ b/include/bootdev.h @@ -320,6 +320,15 @@ int bootdev_hunt(const char *spec, bool show); */ int bootdev_hunt_prio(enum bootdev_prio_t prio, bool show); +/** + * bootdev_unhunt() - Mark a device as needing to be hunted again + * + * @id: uclass ID to update + * Return: 0 if done, -EALREADY if already in this state, -ENOENT if no hunter + * found for that uclass + */ +int bootdev_unhunt(enum uclass_id id); + /** * bootdev_hunt_and_find_by_label() - Hunt for bootdevs by label * -- cgit v1.3.1