}
 
 /*
- * Guest usage of a ptrauth instruction (which the guest EL1 did not turn into
- * a NOP). If we get here, it is that we didn't fixup ptrauth on exit, and all
- * that we can do is give the guest an UNDEF.
+ * Two possibilities to handle a trapping ptrauth instruction:
+ *
+ * - Guest usage of a ptrauth instruction (which the guest EL1 did not
+ *   turn into a NOP). If we get here, it is that we didn't fixup
+ *   ptrauth on exit, and all that we can do is give the guest an
+ *   UNDEF (as the guest isn't supposed to use ptrauth without being
+ *   told it could).
+ *
+ * - Running an L2 NV guest while L1 has left HCR_EL2.API==0, and for
+ *   which we reinject the exception into L1. API==1 is handled as a
+ *   fixup so the only way to get here is when API==0.
+ *
+ * Anything else is an emulation bug (hence the WARN_ON + UNDEF).
  */
 static int kvm_handle_ptrauth(struct kvm_vcpu *vcpu)
 {
+       if (!vcpu_has_ptrauth(vcpu)) {
+               kvm_inject_undefined(vcpu);
+               return 1;
+       }
+
+       if (vcpu_has_nv(vcpu) && !is_hyp_ctxt(vcpu)) {
+               kvm_inject_nested_sync(vcpu, kvm_vcpu_get_esr(vcpu));
+               return 1;
+       }
+
+       /* Really shouldn't be here! */
+       WARN_ON_ONCE(1);
        kvm_inject_undefined(vcpu);
        return 1;
 }