[PATCH] RFT: mips: implement __udivdi3
Daniel Schwierzeck
daniel.schwierzeck at gmail.com
Thu Sep 21 15:42:41 CEST 2023
Hi Linus,
On 9/18/23 08:11, Linus Walleij wrote:
> Squashfs wasn't compiling because the lldiv() directives
> turn into __udivdi3 and we are using private libgcc.
> This is just copied from the Linux kernel v6.6-rc1
> arch/mips/include/asm/div64.h and then adjusted for
> U-Boot.
>
> After this squashfs compiles for MIPS.
>
> Cc: Daniel Schwierzeck <daniel.schwierzeck at gmail.com>
> Cc: Mauro Condarelli <mc5686 at mclink.it>
> Cc: Ralf Baechle <ralf at linux-mips.org>
> Signed-off-by: Linus Walleij <linus.walleij at linaro.org>
> ---
> I can't test this because it didn't work for MTD devices
> as I had expected, but I saw Mauro had this problem
> before so I think I might have fixed it. I better put
> the patch out there rather than let it sit on my drive.
thanks for the patch. IIRC the problem was due to the usage of a/b vs.
do_div(a,b). We already thought about two options: fix the SquashFS code
or add __udivdi3(). Because no upstream MIPS board enabled SquashFS,
this issue remained unresolved.
> ---
> arch/mips/lib/Makefile | 2 +-
> arch/mips/lib/udivdi3.c | 86 +++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 87 insertions(+), 1 deletion(-)
> create mode 100644 arch/mips/lib/udivdi3.c
>
> diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile
> index 9ee1fcb5c702..1621cc9a1ff9 100644
> --- a/arch/mips/lib/Makefile
> +++ b/arch/mips/lib/Makefile
> @@ -14,4 +14,4 @@ obj-$(CONFIG_CMD_BOOTM) += bootm.o
> obj-$(CONFIG_CMD_GO) += boot.o
> obj-$(CONFIG_SPL_BUILD) += spl.o
>
> -lib-$(CONFIG_USE_PRIVATE_LIBGCC) += ashldi3.o ashrdi3.o lshrdi3.o
> +lib-$(CONFIG_USE_PRIVATE_LIBGCC) += ashldi3.o ashrdi3.o lshrdi3.o udivdi3.o
> diff --git a/arch/mips/lib/udivdi3.c b/arch/mips/lib/udivdi3.c
> new file mode 100644
> index 000000000000..6a4ee5fa46ab
> --- /dev/null
> +++ b/arch/mips/lib/udivdi3.c
> @@ -0,0 +1,86 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2000, 2004, 2021 Maciej W. Rozycki
> + * Copyright (C) 2003, 07 Ralf Baechle (ralf at linux-mips.org)
> + */
> +
> +#include "libgcc.h"
> +
> +/*
> + * No traps on overflows for any of these...
> + */
> +
> +#define do_div64_32(res, high, low, base) ({ \
> + unsigned long __cf, __tmp, __tmp2, __i; \
> + unsigned long __quot32, __mod32; \
> + \
> + __asm__( \
> + " .set push \n" \
> + " .set noat \n" \
> + " .set noreorder \n" \
> + " move %2, $0 \n" \
> + " move %3, $0 \n" \
> + " b 1f \n" \
> + " li %4, 0x21 \n" \
> + "0: \n" \
> + " sll $1, %0, 0x1 \n" \
> + " srl %3, %0, 0x1f \n" \
> + " or %0, $1, %5 \n" \
> + " sll %1, %1, 0x1 \n" \
> + " sll %2, %2, 0x1 \n" \
> + "1: \n" \
> + " bnez %3, 2f \n" \
> + " sltu %5, %0, %z6 \n" \
> + " bnez %5, 3f \n" \
> + "2: \n" \
> + " addiu %4, %4, -1 \n" \
> + " subu %0, %0, %z6 \n" \
> + " addiu %2, %2, 1 \n" \
> + "3: \n" \
> + " bnez %4, 0b \n" \
> + " srl %5, %1, 0x1f \n" \
> + " .set pop" \
> + : "=&r" (__mod32), "=&r" (__tmp), \
> + "=&r" (__quot32), "=&r" (__cf), \
> + "=&r" (__i), "=&r" (__tmp2) \
> + : "Jr" (base), "0" (high), "1" (low)); \
> + \
> + (res) = __quot32; \
> + __mod32; \
> +})
> +
> +#define __div64_32(n, base) ({ \
> + unsigned long __upper, __low, __high, __radix; \
> + unsigned long long __quot; \
> + unsigned long long __div; \
> + unsigned long __mod; \
> + \
> + __div = (*n); \
> + __radix = (base); \
> + \
> + __high = __div >> 32; \
> + __low = __div; \
> + \
> + if (__high < __radix) { \
> + __upper = __high; \
> + __high = 0; \
> + } else { \
> + __upper = __high % __radix; \
> + __high /= __radix; \
> + } \
> + \
> + __mod = do_div64_32(__low, __upper, __low, __radix); \
> + \
> + __quot = __high; \
> + __quot = __quot << 32 | __low; \
> + (*n) = __quot; \
> + __mod; \
> +})
> +
> +long long __udivdi3(long long u, word_type b)
> +{
> + long long ret = u;
> +
> + __div64_32(&ret, b);
> + return ret;
> +}
the call to __udivdi3() won't be generated on MIPS64, so the code should
be guarded with #if BITS_PER_LONG == 32 as done in Linux. Also we could
simply use the generic div64.h implementation.
I played around a bit and following simplified code compiles on various
MIPS32 and MIPS64 boards. (E.g. "echo CONFIG_FS_SQUASHFS=y >>
configs/malta[|64|el|64el]_defconfig && make malta[|64|el|64el]_defconfig")
/* SPDX-License-Identifier: GPL-2.0 */
#include "libgcc.h"
#if BITS_PER_LONG == 32
#include <div64.h>
long long __udivdi3(long long u, word_type b)
{
long long ret = u;
__div64_32(&ret, b);
return ret;
}
#endif /* BITS_PER_LONG == 32 */
What do you think?
--
- Daniel
More information about the U-Boot
mailing list