Skip to content

Commit 95e16b4

Browse files
committed
KVM: SEV-ES: go over the sev_pio_data buffer in multiple passes if needed
The PIO scratch buffer is larger than a single page, and therefore it is not possible to copy it in a single step to vcpu->arch/pio_data. Bound each call to emulator_pio_in/out to a single page; keep track of how many I/O operations are left in vcpu->arch.sev_pio_count, so that the operation can be restarted in the complete_userspace_io callback. For OUT, this means that the previous kvm_sev_es_outs implementation becomes an iterator of the loop, and we can consume the sev_pio_data buffer before leaving to userspace. For IN, instead, consuming the buffer and decreasing sev_pio_count is always done in the complete_userspace_io callback, because that is when the memcpy is done into sev_pio_data. Cc: [email protected] Fixes: 7ed9abf ("KVM: SVM: Support string IO operations for an SEV-ES guest") Reported-by: Felix Wilhelm <[email protected]> Reviewed-by: Maxim Levitsky <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]>
1 parent 4fa4b38 commit 95e16b4

File tree

2 files changed

+57
-16
lines changed

2 files changed

+57
-16
lines changed

arch/x86/include/asm/kvm_host.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -703,6 +703,7 @@ struct kvm_vcpu_arch {
703703
struct kvm_pio_request pio;
704704
void *pio_data;
705705
void *sev_pio_data;
706+
unsigned sev_pio_count;
706707

707708
u8 event_exit_inst_len;
708709

arch/x86/kvm/x86.c

Lines changed: 56 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12386,38 +12386,77 @@ int kvm_sev_es_mmio_read(struct kvm_vcpu *vcpu, gpa_t gpa, unsigned int bytes,
1238612386
EXPORT_SYMBOL_GPL(kvm_sev_es_mmio_read);
1238712387

1238812388
static int kvm_sev_es_outs(struct kvm_vcpu *vcpu, unsigned int size,
12389-
unsigned int port, unsigned int count)
12389+
unsigned int port);
12390+
12391+
static int complete_sev_es_emulated_outs(struct kvm_vcpu *vcpu)
1239012392
{
12391-
int ret = emulator_pio_out(vcpu, size, port,
12392-
vcpu->arch.sev_pio_data, count);
12393+
int size = vcpu->arch.pio.size;
12394+
int port = vcpu->arch.pio.port;
12395+
12396+
vcpu->arch.pio.count = 0;
12397+
if (vcpu->arch.sev_pio_count)
12398+
return kvm_sev_es_outs(vcpu, size, port);
12399+
return 1;
12400+
}
12401+
12402+
static int kvm_sev_es_outs(struct kvm_vcpu *vcpu, unsigned int size,
12403+
unsigned int port)
12404+
{
12405+
for (;;) {
12406+
unsigned int count =
12407+
min_t(unsigned int, PAGE_SIZE / size, vcpu->arch.sev_pio_count);
12408+
int ret = emulator_pio_out(vcpu, size, port, vcpu->arch.sev_pio_data, count);
12409+
12410+
/* memcpy done already by emulator_pio_out. */
12411+
vcpu->arch.sev_pio_count -= count;
12412+
vcpu->arch.sev_pio_data += count * vcpu->arch.pio.size;
12413+
if (!ret)
12414+
break;
1239312415

12394-
if (ret) {
1239512416
/* Emulation done by the kernel. */
12396-
return ret;
12417+
if (!vcpu->arch.sev_pio_count)
12418+
return 1;
1239712419
}
1239812420

12399-
vcpu->arch.pio.count = 0;
12421+
vcpu->arch.complete_userspace_io = complete_sev_es_emulated_outs;
1240012422
return 0;
1240112423
}
1240212424

12425+
static int kvm_sev_es_ins(struct kvm_vcpu *vcpu, unsigned int size,
12426+
unsigned int port);
12427+
12428+
static void advance_sev_es_emulated_ins(struct kvm_vcpu *vcpu)
12429+
{
12430+
unsigned count = vcpu->arch.pio.count;
12431+
complete_emulator_pio_in(vcpu, vcpu->arch.sev_pio_data);
12432+
vcpu->arch.sev_pio_count -= count;
12433+
vcpu->arch.sev_pio_data += count * vcpu->arch.pio.size;
12434+
}
12435+
1240312436
static int complete_sev_es_emulated_ins(struct kvm_vcpu *vcpu)
1240412437
{
12405-
memcpy(vcpu->arch.sev_pio_data, vcpu->arch.pio_data,
12406-
vcpu->arch.pio.count * vcpu->arch.pio.size);
12407-
vcpu->arch.pio.count = 0;
12438+
int size = vcpu->arch.pio.size;
12439+
int port = vcpu->arch.pio.port;
1240812440

12441+
advance_sev_es_emulated_ins(vcpu);
12442+
if (vcpu->arch.sev_pio_count)
12443+
return kvm_sev_es_ins(vcpu, size, port);
1240912444
return 1;
1241012445
}
1241112446

1241212447
static int kvm_sev_es_ins(struct kvm_vcpu *vcpu, unsigned int size,
12413-
unsigned int port, unsigned int count)
12448+
unsigned int port)
1241412449
{
12415-
int ret = emulator_pio_in(vcpu, size, port,
12416-
vcpu->arch.sev_pio_data, count);
12450+
for (;;) {
12451+
unsigned int count =
12452+
min_t(unsigned int, PAGE_SIZE / size, vcpu->arch.sev_pio_count);
12453+
if (!__emulator_pio_in(vcpu, size, port, count))
12454+
break;
1241712455

12418-
if (ret) {
1241912456
/* Emulation done by the kernel. */
12420-
return ret;
12457+
advance_sev_es_emulated_ins(vcpu);
12458+
if (!vcpu->arch.sev_pio_count)
12459+
return 1;
1242112460
}
1242212461

1242312462
vcpu->arch.complete_userspace_io = complete_sev_es_emulated_ins;
@@ -12429,8 +12468,9 @@ int kvm_sev_es_string_io(struct kvm_vcpu *vcpu, unsigned int size,
1242912468
int in)
1243012469
{
1243112470
vcpu->arch.sev_pio_data = data;
12432-
return in ? kvm_sev_es_ins(vcpu, size, port, count)
12433-
: kvm_sev_es_outs(vcpu, size, port, count);
12471+
vcpu->arch.sev_pio_count = count;
12472+
return in ? kvm_sev_es_ins(vcpu, size, port)
12473+
: kvm_sev_es_outs(vcpu, size, port);
1243412474
}
1243512475
EXPORT_SYMBOL_GPL(kvm_sev_es_string_io);
1243612476

0 commit comments

Comments
 (0)