mirror of https://github.com/ipxe/ipxe.git
[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>pull/119/head
parent
586b723733
commit
d2fb317fee
|
@ -167,28 +167,19 @@ bigint_is_zero_raw ( const uint32_t *value0, unsigned int size ) {
|
||||||
static inline __attribute__ (( always_inline, pure )) int
|
static inline __attribute__ (( always_inline, pure )) int
|
||||||
bigint_is_geq_raw ( const uint32_t *value0, const uint32_t *reference0,
|
bigint_is_geq_raw ( const uint32_t *value0, const uint32_t *reference0,
|
||||||
unsigned int size ) {
|
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_c;
|
||||||
|
long discard_tmp;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
__asm__ __volatile__ ( "std\n\t"
|
__asm__ __volatile__ ( "\n1:\n\t"
|
||||||
"\n1:\n\t"
|
"movl -4(%3, %1, 4), %k2\n\t"
|
||||||
"lodsl\n\t"
|
"cmpl -4(%4, %1, 4), %k2\n\t"
|
||||||
"scasl\n\t"
|
|
||||||
"loope 1b\n\t"
|
"loope 1b\n\t"
|
||||||
"setae %b0\n\t"
|
"setae %b0\n\t"
|
||||||
"cld\n\t"
|
: "=q" ( result ), "=&c" ( discard_c ),
|
||||||
: "=q" ( result ), "=&S" ( discard_S ),
|
"=&r" ( discard_tmp )
|
||||||
"=&D" ( discard_D ), "=&c" ( discard_c )
|
: "r" ( value0 ), "r" ( reference0 ),
|
||||||
: "0" ( 0 ), "1" ( &value->element[ size - 1 ] ),
|
"0" ( 0 ), "1" ( size ) );
|
||||||
"2" ( &reference->element[ size - 1 ] ),
|
|
||||||
"3" ( size )
|
|
||||||
: "eax" );
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue