
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@gmail.com Cc: Mauro Condarelli mc5686@mclink.it Cc: Ralf Baechle ralf@linux-mips.org Signed-off-by: Linus Walleij linus.walleij@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@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?