Skip to content

Commit 3bf3e0a

Browse files
pratiksampatsean-jc
authored andcommitted
KVM: selftests: Add library support for interacting with SNP
Extend the SEV library to include support for SNP ioctl() wrappers, which aid in launching and interacting with a SEV-SNP guest. Signed-off-by: Pratik R. Sampat <[email protected]> Link: https://lore.kernel.org/r/[email protected] [sean: use BIT()] Signed-off-by: Sean Christopherson <[email protected]>
1 parent 4a4e1e8 commit 3bf3e0a

File tree

4 files changed

+97
-6
lines changed
  • arch/x86/include/uapi/asm
  • tools
    • arch/x86/include/uapi/asm
    • testing/selftests/kvm

4 files changed

+97
-6
lines changed

arch/x86/include/uapi/asm/kvm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -845,6 +845,7 @@ struct kvm_sev_snp_launch_start {
845845
};
846846

847847
/* Kept in sync with firmware values for simplicity. */
848+
#define KVM_SEV_PAGE_TYPE_INVALID 0x0
848849
#define KVM_SEV_SNP_PAGE_TYPE_NORMAL 0x1
849850
#define KVM_SEV_SNP_PAGE_TYPE_ZERO 0x3
850851
#define KVM_SEV_SNP_PAGE_TYPE_UNMEASURED 0x4

tools/arch/x86/include/uapi/asm/kvm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -841,6 +841,7 @@ struct kvm_sev_snp_launch_start {
841841
};
842842

843843
/* Kept in sync with firmware values for simplicity. */
844+
#define KVM_SEV_PAGE_TYPE_INVALID 0x0
844845
#define KVM_SEV_SNP_PAGE_TYPE_NORMAL 0x1
845846
#define KVM_SEV_SNP_PAGE_TYPE_ZERO 0x3
846847
#define KVM_SEV_SNP_PAGE_TYPE_UNMEASURED 0x4

tools/testing/selftests/kvm/include/x86/sev.h

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ enum sev_guest_state {
2525
#define SEV_POLICY_NO_DBG (1UL << 0)
2626
#define SEV_POLICY_ES (1UL << 2)
2727

28+
#define SNP_POLICY_SMT (1ULL << 16)
29+
#define SNP_POLICY_RSVD_MBO (1ULL << 17)
30+
#define SNP_POLICY_DBG (1ULL << 19)
31+
2832
#define GHCB_MSR_TERM_REQ 0x100
2933

3034
static inline bool is_sev_snp_vm(struct kvm_vm *vm)
@@ -45,13 +49,26 @@ static inline bool is_sev_vm(struct kvm_vm *vm)
4549
void sev_vm_launch(struct kvm_vm *vm, uint32_t policy);
4650
void sev_vm_launch_measure(struct kvm_vm *vm, uint8_t *measurement);
4751
void sev_vm_launch_finish(struct kvm_vm *vm);
52+
void snp_vm_launch_start(struct kvm_vm *vm, uint64_t policy);
53+
void snp_vm_launch_update(struct kvm_vm *vm);
54+
void snp_vm_launch_finish(struct kvm_vm *vm);
4855

4956
struct kvm_vm *vm_sev_create_with_one_vcpu(uint32_t type, void *guest_code,
5057
struct kvm_vcpu **cpu);
51-
void vm_sev_launch(struct kvm_vm *vm, uint32_t policy, uint8_t *measurement);
58+
void vm_sev_launch(struct kvm_vm *vm, uint64_t policy, uint8_t *measurement);
5259

5360
kvm_static_assert(SEV_RET_SUCCESS == 0);
5461

62+
/*
63+
* A SEV-SNP VM requires the policy reserved bit to always be set.
64+
* The SMT policy bit is also required to be set based on SMT being
65+
* available and active on the system.
66+
*/
67+
static inline u64 snp_default_policy(void)
68+
{
69+
return SNP_POLICY_RSVD_MBO | (is_smt_on() ? SNP_POLICY_SMT : 0);
70+
}
71+
5572
/*
5673
* The KVM_MEMORY_ENCRYPT_OP uAPI is utter garbage and takes an "unsigned long"
5774
* instead of a proper struct. The size of the parameter is embedded in the
@@ -85,6 +102,7 @@ kvm_static_assert(SEV_RET_SUCCESS == 0);
85102

86103
void sev_vm_init(struct kvm_vm *vm);
87104
void sev_es_vm_init(struct kvm_vm *vm);
105+
void snp_vm_init(struct kvm_vm *vm);
88106

89107
static inline void vmgexit(void)
90108
{
@@ -113,4 +131,17 @@ static inline void sev_launch_update_data(struct kvm_vm *vm, vm_paddr_t gpa,
113131
vm_sev_ioctl(vm, KVM_SEV_LAUNCH_UPDATE_DATA, &update_data);
114132
}
115133

134+
static inline void snp_launch_update_data(struct kvm_vm *vm, vm_paddr_t gpa,
135+
uint64_t hva, uint64_t size, uint8_t type)
136+
{
137+
struct kvm_sev_snp_launch_update update_data = {
138+
.uaddr = hva,
139+
.gfn_start = gpa >> PAGE_SHIFT,
140+
.len = size,
141+
.type = type,
142+
};
143+
144+
vm_sev_ioctl(vm, KVM_SEV_SNP_LAUNCH_UPDATE, &update_data);
145+
}
146+
116147
#endif /* SELFTEST_KVM_SEV_H */

tools/testing/selftests/kvm/lib/x86/sev.c

Lines changed: 63 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
* and find the first range, but that's correct because the condition
1515
* expression would cause us to quit the loop.
1616
*/
17-
static void encrypt_region(struct kvm_vm *vm, struct userspace_mem_region *region)
17+
static void encrypt_region(struct kvm_vm *vm, struct userspace_mem_region *region,
18+
uint8_t page_type, bool private)
1819
{
1920
const struct sparsebit *protected_phy_pages = region->protected_phy_pages;
2021
const vm_paddr_t gpa_base = region->region.guest_phys_addr;
@@ -24,13 +25,23 @@ static void encrypt_region(struct kvm_vm *vm, struct userspace_mem_region *regio
2425
if (!sparsebit_any_set(protected_phy_pages))
2526
return;
2627

27-
sev_register_encrypted_memory(vm, region);
28+
if (!is_sev_snp_vm(vm))
29+
sev_register_encrypted_memory(vm, region);
2830

2931
sparsebit_for_each_set_range(protected_phy_pages, i, j) {
3032
const uint64_t size = (j - i + 1) * vm->page_size;
3133
const uint64_t offset = (i - lowest_page_in_region) * vm->page_size;
3234

33-
sev_launch_update_data(vm, gpa_base + offset, size);
35+
if (private)
36+
vm_mem_set_private(vm, gpa_base + offset, size);
37+
38+
if (is_sev_snp_vm(vm))
39+
snp_launch_update_data(vm, gpa_base + offset,
40+
(uint64_t)addr_gpa2hva(vm, gpa_base + offset),
41+
size, page_type);
42+
else
43+
sev_launch_update_data(vm, gpa_base + offset, size);
44+
3445
}
3546
}
3647

@@ -60,6 +71,14 @@ void sev_es_vm_init(struct kvm_vm *vm)
6071
}
6172
}
6273

74+
void snp_vm_init(struct kvm_vm *vm)
75+
{
76+
struct kvm_sev_init init = { 0 };
77+
78+
TEST_ASSERT_EQ(vm->type, KVM_X86_SNP_VM);
79+
vm_sev_ioctl(vm, KVM_SEV_INIT2, &init);
80+
}
81+
6382
void sev_vm_launch(struct kvm_vm *vm, uint32_t policy)
6483
{
6584
struct kvm_sev_launch_start launch_start = {
@@ -76,7 +95,7 @@ void sev_vm_launch(struct kvm_vm *vm, uint32_t policy)
7695
TEST_ASSERT_EQ(status.state, SEV_GUEST_STATE_LAUNCH_UPDATE);
7796

7897
hash_for_each(vm->regions.slot_hash, ctr, region, slot_node)
79-
encrypt_region(vm, region);
98+
encrypt_region(vm, region, KVM_SEV_PAGE_TYPE_INVALID, false);
8099

81100
if (policy & SEV_POLICY_ES)
82101
vm_sev_ioctl(vm, KVM_SEV_LAUNCH_UPDATE_VMSA, NULL);
@@ -112,6 +131,33 @@ void sev_vm_launch_finish(struct kvm_vm *vm)
112131
TEST_ASSERT_EQ(status.state, SEV_GUEST_STATE_RUNNING);
113132
}
114133

134+
void snp_vm_launch_start(struct kvm_vm *vm, uint64_t policy)
135+
{
136+
struct kvm_sev_snp_launch_start launch_start = {
137+
.policy = policy,
138+
};
139+
140+
vm_sev_ioctl(vm, KVM_SEV_SNP_LAUNCH_START, &launch_start);
141+
}
142+
143+
void snp_vm_launch_update(struct kvm_vm *vm)
144+
{
145+
struct userspace_mem_region *region;
146+
int ctr;
147+
148+
hash_for_each(vm->regions.slot_hash, ctr, region, slot_node)
149+
encrypt_region(vm, region, KVM_SEV_SNP_PAGE_TYPE_NORMAL, true);
150+
151+
vm->arch.is_pt_protected = true;
152+
}
153+
154+
void snp_vm_launch_finish(struct kvm_vm *vm)
155+
{
156+
struct kvm_sev_snp_launch_finish launch_finish = { 0 };
157+
158+
vm_sev_ioctl(vm, KVM_SEV_SNP_LAUNCH_FINISH, &launch_finish);
159+
}
160+
115161
struct kvm_vm *vm_sev_create_with_one_vcpu(uint32_t type, void *guest_code,
116162
struct kvm_vcpu **cpu)
117163
{
@@ -128,8 +174,20 @@ struct kvm_vm *vm_sev_create_with_one_vcpu(uint32_t type, void *guest_code,
128174
return vm;
129175
}
130176

131-
void vm_sev_launch(struct kvm_vm *vm, uint32_t policy, uint8_t *measurement)
177+
void vm_sev_launch(struct kvm_vm *vm, uint64_t policy, uint8_t *measurement)
132178
{
179+
if (is_sev_snp_vm(vm)) {
180+
vm_enable_cap(vm, KVM_CAP_EXIT_HYPERCALL, BIT(KVM_HC_MAP_GPA_RANGE));
181+
182+
snp_vm_launch_start(vm, policy);
183+
184+
snp_vm_launch_update(vm);
185+
186+
snp_vm_launch_finish(vm);
187+
188+
return;
189+
}
190+
133191
sev_vm_launch(vm, policy);
134192

135193
if (!measurement)

0 commit comments

Comments
 (0)