Commit e168bf8d authored by Carsten Otte's avatar Carsten Otte Committed by Avi Kivity

KVM: s390: ucontrol: export page faults to user

This patch introduces a new exit reason in the kvm_run structure
named KVM_EXIT_S390_UCONTROL. This exit indicates, that a virtual cpu
has regognized a fault on the host page table. The idea is that
userspace can handle this fault by mapping memory at the fault
location into the cpu's address space and then continue to run the
virtual cpu.
Signed-off-by: default avatarCarsten Otte <cotte@de.ibm.com>
Signed-off-by: default avatarMarcelo Tosatti <mtosatti@redhat.com>
Signed-off-by: default avatarAvi Kivity <avi@redhat.com>
parent 27e0393f
...@@ -1694,6 +1694,20 @@ s390 specific. ...@@ -1694,6 +1694,20 @@ s390 specific.
s390 specific. s390 specific.
/* KVM_EXIT_S390_UCONTROL */
struct {
__u64 trans_exc_code;
__u32 pgm_code;
} s390_ucontrol;
s390 specific. A page fault has occurred for a user controlled virtual
machine (KVM_VM_S390_UNCONTROL) on it's host page table that cannot be
resolved by the kernel.
The program code and the translation exception code that were placed
in the cpu's lowcore are presented here as defined by the z Architecture
Principles of Operation Book in the Chapter for Dynamic Address Translation
(DAT)
/* KVM_EXIT_DCR */ /* KVM_EXIT_DCR */
struct { struct {
__u32 dcrn; __u32 dcrn;
......
...@@ -493,8 +493,10 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu, ...@@ -493,8 +493,10 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
return -EINVAL; /* not implemented yet */ return -EINVAL; /* not implemented yet */
} }
static void __vcpu_run(struct kvm_vcpu *vcpu) static int __vcpu_run(struct kvm_vcpu *vcpu)
{ {
int rc;
memcpy(&vcpu->arch.sie_block->gg14, &vcpu->arch.guest_gprs[14], 16); memcpy(&vcpu->arch.sie_block->gg14, &vcpu->arch.guest_gprs[14], 16);
if (need_resched()) if (need_resched())
...@@ -511,9 +513,15 @@ static void __vcpu_run(struct kvm_vcpu *vcpu) ...@@ -511,9 +513,15 @@ static void __vcpu_run(struct kvm_vcpu *vcpu)
local_irq_enable(); local_irq_enable();
VCPU_EVENT(vcpu, 6, "entering sie flags %x", VCPU_EVENT(vcpu, 6, "entering sie flags %x",
atomic_read(&vcpu->arch.sie_block->cpuflags)); atomic_read(&vcpu->arch.sie_block->cpuflags));
if (sie64a(vcpu->arch.sie_block, vcpu->arch.guest_gprs)) { rc = sie64a(vcpu->arch.sie_block, vcpu->arch.guest_gprs);
VCPU_EVENT(vcpu, 3, "%s", "fault in sie instruction"); if (rc) {
kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); if (kvm_is_ucontrol(vcpu->kvm)) {
rc = SIE_INTERCEPT_UCONTROL;
} else {
VCPU_EVENT(vcpu, 3, "%s", "fault in sie instruction");
kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
rc = 0;
}
} }
VCPU_EVENT(vcpu, 6, "exit sie icptcode %d", VCPU_EVENT(vcpu, 6, "exit sie icptcode %d",
vcpu->arch.sie_block->icptcode); vcpu->arch.sie_block->icptcode);
...@@ -522,6 +530,7 @@ static void __vcpu_run(struct kvm_vcpu *vcpu) ...@@ -522,6 +530,7 @@ static void __vcpu_run(struct kvm_vcpu *vcpu)
local_irq_enable(); local_irq_enable();
memcpy(&vcpu->arch.guest_gprs[14], &vcpu->arch.sie_block->gg14, 16); memcpy(&vcpu->arch.guest_gprs[14], &vcpu->arch.sie_block->gg14, 16);
return rc;
} }
int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
...@@ -542,6 +551,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) ...@@ -542,6 +551,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
case KVM_EXIT_UNKNOWN: case KVM_EXIT_UNKNOWN:
case KVM_EXIT_INTR: case KVM_EXIT_INTR:
case KVM_EXIT_S390_RESET: case KVM_EXIT_S390_RESET:
case KVM_EXIT_S390_UCONTROL:
break; break;
default: default:
BUG(); BUG();
...@@ -553,7 +563,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) ...@@ -553,7 +563,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
might_fault(); might_fault();
do { do {
__vcpu_run(vcpu); rc = __vcpu_run(vcpu);
if (rc)
break;
rc = kvm_handle_sie_intercept(vcpu); rc = kvm_handle_sie_intercept(vcpu);
} while (!signal_pending(current) && !rc); } while (!signal_pending(current) && !rc);
...@@ -565,6 +577,16 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) ...@@ -565,6 +577,16 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
rc = -EINTR; rc = -EINTR;
} }
#ifdef CONFIG_KVM_S390_UCONTROL
if (rc == SIE_INTERCEPT_UCONTROL) {
kvm_run->exit_reason = KVM_EXIT_S390_UCONTROL;
kvm_run->s390_ucontrol.trans_exc_code =
current->thread.gmap_addr;
kvm_run->s390_ucontrol.pgm_code = 0x10;
rc = 0;
}
#endif
if (rc == -EOPNOTSUPP) { if (rc == -EOPNOTSUPP) {
/* intercept cannot be handled in-kernel, prepare kvm-run */ /* intercept cannot be handled in-kernel, prepare kvm-run */
kvm_run->exit_reason = KVM_EXIT_S390_SIEIC; kvm_run->exit_reason = KVM_EXIT_S390_SIEIC;
......
...@@ -26,6 +26,7 @@ typedef int (*intercept_handler_t)(struct kvm_vcpu *vcpu); ...@@ -26,6 +26,7 @@ typedef int (*intercept_handler_t)(struct kvm_vcpu *vcpu);
/* negativ values are error codes, positive values for internal conditions */ /* negativ values are error codes, positive values for internal conditions */
#define SIE_INTERCEPT_RERUNVCPU (1<<0) #define SIE_INTERCEPT_RERUNVCPU (1<<0)
#define SIE_INTERCEPT_UCONTROL (1<<1)
int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu); int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu);
#define VM_EVENT(d_kvm, d_loglevel, d_string, d_args...)\ #define VM_EVENT(d_kvm, d_loglevel, d_string, d_args...)\
......
...@@ -162,6 +162,7 @@ struct kvm_pit_config { ...@@ -162,6 +162,7 @@ struct kvm_pit_config {
#define KVM_EXIT_INTERNAL_ERROR 17 #define KVM_EXIT_INTERNAL_ERROR 17
#define KVM_EXIT_OSI 18 #define KVM_EXIT_OSI 18
#define KVM_EXIT_PAPR_HCALL 19 #define KVM_EXIT_PAPR_HCALL 19
#define KVM_EXIT_S390_UCONTROL 20
/* For KVM_EXIT_INTERNAL_ERROR */ /* For KVM_EXIT_INTERNAL_ERROR */
#define KVM_INTERNAL_ERROR_EMULATION 1 #define KVM_INTERNAL_ERROR_EMULATION 1
...@@ -249,6 +250,11 @@ struct kvm_run { ...@@ -249,6 +250,11 @@ struct kvm_run {
#define KVM_S390_RESET_CPU_INIT 8 #define KVM_S390_RESET_CPU_INIT 8
#define KVM_S390_RESET_IPL 16 #define KVM_S390_RESET_IPL 16
__u64 s390_reset_flags; __u64 s390_reset_flags;
/* KVM_EXIT_S390_UCONTROL */
struct {
__u64 trans_exc_code;
__u32 pgm_code;
} s390_ucontrol;
/* KVM_EXIT_DCR */ /* KVM_EXIT_DCR */
struct { struct {
__u32 dcrn; __u32 dcrn;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment