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>
This commit is contained in:
Rob Barnes 2022-07-27 18:57:07 +00:00 committed by Martin L Roth
parent b11f9f7e16
commit f6bb293f1c
3 changed files with 76 additions and 1 deletions

View File

@ -108,6 +108,7 @@ Jonas 'Sortie' Termansen
Jonathan A. Kollasch
Jonathan Neuschäfer
Jordan Crouse
Jörg Mische
Joseph Smith
Keith Hui
Keith Packard

View File

@ -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)

View File

@ -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}