@@ -8177,6 +8177,170 @@ static void test_guest_segment_base_addr_fields(void)
vmcs_write(GUEST_AR_ES, ar_saved);
}
+#define TEST_SEGMENT_AR(seg, name, saved_val, mask, test_val, xfail, msg)\
+{ \
+ u32 val = (saved_val & mask) | test_val; \
+ vmcs_write(seg, val); \
+ test_guest_state(msg, xfail, val, name); \
+}
+
+#define TEST_SEGMENT_AR_TYPE_HELPER(seg, name) \
+{ \
+ u32 ar_saved = vmcs_read(seg); \
+ \
+ TEST_SEGMENT_AR(seg, name, (ar_saved | GUEST_SEG_UNUSABLE_MASK),\
+ AR_TYPE_MASK1, 0x1, false, msg); \
+ TEST_SEGMENT_AR(seg, name, (ar_saved | GUEST_SEG_UNUSABLE_MASK),\
+ AR_TYPE_MASK1, 0x0, false, msg); \
+ TEST_SEGMENT_AR(seg, name, (ar_saved & ~GUEST_SEG_UNUSABLE_MASK),\
+ AR_TYPE_MASK1, 0x1, false, msg); \
+ TEST_SEGMENT_AR(seg, name, (ar_saved & ~GUEST_SEG_UNUSABLE_MASK),\
+ AR_TYPE_MASK1, 0x0, true, msg); \
+ TEST_SEGMENT_AR(seg, name, (ar_saved | GUEST_SEG_UNUSABLE_MASK),\
+ AR_TYPE_MASK2, 0x8, false, msg); \
+ TEST_SEGMENT_AR(seg, name, (ar_saved | GUEST_SEG_UNUSABLE_MASK),\
+ AR_TYPE_MASK2, 0x2, false, msg); \
+ TEST_SEGMENT_AR(seg, name, (ar_saved & ~GUEST_SEG_UNUSABLE_MASK),\
+ AR_TYPE_MASK2, 0x9, true, msg); \
+ TEST_SEGMENT_AR(seg, name, (ar_saved & ~GUEST_SEG_UNUSABLE_MASK),\
+ AR_TYPE_MASK2, 0x3, false, msg); \
+ \
+ vmcs_write(seg, ar_saved); \
+}
+
+#define TEST_SEGMENT_AR_S_HELPER(seg, name) \
+{ \
+ u32 ar_saved = vmcs_read(seg); \
+ char msg[] = "Access_Rights[4]"; \
+ \
+ if (seg == GUEST_AR_CS) { \
+ TEST_SEGMENT_AR(seg, name, ar_saved, AR_S_MASK, 0x10, \
+ false, msg); \
+ TEST_SEGMENT_AR(seg, name, ar_saved, AR_S_MASK, ~0x10, \
+ true, msg); \
+ } else { \
+ TEST_SEGMENT_AR(seg, name, (ar_saved | \
+ GUEST_SEG_UNUSABLE_MASK), AR_S_MASK, 0x10, false, msg);\
+ TEST_SEGMENT_AR(seg, name, (ar_saved | \
+ GUEST_SEG_UNUSABLE_MASK), AR_S_MASK, 0x0, false, msg);\
+ TEST_SEGMENT_AR(seg, name, (ar_saved & \
+ ~GUEST_SEG_UNUSABLE_MASK), AR_S_MASK, 0x10, false, msg);\
+ TEST_SEGMENT_AR(seg, name, (ar_saved & \
+ ~GUEST_SEG_UNUSABLE_MASK), AR_S_MASK, 0x0, true, msg);\
+ } \
+ vmcs_write(seg, ar_saved); \
+}
+
+/*
+ * The following checks are done on the Access Rights field of the Guest
+ * Segment Registers:
+ *
+ * Bits 3:0 (Type):
+ * CS:
+ * - If the “unrestricted guest" VM-execution control is 0, value must be
+ * 9, 11, 13, or 15.
+ * - If the “unrestricted guest" VM-execution control is 1, value must be
+ * either 3 or one of 9, 11, 13, and 15.
+ * SS:
+ * - If SS is usable, the Type must be 3 or 7.
+ * DS, ES, FS, GS:
+ * - If the register is usable, bit 0 of the Type must be 1 and if bit 3
+ * of the Type is 1, then bit 1 of the Type must be 1.
+ *
+ * Bit 4 (S): If the register is CS or if the register is usable, S must be 1.
+ *
+ * [Intel SDM]
+ */
+static void test_guest_segment_ar_fields(void)
+{
+ /*
+ * Type [3:0] of CS
+ */
+ u32 ar_saved = vmcs_read(GUEST_AR_CS);
+ char msg[] = "Access_Rights[3:0]";
+
+#define AR_TYPE_MASK ~0xf
+#define AR_TYPE_MASK1 ~0x1
+#define AR_TYPE_MASK2 ~0xa
+
+ TEST_SEGMENT_AR(GUEST_AR_CS, "GUEST_AR_CS", ar_saved,
+ AR_TYPE_MASK, 0x9, false, msg);
+ TEST_SEGMENT_AR(GUEST_AR_CS, "GUEST_AR_CS", ar_saved,
+ AR_TYPE_MASK, 0xb, false, msg);
+ TEST_SEGMENT_AR(GUEST_AR_CS, "GUEST_AR_CS", ar_saved,
+ AR_TYPE_MASK, 0xd, false, msg);
+ TEST_SEGMENT_AR(GUEST_AR_CS, "GUEST_AR_CS", ar_saved,
+ AR_TYPE_MASK, 0xf, false, msg);
+
+ /* Turn off "unrestricted guest" vm-execution control */
+ u32 cpu_ctrl0_saved = vmcs_read(CPU_EXEC_CTRL0);
+ u32 cpu_ctrl1_saved = vmcs_read(CPU_EXEC_CTRL1);
+ if (cpu_ctrl1_saved | CPU_URG)
+ vmcs_write(CPU_EXEC_CTRL1, cpu_ctrl1_saved & ~CPU_URG);
+
+ TEST_SEGMENT_AR(GUEST_AR_CS, "GUEST_AR_CS", ar_saved,
+ AR_TYPE_MASK, 0x3, false, msg);
+
+ /* Turn on "unrestricted guest" vm-execution control */
+ vmcs_write(CPU_EXEC_CTRL0, cpu_ctrl0_saved | CPU_SECONDARY);
+ vmcs_write(CPU_EXEC_CTRL1, cpu_ctrl1_saved | CPU_URG);
+ /* EPT and EPTP must be setup when "unrestricted guest" is on */
+ setup_ept(false);
+
+ TEST_SEGMENT_AR(GUEST_AR_CS, "GUEST_AR_CS", ar_saved,
+ AR_TYPE_MASK, 0x3, false, msg);
+
+ vmcs_write(GUEST_AR_CS, ar_saved);
+ vmcs_write(CPU_EXEC_CTRL0, cpu_ctrl0_saved);
+ vmcs_write(CPU_EXEC_CTRL1, cpu_ctrl1_saved);
+
+ /*
+ * Type [3:0] of SS
+ */
+ ar_saved = vmcs_read(GUEST_AR_SS);
+
+ TEST_SEGMENT_AR(GUEST_AR_SS, "GUEST_AR_SS", (ar_saved |
+ GUEST_SEG_UNUSABLE_MASK), AR_TYPE_MASK, 0x3, false, msg);
+
+ TEST_SEGMENT_AR(GUEST_AR_SS, "GUEST_AR_SS", (ar_saved |
+ GUEST_SEG_UNUSABLE_MASK), AR_TYPE_MASK, 0x7, false, msg);
+
+ TEST_SEGMENT_AR(GUEST_AR_SS, "GUEST_AR_SS", (ar_saved |
+ GUEST_SEG_UNUSABLE_MASK), AR_TYPE_MASK, 0x0, false, msg);
+
+ TEST_SEGMENT_AR(GUEST_AR_SS, "GUEST_AR_SS", (ar_saved &
+ ~GUEST_SEG_UNUSABLE_MASK), AR_TYPE_MASK, 0x3, false, msg);
+
+ TEST_SEGMENT_AR(GUEST_AR_SS, "GUEST_AR_SS", (ar_saved &
+ ~GUEST_SEG_UNUSABLE_MASK), AR_TYPE_MASK, 0x7, false, msg);
+
+ TEST_SEGMENT_AR(GUEST_AR_SS, "GUEST_AR_SS", (ar_saved &
+ ~GUEST_SEG_UNUSABLE_MASK), AR_TYPE_MASK, 0x0, true, msg);
+
+ vmcs_write(GUEST_AR_SS, ar_saved);
+
+ /*
+ * Type [3:0] of DS, ES, FS and GS
+ */
+ TEST_SEGMENT_AR_TYPE_HELPER(GUEST_AR_DS, "GUEST_AR_DS");
+ TEST_SEGMENT_AR_TYPE_HELPER(GUEST_AR_ES, "GUEST_AR_ES");
+ TEST_SEGMENT_AR_TYPE_HELPER(GUEST_AR_FS, "GUEST_AR_FS");
+ TEST_SEGMENT_AR_TYPE_HELPER(GUEST_AR_GS, "GUEST_AR_GS");
+
+ /*
+ * S [4] of CS, SS, DS, ES, FS and GS
+ */
+#define AR_S_MASK ~0x10
+
+ TEST_SEGMENT_AR_S_HELPER(GUEST_AR_CS, "GUEST_AR_CS");
+ TEST_SEGMENT_AR_S_HELPER(GUEST_AR_CS, "GUEST_AR_CS");
+ TEST_SEGMENT_AR_S_HELPER(GUEST_AR_SS, "GUEST_AR_SS");
+ TEST_SEGMENT_AR_S_HELPER(GUEST_AR_DS, "GUEST_AR_DS");
+ TEST_SEGMENT_AR_S_HELPER(GUEST_AR_ES, "GUEST_AR_ES");
+ TEST_SEGMENT_AR_S_HELPER(GUEST_AR_FS, "GUEST_AR_FS");
+ TEST_SEGMENT_AR_S_HELPER(GUEST_AR_GS, "GUEST_AR_GS");
+}
+
/*
* Check that the virtual CPU checks the VMX Guest State Area as
* documented in the Intel SDM.
@@ -8201,6 +8365,7 @@ static void vmx_guest_state_area_test(void)
test_guest_segment_sel_fields();
test_guest_segment_base_addr_fields();
+ test_guest_segment_ar_fields();
test_canonical(GUEST_BASE_GDTR, "GUEST_BASE_GDTR", false);
test_canonical(GUEST_BASE_IDTR, "GUEST_BASE_IDTR", false);
According to section "Checks on Guest Segment Registers" in Intel SDM vol 3C, the following checks are performed on the Guest Segment Registers on vmentry of nested guests: Access-rights field: — Bits 3:0 (Type): - CS: The values allowed depend on the setting of the “unrestricted guest” VM-execution control: - If the control is 0, the Type must be 9, 11, 13, or 15 (accessed code segment). - If the control is 1, the Type must be either 3 (read/write accessed expand-up data segment) or one of 9, 11, 13, and 15 (accessed code segment). - SS: If SS is usable, the Type must be 3 or 7 (read/write, accessed data segment). - DS, ES, FS, GS: The following checks apply if the register is usable: - Bit 0 of the Type must be 1 (accessed). - If bit 3 of the Type is 1 (code segment), then bit 1 of the Type must be 1 (readable). — Bit 4 (S): If the register is CS or if the register is usable, S must be 1. Signed-off-by: Krish Sadhukhan <krish.sadhukhan@oracle.com> --- x86/vmx_tests.c | 165 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 165 insertions(+)