diff mbox series

[kvm-unit-tests,v2,2/2] nSVM: Fix NPT reserved bits test hang

Message ID 162880842856.21995.11223675477768032640.stgit@bmoger-ubuntu (mailing list archive)
State New, archived
Headers show
Series Couple of SVM unit test fixes | expand

Commit Message

Babu Moger Aug. 12, 2021, 10:47 p.m. UTC
From: Babu Moger <Babu.Moger@amd.com>

SVM reserved bits tests hangs in a infinite loop. The test uses the
instruction 'rdtsc' to generate the random reserved bits. It hangs
while generating the valid reserved bits.

The AMD64 Architecture Programmers Manual Volume 2: System
Programming manual says, When using the TSC to measure elapsed time,
programmers must be aware that for some implementations, the rate at
which the TSC is incremented varies based on the processor power
management state (Pstate). For other implementations, the TSC
increment rate is fixed and is not subject to power-management
related changes in processor frequency.

In AMD gen3 machine, the rdtsc value is a P state multiplier.
Here are the rdtsc value in 10 sucessive reads.
0 rdtsc = 0x1ec92919b9710
1 rdtsc = 0x1ec92919c01f0
2 rdtsc = 0x1ec92919c0f70
3 rdtsc = 0x1ec92919c18d0
4 rdtsc = 0x1ec92919c2060
5 rdtsc = 0x1ec92919c28d0
6 rdtsc = 0x1ec92919c30b0
7 rdtsc = 0x1ec92919c5660
8 rdtsc = 0x1ec92919c6150
9 rdtsc = 0x1ec92919c7c80

This test uses the lower nibble and right shifts to generate the
valid reserved bit. It loops forever because the lower nibble is always
zero.

Fixing the issue with replacing rdrand instruction if available or
skipping the test if we cannot generate the valid reserved bits.

Signed-off-by: Babu Moger <Babu.Moger@amd.com>
---
 lib/x86/processor.h |   11 +++++++++++
 x86/svm_tests.c     |   28 ++++++++++++++++++++++++----
 2 files changed, 35 insertions(+), 4 deletions(-)
diff mbox series

Patch

diff --git a/lib/x86/processor.h b/lib/x86/processor.h
index a08ea1f..1e10cc3 100644
--- a/lib/x86/processor.h
+++ b/lib/x86/processor.h
@@ -531,6 +531,17 @@  static inline void sti(void)
     asm volatile ("sti");
 }
 
+static inline unsigned long long rdrand(void)
+{
+	long long r;
+
+	asm volatile("rdrand %0\n\t"
+		     "jc 1f\n\t"
+		     "mov $0, %0\n\t"
+		     "1:\n\t" : "=r" (r));
+	return r;
+}
+
 static inline unsigned long long rdtsc(void)
 {
 	long long r;
diff --git a/x86/svm_tests.c b/x86/svm_tests.c
index 79ed48e..b998b24 100644
--- a/x86/svm_tests.c
+++ b/x86/svm_tests.c
@@ -2671,6 +2671,14 @@  static void _svm_npt_rsvd_bits_test(u64 *pxe, u64 pxe_rsvd_bits,  u64 efer,
 	u64 rsvd_bits;
 	int i;
 
+	/*
+	 * RDTSC or RDRAND can sometimes fail to generate a valid reserved bits
+	 */
+	if (!pxe_rsvd_bits) {
+		report_skip("svm_npt_rsvd_bits_test: Reserved bits are not valid");
+		return;
+	}
+
 	/*
 	 * Test all combinations of guest/host EFER.NX and CR4.SMEP.  If host
 	 * EFER.NX=0, use NX as the reserved bit, otherwise use the passed in
@@ -2704,11 +2712,23 @@  static void _svm_npt_rsvd_bits_test(u64 *pxe, u64 pxe_rsvd_bits,  u64 efer,
 
 static u64 get_random_bits(u64 hi, u64 low)
 {
-	u64 rsvd_bits;
+	unsigned retry = 5;
+	u64 rsvd_bits = 0;
+
+	if (this_cpu_has(X86_FEATURE_RDRAND)) {
+		do {
+			rsvd_bits = (rdrand() << low) & GENMASK_ULL(hi, low);
+			retry--;
+		} while (!rsvd_bits && retry);
+	}
 
-	do {
-		rsvd_bits = (rdtsc() << low) & GENMASK_ULL(hi, low);
-	} while (!rsvd_bits);
+	if (!rsvd_bits) {
+		retry = 5;
+		do {
+			rsvd_bits = (rdtsc() << low) & GENMASK_ULL(hi, low);
+			retry--;
+		} while (!rsvd_bits && retry);
+	}
 
 	return rsvd_bits;
 }