Commit 7ccd615b authored by Oliver Upton's avatar Oliver Upton
Browse files

Merge branch kvm-arm64/psci-1.3 into kvmarm/next



* kvm-arm64/psci-1.3:
  : PSCI v1.3 support, courtesy of David Woodhouse
  :
  : Bump KVM's PSCI implementation up to v1.3, with the added bonus of
  : implementing the SYSTEM_OFF2 call. Like other system-scoped PSCI calls,
  : this gets relayed to userspace for further processing with a new
  : KVM_SYSTEM_EVENT_SHUTDOWN flag.
  :
  : As an added bonus, implement client-side support for hibernation with
  : the SYSTEM_OFF2 call.
  arm64: Use SYSTEM_OFF2 PSCI call to power off for hibernate
  KVM: arm64: nvhe: Pass through PSCI v1.3 SYSTEM_OFF2 call
  KVM: selftests: Add test for PSCI SYSTEM_OFF2
  KVM: arm64: Add support for PSCI v1.2 and v1.3
  KVM: arm64: Add PSCI v1.3 SYSTEM_OFF2 function for hibernation
  firmware/psci: Add definitions for PSCI v1.3 specification

Signed-off-by: default avatarOliver Upton <oliver.upton@linux.dev>
parents 28654634 3e251afa
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -6855,6 +6855,10 @@ the first `ndata` items (possibly zero) of the data array are valid.
   the guest issued a SYSTEM_RESET2 call according to v1.1 of the PSCI
   specification.

 - for arm64, data[0] is set to KVM_SYSTEM_EVENT_SHUTDOWN_FLAG_PSCI_OFF2
   if the guest issued a SYSTEM_OFF2 call according to v1.3 of the PSCI
   specification.

 - for RISC-V, data[0] is set to the value of the second argument of the
   ``sbi_system_reset`` call.

@@ -6888,6 +6892,12 @@ either:
 - Deny the guest request to suspend the VM. See ARM DEN0022D.b 5.19.2
   "Caller responsibilities" for possible return values.

Hibernation using the PSCI SYSTEM_OFF2 call is enabled when PSCI v1.3
is enabled. If a guest invokes the PSCI SYSTEM_OFF2 function, KVM will
exit to userspace with the KVM_SYSTEM_EVENT_SHUTDOWN event type and with
data[0] set to KVM_SYSTEM_EVENT_SHUTDOWN_FLAG_PSCI_OFF2. The only
supported hibernate type for the SYSTEM_OFF2 function is HIBERNATE_OFF.

::

		/* KVM_EXIT_IOAPIC_EOI */
