aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Brown <mcb30@ipxe.org>2020-07-07 00:09:40 +0100
committerMichael Brown <mcb30@ipxe.org>2020-07-07 00:46:45 +0100
commitd2fb317fee9635008b8298add7d6f1d5534cec59 (patch)
tree99828dc7dc4940b11f89ca54db8329853a6488b2
parent586b723733904c0825844582dd19a44c71bc972b (diff)
downloadipxe-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>
-rw-r--r--src/arch/x86/include/bits/bigint.h25
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;
}