[PATCH v2 1/2] riscv: add platform-specific double word shifts for riscv32

Charlie Jenkins thecharlesjenkins at gmail.com
Thu Apr 9 16:22:52 PDT 2026


On Thu, Apr 09, 2026 at 06:38:23AM +0300, Dmitry Antipov wrote:
> Add riscv32-specific '__ashldi3()', '__ashrdi3()', and '__lshrdi3()'.
> Initially it was intended to fix the following link error observed
> when building EFI-enabled kernel with CONFIG_EFI_STUB=y and
> CONFIG_EFI_GENERIC_STUB=y:
> 
> riscv32-linux-gnu-ld: ./drivers/firmware/efi/libstub/lib-cmdline.stub.o: in function `__efistub_.L49':
> __efistub_cmdline.c:(.init.text+0x1f2): undefined reference to `__efistub___ashldi3'
> riscv32-linux-gnu-ld: __efistub_cmdline.c:(.init.text+0x202): undefined reference to `__efistub___lshrdi3'
> 
> Reported at [1] trying to build https://patchew.org/linux/20260212164413.889625-1-dmantipov@yandex.ru,
> tested with 'qemu-system-riscv32 -M virt' only.
> 
> Reported-by: kernel test robot <lkp at intel.com>
> Closes: https://lore.kernel.org/oe-kbuild-all/202603041925.KLKqpK6N-lkp@intel.com [1]
> Suggested-by: Ard Biesheuvel <ardb at kernel.org>
> Signed-off-by: Dmitry Antipov <dmantipov at yandex.ru>

I needed to apply the following to get this to successfully compile for
riscv32 with CONFIG_EFI_ZBOOT. After applying this change, I was able to
successfully EFI boot the vmlinuz.efi in qemu.

diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile
index e386ffd009b7..f83301a19dc5 100644
--- a/drivers/firmware/efi/libstub/Makefile
+++ b/drivers/firmware/efi/libstub/Makefile
@@ -96,7 +96,7 @@ CFLAGS_zboot-decompress-gzip.o        += -I$(srctree)/lib/zlib_inflate
 zboot-obj-$(CONFIG_KERNEL_ZSTD)        := zboot-decompress-zstd.o lib-xxhash.o
 CFLAGS_zboot-decompress-zstd.o += -I$(srctree)/lib/zstd

-zboot-obj-$(CONFIG_RISCV)      += lib-clz_ctz.o lib-ashldi3.o
+zboot-obj-$(CONFIG_RISCV)      += lib-clz_ctz.o lib-ashldi3.o lib-lshrdi3.o
 lib-$(CONFIG_EFI_ZBOOT)                += zboot.o $(zboot-obj-y)

 lib-$(CONFIG_UNACCEPTED_MEMORY) += unaccepted_memory.o bitmap.o find.o


However, this change causes the libstub to bypass these new functions
you have introduced. lib-ashldi3.o and lib-lshrdi3.o use the following
rule to compile the generic arch libs:

$(obj)/lib-%.o: $(srctree)/lib/%.c FORCE
	$(call if_changed_rule,cc_o_c)

This is specifically for the efi libstub, the regular kernel (like in
your test case in the next patch) will use these newly introduced
functions.

One solution is to use this change instead:

diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile
index e386ffd009b7..775c34d80179 100644
--- a/drivers/firmware/efi/libstub/Makefile
+++ b/drivers/firmware/efi/libstub/Makefile
@@ -96,7 +96,7 @@ CFLAGS_zboot-decompress-gzip.o        += -I$(srctree)/lib/zlib_inflate
 zboot-obj-$(CONFIG_KERNEL_ZSTD)        := zboot-decompress-zstd.o lib-xxhash.o
 CFLAGS_zboot-decompress-zstd.o += -I$(srctree)/lib/zstd

-zboot-obj-$(CONFIG_RISCV)      += lib-clz_ctz.o lib-ashldi3.o
+zboot-obj-$(CONFIG_RISCV)      += lib-clz_ctz.o ../../../../arch/riscv/lib/ashldi3.o ../../../../arch/riscv/lib/lshrdi3.o
 lib-$(CONFIG_EFI_ZBOOT)                += zboot.o $(zboot-obj-y)

 lib-$(CONFIG_UNACCEPTED_MEMORY) += unaccepted_memory.o bitmap.o find.o

This will link against the correct shifting libraries.

- Charlie


> ---
> v2: adjust commit message
> ---
>  arch/riscv/Kconfig             |  3 ---
>  arch/riscv/kernel/image-vars.h |  7 +++++++
>  arch/riscv/lib/Makefile        |  1 +
>  arch/riscv/lib/ashldi3.S       | 36 +++++++++++++++++++++++++++++++++
>  arch/riscv/lib/ashrdi3.S       | 37 ++++++++++++++++++++++++++++++++++
>  arch/riscv/lib/lshrdi3.S       | 36 +++++++++++++++++++++++++++++++++
>  6 files changed, 117 insertions(+), 3 deletions(-)
>  create mode 100644 arch/riscv/lib/ashldi3.S
>  create mode 100644 arch/riscv/lib/ashrdi3.S
>  create mode 100644 arch/riscv/lib/lshrdi3.S
> 
> diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
> index 90c531e6abf5..515254720da5 100644
> --- a/arch/riscv/Kconfig
> +++ b/arch/riscv/Kconfig
> @@ -407,9 +407,6 @@ config ARCH_RV32I
>  	bool "RV32I"
>  	depends on NONPORTABLE
>  	select 32BIT
> -	select GENERIC_LIB_ASHLDI3
> -	select GENERIC_LIB_ASHRDI3
> -	select GENERIC_LIB_LSHRDI3
>  	select GENERIC_LIB_UCMPDI2
>  
>  config ARCH_RV64I
> diff --git a/arch/riscv/kernel/image-vars.h b/arch/riscv/kernel/image-vars.h
> index 3bd9d06a8b8f..d66e06daf13e 100644
> --- a/arch/riscv/kernel/image-vars.h
> +++ b/arch/riscv/kernel/image-vars.h
> @@ -32,6 +32,13 @@ __efistub___init_text_end	= __init_text_end;
>  __efistub_sysfb_primary_display	= sysfb_primary_display;
>  #endif
>  
> +/*
> + * These double-word integer shifts are used
> + * by the library code and so EFI stub as well.
> + */
> +PROVIDE(__efistub___lshrdi3    = __lshrdi3);
> +PROVIDE(__efistub___ashldi3    = __ashldi3);
> +
>  #endif
>  
>  #endif /* __RISCV_KERNEL_IMAGE_VARS_H */
> diff --git a/arch/riscv/lib/Makefile b/arch/riscv/lib/Makefile
> index bbc031124974..7cee3da80c68 100644
> --- a/arch/riscv/lib/Makefile
> +++ b/arch/riscv/lib/Makefile
> @@ -13,6 +13,7 @@ ifeq ($(CONFIG_MMU), y)
>  lib-$(CONFIG_RISCV_ISA_V)	+= uaccess_vector.o
>  endif
>  lib-$(CONFIG_MMU)	+= uaccess.o
> +lib-$(CONFIG_32BIT)	+= ashldi3.o ashrdi3.o lshrdi3.o
>  lib-$(CONFIG_64BIT)	+= tishift.o
>  lib-$(CONFIG_RISCV_ISA_ZICBOZ)	+= clear_page.o
>  obj-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o
> diff --git a/arch/riscv/lib/ashldi3.S b/arch/riscv/lib/ashldi3.S
> new file mode 100644
> index 000000000000..c3408862e2f6
> --- /dev/null
> +++ b/arch/riscv/lib/ashldi3.S
> @@ -0,0 +1,36 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/**
> + * Adopted for the Linux kernel from IPXE project, see
> + * https://github.com/ipxe/ipxe/blob/master/src/arch/riscv32/libgcc/llshift.S
> + */
> +
> +#include <linux/linkage.h>
> +#include <asm/asm.h>
> +
> +/**
> + * Shift left
> + *
> + * @v a1:a0             Value to shift
> + * @v a2                Shift amount
> + * @ret a1:a0           Shifted value
> + */
> +
> +SYM_FUNC_START(__ashldi3)
> +
> +        /* Perform shift by 32 bits, if applicable */
> +        li      t0, 32
> +        sub     t1, t0, a2
> +        bgtz    t1, 1f
> +        mv      a1, a0
> +        mv      a0, zero
> +1:      /* Perform shift by modulo-32 bits, if applicable */
> +        andi    a2, a2, 0x1f
> +        beqz    a2, 2f
> +        srl     t2, a0, t1
> +        sll     a0, a0, a2
> +        sll     a1, a1, a2
> +        or      a1, a1, t2
> +2:      ret
> +
> +SYM_FUNC_END(__ashldi3)
> +EXPORT_SYMBOL(__ashldi3)
> diff --git a/arch/riscv/lib/ashrdi3.S b/arch/riscv/lib/ashrdi3.S
> new file mode 100644
> index 000000000000..dd42b3cbb173
> --- /dev/null
> +++ b/arch/riscv/lib/ashrdi3.S
> @@ -0,0 +1,37 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/**
> + * Adopted for the Linux kernel from IPXE project, see
> + * https://github.com/ipxe/ipxe/blob/master/src/arch/riscv32/libgcc/llshift.S
> + */
> +
> +#include <linux/linkage.h>
> +#include <asm/asm.h>
> +
> +/**
> + * Arithmetic shift right
> + *
> + * @v a1:a0             Value to shift
> + * @v a2                Shift amount
> + * @ret a1:a0           Shifted value
> + */
> +
> +SYM_FUNC_START(__ashrdi3)
> +
> +        /* Perform shift by 32 bits, if applicable */
> +        li      t0, 32
> +        sub     t1, t0, a2
> +        bgtz    t1, 1f
> +        mv      a0, a1
> +        srai    a1, a1, 16
> +        srai    a1, a1, 16
> +1:      /* Perform shift by modulo-32 bits, if applicable */
> +        andi    a2, a2, 0x1f
> +        beqz    a2, 2f
> +        sll     t2, a1, t1
> +        sra     a1, a1, a2
> +        srl     a0, a0, a2
> +        or      a0, a0, t2
> +2:      ret
> +
> +SYM_FUNC_END(__ashrdi3)
> +EXPORT_SYMBOL(__ashrdi3)
> diff --git a/arch/riscv/lib/lshrdi3.S b/arch/riscv/lib/lshrdi3.S
> new file mode 100644
> index 000000000000..1af03985ccb7
> --- /dev/null
> +++ b/arch/riscv/lib/lshrdi3.S
> @@ -0,0 +1,36 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/**
> + * Adopted for the Linux kernel from IPXE project, see
> + * https://github.com/ipxe/ipxe/blob/master/src/arch/riscv32/libgcc/llshift.S
> + */
> +
> +#include <linux/linkage.h>
> +#include <asm/asm.h>
> +
> +/**
> + * Logical shift right
> + *
> + * @v a1:a0             Value to shift
> + * @v a2                Shift amount
> + * @ret a1:a0           Shifted value
> + */
> +
> +SYM_FUNC_START(__lshrdi3)
> +
> +        /* Perform shift by 32 bits, if applicable */
> +        li      t0, 32
> +        sub     t1, t0, a2
> +        bgtz    t1, 1f
> +        mv      a0, a1
> +        mv      a1, zero
> +1:      /* Perform shift by modulo-32 bits, if applicable */
> +        andi    a2, a2, 0x1f
> +        beqz    a2, 2f
> +        sll     t2, a1, t1
> +        srl     a1, a1, a2
> +        srl     a0, a0, a2
> +        or      a0, a0, t2
> +2:      ret
> +
> +SYM_FUNC_END(__lshrdi3)
> +EXPORT_SYMBOL(__lshrdi3)
> -- 
> 2.53.0
> 
> 
> _______________________________________________
> linux-riscv mailing list
> linux-riscv at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-riscv
> 



More information about the linux-riscv mailing list