All of lore.kernel.org
 help / color / mirror / Atom feed
From: Sean Christopherson <seanjc@google.com>
To: Yosry Ahmed <yosry@kernel.org>
Cc: Paolo Bonzini <pbonzini@redhat.com>,
	Jim Mattson <jmattson@google.com>,
	kvm@vger.kernel.org,  linux-kernel@vger.kernel.org
Subject: Re: [PATCH v3] KVM: selftests: Add a test for gPAT handling in L2
Date: Wed, 27 May 2026 18:01:48 -0700	[thread overview]
Message-ID: <aheT_AUgWYJxZJlR@google.com> (raw)
In-Reply-To: <20260521175948.522757-1-yosry@kernel.org>

On Thu, May 21, 2026, Yosry Ahmed wrote:
> +static void l1_guest_code_invalid_gpat(struct svm_test_data *svm)
> +{
> +	unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE];
> +	struct vmcb *vmcb = svm->vmcb;
> +
> +	/* VMRUN should fail without running L2 */
> +	generic_svm_setup(svm, NULL, &l2_guest_stack[L2_GUEST_STACK_SIZE]);
> +
> +	vmcb->save.g_pat = INVALID_PAT_VALUE;
> +	run_guest(vmcb, svm->vmcb_gpa);
> +
> +	GUEST_ASSERT_EQ(vmcb->control.exit_code, SVM_EXIT_ERR);
> +	GUEST_DONE();
> +}
> +
> +static void run_test(const char *test_name, void *guest_code, bool do_save_restore)
> +{
> +	struct kvm_x86_state *state;
> +	struct kvm_vcpu *vcpu;
> +	struct kvm_vm *vm;
> +	struct ucall uc;
> +	gva_t svm_gva;
> +
> +	pr_info("Testing: %s\n", test_name);
> +
> +	vm = vm_create_with_one_vcpu(&vcpu, guest_code);
> +	vm_enable_cap(vm, KVM_CAP_DISABLE_QUIRKS2,
> +		      KVM_X86_QUIRK_NESTED_SVM_SHARED_PAT);
> +
> +	if (npt_enabled) {
> +		vm_enable_npt(vm);
> +		tdp_identity_map_default_memslots(vm);
> +	}
> +
> +	vcpu_alloc_svm(vm, &svm_gva);
> +	vcpu_args_set(vcpu, 1, svm_gva);
> +	sync_global_to_guest(vm, npt_enabled);
> +	sync_global_to_guest(vm, nr_iterations);
> +
> +	for (;;) {
> +		vcpu_run(vcpu);
> +		TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO);
> +
> +		switch (get_ucall(vcpu, &uc)) {
> +		case UCALL_ABORT:
> +			REPORT_GUEST_ASSERT(uc);
> +			/* NOT REACHED */
> +		case UCALL_SYNC:
> +			if (do_save_restore) {
> +				pr_info("  Save/restore at sync point %ld\n",
> +					uc.args[1]);

Meh, this is noise to me.  Maybe it's marginally useful if there's a failure, but
I don't see how it can possibly provide enough information to have to avoid
hacking on the test.

> +				state = vcpu_save_state(vcpu);
> +				kvm_vm_release(vm);
> +				vcpu = vm_recreate_with_one_vcpu(vm);
> +				vm_enable_cap(vm, KVM_CAP_DISABLE_QUIRKS2,
> +					      KVM_X86_QUIRK_NESTED_SVM_SHARED_PAT);
> +				vcpu_load_state(vcpu, state);
> +				kvm_x86_state_cleanup(state);
> +			}
> +			break;
> +		case UCALL_DONE:
> +			pr_info("  PASSED\n");

This is useless and noisy.  The test runs in ~.25 seconds, and most of that is
the printks.  If there's a failure, I'll see.  Otherwise it's a pretty safe
assumption the test passed.

> +			kvm_vm_free(vm);
> +			return;
> +		default:
> +			TEST_FAIL("Unknown ucall %lu", uc.cmd);
> +		}
> +	}
> +}
> +
> +#define NPT_DISABLED 0
> +#define NPT_ENABLED 1
> +
> +#define NO_SAVE_RESTORE 0
> +#define DO_SAVE_RESTORE 1

Eww.