+6 −0
Original line number Diff line number Diff line
@@ -484,6 +484,12 @@ enum {
 */
#define KVM_SYSTEM_EVENT_RESET_FLAG_PSCI_RESET2	(1ULL << 0)

/*
 * Shutdown caused by a PSCI v1.3 SYSTEM_OFF2 call.
 * Valid only when the system event has a type of KVM_SYSTEM_EVENT_SHUTDOWN.
 */
#define KVM_SYSTEM_EVENT_SHUTDOWN_FLAG_PSCI_OFF2	(1ULL << 0)

/* run->fail_entry.hardware_entry_failure_reason codes. */
#define KVM_EXIT_FAIL_ENTRY_CPU_UNSUPPORTED	(1ULL << 0)

+2 −0
Original line number Diff line number Diff line
@@ -265,6 +265,8 @@ static unsigned long psci_1_0_handler(u64 func_id, struct kvm_cpu_context *host_
	case PSCI_1_0_FN_PSCI_FEATURES:
	case PSCI_1_0_FN_SET_SUSPEND_MODE:
	case PSCI_1_1_FN64_SYSTEM_RESET2:
	case PSCI_1_3_FN_SYSTEM_OFF2:
	case PSCI_1_3_FN64_SYSTEM_OFF2:
		return psci_forward(host_ctxt);
	case PSCI_1_0_FN64_SYSTEM_SUSPEND:
		return psci_system_suspend(func_id, host_ctxt);
+2 −0
Original line number Diff line number Diff line
@@ -575,6 +575,8 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
		case KVM_ARM_PSCI_0_2:
		case KVM_ARM_PSCI_1_0:
		case KVM_ARM_PSCI_1_1:
		case KVM_ARM_PSCI_1_2:
		case KVM_ARM_PSCI_1_3:
			if (!wants_02)
				return -EINVAL;
			vcpu->kvm->arch.psci_version = val;
+43 −1
Original line number Diff line number Diff line
@@ -194,6 +194,12 @@ static void kvm_psci_system_off(struct kvm_vcpu *vcpu)
	kvm_prepare_system_event(vcpu, KVM_SYSTEM_EVENT_SHUTDOWN, 0);
}

static void kvm_psci_system_off2(struct kvm_vcpu *vcpu)
{
	kvm_prepare_system_event(vcpu, KVM_SYSTEM_EVENT_SHUTDOWN,
				 KVM_SYSTEM_EVENT_SHUTDOWN_FLAG_PSCI_OFF2);
}

static void kvm_psci_system_reset(struct kvm_vcpu *vcpu)
{
	kvm_prepare_system_event(vcpu, KVM_SYSTEM_EVENT_RESET, 0);
@@ -322,7 +328,7 @@ static int kvm_psci_1_x_call(struct kvm_vcpu *vcpu, u32 minor)

	switch(psci_fn) {
	case PSCI_0_2_FN_PSCI_VERSION:
		val = minor == 0 ? KVM_ARM_PSCI_1_0 : KVM_ARM_PSCI_1_1;
		val = PSCI_VERSION(1, minor);
		break;
	case PSCI_1_0_FN_PSCI_FEATURES:
		arg = smccc_get_arg1(vcpu);
@@ -358,6 +364,11 @@ static int kvm_psci_1_x_call(struct kvm_vcpu *vcpu, u32 minor)
			if (minor >= 1)
				val = 0;
			break;
		case PSCI_1_3_FN_SYSTEM_OFF2:
		case PSCI_1_3_FN64_SYSTEM_OFF2:
			if (minor >= 3)
				val = PSCI_1_3_OFF_TYPE_HIBERNATE_OFF;
			break;
		}
		break;
	case PSCI_1_0_FN_SYSTEM_SUSPEND:
@@ -392,6 +403,33 @@ static int kvm_psci_1_x_call(struct kvm_vcpu *vcpu, u32 minor)
			break;
		}
		break;
	case PSCI_1_3_FN_SYSTEM_OFF2:
		kvm_psci_narrow_to_32bit(vcpu);
		fallthrough;
	case PSCI_1_3_FN64_SYSTEM_OFF2:
		if (minor < 3)
			break;

		arg = smccc_get_arg1(vcpu);
		/*
		 * SYSTEM_OFF2 defaults to HIBERNATE_OFF if arg1 is zero. arg2
		 * must be zero.
		 */
		if ((arg && arg != PSCI_1_3_OFF_TYPE_HIBERNATE_OFF) ||
		    smccc_get_arg2(vcpu) != 0) {
			val = PSCI_RET_INVALID_PARAMS;
			break;
		}
		kvm_psci_system_off2(vcpu);
		/*
		 * We shouldn't be going back to the guest after receiving a
		 * SYSTEM_OFF2 request. Preload a return value of
		 * INTERNAL_FAILURE should userspace ignore the exit and resume
		 * the vCPU.
		 */
		val = PSCI_RET_INTERNAL_FAILURE;
		ret = 0;
		break;
	default:
		return kvm_psci_0_2_call(vcpu);
	}
@@ -449,6 +487,10 @@ int kvm_psci_call(struct kvm_vcpu *vcpu)
	}

	switch (version) {
	case KVM_ARM_PSCI_1_3:
		return kvm_psci_1_x_call(vcpu, 3);
	case KVM_ARM_PSCI_1_2:
		return kvm_psci_1_x_call(vcpu, 2);
	case KVM_ARM_PSCI_1_1:
		return kvm_psci_1_x_call(vcpu, 1);
	case KVM_ARM_PSCI_1_0:
Loading