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

Reply via email to