Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

s390/vfio-ap: add s390dbf logging to the vfio_ap_irq_enable function

This patch adds s390dbf logging to the function that executes the
PQAP(AQIC) instruction on behalf of the guest to which the queue for which
interrupts are being enabled or disabled is attached.

Currently, the vfio_ap_irq_enable function sets status response code 06
(notification indicator byte address (nib) invalid) in the status word
when the vfio_pin_pages function - called to pin the page containing the
nib - returns an error or a different number of pages pinned than
requested.

Setting the response code returned to userspace without also logging a
message in the kernel makes it impossible to determine whether the response
was due to an error detected by the vfio_ap device driver or because the
response code was returned by the firmware in response to the PQAP(AQIC)
instruction.

In addition to logging a warning for the situation above, this patch adds
the following:

* A function to validate the nib address invoked prior to calling the
vfio_pin_pages function. This allows for logging a message informing
the reader of the reason the page containing the nib can not be pinned
if the nib address is not valid. Response code 06 (invalid nib address)
will be set in the status word returned to the guest from the
instruction.

* Checks the return value from the kvm_s390_gisc_register and logs a
message informing the reader of the failure. Status response code 08
(invalid gisa) will be set in the status word returned to the guest from
the PQAP(AQIC) instruction.

* Checks the status response code returned from execution of the PQAP(AQIC)
instruction and if it indicates an error, logs a message informing the
reader.

Signed-off-by: Tony Krowiak <akrowiak@linux.ibm.com>
Reviewed-by: Matthew Rosato <mjrosato@linux.ibm.com>
Acked-by: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>

authored by

Tony Krowiak and committed by
Vasily Gorbik
783f0a3c 68f554b7

