summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Barnes <robbarnes@google.com>2022-07-27 18:57:07 +0000
committerMartin L Roth <gaumless@gmail.com>2022-08-13 17:20:32 +0000
commitf6bb293f1c2ed33f09159a5e0b094e81576ef7f3 (patch)
tree5df9a923571495be99201347970e1b62dc861fa1
parentb11f9f7e162759cf5ae0f033e125e9158520030d (diff)
arm/libgcc: Support signed 64-bit division
Add support for signed 64-bit division. The implementation mostly relies on __aeabi_uldivmod, which is already implemented. ldivmod.S was adapted from CrOS EC version of ldivmod.S: https://chromium.googlesource.com/chromiumos/platform/ec/+/main/third_party/libaeabi-cortexm0/core/cortex-m0/ldivmod.S The CrOS EC version was adapted from: https://github.com/bobbl/libaeabi-cortexm0/blob/master/ldivmod.S BUG=b:240316722 BRANCH=None TEST=Signed division works in PSP verstage (runs on ARM) Change-Id: I53785c732b0fa35a4809bc054f1482c5461ada7b Signed-off-by: Rob Barnes <robbarnes@google.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/66207 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Julius Werner <jwerner@chromium.org> Reviewed-by: Tim Van Patten <timvp@google.com>
-rw-r--r--AUTHORS1
-rw-r--r--src/arch/arm/libgcc/Makefile.inc2
-rw-r--r--src/arch/arm/libgcc/ldivmod.S74
3 files changed, 76 insertions, 1 deletions
diff --git a/AUTHORS b/AUTHORS
index 8b1cb22608..169d2b4401 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -108,6 +108,7 @@ Jonas 'Sortie' Termansen
Jonathan A. Kollasch
Jonathan Neuschäfer
Jordan Crouse
+Jörg Mische
Joseph Smith
Keith Hui
Keith Packard
diff --git a/src/arch/arm/libgcc/Makefile.inc b/src/arch/arm/libgcc/Makefile.inc
index 0da655ea98..c6ca45e24c 100644
--- a/src/arch/arm/libgcc/Makefile.inc
+++ b/src/arch/arm/libgcc/Makefile.inc
@@ -1,6 +1,6 @@
## SPDX-License-Identifier: GPL-2.0-only
-libgcc_files = ashldi3.S lib1funcs.S lshrdi3.S muldi3.S ucmpdi2.S uldivmod.S
+libgcc_files = ashldi3.S lib1funcs.S lshrdi3.S muldi3.S ucmpdi2.S uldivmod.S ldivmod.S
libgcc_files += udivmoddi4.c umoddi3.c
ifeq ($(CONFIG_ARCH_BOOTBLOCK_ARM),y)
diff --git a/src/arch/arm/libgcc/ldivmod.S b/src/arch/arm/libgcc/ldivmod.S
new file mode 100644
index 0000000000..39b89434cd
--- /dev/null
+++ b/src/arch/arm/libgcc/ldivmod.S
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: ISC OR GPL-2.0-only */
+
+/*
+ * ldivmod.S: signed 64 bit division (quotient and remainder)
+ *
+ * Taken from CrOS EC: third_party/libaeabi-cortexm0/core/cortex-m0/ldivmod.S
+ */
+
+#include <arch/asm.h>
+
+
+@ {long long quotient, long long remainder}
+@ __aeabi_ldivmod(long long numerator, long long denominator)
+@
+@ Divide r1:r0 by r3:r2 and return the quotient in r1:r0 and the remainder in
+@ r3:r2 (all signed)
+@
+
+ENTRY(__aeabi_ldivmod)
+
+ cmp r1, #0
+ bge L_num_pos
+
+ push {r4, lr}
+ movs r4, #0 @ num = -num
+ rsbs r0, r0, #0
+ sbcs r4, r1
+ mov r1, r4
+
+ cmp r3, #0
+ bge L_neg_both
+
+ movs r4, #0 @ den = -den
+ rsbs r2, r2, #0
+ sbcs r4, r3
+ mov r3, r4
+ bl __aeabi_uldivmod
+ movs r4, #0 @ rem = -rem
+ rsbs r2, r2, #0
+ sbcs r4, r3
+ mov r3, r4
+ pop {r4, pc}
+
+L_neg_both:
+ bl __aeabi_uldivmod
+ movs r4, #0 @ quot = -quot
+ rsbs r0, r0, #0
+ sbcs r4, r1
+ mov r1, r4
+ movs r4, #0 @ rem = -rem
+ rsbs r2, r2, #0
+ sbcs r4, r3
+ mov r3, r4
+ pop {r4, pc}
+
+L_num_pos:
+ cmp r3, #0
+ blt L_den_neg
+ push {r4, lr}
+ bl __aeabi_uldivmod @ offset too big for b / bge
+ pop {r4, pc}
+
+L_den_neg:
+ push {r4, lr}
+ movs r4, #0 @ den = -den
+ rsbs r2, r2, #0
+ sbcs r4, r3
+ mov r3, r4
+ bl __aeabi_uldivmod
+ movs r4, #0 @ quot = -quot
+ rsbs r0, r0, #0
+ sbcs r4, r1
+ mov r1, r4
+ pop {r4, pc}