diff mbox series

[kvm-unit-tests,v3,3/4] x86: Add test cases for LAM_{U48,U57}

Message ID 20230412075134.21240-4-binbin.wu@linux.intel.com (mailing list archive)
State New, archived
Headers show
Series x86: Add test cases for LAM | expand

Commit Message

Binbin Wu April 12, 2023, 7:51 a.m. UTC
This unit test covers:
1. CR3 LAM bits toggles.
2. Memory/MMIO access with user mode address containing LAM metadata.

Signed-off-by: Binbin Wu <binbin.wu@linux.intel.com>
---
 lib/x86/processor.h |  2 ++
 x86/lam.c           | 71 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 73 insertions(+)

Comments

Chao Gao April 21, 2023, 5:06 a.m. UTC | #1
On Wed, Apr 12, 2023 at 03:51:33PM +0800, Binbin Wu wrote:
>This unit test covers:
>1. CR3 LAM bits toggles.
>2. Memory/MMIO access with user mode address containing LAM metadata.
>
>Signed-off-by: Binbin Wu <binbin.wu@linux.intel.com>

Reviewed-by: Chao Gao <chao.gao@intel.com>

two nits below:

>---
>+static void test_lam_user(bool has_lam)
>+{
>+	phys_addr_t paddr;
>+	unsigned long cr3 = read_cr3();
>+
>+	/*
>+	 * The physical address width is within 36 bits, so that using identical
>+	 * mapping, the linear address will be considered as user mode address
>+	 * from the view of LAM.
>+	 */

Why 36 bits (i.e., 64G)?

would you mind adding a comment in patch 2 to explain why the virtual
addresses are kernel mode addresses?

>+	paddr = virt_to_phys(alloc_page());
>+	install_page((void *)cr3, paddr, (void *)paddr);
>+	install_page((void *)cr3, IORAM_BASE_PHYS, (void *)IORAM_BASE_PHYS);

are the two lines necessary?

>+
>+	test_lam_user_mode(has_lam, LAM48_MASK, paddr, IORAM_BASE_PHYS);
>+	test_lam_user_mode(has_lam, LAM57_MASK, paddr, IORAM_BASE_PHYS);
>+}
>+
> int main(int ac, char **av)
> {
> 	bool has_lam;
>@@ -239,6 +309,7 @@ int main(int ac, char **av)
> 			    "use kvm.force_emulation_prefix=1 to enable\n");
> 
> 	test_lam_sup(has_lam, fep_available);
>+	test_lam_user(has_lam);
> 
> 	return report_summary();
> }
>-- 
>2.25.1
>
Binbin Wu April 23, 2023, 3:07 a.m. UTC | #2
On 4/21/2023 1:06 PM, Chao Gao wrote:
> On Wed, Apr 12, 2023 at 03:51:33PM +0800, Binbin Wu wrote:
>> This unit test covers:
>> 1. CR3 LAM bits toggles.
>> 2. Memory/MMIO access with user mode address containing LAM metadata.
>>
>> Signed-off-by: Binbin Wu <binbin.wu@linux.intel.com>
> Reviewed-by: Chao Gao <chao.gao@intel.com>
>
> two nits below:
>
>> ---
>> +static void test_lam_user(bool has_lam)
>> +{
>> +	phys_addr_t paddr;
>> +	unsigned long cr3 = read_cr3();
>> +
>> +	/*
>> +	 * The physical address width is within 36 bits, so that using identical
>> +	 * mapping, the linear address will be considered as user mode address
>> +	 * from the view of LAM.
>> +	 */
> Why 36 bits (i.e., 64G)?

KUT memory allocator supports 4 Memory Areas:
AREA_NORMAL, AREA_HIGH, AREA_LOW and AREA_LOWEST.
AREA_NORMAL has the maximum address width, which is 36 bits.

How about change the comment to this:

+	/*
+	 * The physical address width supported by KUT memory allocator is within 36 bits,
+	 * so that using identical mapping, the linear address will be considered as user
+        * mode address from the view of LAM.
+	 */


>
> would you mind adding a comment in patch 2 to explain why the virtual
> addresses are kernel mode addresses?

OK. Will add the following comments:

     /*
      * KUT initializes vfree_top to 0 for X86_64, and each virtual address
      * allocation decreases the size from vfree_top. It's guaranteed that
      * the return value of alloc_vpage() is considered as kernel mode
      * address and canonical since only a small mount virtual address range
      * is allocated in this test.
      */



>
>> +	paddr = virt_to_phys(alloc_page());
>> +	install_page((void *)cr3, paddr, (void *)paddr);
>> +	install_page((void *)cr3, IORAM_BASE_PHYS, (void *)IORAM_BASE_PHYS);
> are the two lines necessary?

The two lines are not necessary.
Check setup_mmu(), it already sets up the identical mapping for avialble 
physcial memory/MMIO.
Will remove them.


>
>> +
>> +	test_lam_user_mode(has_lam, LAM48_MASK, paddr, IORAM_BASE_PHYS);
>> +	test_lam_user_mode(has_lam, LAM57_MASK, paddr, IORAM_BASE_PHYS);
>> +}
>> +
>> int main(int ac, char **av)
>> {
>> 	bool has_lam;
>> @@ -239,6 +309,7 @@ int main(int ac, char **av)
>> 			    "use kvm.force_emulation_prefix=1 to enable\n");
>>
>> 	test_lam_sup(has_lam, fep_available);
>> +	test_lam_user(has_lam);
>>
>> 	return report_summary();
>> }
>> -- 
>> 2.25.1
>>
diff mbox series

