tools/testing/selftests/kvm/x86/nested_tdp_fault_test.c

Source file repositories/reference/linux-study-clean/tools/testing/selftests/kvm/x86/nested_tdp_fault_test.c

File Facts

System
Linux kernel
Corpus path
tools/testing/selftests/kvm/x86/nested_tdp_fault_test.c
Extension
.c
Size
9084 bytes
Lines
314
Domain
Support Tooling And Documentation
Bucket
tools
Inferred role
Support Tooling And Documentation: implementation source
Status
source implementation candidate

Why This File Exists

Repository support layer: documentation, build tooling, samples, user-space helper tools, generated initramfs support, licenses, and validation utilities.

Dependency Surface

Detected Declarations

Annotated Snippet

// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (C) 2025, Google, Inc.
 */

#include "test_util.h"
#include "kvm_util.h"
#include "processor.h"
#include "svm_util.h"
#include "vmx.h"

#define L2_GUEST_STACK_SIZE 64

enum test_type {
	TEST_FINAL_PAGE_UNMAPPED,	    /* Final data page not present */
	TEST_PT_PAGE_UNMAPPED,		    /* Page table page not present */
	TEST_FINAL_PAGE_WRITE_PROTECTED,    /* Final data page read-only */
	TEST_PT_PAGE_WRITE_PROTECTED,	    /* Page table page read-only */
};

static gva_t l2_test_page;
static void (*l2_entry)(void);

#define TEST_IO_PORT 0x80
#define TEST1_VADDR 0x8000000ULL
#define TEST2_VADDR 0x10000000ULL
#define TEST3_VADDR 0x18000000ULL
#define TEST4_VADDR 0x20000000ULL

/*
 * L2 executes OUTS reading from l2_test_page, triggering a nested page
 * fault on the read access.
 */
static void l2_guest_code_outs(void)
{
	asm volatile("outsb" ::"S"(l2_test_page), "d"(TEST_IO_PORT) : "memory");
	GUEST_FAIL("L2 should not reach here");
}

/*
 * L2 executes INS writing to l2_test_page, triggering a nested page
 * fault on the write access.
 */
static void l2_guest_code_ins(void)
{
	asm volatile("insb" ::"D"(l2_test_page), "d"(TEST_IO_PORT) : "memory");
	GUEST_FAIL("L2 should not reach here");
}

#define GUEST_ASSERT_EXIT_QUAL(ac_eq, ex_eq)		\
	__GUEST_ASSERT((ac_eq) == (ex_eq),		\
		       "Wanted EXIT_QUAL '0x%lx', got '0x%lx'", ex_eq, ac_eq)

static void l1_vmx_code(struct vmx_pages *vmx, u64 expected_fault_gpa,
			u64 test_type)
{
	unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE];
	u64 exit_qual;

	GUEST_ASSERT(vmx->vmcs_gpa);
	GUEST_ASSERT(prepare_for_vmx_operation(vmx));
	GUEST_ASSERT(load_vmcs(vmx));

	prepare_vmcs(vmx, l2_entry, &l2_guest_stack[L2_GUEST_STACK_SIZE]);

	GUEST_ASSERT(!vmlaunch());

	/* Verify we got an EPT violation exit */
	__GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_EPT_VIOLATION,
		       "Expected EPT violation (0x%x), got 0x%lx",
		       EXIT_REASON_EPT_VIOLATION,
		       vmreadz(VM_EXIT_REASON));

	__GUEST_ASSERT(vmreadz(GUEST_PHYSICAL_ADDRESS) == expected_fault_gpa,
		       "Expected guest_physical_address = 0x%lx, got 0x%lx",
		       expected_fault_gpa,
		       vmreadz(GUEST_PHYSICAL_ADDRESS));

	exit_qual = vmreadz(EXIT_QUALIFICATION);

	/*
	 * Note, EPT page table accesses are always read+write, e.g. so that
	 * the CPU can do A/D updates at-will.
	 */
	switch (test_type) {
	case TEST_FINAL_PAGE_UNMAPPED:
		GUEST_ASSERT_EXIT_QUAL(exit_qual, EPT_VIOLATION_ACC_READ |
						  EPT_VIOLATION_GVA_IS_VALID |
						  EPT_VIOLATION_GVA_TRANSLATED);
		break;

Annotation

Implementation Notes