* [PATCH v1 0/2] KVM: s390: Fix AR parameter in MEM_OP ioctl
@ 2024-02-09 20:45 Eric Farman
2024-02-09 20:45 ` [PATCH v1 1/2] KVM: s390: load guest access registers " Eric Farman
2024-02-09 20:45 ` [PATCH v1 2/2] KVM: s390: selftests: memop: add a simple AR test Eric Farman
0 siblings, 2 replies; 6+ messages in thread
From: Eric Farman @ 2024-02-09 20:45 UTC (permalink / raw)
To: Christian Borntraeger, Janosch Frank, Claudio Imbrenda,
David Hildenbrand
Cc: Heiko Carstens, Vasily Gorbik, Alexander Gordeev, Sven Schnelle,
Paolo Bonzini, Shuah Khan, kvm, linux-s390, linux-kselftest,
Eric Farman
Hi Christian, Janosch, Heiko,
Here is a pair of patches to replace the RFC I recently sent [1].
Patch 1 performs the host/guest access register swap that Christian
suggested (instead of a full sync_reg/store_reg process).
Patch 2 provides a selftest patch that exercises this scenario.
Applying patch 2 without patch 1 fails in the following way:
[eric@host linux]# ./tools/testing/selftests/kvm/s390x/memop
TAP version 13
1..16
ok 1 simple copy
ok 2 generic error checks
ok 3 copy with storage keys
ok 4 cmpxchg with storage keys
ok 5 concurrently cmpxchg with storage keys
ok 6 copy with key storage protection override
ok 7 copy with key fetch protection
ok 8 copy with key fetch protection override
==== Test Assertion Failure ====
s390x/memop.c:186: !r
pid=5720 tid=5720 errno=4 - Interrupted system call
1 0x00000000010042af: memop_ioctl at memop.c:186 (discriminator 3)
2 0x0000000001006697: test_copy_access_register at memop.c:400 (discriminator 2)
3 0x0000000001002aaf: main at memop.c:1181
4 0x000003ffaec33a5b: ?? ??:0
5 0x000003ffaec33b5d: ?? ??:0
6 0x0000000001002ba9: _start at ??:?
KVM_S390_MEM_OP failed, rc: 40 errno: 4 (Interrupted system call)
Thoughts on this approach?
Thanks,
Eric
[1] https://lore.kernel.org/r/20240131205832.2179029-1-farman@linux.ibm.com/
Eric Farman (2):
KVM: s390: load guest access registers in MEM_OP ioctl
KVM: s390: selftests: memop: add a simple AR test
arch/s390/kvm/kvm-s390.c | 6 +++++
tools/testing/selftests/kvm/s390x/memop.c | 28 +++++++++++++++++++++++
2 files changed, 34 insertions(+)
--
2.40.1
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v1 1/2] KVM: s390: load guest access registers in MEM_OP ioctl
2024-02-09 20:45 [PATCH v1 0/2] KVM: s390: Fix AR parameter in MEM_OP ioctl Eric Farman
@ 2024-02-09 20:45 ` Eric Farman
2024-02-12 10:21 ` Heiko Carstens
2024-02-09 20:45 ` [PATCH v1 2/2] KVM: s390: selftests: memop: add a simple AR test Eric Farman
1 sibling, 1 reply; 6+ messages in thread
From: Eric Farman @ 2024-02-09 20:45 UTC (permalink / raw)
To: Christian Borntraeger, Janosch Frank, Claudio Imbrenda,
David Hildenbrand
Cc: Heiko Carstens, Vasily Gorbik, Alexander Gordeev, Sven Schnelle,
Paolo Bonzini, Shuah Khan, kvm, linux-s390, linux-kselftest,
Eric Farman
The routine ar_translation() is called by get_vcpu_asce(), which is
called by both the instruction intercept path (where the access
registers had been loaded with the guest's values), and the MEM_OP
ioctl (which hadn't). This means that any ALET the guest expects to
be used would be ignored.
Furthermore, the logic in ar_translation() will store the contents
of the access registers back to the KVM_RUN struct. This unexpected
change of AR values can lead to problems after invoking the MEM_OP,
for example an ALET Specification Exception.
Fix this by swapping the host/guest access registers around the
MEM_OP ioctl, in the same way that the KVM_RUN ioctl does with
sync_regs()/store_regs(). The full register swap isn't needed here,
since only the access registers are used in this interface.
Suggested-by: Christian Borntraeger <borntraeger@linux.ibm.com>
Signed-off-by: Eric Farman <farman@linux.ibm.com>
---
arch/s390/kvm/kvm-s390.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index ea63ac769889..c2dfeea55dcf 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -5391,6 +5391,10 @@ static long kvm_s390_vcpu_mem_op(struct kvm_vcpu *vcpu,
return -ENOMEM;
}
+ /* Swap host/guest access registers in the event of a MEM_OP with AR specified */
+ save_access_regs(vcpu->arch.host_acrs);
+ restore_access_regs(vcpu->run->s.regs.acrs);
+
acc_mode = mop->op == KVM_S390_MEMOP_LOGICAL_READ ? GACC_FETCH : GACC_STORE;
if (mop->flags & KVM_S390_MEMOP_F_CHECK_ONLY) {
r = check_gva_range(vcpu, mop->gaddr, mop->ar, mop->size,
@@ -5420,6 +5424,8 @@ static long kvm_s390_vcpu_mem_op(struct kvm_vcpu *vcpu,
kvm_s390_inject_prog_irq(vcpu, &vcpu->arch.pgm);
out_free:
+ save_access_regs(vcpu->run->s.regs.acrs);
+ restore_access_regs(vcpu->arch.host_acrs);
vfree(tmpbuf);
return r;
}
--
2.40.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v1 2/2] KVM: s390: selftests: memop: add a simple AR test
2024-02-09 20:45 [PATCH v1 0/2] KVM: s390: Fix AR parameter in MEM_OP ioctl Eric Farman
2024-02-09 20:45 ` [PATCH v1 1/2] KVM: s390: load guest access registers " Eric Farman
@ 2024-02-09 20:45 ` Eric Farman
1 sibling, 0 replies; 6+ messages in thread
From: Eric Farman @ 2024-02-09 20:45 UTC (permalink / raw)
To: Christian Borntraeger, Janosch Frank, Claudio Imbrenda,
David Hildenbrand
Cc: Heiko Carstens, Vasily Gorbik, Alexander Gordeev, Sven Schnelle,
Paolo Bonzini, Shuah Khan, kvm, linux-s390, linux-kselftest,
Eric Farman
There is a selftest that checks for an (expected) error when an
invalid AR is specified, but not one that exercises the AR path.
Add a simple test that mirrors the vanilla write/read test while
providing an AR. An AR that contains zero will direct the CPU to
use the primary address space normally used anyway. AR[1] is
selected for this test because the host AR[1] is usually non-zero,
and KVM needs to correctly swap those values.
Signed-off-by: Eric Farman <farman@linux.ibm.com>
---
tools/testing/selftests/kvm/s390x/memop.c | 28 +++++++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/tools/testing/selftests/kvm/s390x/memop.c b/tools/testing/selftests/kvm/s390x/memop.c
index bb3ca9a5d731..be20c26ee545 100644
--- a/tools/testing/selftests/kvm/s390x/memop.c
+++ b/tools/testing/selftests/kvm/s390x/memop.c
@@ -375,6 +375,29 @@ static void test_copy(void)
kvm_vm_free(t.kvm_vm);
}
+static void test_copy_access_register(void)
+{
+ struct test_default t = test_default_init(guest_copy);
+
+ HOST_SYNC(t.vcpu, STAGE_INITED);
+
+ prepare_mem12();
+ t.run->psw_mask &= ~(3UL << (63 - 17));
+ t.run->psw_mask |= 1UL << (63 - 17); /* Enable AR mode */
+
+ CHECK_N_DO(MOP, t.vcpu, LOGICAL, WRITE, mem1, t.size,
+ GADDR_V(mem1), AR(1));
+ HOST_SYNC(t.vcpu, STAGE_COPIED);
+
+ CHECK_N_DO(MOP, t.vcpu, LOGICAL, READ, mem2, t.size,
+ GADDR_V(mem2), AR(1));
+ ASSERT_MEM_EQ(mem1, mem2, t.size);
+
+ t.run->psw_mask &= ~(3UL << (63 - 17)); /* Disable AR mode */
+
+ kvm_vm_free(t.kvm_vm);
+}
+
static void set_storage_key_range(void *addr, size_t len, uint8_t key)
{
uintptr_t _addr, abs, i;
@@ -1101,6 +1124,11 @@ int main(int argc, char *argv[])
.test = test_copy_key_fetch_prot_override,
.requirements_met = extension_cap > 0,
},
+ {
+ .name = "copy with access register mode",
+ .test = test_copy_access_register,
+ .requirements_met = true,
+ },
{
.name = "error checks with key",
.test = test_errors_key,
--
2.40.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v1 1/2] KVM: s390: load guest access registers in MEM_OP ioctl
2024-02-09 20:45 ` [PATCH v1 1/2] KVM: s390: load guest access registers " Eric Farman
@ 2024-02-12 10:21 ` Heiko Carstens
2024-02-12 11:52 ` Heiko Carstens
0 siblings, 1 reply; 6+ messages in thread
From: Heiko Carstens @ 2024-02-12 10:21 UTC (permalink / raw)
To: Eric Farman
Cc: Christian Borntraeger, Janosch Frank, Claudio Imbrenda,
David Hildenbrand, Vasily Gorbik, Alexander Gordeev,
Sven Schnelle, Paolo Bonzini, Shuah Khan, kvm, linux-s390,
linux-kselftest
On Fri, Feb 09, 2024 at 09:45:38PM +0100, Eric Farman wrote:
> The routine ar_translation() is called by get_vcpu_asce(), which is
> called by both the instruction intercept path (where the access
> registers had been loaded with the guest's values), and the MEM_OP
> ioctl (which hadn't). This means that any ALET the guest expects to
> be used would be ignored.
>
> Furthermore, the logic in ar_translation() will store the contents
> of the access registers back to the KVM_RUN struct. This unexpected
> change of AR values can lead to problems after invoking the MEM_OP,
> for example an ALET Specification Exception.
>
> Fix this by swapping the host/guest access registers around the
> MEM_OP ioctl, in the same way that the KVM_RUN ioctl does with
> sync_regs()/store_regs(). The full register swap isn't needed here,
> since only the access registers are used in this interface.
>
> Suggested-by: Christian Borntraeger <borntraeger@linux.ibm.com>
> Signed-off-by: Eric Farman <farman@linux.ibm.com>
> ---
> arch/s390/kvm/kvm-s390.c | 6 ++++++
> 1 file changed, 6 insertions(+)
>
> diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
> index ea63ac769889..c2dfeea55dcf 100644
> --- a/arch/s390/kvm/kvm-s390.c
> +++ b/arch/s390/kvm/kvm-s390.c
> @@ -5391,6 +5391,10 @@ static long kvm_s390_vcpu_mem_op(struct kvm_vcpu *vcpu,
> return -ENOMEM;
> }
>
> + /* Swap host/guest access registers in the event of a MEM_OP with AR specified */
> + save_access_regs(vcpu->arch.host_acrs);
> + restore_access_regs(vcpu->run->s.regs.acrs);
> +
> acc_mode = mop->op == KVM_S390_MEMOP_LOGICAL_READ ? GACC_FETCH : GACC_STORE;
> if (mop->flags & KVM_S390_MEMOP_F_CHECK_ONLY) {
> r = check_gva_range(vcpu, mop->gaddr, mop->ar, mop->size,
> @@ -5420,6 +5424,8 @@ static long kvm_s390_vcpu_mem_op(struct kvm_vcpu *vcpu,
> kvm_s390_inject_prog_irq(vcpu, &vcpu->arch.pgm);
>
> out_free:
> + save_access_regs(vcpu->run->s.regs.acrs);
> + restore_access_regs(vcpu->arch.host_acrs);
I guess we will end up with more and more of such constructs until nobody
knows when which register contents are loaded. I would higly prefer a TIF flag
which indicates if the access registers contain the host or guest register
contents, and actual users grab the required content from the correct location
- or better: always take it from guest save area, and write to the guest save
area if the to be invented TIF flag indicates that access registers contain
guest registers...
Or maybe a TIF flag with different semantics: "guest save area does not
reflect current state - which is within registers".
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v1 1/2] KVM: s390: load guest access registers in MEM_OP ioctl
2024-02-12 10:21 ` Heiko Carstens
@ 2024-02-12 11:52 ` Heiko Carstens
2024-02-13 17:31 ` Eric Farman
0 siblings, 1 reply; 6+ messages in thread
From: Heiko Carstens @ 2024-02-12 11:52 UTC (permalink / raw)
To: Heiko Carstens
Cc: Eric Farman, Christian Borntraeger, Janosch Frank,
Claudio Imbrenda, David Hildenbrand, Vasily Gorbik,
Alexander Gordeev, Sven Schnelle, Paolo Bonzini, Shuah Khan, kvm,
linux-s390, linux-kselftest
On Mon, Feb 12, 2024 at 11:21:30AM +0100, Heiko Carstens wrote:
> Or maybe a TIF flag with different semantics: "guest save area does not
> reflect current state - which is within registers".
Something like the below; untested of course. But I guess there must be
some arch specific vcpu flags, which can be used to achieve the same?
diff --git a/arch/s390/include/asm/thread_info.h b/arch/s390/include/asm/thread_info.h
index a674c7d25da5..b9ff8b125fb8 100644
--- a/arch/s390/include/asm/thread_info.h
+++ b/arch/s390/include/asm/thread_info.h
@@ -69,6 +69,7 @@ void arch_setup_new_exec(void);
#define TIF_PATCH_PENDING 5 /* pending live patching update */
#define TIF_PGSTE 6 /* New mm's will use 4K page tables */
#define TIF_NOTIFY_SIGNAL 7 /* signal notifications exist */
+#define TIF_KVM_ACRS 8 /* access registers contain guest content */
#define TIF_ISOLATE_BP_GUEST 9 /* Run KVM guests with isolated BP */
#define TIF_PER_TRAP 10 /* Need to handle PER trap on exit to usermode */
diff --git a/arch/s390/kvm/gaccess.c b/arch/s390/kvm/gaccess.c
index 5bfcc50c1a68..b0ef242d2371 100644
--- a/arch/s390/kvm/gaccess.c
+++ b/arch/s390/kvm/gaccess.c
@@ -391,7 +391,8 @@ static int ar_translation(struct kvm_vcpu *vcpu, union asce *asce, u8 ar,
if (ar >= NUM_ACRS)
return -EINVAL;
- save_access_regs(vcpu->run->s.regs.acrs);
+ if (test_thread_flag(TIF_KVM_ACRS))
+ save_access_regs(vcpu->run->s.regs.acrs);
alet.val = vcpu->run->s.regs.acrs[ar];
if (ar == 0 || alet.val == 0) {
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index ea63ac769889..3ee0913639d5 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -4951,6 +4951,7 @@ static void sync_regs(struct kvm_vcpu *vcpu)
}
save_access_regs(vcpu->arch.host_acrs);
restore_access_regs(vcpu->run->s.regs.acrs);
+ set_thread_flag(TIF_KVM_ACRS);
/* save host (userspace) fprs/vrs */
save_fpu_regs();
vcpu->arch.host_fpregs.fpc = current->thread.fpu.fpc;
@@ -5020,6 +5021,7 @@ static void store_regs(struct kvm_vcpu *vcpu)
kvm_run->s.regs.pfs = vcpu->arch.pfault_select;
kvm_run->s.regs.pfc = vcpu->arch.pfault_compare;
save_access_regs(vcpu->run->s.regs.acrs);
+ clear_thread_flag(TIF_KVM_ACRS);
restore_access_regs(vcpu->arch.host_acrs);
/* Save guest register state */
save_fpu_regs();
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v1 1/2] KVM: s390: load guest access registers in MEM_OP ioctl
2024-02-12 11:52 ` Heiko Carstens
@ 2024-02-13 17:31 ` Eric Farman
0 siblings, 0 replies; 6+ messages in thread
From: Eric Farman @ 2024-02-13 17:31 UTC (permalink / raw)
To: Heiko Carstens
Cc: Christian Borntraeger, Janosch Frank, Claudio Imbrenda,
David Hildenbrand, Vasily Gorbik, Alexander Gordeev,
Sven Schnelle, Paolo Bonzini, Shuah Khan, kvm, linux-s390,
linux-kselftest
On Mon, 2024-02-12 at 12:52 +0100, Heiko Carstens wrote:
> > On Mon, Feb 12, 2024 at 11:21:30AM +0100, Heiko Carstens wrote:
> > > > Or maybe a TIF flag with different semantics: "guest save area
> > > > does
> > > > not
> > > > reflect current state - which is within registers".
> >
> > Something like the below; untested of course.
Ooops, yeah. Christian suggested something similar in his first
response to the RFC which I'd overlooked.
> > But I guess there must be
> > some arch specific vcpu flags, which can be used to achieve the
> > same?
Agreed. Putting something there probably makes sense to keep it in the
KVM sphere
> >
> > diff --git a/arch/s390/include/asm/thread_info.h
> > b/arch/s390/include/asm/thread_info.h
> > index a674c7d25da5..b9ff8b125fb8 100644
> > --- a/arch/s390/include/asm/thread_info.h
> > +++ b/arch/s390/include/asm/thread_info.h
> > @@ -69,6 +69,7 @@ void arch_setup_new_exec(void);
> > #define TIF_PATCH_PENDING 5 /* pending live patching update */
> > #define TIF_PGSTE 6 /* New mm's will use 4K page tables */
> > #define TIF_NOTIFY_SIGNAL 7 /* signal notifications exist */
> > +#define TIF_KVM_ACRS 8 /* access registers contain guest content
> > */
> > #define TIF_ISOLATE_BP_GUEST 9 /* Run KVM guests with isolated BP
> > */
> > #define TIF_PER_TRAP 10 /* Need to handle PER trap on exit to
> > usermode */
> >
> > diff --git a/arch/s390/kvm/gaccess.c b/arch/s390/kvm/gaccess.c
> > index 5bfcc50c1a68..b0ef242d2371 100644
> > --- a/arch/s390/kvm/gaccess.c
> > +++ b/arch/s390/kvm/gaccess.c
> > @@ -391,7 +391,8 @@ static int ar_translation(struct kvm_vcpu
> > *vcpu,
> > union asce *asce, u8 ar,
> > if (ar >= NUM_ACRS)
> > return -EINVAL;
> >
> > - save_access_regs(vcpu->run->s.regs.acrs);
> > + if (test_thread_flag(TIF_KVM_ACRS))
> > + save_access_regs(vcpu->run->s.regs.acrs);
...or WARN if not set, so that we know of the missing path. Will send
this all as a v2. Thanks.
> > alet.val = vcpu->run->s.regs.acrs[ar];
> >
> > if (ar == 0 || alet.val == 0) {
> > diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
> > index ea63ac769889..3ee0913639d5 100644
> > --- a/arch/s390/kvm/kvm-s390.c
> > +++ b/arch/s390/kvm/kvm-s390.c
> > @@ -4951,6 +4951,7 @@ static void sync_regs(struct kvm_vcpu *vcpu)
> > }
> > save_access_regs(vcpu->arch.host_acrs);
> > restore_access_regs(vcpu->run->s.regs.acrs);
> > + set_thread_flag(TIF_KVM_ACRS);
> > /* save host (userspace) fprs/vrs */
> > save_fpu_regs();
> > vcpu->arch.host_fpregs.fpc = current->thread.fpu.fpc;
> > @@ -5020,6 +5021,7 @@ static void store_regs(struct kvm_vcpu *vcpu)
> > kvm_run->s.regs.pfs = vcpu->arch.pfault_select;
> > kvm_run->s.regs.pfc = vcpu->arch.pfault_compare;
> > save_access_regs(vcpu->run->s.regs.acrs);
> > + clear_thread_flag(TIF_KVM_ACRS);
> > restore_access_regs(vcpu->arch.host_acrs);
> > /* Save guest register state */
> > save_fpu_regs();
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2024-02-13 17:31 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-02-09 20:45 [PATCH v1 0/2] KVM: s390: Fix AR parameter in MEM_OP ioctl Eric Farman
2024-02-09 20:45 ` [PATCH v1 1/2] KVM: s390: load guest access registers " Eric Farman
2024-02-12 10:21 ` Heiko Carstens
2024-02-12 11:52 ` Heiko Carstens
2024-02-13 17:31 ` Eric Farman
2024-02-09 20:45 ` [PATCH v1 2/2] KVM: s390: selftests: memop: add a simple AR test Eric Farman
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox