Skip to content

Commit 1d55934

Browse files
committed
Merge tag 'kvm-x86-svm-6.9' of https://github.com/kvm-x86/linux into HEAD
KVM SVM changes for 6.9: - Add support for systems that are configured with SEV and SEV-ES+ enabled, but have all ASIDs assigned to SEV-ES+ guests, which effectively makes SEV unusuable. Cleanup ASID handling to make supporting this scenario less brittle/ugly. - Return -EINVAL instead of -EBUSY if userspace attempts to invoke KVM_SEV{,ES}_INIT on an SEV+ guest. The operation is simply invalid, and not related to resource contention in any way.
2 parents bf3a69c + fdd5883 commit 1d55934

File tree

2 files changed

+39
-29
lines changed

2 files changed

+39
-29
lines changed

arch/x86/kvm/svm/sev.c

Lines changed: 34 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,10 @@ struct enc_region {
8484
};
8585

8686
/* Called with the sev_bitmap_lock held, or on shutdown */
87-
static int sev_flush_asids(int min_asid, int max_asid)
87+
static int sev_flush_asids(unsigned int min_asid, unsigned int max_asid)
8888
{
89-
int ret, asid, error = 0;
89+
int ret, error = 0;
90+
unsigned int asid;
9091

9192
/* Check if there are any ASIDs to reclaim before performing a flush */
9293
asid = find_next_bit(sev_reclaim_asid_bitmap, nr_asids, min_asid);
@@ -116,7 +117,7 @@ static inline bool is_mirroring_enc_context(struct kvm *kvm)
116117
}
117118

118119
/* Must be called with the sev_bitmap_lock held */
119-
static bool __sev_recycle_asids(int min_asid, int max_asid)
120+
static bool __sev_recycle_asids(unsigned int min_asid, unsigned int max_asid)
120121
{
121122
if (sev_flush_asids(min_asid, max_asid))
122123
return false;
@@ -143,8 +144,20 @@ static void sev_misc_cg_uncharge(struct kvm_sev_info *sev)
143144

144145
static int sev_asid_new(struct kvm_sev_info *sev)
145146
{
146-
int asid, min_asid, max_asid, ret;
147+
/*
148+
* SEV-enabled guests must use asid from min_sev_asid to max_sev_asid.
149+
* SEV-ES-enabled guest can use from 1 to min_sev_asid - 1.
150+
* Note: min ASID can end up larger than the max if basic SEV support is
151+
* effectively disabled by disallowing use of ASIDs for SEV guests.
152+
*/
153+
unsigned int min_asid = sev->es_active ? 1 : min_sev_asid;
154+
unsigned int max_asid = sev->es_active ? min_sev_asid - 1 : max_sev_asid;
155+
unsigned int asid;
147156
bool retry = true;
157+
int ret;
158+
159+
if (min_asid > max_asid)
160+
return -ENOTTY;
148161

149162
WARN_ON(sev->misc_cg);
150163
sev->misc_cg = get_current_misc_cg();
@@ -157,12 +170,6 @@ static int sev_asid_new(struct kvm_sev_info *sev)
157170

158171
mutex_lock(&sev_bitmap_lock);
159172

160-
/*
161-
* SEV-enabled guests must use asid from min_sev_asid to max_sev_asid.
162-
* SEV-ES-enabled guest can use from 1 to min_sev_asid - 1.
163-
*/
164-
min_asid = sev->es_active ? 1 : min_sev_asid;
165-
max_asid = sev->es_active ? min_sev_asid - 1 : max_sev_asid;
166173
again:
167174
asid = find_next_zero_bit(sev_asid_bitmap, max_asid + 1, min_asid);
168175
if (asid > max_asid) {
@@ -179,15 +186,16 @@ static int sev_asid_new(struct kvm_sev_info *sev)
179186

180187
mutex_unlock(&sev_bitmap_lock);
181188

182-
return asid;
189+
sev->asid = asid;
190+
return 0;
183191
e_uncharge:
184192
sev_misc_cg_uncharge(sev);
185193
put_misc_cg(sev->misc_cg);
186194
sev->misc_cg = NULL;
187195
return ret;
188196
}
189197

190-
static int sev_get_asid(struct kvm *kvm)
198+
static unsigned int sev_get_asid(struct kvm *kvm)
191199
{
192200
struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
193201

@@ -247,21 +255,19 @@ static int sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp)
247255
{
248256
struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
249257
struct sev_platform_init_args init_args = {0};
250-
int asid, ret;
258+
int ret;
251259

252260
if (kvm->created_vcpus)
253261
return -EINVAL;
254262

255-
ret = -EBUSY;
256263
if (unlikely(sev->active))
257-
return ret;
264+
return -EINVAL;
258265

259266
sev->active = true;
260267
sev->es_active = argp->id == KVM_SEV_ES_INIT;
261-
asid = sev_asid_new(sev);
262-
if (asid < 0)
268+
ret = sev_asid_new(sev);
269+
if (ret)
263270
goto e_no_asid;
264-
sev->asid = asid;
265271

266272
init_args.probe = false;
267273
ret = sev_platform_init(&init_args);
@@ -287,8 +293,8 @@ static int sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp)
287293

288294
static int sev_bind_asid(struct kvm *kvm, unsigned int handle, int *error)
289295
{
296+
unsigned int asid = sev_get_asid(kvm);
290297
struct sev_data_activate activate;
291-
int asid = sev_get_asid(kvm);
292298
int ret;
293299

294300
/* activate ASID on the given handle */
@@ -2240,8 +2246,10 @@ void __init sev_hardware_setup(void)
22402246
goto out;
22412247
}
22422248

2243-
sev_asid_count = max_sev_asid - min_sev_asid + 1;
2244-
WARN_ON_ONCE(misc_cg_set_capacity(MISC_CG_RES_SEV, sev_asid_count));
2249+
if (min_sev_asid <= max_sev_asid) {
2250+
sev_asid_count = max_sev_asid - min_sev_asid + 1;
2251+
WARN_ON_ONCE(misc_cg_set_capacity(MISC_CG_RES_SEV, sev_asid_count));
2252+
}
22452253
sev_supported = true;
22462254

22472255
/* SEV-ES support requested? */
@@ -2272,7 +2280,9 @@ void __init sev_hardware_setup(void)
22722280
out:
22732281
if (boot_cpu_has(X86_FEATURE_SEV))
22742282
pr_info("SEV %s (ASIDs %u - %u)\n",
2275-
sev_supported ? "enabled" : "disabled",
2283+
sev_supported ? min_sev_asid <= max_sev_asid ? "enabled" :
2284+
"unusable" :
2285+
"disabled",
22762286
min_sev_asid, max_sev_asid);
22772287
if (boot_cpu_has(X86_FEATURE_SEV_ES))
22782288
pr_info("SEV-ES %s (ASIDs %u - %u)\n",
@@ -2320,7 +2330,7 @@ int sev_cpu_init(struct svm_cpu_data *sd)
23202330
*/
23212331
static void sev_flush_encrypted_page(struct kvm_vcpu *vcpu, void *va)
23222332
{
2323-
int asid = to_kvm_svm(vcpu->kvm)->sev_info.asid;
2333+
unsigned int asid = sev_get_asid(vcpu->kvm);
23242334

23252335
/*
23262336
* Note! The address must be a kernel address, as regular page walk
@@ -2638,7 +2648,7 @@ void sev_es_unmap_ghcb(struct vcpu_svm *svm)
26382648
void pre_sev_run(struct vcpu_svm *svm, int cpu)
26392649
{
26402650
struct svm_cpu_data *sd = per_cpu_ptr(&svm_data, cpu);
2641-
int asid = sev_get_asid(svm->vcpu.kvm);
2651+
unsigned int asid = sev_get_asid(svm->vcpu.kvm);
26422652

26432653
/* Assign the asid allocated with this SEV guest */
26442654
svm->asid = asid;

arch/x86/kvm/trace.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -735,13 +735,13 @@ TRACE_EVENT(kvm_nested_intr_vmexit,
735735
* Tracepoint for nested #vmexit because of interrupt pending
736736
*/
737737
TRACE_EVENT(kvm_invlpga,
738-
TP_PROTO(__u64 rip, int asid, u64 address),
738+
TP_PROTO(__u64 rip, unsigned int asid, u64 address),
739739
TP_ARGS(rip, asid, address),
740740

741741
TP_STRUCT__entry(
742-
__field( __u64, rip )
743-
__field( int, asid )
744-
__field( __u64, address )
742+
__field( __u64, rip )
743+
__field( unsigned int, asid )
744+
__field( __u64, address )
745745
),
746746

747747
TP_fast_assign(
@@ -750,7 +750,7 @@ TRACE_EVENT(kvm_invlpga,
750750
__entry->address = address;
751751
),
752752

753-
TP_printk("rip: 0x%016llx asid: %d address: 0x%016llx",
753+
TP_printk("rip: 0x%016llx asid: %u address: 0x%016llx",
754754
__entry->rip, __entry->asid, __entry->address)
755755
);
756756

0 commit comments

Comments
 (0)