From 9385c9b0cd9761b49033df13ccf45d3dd17f4027 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Tue, 26 Sep 2023 09:16:34 +0200 Subject: [PATCH 01/12] riscv: remove dram_init_banksize() Remove dram_init_banksize() on the architecture level. Limiting used RAM to under 4 GiB is only necessary for CPUs which have a DMA issue. SoC specific code already exists for FU540, FU740, JH7110. Not all RISC-V boards will have memory below 4 GiB. A weak implementation of dram_init_banksize() exists in common/board_f.c. See the discussion in https://lore.kernel.org/u-boot/545fe813-cb1e-469c-a131-0025c77aeaa2@canonical.com/T/ Signed-off-by: Heinrich Schuchardt Reviewed-by: Anup Patel --- arch/riscv/cpu/generic/dram.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/arch/riscv/cpu/generic/dram.c b/arch/riscv/cpu/generic/dram.c index 94d8018407e..1b51bae9b66 100644 --- a/arch/riscv/cpu/generic/dram.c +++ b/arch/riscv/cpu/generic/dram.c @@ -20,19 +20,3 @@ int dram_init_banksize(void) { return fdtdec_setup_memory_banksize(); } - -phys_addr_t board_get_usable_ram_top(phys_size_t total_size) -{ - /* - * Ensure that we run from first 4GB so that all - * addresses used by U-Boot are 32bit addresses. - * - * This in-turn ensures that 32bit DMA capable - * devices work fine because DMA mapping APIs will - * provide 32bit DMA addresses only. - */ - if (gd->ram_top >= SZ_4G) - return SZ_4G - 1; - - return gd->ram_top; -} From e96e537efd95f77903c4503c67667543d7b88965 Mon Sep 17 00:00:00 2001 From: Chanho Park Date: Tue, 10 Oct 2023 17:49:18 +0900 Subject: [PATCH 02/12] configs: visionfive2: enable bootstage configs Enable BOOTSTAGE configuration and its command for visionfive2 board. The feature can be useful for analyzing the elapsed time between boot stages. TODO: define / reserve memory region for boot stage stash StarFive # bootstage report Timer summary in microseconds (10 records): Mark Elapsed Stage 0 0 reset 3,139,338 3,139,338 board_init_f 3,176,753 37,415 board_init_r 4,036,111 859,358 eth_common_init 4,101,599 65,488 eth_initialize 4,105,799 4,200 main_loop 4,145,207 39,408 usb_start 5,440,963 1,295,756 cli_loop Accumulated time: 10,093 dm_f 15,867 dm_r Signed-off-by: Chanho Park Reviewed-by: Leo Yu-Chi Liang --- configs/starfive_visionfive2_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configs/starfive_visionfive2_defconfig b/configs/starfive_visionfive2_defconfig index 6590727fe75..b21754feafc 100644 --- a/configs/starfive_visionfive2_defconfig +++ b/configs/starfive_visionfive2_defconfig @@ -31,6 +31,7 @@ CONFIG_RISCV_SMODE=y # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set CONFIG_FIT=y CONFIG_DISTRO_DEFAULTS=y +CONFIG_BOOTSTAGE=y CONFIG_QSPI_BOOT=y CONFIG_SD_BOOT=y CONFIG_OF_BOARD_SETUP=y @@ -72,6 +73,7 @@ CONFIG_CMD_I2C=y CONFIG_CMD_PCI=y CONFIG_CMD_USB=y CONFIG_CMD_TFTPPUT=y +CONFIG_CMD_BOOTSTAGE=y CONFIG_OF_BOARD=y CONFIG_ENV_OVERWRITE=y CONFIG_ENV_IS_NOWHERE=y From 5a348ccf025702fc6bb30d9c8da367a9e78d3d2b Mon Sep 17 00:00:00 2001 From: Mayuresh Chitale Date: Wed, 11 Oct 2023 21:00:20 +0530 Subject: [PATCH 03/12] riscv: binman: Fix compilation error Some platforms may not have any DDR memory below 4G and for such platforms the TEXT_BASE and LOAD addresses etc are all 64 bit addresses due to which the u-boot build fails with below error: u-boot/arch/riscv/dts/binman.dtsi:30.14-25 Value out of range for 32-bit array element u-boot/arch/riscv/dts/binman.dtsi:43.14-25 Value out of range for 32-bit array element u-boot/arch/riscv/dts/binman.dtsi:44.15-26 Value out of range for 32-bit array element FATAL ERROR: Syntax error parsing input tree Fix by setting the address-cells property to 2 and converting load addresses to 64 bit values. Signed-off-by: Mayuresh Chitale Reviewed-by: Simon Glass --- arch/riscv/dts/binman.dtsi | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/arch/riscv/dts/binman.dtsi b/arch/riscv/dts/binman.dtsi index 156cb00971e..b448b2a712b 100644 --- a/arch/riscv/dts/binman.dtsi +++ b/arch/riscv/dts/binman.dtsi @@ -5,6 +5,9 @@ #include +#define U64_TO_U32_H(addr) (((addr) >> 32) & 0xffffffff) +#define U64_TO_U32_L(addr) ((addr) & 0xffffffff) + / { binman: binman { multiple-images; @@ -17,7 +20,7 @@ fit { description = "Configuration to load OpenSBI before U-Boot"; - #address-cells = <1>; + #address-cells = <2>; fit,fdt-list = "of-list"; images { @@ -27,7 +30,8 @@ os = "U-Boot"; arch = "riscv"; compression = "none"; - load = ; + load = ; uboot_blob: blob-ext { filename = "u-boot-nodtb.bin"; @@ -40,8 +44,10 @@ os = "opensbi"; arch = "riscv"; compression = "none"; - load = ; - entry = ; + load = ; + entry = ; opensbi_blob: opensbi { filename = "fw_dynamic.bin"; From 04b2123b4d28c47587e038df9861838c55e3365e Mon Sep 17 00:00:00 2001 From: Randolph Date: Thu, 12 Oct 2023 13:35:34 +0800 Subject: [PATCH 04/12] riscv: andes: Rearrange Andes PLICSW to single-bit-per-hart strategy Source hart information is not necessary in IPI, so we could use single-bit-per-hart strategy to rearrange PLICSW mapping. Bit 0 of Interrupt Pending Bits is hardwired to 0. Therefore, we use bit 1 to send IPI to hart 0, bit 2 to hart 1, ..., and so on. Signed-off-by: Randolph Reviewed-by: Leo Yu-Chi Liang --- arch/riscv/lib/andes_plicsw.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/arch/riscv/lib/andes_plicsw.c b/arch/riscv/lib/andes_plicsw.c index 75184080890..6fd49e873b1 100644 --- a/arch/riscv/lib/andes_plicsw.c +++ b/arch/riscv/lib/andes_plicsw.c @@ -22,7 +22,7 @@ #include /* pending register */ -#define PENDING_REG(base, hart) ((ulong)(base) + 0x1000 + ((hart) / 4) * 4) +#define PENDING_REG(base) ((ulong)(base) + 0x1000) /* enable register */ #define ENABLE_REG(base, hart) ((ulong)(base) + 0x2000 + (hart) * 0x80) /* claim register */ @@ -30,10 +30,11 @@ /* priority register */ #define PRIORITY_REG(base) ((ulong)(base) + PLICSW_PRIORITY_BASE) -#define ENABLE_HART_IPI (0x01010101) -#define SEND_IPI_TO_HART(hart) (0x1 << (hart)) +/* Bit 0 of PLIC-SW pending array is hardwired to zero, so we start from bit 1 */ +#define FIRST_AVAILABLE_BIT 0x2 +#define SEND_IPI_TO_HART(hart) (FIRST_AVAILABLE_BIT << (hart)) #define PLICSW_PRIORITY_BASE 0x4 -#define PLICSW_INTERRUPT_PER_HART 0x8 +#define PLICSW_INTERRUPT_PER_HART 0x1 DECLARE_GLOBAL_DATA_PTR; @@ -41,9 +42,8 @@ static int enable_ipi(int hart) { unsigned int en; - en = ENABLE_HART_IPI << hart; + en = FIRST_AVAILABLE_BIT << hart; writel(en, (void __iomem *)ENABLE_REG(gd->arch.plicsw, hart)); - writel(en, (void __iomem *)ENABLE_REG(gd->arch.plicsw + 0x4, hart)); return 0; } @@ -75,7 +75,7 @@ int riscv_init_ipi(void) ret = uclass_find_first_device(UCLASS_CPU, &dev); if (ret) return ret; - else if (!dev) + if (!dev) return -ENODEV; ofnode_for_each_subnode(node, dev_ofnode(dev->parent)) { @@ -105,10 +105,9 @@ int riscv_init_ipi(void) int riscv_send_ipi(int hart) { - unsigned int ipi = (SEND_IPI_TO_HART(hart) << (8 * gd->arch.boot_hart)); + unsigned int ipi = SEND_IPI_TO_HART(hart); - writel(ipi, (void __iomem *)PENDING_REG(gd->arch.plicsw, - gd->arch.boot_hart)); + writel(ipi, (void __iomem *)PENDING_REG(gd->arch.plicsw)); return 0; } @@ -125,10 +124,9 @@ int riscv_clear_ipi(int hart) int riscv_get_ipi(int hart, int *pending) { - unsigned int ipi = (SEND_IPI_TO_HART(hart) << (8 * gd->arch.boot_hart)); + unsigned int ipi = SEND_IPI_TO_HART(hart); - *pending = readl((void __iomem *)PENDING_REG(gd->arch.plicsw, - gd->arch.boot_hart)); + *pending = readl((void __iomem *)PENDING_REG(gd->arch.plicsw)); *pending = !!(*pending & ipi); return 0; From 5367b9e798279bd28d920212e842f637eec359bc Mon Sep 17 00:00:00 2001 From: Randolph Date: Thu, 12 Oct 2023 14:35:03 +0800 Subject: [PATCH 05/12] spl: riscv: opensbi: change the default os_type as varible In order to introduce the Opensbi OS boot mode, the next stage boot image of OpenSBI should be configurable. Signed-off-by: Randolph Reviewed-by: Simon Glass --- common/spl/spl_opensbi.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/common/spl/spl_opensbi.c b/common/spl/spl_opensbi.c index 0df611623ae..6583b319530 100644 --- a/common/spl/spl_opensbi.c +++ b/common/spl/spl_opensbi.c @@ -21,7 +21,7 @@ DECLARE_GLOBAL_DATA_PTR; struct fw_dynamic_info opensbi_info; -static int spl_opensbi_find_uboot_node(void *blob, int *uboot_node) +static int spl_opensbi_find_os_node(void *blob, int *uboot_node, int os_type) { int fit_images_node, node; const char *fit_os; @@ -35,7 +35,7 @@ static int spl_opensbi_find_uboot_node(void *blob, int *uboot_node) if (!fit_os) continue; - if (genimg_get_os_id(fit_os) == IH_OS_U_BOOT) { + if (genimg_get_os_id(fit_os) == os_type) { *uboot_node = node; return 0; } @@ -46,8 +46,9 @@ static int spl_opensbi_find_uboot_node(void *blob, int *uboot_node) void __noreturn spl_invoke_opensbi(struct spl_image_info *spl_image) { - int ret, uboot_node; - ulong uboot_entry; + int ret, os_node; + ulong os_entry; + int os_type; typedef void __noreturn (*opensbi_entry_t)(ulong hartid, ulong dtb, ulong info); opensbi_entry_t opensbi_entry; @@ -56,22 +57,27 @@ void __noreturn spl_invoke_opensbi(struct spl_image_info *spl_image) hang(); } - /* Find U-Boot image in /fit-images */ - ret = spl_opensbi_find_uboot_node(spl_image->fdt_addr, &uboot_node); + /* + * Find next os image in /fit-images + * The next os image default is u-boot proper + */ + os_type = IH_OS_U_BOOT; + ret = spl_opensbi_find_os_node(spl_image->fdt_addr, &os_node, os_type); if (ret) { - pr_err("Can't find U-Boot node, %d\n", ret); + pr_err("Can't find %s node for opensbi, %d\n", + genimg_get_os_name(os_type), ret); hang(); } /* Get U-Boot entry point */ - ret = fit_image_get_entry(spl_image->fdt_addr, uboot_node, &uboot_entry); + ret = fit_image_get_entry(spl_image->fdt_addr, os_node, &os_entry); if (ret) - ret = fit_image_get_load(spl_image->fdt_addr, uboot_node, &uboot_entry); + ret = fit_image_get_load(spl_image->fdt_addr, os_node, &os_entry); /* Prepare opensbi_info object */ opensbi_info.magic = FW_DYNAMIC_INFO_MAGIC_VALUE; opensbi_info.version = FW_DYNAMIC_INFO_VERSION; - opensbi_info.next_addr = uboot_entry; + opensbi_info.next_addr = os_entry; opensbi_info.next_mode = FW_DYNAMIC_INFO_NEXT_MODE_S; opensbi_info.options = CONFIG_SPL_OPENSBI_SCRATCH_OPTIONS; opensbi_info.boot_hart = gd->arch.boot_hart; From e09a2287c1faf8951ec7e7517788dae55d41a2c6 Mon Sep 17 00:00:00 2001 From: Randolph Date: Thu, 12 Oct 2023 14:35:04 +0800 Subject: [PATCH 06/12] riscv: kconfig: introduce SPL_LOAD_FIT_OPENSBI_OS_BOOT symbol Introduce common Kconfig symbol for riscv architecture. This symbol SPL_LOAD_FIT_OPENSBI_OS_BOOT is like falcon mode on ARM, the Falcon boot is a shortcut boot method for SD/eMMC targets. It skips the loading the RAM version U-Boot. Instead, it will loads the FIT image and boots directly to Linux. When SPL_OPENSBI_OS_BOOT is enabled, linux.itb is created after compilation instead of the default u-boot.itb. It initialises memory with the U-Boot SPL at the first stage, just as a normal boot process does at the beginning. Instead of jumping to the U-Boot proper from OpenSBI before booting the Linux kernel, the RISC-V falcon mode process jumps directly to the Linux kernel to gain shorter booting time. Signed-off-by: Randolph Reviewed-by: Simon Glass --- arch/riscv/Kconfig | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 183885ebe7d..49b6e1a4d6e 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -424,4 +424,12 @@ config TPL_USE_ARCH_MEMSET endmenu +config SPL_LOAD_FIT_OPENSBI_OS_BOOT + bool "Enable SPL (OpenSBI OS boot mode) applying linux from FIT" + depends on SPL_LOAD_FIT + help + Use fw_dynamic from the FIT image, and u-boot SPL will invoke it directly. + This is a shortcut boot flow, from u-boot SPL -> OpenSBI -> u-boot proper + -> linux to u-boot SPL -> OpenSBI -> linux. + endmenu From d311df8b31693809d0aa2073e3b5eda155bf04d2 Mon Sep 17 00:00:00 2001 From: Randolph Date: Thu, 12 Oct 2023 14:35:05 +0800 Subject: [PATCH 07/12] riscv: dts: binman: add condition for opensbi os boot Add condition for OpenSBI OS boot mode, by default it is not enabled. By default, binman creates the output file u-boot.itb. If SPL_OPENSBI_OS_BOOT is enabled, linux.itb will be created after compilation instead of the default u-boot.itb. Signed-off-by: Randolph Reviewed-by: Simon Glass --- arch/riscv/dts/binman.dtsi | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/arch/riscv/dts/binman.dtsi b/arch/riscv/dts/binman.dtsi index b448b2a712b..6b4eb8dc7b9 100644 --- a/arch/riscv/dts/binman.dtsi +++ b/arch/riscv/dts/binman.dtsi @@ -16,7 +16,12 @@ &binman { itb { + +#ifndef CONFIG_SPL_LOAD_FIT_OPENSBI_OS_BOOT filename = "u-boot.itb"; +#else + filename = "linux.itb"; +#endif fit { description = "Configuration to load OpenSBI before U-Boot"; @@ -24,6 +29,7 @@ fit,fdt-list = "of-list"; images { +#ifndef CONFIG_SPL_LOAD_FIT_OPENSBI_OS_BOOT uboot { description = "U-Boot"; type = "standalone"; @@ -37,6 +43,20 @@ filename = "u-boot-nodtb.bin"; }; }; +#else + linux { + description = "Linux"; + type = "standalone"; + os = "Linux"; + arch = "riscv"; + compression = "none"; + load = ; + + linux_blob: blob-ext { + filename = "Image"; + }; + }; +#endif opensbi { description = "OpenSBI fw_dynamic Firmware"; @@ -74,7 +94,11 @@ #endif description = "NAME"; firmware = "opensbi"; +#ifndef CONFIG_SPL_LOAD_FIT_OPENSBI_OS_BOOT loadables = "uboot"; +#else + loadables = "linux"; +#endif #ifndef CONFIG_OF_BOARD fdt = "fdt-SEQ"; #endif From 9421e419817a2a86ad73995ff3ffd0957bec7b82 Mon Sep 17 00:00:00 2001 From: Randolph Date: Thu, 12 Oct 2023 14:35:06 +0800 Subject: [PATCH 08/12] Makefile: delete file *.itb when make clean Delete the output file *.itb Signed-off-by: Randolph Reviewed-by: Simon Glass --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b204a500438..e0040a40d33 100644 --- a/Makefile +++ b/Makefile @@ -2165,7 +2165,7 @@ CLEAN_FILES += include/bmp_logo.h include/bmp_logo_data.h \ mkimage-out.spl.mkimage mkimage.spl.mkimage imx-boot.map \ itb.fit.fit itb.fit.itb itb.map spl.map mkimage-out.rom.mkimage \ mkimage.rom.mkimage rom.map simple-bin.map simple-bin-spi.map \ - idbloader-spi.img lib/efi_loader/helloworld_efi.S + idbloader-spi.img lib/efi_loader/helloworld_efi.S *.itb # Directories & files removed with 'make mrproper' MRPROPER_DIRS += include/config include/generated spl tpl vpl \ From 58fa2a5aa164fd8b516bd66649bbb595ebf1540c Mon Sep 17 00:00:00 2001 From: Randolph Date: Thu, 12 Oct 2023 14:35:07 +0800 Subject: [PATCH 09/12] spl: riscv: add os type for next booting stage If SPL_LOAD_FIT_OPENSBI_OS_BOOT is enabled, the function spl_invoke_opensbi should change the target OS type to IH_OS_LINUX. OpenSBI will load the Linux image as the next boot stage. The os_takes_devicetree function returns a value of true or false depending on whether or not SPL_LOAD_FIT_OPENSBI_OS_BOOT is enabled. Signed-off-by: Randolph Reviewed-by: Simon Glass --- common/spl/spl_fit.c | 3 ++- common/spl/spl_opensbi.c | 9 +++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/common/spl/spl_fit.c b/common/spl/spl_fit.c index c026e1a1945..70d8d5942d9 100644 --- a/common/spl/spl_fit.c +++ b/common/spl/spl_fit.c @@ -367,7 +367,8 @@ static bool os_takes_devicetree(uint8_t os) case IH_OS_U_BOOT: return true; case IH_OS_LINUX: - return IS_ENABLED(CONFIG_SPL_OS_BOOT); + return IS_ENABLED(CONFIG_SPL_OS_BOOT) || + IS_ENABLED(CONFIG_SPL_OPENSBI); default: return false; } diff --git a/common/spl/spl_opensbi.c b/common/spl/spl_opensbi.c index 6583b319530..9801d38c0b3 100644 --- a/common/spl/spl_opensbi.c +++ b/common/spl/spl_opensbi.c @@ -59,9 +59,14 @@ void __noreturn spl_invoke_opensbi(struct spl_image_info *spl_image) /* * Find next os image in /fit-images - * The next os image default is u-boot proper + * The next os image default is u-boot proper, once enable + * OpenSBI OS boot mode, the OS image should be linux. */ - os_type = IH_OS_U_BOOT; + if (CONFIG_IS_ENABLED(LOAD_FIT_OPENSBI_OS_BOOT)) + os_type = IH_OS_LINUX; + else + os_type = IH_OS_U_BOOT; + ret = spl_opensbi_find_os_node(spl_image->fdt_addr, &os_node, os_type); if (ret) { pr_err("Can't find %s node for opensbi, %d\n", From fe192679ef269585606b7c95fa587579b908ef0d Mon Sep 17 00:00:00 2001 From: Randolph Date: Thu, 12 Oct 2023 14:35:08 +0800 Subject: [PATCH 10/12] andes: config: add riscv falcon mode for ae350 platform Fork from ae350_rv[32/64]_spl_[xip]_defconfig and append CONFIG_SPL_LOAD_FIT_OPENSBI_OS_BOOT=y Signed-off-by: Randolph Reviewed-by: Leo Yu-Chi Liang --- configs/ae350_rv32_falcon_defconfig | 60 ++++++++++++++++++++++++ configs/ae350_rv32_falcon_xip_defconfig | 61 +++++++++++++++++++++++++ configs/ae350_rv64_falcon_defconfig | 60 ++++++++++++++++++++++++ configs/ae350_rv64_falcon_xip_defconfig | 61 +++++++++++++++++++++++++ 4 files changed, 242 insertions(+) create mode 100644 configs/ae350_rv32_falcon_defconfig create mode 100644 configs/ae350_rv32_falcon_xip_defconfig create mode 100644 configs/ae350_rv64_falcon_defconfig create mode 100644 configs/ae350_rv64_falcon_xip_defconfig diff --git a/configs/ae350_rv32_falcon_defconfig b/configs/ae350_rv32_falcon_defconfig new file mode 100644 index 00000000000..8f796d88e36 --- /dev/null +++ b/configs/ae350_rv32_falcon_defconfig @@ -0,0 +1,60 @@ +CONFIG_RISCV=y +CONFIG_TEXT_BASE=0x01800000 +CONFIG_SYS_MALLOC_LEN=0x80000 +CONFIG_NR_DRAM_BANKS=2 +CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR=y +CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0x10000000 +CONFIG_ENV_SECT_SIZE=0x1000 +CONFIG_DEFAULT_DEVICE_TREE="ae350_32" +CONFIG_SYS_PROMPT="RISC-V # " +CONFIG_SYS_MONITOR_LEN=786432 +CONFIG_SPL_SYS_MALLOC_F_LEN=0x2000000 +CONFIG_SPL=y +CONFIG_SYS_LOAD_ADDR=0x100000 +CONFIG_TARGET_ANDES_AE350=y +CONFIG_RISCV_SMODE=y +# CONFIG_AVAILABLE_HARTS is not set +CONFIG_FIT=y +CONFIG_SPL_LOAD_FIT_ADDRESS=0x10000000 +CONFIG_SYS_MONITOR_BASE=0x88000000 +CONFIG_DISTRO_DEFAULTS=y +CONFIG_BOOTDELAY=3 +CONFIG_DISPLAY_CPUINFO=y +CONFIG_DISPLAY_BOARDINFO=y +CONFIG_BOARD_EARLY_INIT_F=y +CONFIG_SPL_MAX_SIZE=0x100000 +CONFIG_SPL_BSS_START_ADDR=0x400000 +CONFIG_SPL_BOARD_INIT=y +CONFIG_SPL_CACHE=y +CONFIG_SPL_OPENSBI_SCRATCH_OPTIONS=0x0 +CONFIG_SYS_PBSIZE=1050 +CONFIG_SYS_BOOTM_LEN=0x4000000 +CONFIG_CMD_IMLS=y +CONFIG_CMD_MMC=y +CONFIG_CMD_SF_TEST=y +# CONFIG_CMD_SETEXPR is not set +CONFIG_BOOTP_PREFER_SERVERIP=y +CONFIG_CMD_CACHE=y +CONFIG_ENV_OVERWRITE=y +CONFIG_ENV_IS_IN_SPI_FLASH=y +CONFIG_NET_RETRY_COUNT=50 +CONFIG_BOOTP_SEND_HOSTNAME=y +CONFIG_NET_RANDOM_ETHADDR=y +CONFIG_MMC=y +CONFIG_FTSDC010=y +CONFIG_FTSDC010_SDIO=y +CONFIG_MTD_NOR_FLASH=y +CONFIG_FLASH_CFI_DRIVER=y +CONFIG_SYS_FLASH_CFI_WIDTH_16BIT=y +CONFIG_FLASH_SHOW_PROGRESS=0 +CONFIG_SYS_CFI_FLASH_STATUS_POLL=y +CONFIG_SYS_FLASH_USE_BUFFER_WRITE=y +CONFIG_SYS_FLASH_CFI=y +CONFIG_SPI_FLASH_MACRONIX=y +CONFIG_FTMAC100=y +CONFIG_BAUDRATE=38400 +CONFIG_SYS_NS16550=y +CONFIG_SPI=y +CONFIG_ATCSPI200_SPI=y +# CONFIG_BINMAN_FDT is not set +CONFIG_SPL_LOAD_FIT_OPENSBI_OS_BOOT=y \ No newline at end of file diff --git a/configs/ae350_rv32_falcon_xip_defconfig b/configs/ae350_rv32_falcon_xip_defconfig new file mode 100644 index 00000000000..e01dd6fc513 --- /dev/null +++ b/configs/ae350_rv32_falcon_xip_defconfig @@ -0,0 +1,61 @@ +CONFIG_RISCV=y +CONFIG_TEXT_BASE=0x01800000 +CONFIG_SYS_MALLOC_LEN=0x80000 +CONFIG_NR_DRAM_BANKS=2 +CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR=y +CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0x10000000 +CONFIG_ENV_SECT_SIZE=0x1000 +CONFIG_DEFAULT_DEVICE_TREE="ae350_32" +CONFIG_SPL_TEXT_BASE=0x80000000 +CONFIG_SYS_PROMPT="RISC-V # " +CONFIG_SYS_MONITOR_LEN=786432 +CONFIG_SPL_SYS_MALLOC_F_LEN=0x2000000 +CONFIG_SPL=y +CONFIG_SYS_LOAD_ADDR=0x100000 +CONFIG_TARGET_ANDES_AE350=y +CONFIG_RISCV_SMODE=y +CONFIG_SPL_XIP=y +CONFIG_FIT=y +CONFIG_SPL_LOAD_FIT_ADDRESS=0x80010000 +CONFIG_SYS_MONITOR_BASE=0x88000000 +CONFIG_DISTRO_DEFAULTS=y +CONFIG_BOOTDELAY=3 +CONFIG_DISPLAY_CPUINFO=y +CONFIG_DISPLAY_BOARDINFO=y +CONFIG_BOARD_EARLY_INIT_F=y +CONFIG_SPL_MAX_SIZE=0x100000 +CONFIG_SPL_BSS_START_ADDR=0x400000 +CONFIG_SPL_BOARD_INIT=y +CONFIG_SPL_CACHE=y +CONFIG_SPL_OPENSBI_SCRATCH_OPTIONS=0x0 +CONFIG_SYS_PBSIZE=1050 +CONFIG_SYS_BOOTM_LEN=0x4000000 +CONFIG_CMD_IMLS=y +CONFIG_CMD_MMC=y +CONFIG_CMD_SF_TEST=y +# CONFIG_CMD_SETEXPR is not set +CONFIG_BOOTP_PREFER_SERVERIP=y +CONFIG_CMD_CACHE=y +CONFIG_ENV_OVERWRITE=y +CONFIG_ENV_IS_IN_SPI_FLASH=y +CONFIG_NET_RETRY_COUNT=50 +CONFIG_BOOTP_SEND_HOSTNAME=y +CONFIG_NET_RANDOM_ETHADDR=y +CONFIG_MMC=y +CONFIG_FTSDC010=y +CONFIG_FTSDC010_SDIO=y +CONFIG_MTD_NOR_FLASH=y +CONFIG_FLASH_CFI_DRIVER=y +CONFIG_SYS_FLASH_CFI_WIDTH_16BIT=y +CONFIG_FLASH_SHOW_PROGRESS=0 +CONFIG_SYS_CFI_FLASH_STATUS_POLL=y +CONFIG_SYS_FLASH_USE_BUFFER_WRITE=y +CONFIG_SYS_FLASH_CFI=y +CONFIG_SPI_FLASH_MACRONIX=y +CONFIG_FTMAC100=y +CONFIG_BAUDRATE=38400 +CONFIG_SYS_NS16550=y +CONFIG_SPI=y +CONFIG_ATCSPI200_SPI=y +# CONFIG_BINMAN_FDT is not set +CONFIG_SPL_LOAD_FIT_OPENSBI_OS_BOOT=y \ No newline at end of file diff --git a/configs/ae350_rv64_falcon_defconfig b/configs/ae350_rv64_falcon_defconfig new file mode 100644 index 00000000000..d11be976de3 --- /dev/null +++ b/configs/ae350_rv64_falcon_defconfig @@ -0,0 +1,60 @@ +CONFIG_RISCV=y +CONFIG_TEXT_BASE=0x01800000 +CONFIG_SYS_MALLOC_LEN=0x80000 +CONFIG_NR_DRAM_BANKS=2 +CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR=y +CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0x10000000 +CONFIG_ENV_SECT_SIZE=0x1000 +CONFIG_DEFAULT_DEVICE_TREE="ae350_64" +CONFIG_SYS_PROMPT="RISC-V # " +CONFIG_SPL_SYS_MALLOC_F_LEN=0x2000000 +CONFIG_SPL=y +CONFIG_SYS_LOAD_ADDR=0x100000 +CONFIG_TARGET_ANDES_AE350=y +CONFIG_ARCH_RV64I=y +CONFIG_RISCV_SMODE=y +# CONFIG_AVAILABLE_HARTS is not set +CONFIG_FIT=y +CONFIG_SPL_LOAD_FIT_ADDRESS=0x10000000 +CONFIG_SYS_MONITOR_BASE=0x88000000 +CONFIG_DISTRO_DEFAULTS=y +CONFIG_BOOTDELAY=3 +CONFIG_DISPLAY_CPUINFO=y +CONFIG_DISPLAY_BOARDINFO=y +CONFIG_BOARD_EARLY_INIT_F=y +CONFIG_SPL_MAX_SIZE=0x100000 +CONFIG_SPL_BSS_START_ADDR=0x400000 +CONFIG_SPL_BOARD_INIT=y +CONFIG_SPL_CACHE=y +CONFIG_SPL_OPENSBI_SCRATCH_OPTIONS=0x0 +CONFIG_SYS_PBSIZE=1050 +CONFIG_SYS_BOOTM_LEN=0x4000000 +CONFIG_CMD_IMLS=y +CONFIG_CMD_MMC=y +CONFIG_CMD_SF_TEST=y +# CONFIG_CMD_SETEXPR is not set +CONFIG_BOOTP_PREFER_SERVERIP=y +CONFIG_CMD_CACHE=y +CONFIG_ENV_OVERWRITE=y +CONFIG_ENV_IS_IN_SPI_FLASH=y +CONFIG_NET_RETRY_COUNT=50 +CONFIG_BOOTP_SEND_HOSTNAME=y +CONFIG_NET_RANDOM_ETHADDR=y +CONFIG_MMC=y +CONFIG_FTSDC010=y +CONFIG_FTSDC010_SDIO=y +CONFIG_MTD_NOR_FLASH=y +CONFIG_FLASH_CFI_DRIVER=y +CONFIG_SYS_FLASH_CFI_WIDTH_16BIT=y +CONFIG_FLASH_SHOW_PROGRESS=0 +CONFIG_SYS_CFI_FLASH_STATUS_POLL=y +CONFIG_SYS_FLASH_USE_BUFFER_WRITE=y +CONFIG_SYS_FLASH_CFI=y +CONFIG_SPI_FLASH_MACRONIX=y +CONFIG_FTMAC100=y +CONFIG_BAUDRATE=38400 +CONFIG_SYS_NS16550=y +CONFIG_SPI=y +CONFIG_ATCSPI200_SPI=y +# CONFIG_BINMAN_FDT is not set +CONFIG_SPL_LOAD_FIT_OPENSBI_OS_BOOT=y \ No newline at end of file diff --git a/configs/ae350_rv64_falcon_xip_defconfig b/configs/ae350_rv64_falcon_xip_defconfig new file mode 100644 index 00000000000..492451ecf13 --- /dev/null +++ b/configs/ae350_rv64_falcon_xip_defconfig @@ -0,0 +1,61 @@ +CONFIG_RISCV=y +CONFIG_TEXT_BASE=0x01800000 +CONFIG_SYS_MALLOC_LEN=0x80000 +CONFIG_NR_DRAM_BANKS=2 +CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR=y +CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0x10000000 +CONFIG_ENV_SECT_SIZE=0x1000 +CONFIG_DEFAULT_DEVICE_TREE="ae350_64" +CONFIG_SPL_TEXT_BASE=0x80000000 +CONFIG_SYS_PROMPT="RISC-V # " +CONFIG_SPL_SYS_MALLOC_F_LEN=0x2000000 +CONFIG_SPL=y +CONFIG_SYS_LOAD_ADDR=0x100000 +CONFIG_TARGET_ANDES_AE350=y +CONFIG_ARCH_RV64I=y +CONFIG_RISCV_SMODE=y +CONFIG_SPL_XIP=y +CONFIG_FIT=y +CONFIG_SPL_LOAD_FIT_ADDRESS=0x80010000 +CONFIG_SYS_MONITOR_BASE=0x88000000 +CONFIG_DISTRO_DEFAULTS=y +CONFIG_BOOTDELAY=3 +CONFIG_DISPLAY_CPUINFO=y +CONFIG_DISPLAY_BOARDINFO=y +CONFIG_BOARD_EARLY_INIT_F=y +CONFIG_SPL_MAX_SIZE=0x100000 +CONFIG_SPL_BSS_START_ADDR=0x400000 +CONFIG_SPL_BOARD_INIT=y +CONFIG_SPL_CACHE=y +CONFIG_SPL_OPENSBI_SCRATCH_OPTIONS=0x0 +CONFIG_SYS_PBSIZE=1050 +CONFIG_SYS_BOOTM_LEN=0x4000000 +CONFIG_CMD_IMLS=y +CONFIG_CMD_MMC=y +CONFIG_CMD_SF_TEST=y +# CONFIG_CMD_SETEXPR is not set +CONFIG_BOOTP_PREFER_SERVERIP=y +CONFIG_CMD_CACHE=y +CONFIG_ENV_OVERWRITE=y +CONFIG_ENV_IS_IN_SPI_FLASH=y +CONFIG_NET_RETRY_COUNT=50 +CONFIG_BOOTP_SEND_HOSTNAME=y +CONFIG_NET_RANDOM_ETHADDR=y +CONFIG_MMC=y +CONFIG_FTSDC010=y +CONFIG_FTSDC010_SDIO=y +CONFIG_MTD_NOR_FLASH=y +CONFIG_FLASH_CFI_DRIVER=y +CONFIG_SYS_FLASH_CFI_WIDTH_16BIT=y +CONFIG_FLASH_SHOW_PROGRESS=0 +CONFIG_SYS_CFI_FLASH_STATUS_POLL=y +CONFIG_SYS_FLASH_USE_BUFFER_WRITE=y +CONFIG_SYS_FLASH_CFI=y +CONFIG_SPI_FLASH_MACRONIX=y +CONFIG_FTMAC100=y +CONFIG_BAUDRATE=38400 +CONFIG_SYS_NS16550=y +CONFIG_SPI=y +CONFIG_ATCSPI200_SPI=y +# CONFIG_BINMAN_FDT is not set +CONFIG_SPL_LOAD_FIT_OPENSBI_OS_BOOT=y \ No newline at end of file From 03a4504659bf8b0a1945a79696ae9a2b7ca4938a Mon Sep 17 00:00:00 2001 From: Randolph Date: Thu, 12 Oct 2023 14:35:09 +0800 Subject: [PATCH 11/12] riscv: spl: andes: Move the DTB in front of kernel Originally, u-boot SPL will place the DTB directly after the kernel, but the size of the kernel does not include the BSS section, This means that u-boot SPL places the DTB in the kernel BSS section causing the DTB to be cleared by the kernel BSS initialisation. Moving the DTB in front of the kernel can avoid this error. Signed-off-by: Randolph Reviewed-by: Leo Yu-Chi Liang --- board/AndesTech/ae350/ae350.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/board/AndesTech/ae350/ae350.c b/board/AndesTech/ae350/ae350.c index 1c2288b6ce9..d78ee403e6c 100644 --- a/board/AndesTech/ae350/ae350.c +++ b/board/AndesTech/ae350/ae350.c @@ -19,6 +19,8 @@ #include #include #include +#include +#include DECLARE_GLOBAL_DATA_PTR; @@ -26,6 +28,29 @@ DECLARE_GLOBAL_DATA_PTR; * Miscellaneous platform dependent initializations */ +#if CONFIG_IS_ENABLED(LOAD_FIT) || CONFIG_IS_ENABLED(LOAD_FIT_FULL) +#define ANDES_SPL_FDT_ADDR (CONFIG_TEXT_BASE - 0x100000) +void spl_perform_fixups(struct spl_image_info *spl_image) +{ + /* + * Originally, u-boot-spl will place DTB directly after the kernel, + * but the size of the kernel did not include the BSS section, which + * means u-boot-spl will place the DTB in the kernel BSS section + * causing the DTB to be cleared by kernel BSS initializtion. + * Moving DTB in front of the kernel can avoid the error. + */ + if (ANDES_SPL_FDT_ADDR < 0) { + printf("%s: CONFIG_TEXT_BASE needs to be larger than 0x100000\n", + __func__); + hang(); + } + + memcpy((void *)ANDES_SPL_FDT_ADDR, spl_image->fdt_addr, + fdt_totalsize(spl_image->fdt_addr)); + spl_image->fdt_addr = map_sysmem(ANDES_SPL_FDT_ADDR, 0); +} +#endif + int board_init(void) { gd->bd->bi_boot_params = PHYS_SDRAM_0 + 0x400; From bc5a50452bd42029d6587e1596b44ff235655e90 Mon Sep 17 00:00:00 2001 From: Yu Chien Peter Lin Date: Wed, 9 Aug 2023 18:49:30 +0800 Subject: [PATCH 12/12] riscv: Add Zbb support for building U-Boot This patch adds ISA string to the -march to generate zbb instructions for U-Boot binaries, along with optimized string functions introduced from Linux kernel. Signed-off-by: Yu Chien Peter Lin Reviewed-by: Leo Yu-Chi Liang --- arch/riscv/Kconfig | 91 ++++++++++++++++++++++++++++ arch/riscv/Makefile | 5 +- arch/riscv/include/asm/string.h | 18 ++++++ arch/riscv/lib/Makefile | 3 + arch/riscv/lib/strcmp_zbb.S | 81 +++++++++++++++++++++++++ arch/riscv/lib/strlen_zbb.S | 101 ++++++++++++++++++++++++++++++++ arch/riscv/lib/strncmp_zbb.S | 94 +++++++++++++++++++++++++++++ 7 files changed, 392 insertions(+), 1 deletion(-) create mode 100644 arch/riscv/lib/strcmp_zbb.S create mode 100644 arch/riscv/lib/strlen_zbb.S create mode 100644 arch/riscv/lib/strncmp_zbb.S diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 49b6e1a4d6e..e291456530b 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -187,6 +187,97 @@ config RISCV_ISA_D riscv32 ABI from ilp32 to ilp32d and the riscv64 ABI from lp64 to lp64d. +config RISCV_ISA_ZBB + bool "Zbb extension support for bit manipulation instructions" + help + Adds ZBB extension (basic bit manipulation) to the ISA subsets + that the toolchain is allowed to emit when building U-Boot. + The Zbb extension provides instructions to accelerate a number + of bit-specific operations (count bit population, sign extending, + bitrotation, etc) and enables optimized string routines. + +menu "Use assembly optimized implementation of string routines" + +config USE_ARCH_STRLEN + bool "Use an assembly optimized implementation of strlen" + default y + depends on RISCV_ISA_ZBB + help + Enable the generation of an optimized version of strlen using + Zbb extension. + +config SPL_USE_ARCH_STRLEN + bool "Use an assembly optimized implementation of strlen for SPL" + default y if USE_ARCH_STRLEN + depends on RISCV_ISA_ZBB + depends on SPL + help + Enable the generation of an optimized version of strlen using + Zbb extension. + +config TPL_USE_ARCH_STRLEN + bool "Use an assembly optimized implementation of strlen for TPL" + default y if USE_ARCH_STRLEN + depends on RISCV_ISA_ZBB + depends on TPL + help + Enable the generation of an optimized version of strlen using + Zbb extension. + +config USE_ARCH_STRCMP + bool "Use an assembly optimized implementation of strcmp" + default y + depends on RISCV_ISA_ZBB + help + Enable the generation of an optimized version of strcmp using + Zbb extension. + +config SPL_USE_ARCH_STRCMP + bool "Use an assembly optimized implementation of strcmp for SPL" + default y if USE_ARCH_STRCMP + depends on RISCV_ISA_ZBB + depends on SPL + help + Enable the generation of an optimized version of strcmp using + Zbb extension. + +config TPL_USE_ARCH_STRCMP + bool "Use an assembly optimized implementation of strcmp for TPL" + default y if USE_ARCH_STRCMP + depends on RISCV_ISA_ZBB + depends on TPL + help + Enable the generation of an optimized version of strcmp using + Zbb extension. + +config USE_ARCH_STRNCMP + bool "Use an assembly optimized implementation of strncmp" + default y + depends on RISCV_ISA_ZBB + help + Enable the generation of an optimized version of strncmp using + Zbb extension. + +config SPL_USE_ARCH_STRNCMP + bool "Use an assembly optimized implementation of strncmp for SPL" + default y if USE_ARCH_STRNCMP + depends on RISCV_ISA_ZBB + depends on SPL + help + Enable the generation of an optimized version of strncmp using + Zbb extension. + +config TPL_USE_ARCH_STRNCMP + bool "Use an assembly optimized implementation of strncmp for TPL" + default y if USE_ARCH_STRNCMP + depends on RISCV_ISA_ZBB + depends on TPL + help + Enable the generation of an optimized version of strncmp using + Zbb extension. + +endmenu + config RISCV_ISA_A def_bool y diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile index 4963b5109b2..b3ef87078b5 100644 --- a/arch/riscv/Makefile +++ b/arch/riscv/Makefile @@ -24,6 +24,9 @@ endif ifeq ($(CONFIG_RISCV_ISA_C),y) ARCH_C = c endif +ifeq ($(CONFIG_RISCV_ISA_ZBB),y) + ARCH_ZBB = _zbb +endif ifeq ($(CONFIG_CMODEL_MEDLOW),y) CMODEL = medlow endif @@ -32,7 +35,7 @@ ifeq ($(CONFIG_CMODEL_MEDANY),y) endif -RISCV_MARCH = $(ARCH_BASE)$(ARCH_A)$(ARCH_F)$(ARCH_D)$(ARCH_C) +RISCV_MARCH = $(ARCH_BASE)$(ARCH_A)$(ARCH_F)$(ARCH_D)$(ARCH_C)$(ARCH_ZBB) ABI = $(ABI_BASE)$(ABI_D) # Newer binutils versions default to ISA spec version 20191213 which moves some diff --git a/arch/riscv/include/asm/string.h b/arch/riscv/include/asm/string.h index 7dee3e4c9f6..38ad85fe3bb 100644 --- a/arch/riscv/include/asm/string.h +++ b/arch/riscv/include/asm/string.h @@ -40,4 +40,22 @@ extern void *memmove(void *, const void *, __kernel_size_t); #endif extern void *memset(void *, int, __kernel_size_t); +#undef __HAVE_ARCH_STRLEN +#if CONFIG_IS_ENABLED(USE_ARCH_STRLEN) +#define __HAVE_ARCH_STRLEN +#endif +extern __kernel_size_t strlen(const char *); + +#undef __HAVE_ARCH_STRCMP +#if CONFIG_IS_ENABLED(USE_ARCH_STRCMP) +#define __HAVE_ARCH_STRCMP +#endif +extern int strcmp(const char *, const char *); + +#undef __HAVE_ARCH_STRNCMP +#if CONFIG_IS_ENABLED(USE_ARCH_STRNCMP) +#define __HAVE_ARCH_STRNCMP +#endif +extern int strncmp(const char *, const char *, size_t __kernel_size_t); + #endif /* __ASM_RISCV_STRING_H */ diff --git a/arch/riscv/lib/Makefile b/arch/riscv/lib/Makefile index 02c4d8fcc6c..9a05b662fd6 100644 --- a/arch/riscv/lib/Makefile +++ b/arch/riscv/lib/Makefile @@ -42,5 +42,8 @@ extra-$(CONFIG_EFI) += $(EFI_CRT0) $(EFI_RELOC) obj-$(CONFIG_$(SPL_TPL_)USE_ARCH_MEMSET) += memset.o obj-$(CONFIG_$(SPL_TPL_)USE_ARCH_MEMMOVE) += memmove.o obj-$(CONFIG_$(SPL_TPL_)USE_ARCH_MEMCPY) += memcpy.o +obj-$(CONFIG_$(SPL_TPL_)USE_ARCH_STRLEN) += strlen_zbb.o +obj-$(CONFIG_$(SPL_TPL_)USE_ARCH_STRCMP) += strcmp_zbb.o +obj-$(CONFIG_$(SPL_TPL_)USE_ARCH_STRNCMP) += strncmp_zbb.o obj-$(CONFIG_$(SPL_TPL_)SEMIHOSTING) += semihosting.o diff --git a/arch/riscv/lib/strcmp_zbb.S b/arch/riscv/lib/strcmp_zbb.S new file mode 100644 index 00000000000..e5a367c0e5c --- /dev/null +++ b/arch/riscv/lib/strcmp_zbb.S @@ -0,0 +1,81 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Taken from Linux arch/riscv/lib/strcmp.S + */ + +#include +#include + +ENTRY(__strcmp) +WEAK(strcmp) +.option push +.option arch,+zbb + /* + * Returns + * a0 - comparison result, value like strcmp + * + * Parameters + * a0 - string1 + * a1 - string2 + * + * Clobbers + * t0, t1, t2, t3, t4 + */ + + or t2, a0, a1 + li t4, -1 + and t2, t2, SZREG-1 + bnez t2, 3f + + /* Main loop for aligned string. */ + .p2align 3 +1: + REG_L t0, 0(a0) + REG_L t1, 0(a1) + orc.b t3, t0 + bne t3, t4, 2f + addi a0, a0, SZREG + addi a1, a1, SZREG + beq t0, t1, 1b + + /* + * Words don't match, and no null byte in the first + * word. Get bytes in big-endian order and compare. + */ +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + rev8 t0, t0 + rev8 t1, t1 +#endif + + /* Synthesize (t0 >= t1) ? 1 : -1 in a branchless sequence. */ + sltu a0, t0, t1 + neg a0, a0 + ori a0, a0, 1 + ret + +2: + /* + * Found a null byte. + * If words don't match, fall back to simple loop. + */ + bne t0, t1, 3f + + /* Otherwise, strings are equal. */ + li a0, 0 + ret + + /* Simple loop for misaligned strings. */ + .p2align 3 +3: + lbu t0, 0(a0) + lbu t1, 0(a1) + addi a0, a0, 1 + addi a1, a1, 1 + bne t0, t1, 4f + bnez t0, 3b + +4: + sub a0, t0, t1 + ret +.option pop +END(__strcmp) diff --git a/arch/riscv/lib/strlen_zbb.S b/arch/riscv/lib/strlen_zbb.S new file mode 100644 index 00000000000..bd8fa4c0bd0 --- /dev/null +++ b/arch/riscv/lib/strlen_zbb.S @@ -0,0 +1,101 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Taken from Linux arch/riscv/lib/strlen.S + */ + +#include +#include + +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +# define CZ ctz +# define SHIFT srl +#else +# define CZ clz +# define SHIFT sll +#endif + +ENTRY(__strlen) +WEAK(strlen) +.option push +.option arch,+zbb + /* + * Returns + * a0 - string length + * + * Parameters + * a0 - String to measure + * + * Clobbers + * t0, t1, t2, t3 + */ + + /* Number of irrelevant bytes in the first word. */ + andi t2, a0, SZREG-1 + + /* Align pointer. */ + andi t0, a0, -SZREG + + li t3, SZREG + sub t3, t3, t2 + slli t2, t2, 3 + + /* Get the first word. */ + REG_L t1, 0(t0) + + /* + * Shift away the partial data we loaded to remove the irrelevant bytes + * preceding the string with the effect of adding NUL bytes at the + * end of the string's first word. + */ + SHIFT t1, t1, t2 + + /* Convert non-NUL into 0xff and NUL into 0x00. */ + orc.b t1, t1 + + /* Convert non-NUL into 0x00 and NUL into 0xff. */ + not t1, t1 + + /* + * Search for the first set bit (corresponding to a NUL byte in the + * original chunk). + */ + CZ t1, t1 + + /* + * The first chunk is special: compare against the number + * of valid bytes in this chunk. + */ + srli a0, t1, 3 + bgtu t3, a0, 2f + + /* Prepare for the word comparison loop. */ + addi t2, t0, SZREG + li t3, -1 + + /* + * Our critical loop is 4 instructions and processes data in + * 4 byte or 8 byte chunks. + */ + .p2align 3 +1: + REG_L t1, SZREG(t0) + addi t0, t0, SZREG + orc.b t1, t1 + beq t1, t3, 1b + + not t1, t1 + CZ t1, t1 + srli t1, t1, 3 + + /* Get number of processed bytes. */ + sub t2, t0, t2 + + /* Add number of characters in the first word. */ + add a0, a0, t2 + + /* Add number of characters in the last word. */ + add a0, a0, t1 +2: + ret +.option pop +END(__strlen) diff --git a/arch/riscv/lib/strncmp_zbb.S b/arch/riscv/lib/strncmp_zbb.S new file mode 100644 index 00000000000..00e0fec3a66 --- /dev/null +++ b/arch/riscv/lib/strncmp_zbb.S @@ -0,0 +1,94 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Taken from Linux arch/riscv/lib/strncmp.S + */ + +#include +#include + +ENTRY(__strncmp) +WEAK(strncmp) +.option push +.option arch,+zbb + /* + * Returns + * a0 - comparison result, like strncmp + * + * Parameters + * a0 - string1 + * a1 - string2 + * a2 - number of characters to compare + * + * Clobbers + * t0, t1, t2, t3, t4, t5, t6 + */ + + or t2, a0, a1 + li t5, -1 + and t2, t2, SZREG-1 + add t4, a0, a2 + bnez t2, 3f + + /* Adjust limit for fast-path. */ + andi t6, t4, -SZREG + + /* Main loop for aligned string. */ + .p2align 3 +1: + bge a0, t6, 3f + REG_L t0, 0(a0) + REG_L t1, 0(a1) + orc.b t3, t0 + bne t3, t5, 2f + orc.b t3, t1 + bne t3, t5, 2f + addi a0, a0, SZREG + addi a1, a1, SZREG + beq t0, t1, 1b + + /* + * Words don't match, and no null byte in the first + * word. Get bytes in big-endian order and compare. + */ +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + rev8 t0, t0 + rev8 t1, t1 +#endif + + /* Synthesize (t0 >= t1) ? 1 : -1 in a branchless sequence. */ + sltu a0, t0, t1 + neg a0, a0 + ori a0, a0, 1 + ret + +2: + /* + * Found a null byte. + * If words don't match, fall back to simple loop. + */ + bne t0, t1, 3f + + /* Otherwise, strings are equal. */ + li a0, 0 + ret + + /* Simple loop for misaligned strings. */ + .p2align 3 +3: + bge a0, t4, 5f + lbu t0, 0(a0) + lbu t1, 0(a1) + addi a0, a0, 1 + addi a1, a1, 1 + bne t0, t1, 4f + bnez t0, 3b + +4: + sub a0, t0, t1 + ret + +5: + li a0, 0 + ret +.option pop +END(__strncmp)