+72 -6
+1
drivers/s390/crypto/ap_bus.h
··· 47 47 #define AP_RESPONSE_BUSY 0x05 48 48 #define AP_RESPONSE_INVALID_ADDRESS 0x06 49 49 #define AP_RESPONSE_OTHERWISE_CHANGED 0x07 50 + #define AP_RESPONSE_INVALID_GISA 0x08 50 51 #define AP_RESPONSE_Q_FULL 0x10 51 52 #define AP_RESPONSE_NO_PENDING_REPLY 0x10 52 53 #define AP_RESPONSE_INDEX_TOO_BIG 0x11
+71 -6
drivers/s390/crypto/vfio_ap_ops.c
··· 186 186 } 187 187 188 188 /** 189 + * vfio_ap_validate_nib - validate a notification indicator byte (nib) address. 190 + * 191 + * @vcpu: the object representing the vcpu executing the PQAP(AQIC) instruction. 192 + * @nib: the location for storing the nib address. 193 + * @g_pfn: the location for storing the page frame number of the page containing 194 + * the nib. 195 + * 196 + * When the PQAP(AQIC) instruction is executed, general register 2 contains the 197 + * address of the notification indicator byte (nib) used for IRQ notification. 198 + * This function parses the nib from gr2 and calculates the page frame 199 + * number for the guest of the page containing the nib. The values are 200 + * stored in @nib and @g_pfn respectively. 201 + * 202 + * The g_pfn of the nib is then validated to ensure the nib address is valid. 203 + * 204 + * Return: returns zero if the nib address is a valid; otherwise, returns 205 + * -EINVAL. 206 + */ 207 + static int vfio_ap_validate_nib(struct kvm_vcpu *vcpu, unsigned long *nib, 208 + unsigned long *g_pfn) 209 + { 210 + *nib = vcpu->run->s.regs.gprs[2]; 211 + *g_pfn = *nib >> PAGE_SHIFT; 212 + 213 + if (kvm_is_error_hva(gfn_to_hva(vcpu->kvm, *g_pfn))) 214 + return -EINVAL; 215 + 216 + return 0; 217 + } 218 + 219 + /** 189 220 * vfio_ap_irq_enable - Enable Interruption for a APQN 190 221 * 191 222 * @q: the vfio_ap_queue holding AQIC parameters 192 223 * @isc: the guest ISC to register with the GIB interface 193 - * @nib: the notification indicator byte to pin. 224 + * @vcpu: the vcpu object containing the registers specifying the parameters 225 + * passed to the PQAP(AQIC) instruction. 194 226 * 195 227 * Pin the NIB saved in *q 196 228 * Register the guest ISC to GIB interface and retrieve the ··· 238 206 */ 239 207 static struct ap_queue_status vfio_ap_irq_enable(struct vfio_ap_queue *q, 240 208 int isc, 241 - unsigned long nib) 209 + struct kvm_vcpu *vcpu) 242 210 { 211 + unsigned long nib; 243 212 struct ap_qirq_ctrl aqic_gisa = {}; 244 213 struct ap_queue_status status = {}; 245 214 struct kvm_s390_gisa *gisa; 215 + int nisc; 246 216 struct kvm *kvm; 247 217 unsigned long h_nib, g_pfn, h_pfn; 248 218 int ret; 249 219 250 - g_pfn = nib >> PAGE_SHIFT; 220 + /* Verify that the notification indicator byte address is valid */ 221 + if (vfio_ap_validate_nib(vcpu, &nib, &g_pfn)) { 222 + VFIO_AP_DBF_WARN("%s: invalid NIB address: nib=%#lx, g_pfn=%#lx, apqn=%#04x\n", 223 + __func__, nib, g_pfn, q->apqn); 224 + 225 + status.response_code = AP_RESPONSE_INVALID_ADDRESS; 226 + return status; 227 + } 228 + 251 229 ret = vfio_pin_pages(mdev_dev(q->matrix_mdev->mdev), &g_pfn, 1, 252 230 IOMMU_READ | IOMMU_WRITE, &h_pfn); 253 231 switch (ret) { 254 232 case 1: 255 233 break; 256 234 default: 235 + VFIO_AP_DBF_WARN("%s: vfio_pin_pages failed: rc=%d," 236 + "nib=%#lx, g_pfn=%#lx, apqn=%#04x\n", 237 + __func__, ret, nib, g_pfn, q->apqn); 238 + 257 239 status.response_code = AP_RESPONSE_INVALID_ADDRESS; 258 240 return status; 259 241 } ··· 277 231 278 232 h_nib = (h_pfn << PAGE_SHIFT) | (nib & ~PAGE_MASK); 279 233 aqic_gisa.gisc = isc; 280 - aqic_gisa.isc = kvm_s390_gisc_register(kvm, isc); 234 + 235 + nisc = kvm_s390_gisc_register(kvm, isc); 236 + if (nisc < 0) { 237 + VFIO_AP_DBF_WARN("%s: gisc registration failed: nisc=%d, isc=%d, apqn=%#04x\n", 238 + __func__, nisc, isc, q->apqn); 239 + 240 + status.response_code = AP_RESPONSE_INVALID_GISA; 241 + return status; 242 + } 243 + 244 + aqic_gisa.isc = nisc; 281 245 aqic_gisa.ir = 1; 282 246 aqic_gisa.gisa = (uint64_t)gisa >> 4; 283 247 ··· 309 253 status.response_code); 310 254 vfio_ap_irq_disable(q); 311 255 break; 256 + } 257 + 258 + if (status.response_code != AP_RESPONSE_NORMAL) { 259 + VFIO_AP_DBF_WARN("%s: PQAP(AQIC) failed with status=%#02x: " 260 + "zone=%#x, ir=%#x, gisc=%#x, f=%#x," 261 + "gisa=%#x, isc=%#x, apqn=%#04x\n", 262 + __func__, status.response_code, 263 + aqic_gisa.zone, aqic_gisa.ir, aqic_gisa.gisc, 264 + aqic_gisa.gf, aqic_gisa.gisa, aqic_gisa.isc, 265 + q->apqn); 312 266 } 313 267 314 268 return status; ··· 438 372 439 373 /* If IR bit(16) is set we enable the interrupt */ 440 374 if ((status >> (63 - 16)) & 0x01) 441 - qstatus = vfio_ap_irq_enable(q, status & 0x07, 442 - vcpu->run->s.regs.gprs[2]); 375 + qstatus = vfio_ap_irq_enable(q, status & 0x07, vcpu); 443 376 else 444 377 qstatus = vfio_ap_irq_disable(q); 445 378