diff options
Diffstat (limited to 'arch/s390/kvm/diag.c')
-rw-r--r-- | arch/s390/kvm/diag.c | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/arch/s390/kvm/diag.c b/arch/s390/kvm/diag.c index 6f9cfa500372..08dfc839a6cf 100644 --- a/arch/s390/kvm/diag.c +++ b/arch/s390/kvm/diag.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include "kvm-s390.h" | 18 | #include "kvm-s390.h" |
19 | #include "trace.h" | 19 | #include "trace.h" |
20 | #include "trace-s390.h" | 20 | #include "trace-s390.h" |
21 | #include "gaccess.h" | ||
21 | 22 | ||
22 | static int diag_release_pages(struct kvm_vcpu *vcpu) | 23 | static int diag_release_pages(struct kvm_vcpu *vcpu) |
23 | { | 24 | { |
@@ -47,6 +48,87 @@ static int diag_release_pages(struct kvm_vcpu *vcpu) | |||
47 | return 0; | 48 | return 0; |
48 | } | 49 | } |
49 | 50 | ||
51 | static int __diag_page_ref_service(struct kvm_vcpu *vcpu) | ||
52 | { | ||
53 | struct prs_parm { | ||
54 | u16 code; | ||
55 | u16 subcode; | ||
56 | u16 parm_len; | ||
57 | u16 parm_version; | ||
58 | u64 token_addr; | ||
59 | u64 select_mask; | ||
60 | u64 compare_mask; | ||
61 | u64 zarch; | ||
62 | }; | ||
63 | struct prs_parm parm; | ||
64 | int rc; | ||
65 | u16 rx = (vcpu->arch.sie_block->ipa & 0xf0) >> 4; | ||
66 | u16 ry = (vcpu->arch.sie_block->ipa & 0x0f); | ||
67 | unsigned long hva_token = KVM_HVA_ERR_BAD; | ||
68 | |||
69 | if (vcpu->run->s.regs.gprs[rx] & 7) | ||
70 | return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); | ||
71 | if (copy_from_guest(vcpu, &parm, vcpu->run->s.regs.gprs[rx], sizeof(parm))) | ||
72 | return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); | ||
73 | if (parm.parm_version != 2 || parm.parm_len < 5 || parm.code != 0x258) | ||
74 | return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); | ||
75 | |||
76 | switch (parm.subcode) { | ||
77 | case 0: /* TOKEN */ | ||
78 | if (vcpu->arch.pfault_token != KVM_S390_PFAULT_TOKEN_INVALID) { | ||
79 | /* | ||
80 | * If the pagefault handshake is already activated, | ||
81 | * the token must not be changed. We have to return | ||
82 | * decimal 8 instead, as mandated in SC24-6084. | ||
83 | */ | ||
84 | vcpu->run->s.regs.gprs[ry] = 8; | ||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | if ((parm.compare_mask & parm.select_mask) != parm.compare_mask || | ||
89 | parm.token_addr & 7 || parm.zarch != 0x8000000000000000ULL) | ||
90 | return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); | ||
91 | |||
92 | hva_token = gfn_to_hva(vcpu->kvm, gpa_to_gfn(parm.token_addr)); | ||
93 | if (kvm_is_error_hva(hva_token)) | ||
94 | return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); | ||
95 | |||
96 | vcpu->arch.pfault_token = parm.token_addr; | ||
97 | vcpu->arch.pfault_select = parm.select_mask; | ||
98 | vcpu->arch.pfault_compare = parm.compare_mask; | ||
99 | vcpu->run->s.regs.gprs[ry] = 0; | ||
100 | rc = 0; | ||
101 | break; | ||
102 | case 1: /* | ||
103 | * CANCEL | ||
104 | * Specification allows to let already pending tokens survive | ||
105 | * the cancel, therefore to reduce code complexity, we assume | ||
106 | * all outstanding tokens are already pending. | ||
107 | */ | ||
108 | if (parm.token_addr || parm.select_mask || | ||
109 | parm.compare_mask || parm.zarch) | ||
110 | return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); | ||
111 | |||
112 | vcpu->run->s.regs.gprs[ry] = 0; | ||
113 | /* | ||
114 | * If the pfault handling was not established or is already | ||
115 | * canceled SC24-6084 requests to return decimal 4. | ||
116 | */ | ||
117 | if (vcpu->arch.pfault_token == KVM_S390_PFAULT_TOKEN_INVALID) | ||
118 | vcpu->run->s.regs.gprs[ry] = 4; | ||
119 | else | ||
120 | vcpu->arch.pfault_token = KVM_S390_PFAULT_TOKEN_INVALID; | ||
121 | |||
122 | rc = 0; | ||
123 | break; | ||
124 | default: | ||
125 | rc = -EOPNOTSUPP; | ||
126 | break; | ||
127 | } | ||
128 | |||
129 | return rc; | ||
130 | } | ||
131 | |||
50 | static int __diag_time_slice_end(struct kvm_vcpu *vcpu) | 132 | static int __diag_time_slice_end(struct kvm_vcpu *vcpu) |
51 | { | 133 | { |
52 | VCPU_EVENT(vcpu, 5, "%s", "diag time slice end"); | 134 | VCPU_EVENT(vcpu, 5, "%s", "diag time slice end"); |
@@ -85,6 +167,10 @@ static int __diag_ipl_functions(struct kvm_vcpu *vcpu) | |||
85 | 167 | ||
86 | VCPU_EVENT(vcpu, 5, "diag ipl functions, subcode %lx", subcode); | 168 | VCPU_EVENT(vcpu, 5, "diag ipl functions, subcode %lx", subcode); |
87 | switch (subcode) { | 169 | switch (subcode) { |
170 | case 0: | ||
171 | case 1: | ||
172 | page_table_reset_pgste(current->mm, 0, TASK_SIZE); | ||
173 | return -EOPNOTSUPP; | ||
88 | case 3: | 174 | case 3: |
89 | vcpu->run->s390_reset_flags = KVM_S390_RESET_CLEAR; | 175 | vcpu->run->s390_reset_flags = KVM_S390_RESET_CLEAR; |
90 | page_table_reset_pgste(current->mm, 0, TASK_SIZE); | 176 | page_table_reset_pgste(current->mm, 0, TASK_SIZE); |
@@ -153,6 +239,8 @@ int kvm_s390_handle_diag(struct kvm_vcpu *vcpu) | |||
153 | return __diag_time_slice_end(vcpu); | 239 | return __diag_time_slice_end(vcpu); |
154 | case 0x9c: | 240 | case 0x9c: |
155 | return __diag_time_slice_end_directed(vcpu); | 241 | return __diag_time_slice_end_directed(vcpu); |
242 | case 0x258: | ||
243 | return __diag_page_ref_service(vcpu); | ||
156 | case 0x308: | 244 | case 0x308: |
157 | return __diag_ipl_functions(vcpu); | 245 | return __diag_ipl_functions(vcpu); |
158 | case 0x500: | 246 | case 0x500: |