1// SPDX-License-Identifier: GPL-2.0-only
2#include <fcntl.h>
3#include <stdio.h>
4#include <stdlib.h>
5#include <string.h>
6#include <sys/ioctl.h>
7
8#include "test_util.h"
9#include "kvm_util.h"
10#include "processor.h"
11#include "svm_util.h"
12#include "linux/psp-sev.h"
13#include "sev.h"
14
15
16static void guest_sev_es_code(void)
17{
18	/* TODO: Check CPUID after GHCB-based hypercall support is added. */
19	GUEST_ASSERT(rdmsr(MSR_AMD64_SEV) & MSR_AMD64_SEV_ENABLED);
20	GUEST_ASSERT(rdmsr(MSR_AMD64_SEV) & MSR_AMD64_SEV_ES_ENABLED);
21
22	/*
23	 * TODO: Add GHCB and ucall support for SEV-ES guests.  For now, simply
24	 * force "termination" to signal "done" via the GHCB MSR protocol.
25	 */
26	wrmsr(MSR_AMD64_SEV_ES_GHCB, GHCB_MSR_TERM_REQ);
27	__asm__ __volatile__("rep; vmmcall");
28}
29
30static void guest_sev_code(void)
31{
32	GUEST_ASSERT(this_cpu_has(X86_FEATURE_SEV));
33	GUEST_ASSERT(rdmsr(MSR_AMD64_SEV) & MSR_AMD64_SEV_ENABLED);
34
35	GUEST_DONE();
36}
37
38static void test_sev(void *guest_code, uint64_t policy)
39{
40	struct kvm_vcpu *vcpu;
41	struct kvm_vm *vm;
42	struct ucall uc;
43
44	vm = vm_sev_create_with_one_vcpu(policy, guest_code, &vcpu);
45
46	for (;;) {
47		vcpu_run(vcpu);
48
49		if (policy & SEV_POLICY_ES) {
50			TEST_ASSERT(vcpu->run->exit_reason == KVM_EXIT_SYSTEM_EVENT,
51				    "Wanted SYSTEM_EVENT, got %s",
52				    exit_reason_str(vcpu->run->exit_reason));
53			TEST_ASSERT_EQ(vcpu->run->system_event.type, KVM_SYSTEM_EVENT_SEV_TERM);
54			TEST_ASSERT_EQ(vcpu->run->system_event.ndata, 1);
55			TEST_ASSERT_EQ(vcpu->run->system_event.data[0], GHCB_MSR_TERM_REQ);
56			break;
57		}
58
59		switch (get_ucall(vcpu, &uc)) {
60		case UCALL_SYNC:
61			continue;
62		case UCALL_DONE:
63			return;
64		case UCALL_ABORT:
65			REPORT_GUEST_ASSERT(uc);
66		default:
67			TEST_FAIL("Unexpected exit: %s",
68				  exit_reason_str(vcpu->run->exit_reason));
69		}
70	}
71
72	kvm_vm_free(vm);
73}
74
75int main(int argc, char *argv[])
76{
77	TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_SEV));
78
79	test_sev(guest_sev_code, SEV_POLICY_NO_DBG);
80	test_sev(guest_sev_code, 0);
81
82	if (kvm_cpu_has(X86_FEATURE_SEV_ES)) {
83		test_sev(guest_sev_es_code, SEV_POLICY_ES | SEV_POLICY_NO_DBG);
84		test_sev(guest_sev_es_code, SEV_POLICY_ES);
85	}
86
87	return 0;
88}
89