Patch

diff --git a/lib/x86/processor.h b/lib/x86/processor.h
index 4bb8cd7..a181e0b 100644
--- a/lib/x86/processor.h
+++ b/lib/x86/processor.h
@@ -56,7 +56,9 @@ 
 
 #define X86_CR3_PCID_MASK	GENMASK(11, 0)
 #define X86_CR3_LAM_U57_BIT	(61)
+#define X86_CR3_LAM_U57		BIT_ULL(X86_CR3_LAM_U57_BIT)
 #define X86_CR3_LAM_U48_BIT	(62)
+#define X86_CR3_LAM_U48		BIT_ULL(X86_CR3_LAM_U48_BIT)
 
 #define X86_CR4_VME_BIT		(0)
 #define X86_CR4_VME		BIT(X86_CR4_VME_BIT)
diff --git a/x86/lam.c b/x86/lam.c
index 63c3fde..50bcdf5 100644
--- a/x86/lam.c
+++ b/x86/lam.c
@@ -18,9 +18,11 @@ 
 #include "vm.h"
 #include "asm/io.h"
 #include "ioram.h"
+#include "usermode.h"
 
 #define LAM57_MASK	GENMASK_ULL(62, 57)
 #define LAM48_MASK	GENMASK_ULL(62, 48)
+#define CR3_LAM_BITS_MASK (X86_CR3_LAM_U48 | X86_CR3_LAM_U57)
 
 #define FLAGS_LAM_ACTIVE	BIT_ULL(0)
 #define FLAGS_LA57		BIT_ULL(1)
@@ -41,6 +43,16 @@  static inline bool lam_sup_active(void)
 	return !!(read_cr4() & X86_CR4_LAM_SUP);
 }
 