> +
> +#define NESTED_PAT_TEST(test_name, guest_code, npt, sr, iter)	\
> +({								\

Unless you need to "return" a value, do-while (0) is preferred over ({}).  There's
a technical reason, but I can't remember it off the top of my head.

> +	npt_enabled = npt;					\
> +	nr_iterations = iter;					\
> +	run_test(test_name, guest_code, sr);			\

LOL, all of this, and the one thing that _doesn't_ use macro shenanigans is
string concatenation.

> +})
> +
> +int main(int argc, char *argv[])
> +{
> +	TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_SVM));
> +	TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_NPT));
> +	TEST_REQUIRE(kvm_has_cap(KVM_CAP_NESTED_STATE));
> +	TEST_REQUIRE(kvm_check_cap(KVM_CAP_DISABLE_QUIRKS2) &
> +		     KVM_X86_QUIRK_NESTED_SVM_SHARED_PAT);
> +
> +	NESTED_PAT_TEST("Invalid gPAT", l1_guest_code_invalid_gpat,
> +			NPT_ENABLED, NO_SAVE_RESTORE, 1);
> +
> +	NESTED_PAT_TEST("Nested NPT disabled", l1_guest_code,
> +			NPT_DISABLED, NO_SAVE_RESTORE, 1);
> +
> +	NESTED_PAT_TEST("Nested NPT enabled", l1_guest_code,
> +			NPT_ENABLED, NO_SAVE_RESTORE, 1);
> +
> +	NESTED_PAT_TEST("Save/Restore", l1_guest_code,
> +			NPT_ENABLED, DO_SAVE_RESTORE, 1);
> +
> +	NESTED_PAT_TEST("Multiple VM-Entries", l1_guest_code,
> +			NPT_ENABLED, NO_SAVE_RESTORE, 10);

I appreciated trying to avoid true/false literals, but this is harder to read.
At least "true" and "false" are visually different, {N,D}O_SAVE_RESTORE are one
char, and NPT_{DIS,EN}ABLED are two.

And explicitly defining the number of iterations and whether or not to do save/restore
is silly.  It requires _more_ code to provide _less_ coverage.  Just run the combos
for npt_enabled=false.

If we're going to use macro shenanigans, let's actually use them!  I've got this
working, I'll post a v4.

#define gpat_test(test_name, guest_code, npt_input)			\
do {									\
	npt_input;							\
									\
	pr_info("Testing: " test_name "\n");				\
	run_test(guest_code, false, 1);					\
									\
	if (guest_code == l1_guest_code) {				\
		pr_info("Testing: " test_name " Save/Restore\n");	\
		run_test(guest_code, true, 1);				\
									\
		pr_info("Testing: " test_name " Multiple VMRUNs\n");	\
		run_test(guest_code, false, 10);			\
	}								\
} while (0)

int main(int argc, char *argv[])
{
	TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_SVM));
	TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_NPT));
	TEST_REQUIRE(kvm_has_cap(KVM_CAP_NESTED_STATE));
	TEST_REQUIRE(kvm_check_cap(KVM_CAP_DISABLE_QUIRKS2) &
		     KVM_X86_QUIRK_NESTED_SVM_SHARED_PAT);

	gpat_test("Invalid gPAT", l1_guest_code_invalid_gpat, npt_enabled = true);
	gpat_test("Nested NPT disabled", l1_guest_code, npt_enabled = false);
	gpat_test("Nested NPT enabled", l1_guest_code, npt_enabled = true);

	return 0;
}

> +
> +	return 0;
> +}
> 
> base-commit: 4f256d5770febb9d61f9b57a4c79c491bf4987f1
> -- 
> 2.54.0.794.g4f17f83d09-goog
> 

  reply	other threads:[~2026-05-28  1:01 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-21 17:59 [PATCH v3] KVM: selftests: Add a test for gPAT handling in L2 Yosry Ahmed
2026-05-28  1:01 ` Sean Christopherson [this message]
2026-05-28 17:47   ` Yosry Ahmed
2026-05-28 17:58     ` Sean Christopherson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=aheT_AUgWYJxZJlR@google.com \
    --to=seanjc@google.com \
    --cc=jmattson@google.com \
    --cc=kvm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=pbonzini@redhat.com \
    --cc=yosry@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.