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 <[email protected]>
Cc: Mauro Condarelli <[email protected]>
Cc: Ralf Baechle <[email protected]>
Signed-off-by: Linus Walleij <[email protected]>
---
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 ([email protected])
+ */
+
+#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