+static inline bool lam_u48_active(void)
+{
+	return (read_cr3() & CR3_LAM_BITS_MASK) == X86_CR3_LAM_U48;
+}
+
+static inline bool lam_u57_active(void)
+{
+	return !!(read_cr3() & X86_CR3_LAM_U57);
+}
+
 /* According to LAM mode, set metadata in high bits */
 static inline u64 set_metadata(u64 src, u64 metadata_mask)
 {
@@ -92,6 +104,7 @@  static void do_mov(void *mem)
 static u64 test_ptr(u64 arg1, u64 arg2, u64 arg3, u64 arg4)
 {
 	bool lam_active = !!(arg1 & FLAGS_LAM_ACTIVE);
+	bool la_57 = !!(arg1 & FLAGS_LA57);
 	u64 lam_mask = arg2;
 	u64 *ptr = (u64 *)arg3;
 	bool is_mmio = !!arg4;
@@ -105,6 +118,17 @@  static u64 test_ptr(u64 arg1, u64 arg2, u64 arg3, u64 arg4)
 	report(fault != lam_active,"Test tagged addr (%s)",
 	       is_mmio ? "MMIO" : "Memory");
 
+	/*
+	 * This test case is only triggered when LAM_U57 is active and 4-level
+	 * paging is used. For the case, bit[56:47] aren't all 0 triggers #GP.
+	 */
+	if (lam_active && (lam_mask == LAM57_MASK) && !la_57) {
+		ptr = (u64 *)set_metadata((u64)ptr, LAM48_MASK);
+		fault = test_for_exception(GP_VECTOR, do_mov, ptr);
+		report(fault,  "Test non-LAM-canonical addr (%s)",
+		       is_mmio ? "MMIO" : "Memory");
+	}
+
 	return 0;
 }
 
@@ -221,6 +245,52 @@  static void test_lam_sup(bool has_lam, bool fep_available)
 		test_invlpg(lam_mask, vaddr, true);
 }
 
+static void test_lam_user_mode(bool has_lam, u64 lam_mask, u64 mem, u64 mmio)
+{
+	unsigned r;
+	bool raised_vector;
+	unsigned long cr3 = read_cr3() & ~CR3_LAM_BITS_MASK;
+	u64 flags = 0;
+
+	if (is_la57())
+		flags |= FLAGS_LA57;
+
+	if (has_lam) {
+		if (lam_mask == LAM48_MASK) {
+			r = write_cr3_safe(cr3 | X86_CR3_LAM_U48);
+			report((r == 0) && lam_u48_active(), "Set LAM_U48");
+		} else {
+			r = write_cr3_safe(cr3 | X86_CR3_LAM_U57);
+			report((r == 0) && lam_u57_active(), "Set LAM_U57");
+		}
+	}
+	if (lam_u48_active() || lam_u57_active())
+		flags |= FLAGS_LAM_ACTIVE;
+
+	run_in_user((usermode_func)test_ptr, GP_VECTOR, flags, lam_mask, mem,
+		    false, &raised_vector);
+	run_in_user((usermode_func)test_ptr, GP_VECTOR, flags, lam_mask, mmio,
+		    true, &raised_vector);
+}
+
+static void test_lam_user(bool has_lam)
+{
+	phys_addr_t paddr;
+	unsigned long cr3 = read_cr3();
+
+	/*
+	 * The physical address width is within 36 bits, so that using identical
+	 * mapping, the linear address will be considered as user mode address
+	 * from the view of LAM.
+	 */
+	paddr = virt_to_phys(alloc_page());
+	install_page((void *)cr3, paddr, (void *)paddr);
+	install_page((void *)cr3, IORAM_BASE_PHYS, (void *)IORAM_BASE_PHYS);
+
+	test_lam_user_mode(has_lam, LAM48_MASK, paddr, IORAM_BASE_PHYS);
+	test_lam_user_mode(has_lam, LAM57_MASK, paddr, IORAM_BASE_PHYS);
+}
+
 int main(int ac, char **av)
 {
 	bool has_lam;
@@ -239,6 +309,7 @@  int main(int ac, char **av)
 			    "use kvm.force_emulation_prefix=1 to enable\n");
 
 	test_lam_sup(has_lam, fep_available);
+	test_lam_user(has_lam);
 
 	return report_summary();
 }