diff options
author | Michael Brown <mcb30@ipxe.org> | 2020-07-07 00:09:40 +0100 |
---|---|---|
committer | Michael Brown <mcb30@ipxe.org> | 2020-07-07 00:46:45 +0100 |
commit | d2fb317fee9635008b8298add7d6f1d5534cec59 (patch) | |
tree | 99828dc7dc4940b11f89ca54db8329853a6488b2 /src/arch | |
parent | 586b723733904c0825844582dd19a44c71bc972b (diff) | |
download | ipxe-d2fb317fee9635008b8298add7d6f1d5534cec59.zip ipxe-d2fb317fee9635008b8298add7d6f1d5534cec59.tar.gz ipxe-d2fb317fee9635008b8298add7d6f1d5534cec59.tar.bz2 |
[crypto] Avoid temporarily setting direction flag in bigint_is_geq()
The UEFI specification states that the calling convention for IA-32
and x64 includes "Direction flag in EFLAGS is clear". This
specification covers only the calling convention used at the point of
calling functions annotated with EFIAPI. The specification explicitly
states that other functions (such as private functions or static
library calls) are not required to follow the UEFI calling
conventions.
The reference EDK2 implementation follows this specification. In
particular, the EDK2 interrupt handlers will clear the direction flag
before calling any EFIAPI functions, and will restore the direction
flag when returning from the interrupt handler. Some EDK2 private
library functions (most notably InternalMemCopyMem) may set the
direction flag temporarily in order to make efficient use of CPU
string operations.
The current implementation of iPXE's bigint_is_geq() for i386 and
x86_64 will similarly set the direction flag temporarily in order to
make efficient use of CPU string operations.
On some UEFI implementations (observed with a Getac RX10 tablet), a
timer interrupt that happens to occur while the direction flag is set
will reboot the machine. This very strongly indicates that the UEFI
timer interrupt handler is failing to clear the direction flag before
performing an affected operation (such as copying a block of memory).
Work around such buggy UEFI implementations by rewriting
bigint_is_geq() to avoid the use of string operations and so obviate
the requirement to temporarily set the direction flag.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/arch')
-rw-r--r-- | src/arch/x86/include/bits/bigint.h | 25 |
1 files changed, 8 insertions, 17 deletions
diff --git a/src/arch/x86/include/bits/bigint.h b/src/arch/x86/include/bits/bigint.h index c9bb6ea..4f1bc87 100644 --- a/src/arch/x86/include/bits/bigint.h +++ b/src/arch/x86/include/bits/bigint.h @@ -167,28 +167,19 @@ bigint_is_zero_raw ( const uint32_t *value0, unsigned int size ) { static inline __attribute__ (( always_inline, pure )) int bigint_is_geq_raw ( const uint32_t *value0, const uint32_t *reference0, unsigned int size ) { - const bigint_t ( size ) __attribute__ (( may_alias )) *value = - ( ( const void * ) value0 ); - const bigint_t ( size ) __attribute__ (( may_alias )) *reference = - ( ( const void * ) reference0 ); - void *discard_S; - void *discard_D; long discard_c; + long discard_tmp; int result; - __asm__ __volatile__ ( "std\n\t" - "\n1:\n\t" - "lodsl\n\t" - "scasl\n\t" + __asm__ __volatile__ ( "\n1:\n\t" + "movl -4(%3, %1, 4), %k2\n\t" + "cmpl -4(%4, %1, 4), %k2\n\t" "loope 1b\n\t" "setae %b0\n\t" - "cld\n\t" - : "=q" ( result ), "=&S" ( discard_S ), - "=&D" ( discard_D ), "=&c" ( discard_c ) - : "0" ( 0 ), "1" ( &value->element[ size - 1 ] ), - "2" ( &reference->element[ size - 1 ] ), - "3" ( size ) - : "eax" ); + : "=q" ( result ), "=&c" ( discard_c ), + "=&r" ( discard_tmp ) + : "r" ( value0 ), "r" ( reference0 ), + "0" ( 0 ), "1" ( size ) ); return result; } |