QEMU maintainers have found and issue related to incorrect usage of
STFLE instruction [1], which is used to get features supported by the
machine. There are three potential problems with the current usage:
- R0 must contain the number of requested doublewords *minus one*. The
existing code lacks the "minus one" part.
- Older machines may not fill all the doublewords - this is fixed by
calling `memset`.
- STFLE updates R0, but we don't tell the compiler about this - this is
fixed by using a `+` constraint.
- Not really a problem, but it's enough to load 8 bits into R0, so its
type was changed to `uint8_t`. Also, STFLE only writes to `facilities`
variable, therefore memory clobber is unnecessary.
[1] https://lists.gnu.org/archive/html/qemu-devel/2019-06/msg00113.html
static inline int is_dfltcc_enabled(void)
{
uint64_t facilities[(DFLTCC_FACILITY / 64) + 1];
- register int r0 __asm__("r0");
+ register uint8_t r0 __asm__("r0");
- r0 = sizeof(facilities) / sizeof(facilities[0]);
- __asm__ volatile("stfle %[facilities]\n"
- : [facilities] "=Q" (facilities)
- : [r0] "r" (r0)
- : "cc", "memory");
+ memset(facilities, 0, sizeof(facilities));
+ r0 = sizeof(facilities) / sizeof(facilities[0]) - 1;
+ __asm__ volatile("stfle %[facilities]\n" : [facilities] "=Q" (facilities), [r0] "+r" (r0) :: "cc");
return is_bit_set((const char *)facilities, DFLTCC_FACILITY);
}